Commit b961c279 authored by William Jon McCann's avatar William Jon McCann

Add skeleton for gobject redesign. Doesn't really work but should compile.

svn path=/branches/mccann-gobject/; revision=4911
parent 088ff8db
NULL =
SUBDIRS = \
po \
data \
config \
pixmaps \
common \
......@@ -9,6 +9,7 @@ SUBDIRS = \
gui \
utils \
docs \
po \
$(NULL)
# add these when help gets added back
......
......@@ -28,6 +28,8 @@ noinst_LIBRARIES = \
$(null)
libgdmcommon_a_SOURCES = \
gdm-address.h \
gdm-address.c \
gdm-common.h \
gdm-common.c \
gdm-common-config.h \
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#ifndef G_OS_WIN32
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <glib-object.h>
#include "gdm-address.h"
struct _GdmAddress
{
struct sockaddr_storage *ss;
};
/* Register GdmAddress in the glib type system */
GType
gdm_address_get_type (void)
{
static GType addr_type = 0;
if (addr_type == 0) {
addr_type = g_boxed_type_register_static ("GdmAddress",
(GBoxedCopyFunc) gdm_address_copy,
(GBoxedFreeFunc) gdm_address_free);
}
return addr_type;
}
/**
* gdm_address_get_family_type:
* @address: A pointer to a #GdmAddress
*
* Use this function to retrive the address family of @address.
*
* Return value: The address family of @address.
**/
int
gdm_address_get_family_type (GdmAddress *address)
{
g_return_val_if_fail (address != NULL, -1);
return address->ss->ss_family;
}
/**
* gdm_address_new_from_sockaddr:
* @sa: A pointer to a sockaddr_storage.
*
* Creates a new #GdmAddress from @ss.
*
* Return value: The new #GdmAddress
* or %NULL if @sa was invalid or the address family isn't supported.
**/
GdmAddress *
gdm_address_new_from_sockaddr_storage (struct sockaddr_storage *ss)
{
GdmAddress *addr;
g_return_val_if_fail (ss != NULL, NULL);
addr = g_new0 (GdmAddress, 1);
addr->ss = g_memdup (ss, sizeof (struct sockaddr_storage));
return addr;
}
/**
* gdm_address_get_sockaddr_storage:
* @address: A #GdmAddress
*
* This function tanslates @address into a equivalent
* sockaddr_storage
*
* Return value: A newly allocated sockaddr_storage structure the caller must free
* or %NULL if @address did not point to a valid #GdmAddress.
**/
struct sockaddr_storage *
gdm_address_get_sockaddr_storage (GdmAddress *address)
{
struct sockaddr_storage *ss;
g_return_val_if_fail (address != NULL, NULL);
ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
return ss;
}
struct sockaddr_storage *
gdm_address_peek_sockaddr_storage (GdmAddress *address)
{
g_return_val_if_fail (address != NULL, NULL);
return address->ss;
}
static gboolean
v4_v4_equal (const struct sockaddr_in *a,
const struct sockaddr_in *b)
{
return a->sin_addr.s_addr == b->sin_addr.s_addr;
}
#ifdef ENABLE_IPV6
static gboolean
v6_v6_equal (struct sockaddr_in6 *a,
struct sockaddr_in6 *b)
{
return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
}
#endif
#define SA(__s) ((struct sockaddr *) __s)
#define SIN(__s) ((struct sockaddr_in *) __s)
#define SIN6(__s) ((struct sockaddr_in6 *) __s)
gboolean
gdm_address_equal (GdmAddress *a,
GdmAddress *b)
{
guint8 fam_a;
guint8 fam_b;
g_return_val_if_fail (a != NULL || a->ss != NULL, FALSE);
g_return_val_if_fail (b != NULL || b->ss != NULL, FALSE);
fam_a = a->ss->ss_family;
fam_b = b->ss->ss_family;
if (fam_a == AF_INET && fam_b == AF_INET) {
return v4_v4_equal (SIN (a->ss), SIN (b->ss));
}
#ifdef ENABLE_IPV6
else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss));
}
#endif
return FALSE;
}
char *
gdm_address_get_hostname (GdmAddress *address)
{
char host [NI_MAXHOST];
g_return_val_if_fail (address != NULL || address->ss != NULL, NULL);
host [0] = '\0';
getnameinfo ((const struct sockaddr *)address->ss,
sizeof (struct sockaddr_storage),
host, sizeof (host),
NULL, 0,
0);
return g_strdup (host);
}
void
gdm_address_get_numeric_info (GdmAddress *address,
char **hostp,
char **servp)
{
char host [NI_MAXHOST];
char serv [NI_MAXSERV];
g_return_if_fail (address != NULL || address->ss != NULL);
host [0] = '\0';
serv [0] = '\0';
getnameinfo ((const struct sockaddr *)address->ss,
sizeof (struct sockaddr_storage),
host, sizeof (host),
serv, sizeof (serv),
NI_NUMERICHOST | NI_NUMERICSERV);
if (servp != NULL) {
*servp = g_strdup (serv);
}
if (hostp != NULL) {
*hostp = g_strdup (host);
}
}
gboolean
gdm_address_is_loopback (GdmAddress *address)
{
g_return_val_if_fail (address != NULL || address->ss != NULL, FALSE);
switch (address->ss->ss_family){
#ifdef AF_INET6
case AF_INET6:
return IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)address->ss)->sin6_addr);
break;
#endif
case AF_INET:
return (INADDR_LOOPBACK == (((struct sockaddr_in *)address->ss)->sin_addr.s_addr));
break;
default:
break;
}
return FALSE;
}
const GList *
gdm_address_peek_local_list (void)
{
static GList *the_list = NULL;
static time_t last_time = 0;
char hostbuf[BUFSIZ];
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo *res;
/* Don't check more then every 5 seconds */
if (last_time + 5 > time (NULL)) {
return the_list;
}
g_list_foreach (the_list, (GFunc)gdm_address_free, NULL);
g_list_free (the_list);
the_list = NULL;
last_time = time (NULL);
hostbuf[BUFSIZ-1] = '\0';
if (gethostname (hostbuf, BUFSIZ-1) != 0) {
g_debug ("%s: Could not get server hostname, using localhost", "gdm_peek_local_address_list");
snprintf (hostbuf, BUFSIZ-1, "localhost");
}
memset (&hints, 0, sizeof (hints));
hints.ai_family = AF_INET;
#ifdef ENABLE_IPV6
hints.ai_family |= AF_INET6;
#endif
if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) {
g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list");
return NULL;
}
for (res = result; res != NULL; res = res->ai_next) {
GdmAddress *address;
address = gdm_address_new_from_sockaddr_storage ((struct sockaddr_storage *)res->ai_addr);
the_list = g_list_append (the_list, address);
}
if (result != NULL) {
freeaddrinfo (result);
result = NULL;
}
return the_list;
}
gboolean
gdm_address_is_local (GdmAddress *address)
{
const GList *list;
if (gdm_address_is_loopback (address)) {
return TRUE;
}
list = gdm_address_peek_local_list ();
while (list != NULL) {
GdmAddress *addr = list->data;
if (gdm_address_equal (address, addr)) {
return TRUE;
}
list = list->next;
}
return FALSE;
}
/**
* gdm_address_copy:
* @address: A #GdmAddress.
*
* Duplicates @address.
*
* Return value: Duplicated @address or %NULL if @address was not valid.
**/
GdmAddress *
gdm_address_copy (GdmAddress *address)
{
GdmAddress *addr;
g_return_val_if_fail (address != NULL, NULL);
addr = g_new0 (GdmAddress, 1);
addr->ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
return addr;
}
/**
* gdm_address_free:
* @address: A #GdmAddress.
*
* Frees the memory allocated for @address.
**/
void
gdm_address_free (GdmAddress *address)
{
g_return_if_fail (address != NULL);
g_free (address->ss);
g_free (address);
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GDM_ADDRESS_H
#define __GDM_ADDRESS_H
#include <glib-object.h>
#ifndef G_OS_WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#else
#include <winsock2.h>
#undef interface
#endif
G_BEGIN_DECLS
#define GDM_TYPE_ADDRESS (gdm_address_get_type ())
typedef struct _GdmAddress GdmAddress;
GType gdm_address_get_type (void);
GdmAddress * gdm_address_new_from_sockaddr_storage (struct sockaddr_storage *ss);
int gdm_address_get_family_type (GdmAddress *address);
struct sockaddr_storage *gdm_address_get_sockaddr_storage (GdmAddress *address);
struct sockaddr_storage *gdm_address_peek_sockaddr_storage (GdmAddress *address);
char * gdm_address_get_hostname (GdmAddress *address);
void gdm_address_get_numeric_info (GdmAddress *address,
char **numeric_hostname,
char **service);
gboolean gdm_address_is_local (GdmAddress *address);
gboolean gdm_address_is_loopback (GdmAddress *address);
gboolean gdm_address_equal (GdmAddress *a,
GdmAddress *b);
GdmAddress * gdm_address_copy (GdmAddress *address);
void gdm_address_free (GdmAddress *address);
const GList * gdm_address_peek_local_list (void);
G_END_DECLS
#endif /* __GDM_ADDRESS_H */
......@@ -25,98 +25,726 @@
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <setjmp.h>
#include <dirent.h>
#ifdef HAVE_CRT_EXTERNS_H
#include <crt_externs.h>
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include "gdm-common.h"
static gboolean
v4_v4_equal (const struct sockaddr_in *a,
const struct sockaddr_in *b)
int
gdm_fdgetc (int fd)
{
return a->sin_addr.s_addr == b->sin_addr.s_addr;
char buf[1];
int bytes;
VE_IGNORE_EINTR (bytes = read (fd, buf, 1));
if (bytes != 1)
return EOF;
else
return (int)buf[0];
}
#ifdef ENABLE_IPV6
static gboolean
v6_v6_equal (struct sockaddr_in6 *a,
struct sockaddr_in6 *b)
char *
gdm_fdgets (int fd)
{
return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
int c;
int bytes = 0;
GString *gs = g_string_new (NULL);
for (;;) {
c = gdm_fdgetc (fd);
if (c == '\n')
return g_string_free (gs, FALSE);
/* on EOF */
if (c < 0) {
if (bytes == 0) {
g_string_free (gs, TRUE);
return NULL;
} else {
return g_string_free (gs, FALSE);
}
} else {
bytes++;
g_string_append_c (gs, c);
}
}
}
#endif
#define SA(__s) ((struct sockaddr *) __s)
#define SIN(__s) ((struct sockaddr_in *) __s)
#define SIN6(__s) ((struct sockaddr_in6 *) __s)
void
gdm_fdprintf (int fd, const gchar *format, ...)
{
va_list args;
gchar *s;
int written, len;
gboolean
gdm_address_equal (struct sockaddr_storage *sa,
struct sockaddr_storage *sb)
va_start (args, format);
s = g_strdup_vprintf (format, args);
va_end (args);
len = strlen (s);
if (len == 0) {
g_free (s);
return;
}
written = 0;
while (written < len) {
int w;
VE_IGNORE_EINTR (w = write (fd, &s[written], len - written));
if (w < 0)
/* evil! */
break;
written += w;
}
g_free (s);
}
void
gdm_close_all_descriptors (int from, int except, int except2)
{
guint8 fam_a;
guint8 fam_b;
DIR *dir;
struct dirent *ent;
GSList *openfds = NULL;
/*
* Evil, but less evil then going to _SC_OPEN_MAX
* which can be very VERY large
*/
dir = opendir ("/proc/self/fd/"); /* This is the Linux dir */
if (dir == NULL)
dir = opendir ("/dev/fd/"); /* This is the FreeBSD dir */
if G_LIKELY (dir != NULL) {
GSList *li;
while ((ent = readdir (dir)) != NULL) {
int fd;
if (ent->d_name[0] == '.')
continue;
fd = atoi (ent->d_name);
if (fd >= from && fd != except && fd != except2)
openfds = g_slist_prepend (openfds, GINT_TO_POINTER (fd));
}
closedir (dir);
for (li = openfds; li != NULL; li = li->next) {
int fd = GPOINTER_TO_INT (li->data);
VE_IGNORE_EINTR (close (fd));
}
g_slist_free (openfds);
} else {
int i;
int max = sysconf (_SC_OPEN_MAX);
/*
* Don't go higher then this. This is
* a safety measure to not hang on crazy
* systems
*/
if G_UNLIKELY (max > 4096) {
/* FIXME: warn about this perhaps */
/*
* Try an open, in case we're really
* leaking fds somewhere badly, this
* should be very high
*/
i = gdm_open_dev_null (O_RDONLY);
max = MAX (i+1, 4096);
}
for (i = from; i < max; i++) {
if G_LIKELY (i != except && i != except2)
VE_IGNORE_EINTR (close (i));
}
}
}
void
gdm_signal_ignore (int signal)
{
struct sigaction ign_signal;
ign_signal.sa_handler = SIG_IGN;
ign_signal.sa_flags = SA_RESTART;
sigemptyset (&ign_signal.sa_mask);
if G_UNLIKELY (sigaction (signal, &ign_signal, NULL) < 0)
g_warning (_("%s: Error setting signal %d to %s"),
"gdm_signal_ignore", signal, "SIG_IGN");
}
void
gdm_signal_default (int signal)
{
struct sigaction def_signal;
g_return_val_if_fail (sa != NULL, FALSE);
g_return_val_if_fail (sb != NULL, FALSE);
def_signal.sa_handler = SIG_DFL;
def_signal.sa_flags = SA_RESTART;
sigemptyset (&def_signal.sa_mask);
fam_a = sa->ss_family;
fam_b = sb->ss_family;
if G_UNLIKELY (sigaction (signal, &def_signal, NULL) < 0)
g_warning (_("%s: Error setting signal %d to %s"),
"gdm_signal_ignore", signal, "SIG_DFL");
}
if (fam_a == AF_INET && fam_b == AF_INET) {
return v4_v4_equal (SIN (sa), SIN (sb));
int
gdm_open_dev_null (mode_t mode)
{
int ret;
VE_IGNORE_EINTR (ret = open ("/dev/null", mode));
if G_UNLIKELY (ret < 0) {
/*
* Never output anything, we're likely in some
* strange state right now
*/
gdm_signal_ignore (SIGPIPE);
VE_IGNORE_EINTR (close (2));
g_error ("Cannot open /dev/null, system on crack!");
}
#ifdef ENABLE_IPV6
else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
return v6_v6_equal (SIN6 (sa), SIN6 (sb));
return ret;
}
char *
gdm_make_filename (const char *dir,
const char *name,
const char *extension)
{
char *base = g_strconcat (name, extension, NULL);
char *full = g_build_filename (dir, base, NULL);
g_free (base);
return full;
}
static int sigchld_blocked = 0;
static sigset_t sigchldblock_mask, sigchldblock_oldmask;
static int sigterm_blocked = 0;
static sigset_t sigtermblock_mask, sigtermblock_oldmask;
static int sigusr2_blocked = 0;
static sigset_t sigusr2block_mask, sigusr2block_oldmask;
void
gdm_sigchld_block_push (void)
{
sigchld_blocked++;
if (sigchld_blocked == 1) {
/* Set signal mask */
sigemptyset (&sigchldblock_mask);
sigaddset (&sigchldblock_mask, SIGCHLD);
sigprocmask (SIG_BLOCK, &sigchldblock_mask, &sigchldblock_oldmask);
}
#endif
return FALSE;
}
gboolean
gdm_address_is_loopback (struct sockaddr_storage *sa)
void
gdm_sigchld_block_pop (void)
{
sigchld_blocked --;
if (sigchld_blocked == 0) {
/* Reset signal mask back */
sigprocmask (SIG_SETMASK, &sigchldblock_oldmask, NULL);
}
}
void
gdm_sigterm_block_push (void)
{
sigterm_blocked++;
if (sigterm_blocked == 1) {
/* Set signal mask */
sigemptyset (&sigtermblock_mask);
sigaddset (&sigtermblock_mask, SIGTERM);
sigaddset (&sigtermblock_mask, SIGINT);
sigaddset (&sigtermblock_mask, SIGHUP);
sigprocmask (SIG_BLOCK, &sigtermblock_mask, &sigtermblock_oldmask);
}
}
void
gdm_sigterm_block_pop (void)