#include "gnunet_protocols.h"
#include "gnunet_constants.h"
#include "gnunet_resolver_service.h"
+#include "speedup.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+#include "gauger.h"
+#endif
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
/**
int ret;
/**
- * Inherited listening sockets, only
- * used during initialization.
- * FIXME: remove from struct
+ * If GNUNET_YES, consider unknown message types an error where the
+ * client is disconnected.
+ * FIXME: remove?
*/
- struct GNUNET_NETWORK_Handle **lsocks;
+ int require_found;
};
struct GNUNET_SERVICE_Client *prev;
/**
- * Server that this client belongs to.
+ * Service that this client belongs to.
*/
- struct GNUNET_SERVER_Handle *sh;
+ struct GNUNET_SERVICE_Handle *sh;
/**
* Socket of this client.
* @param cls our `struct GNUNET_SERVICE_Handle`
*/
static void
-service_main (void *cls)
+service_shutdown (void *cls)
{
struct GNUNET_SERVICE_Handle *sh = cls;
- struct GNUNET_SERVICE_Client *client;
- int alive;
switch (sh->options)
{
*/
static int
process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
- struct GNUNET_SERVICE_Context *sh,
+ struct GNUNET_SERVICE_Handle *sh,
const char *option)
{
char *opt;
{
LOG (GNUNET_ERROR_TYPE_WARNING,
_("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
- opt, sh->service_name, option);
+ opt,
+ sh->service_name,
+ option);
GNUNET_free (opt);
return GNUNET_SYSERR;
}
*/
static int
process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
- struct GNUNET_SERVICE_Context *sh,
+ struct GNUNET_SERVICE_Handle *sh,
const char *option)
{
char *opt;
}
+/**
+ * Add the given UNIX domain path as an address to the
+ * list (as the first entry).
+ *
+ * @param saddrs array to update
+ * @param saddrlens where to store the address length
+ * @param unixpath path to add
+ * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
+ * parameter is ignore on systems other than LINUX
+ */
+static void
+add_unixpath (struct sockaddr **saddrs,
+ socklen_t *saddrlens,
+ const char *unixpath,
+ int abstract)
+{
+#ifdef AF_UNIX
+ struct sockaddr_un *un;
+
+ un = GNUNET_new (struct sockaddr_un);
+ un->sun_family = AF_UNIX;
+ strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+ if (GNUNET_YES == abstract)
+ un->sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+ *saddrs = (struct sockaddr *) un;
+ *saddrlens = sizeof (struct sockaddr_un);
+#else
+ /* this function should never be called
+ * unless AF_UNIX is defined! */
+ GNUNET_assert (0);
+#endif
+}
+
+
/**
* Get the list of addresses that a server for the given service
* should bind to.
*/
static int
get_server_addresses (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct sockaddr ***addrs,
- socklen_t ** addr_lens)
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct sockaddr ***addrs,
+ socklen_t **addr_lens)
{
int disablev6;
struct GNUNET_NETWORK_Handle *desc;
*addrs = NULL;
*addr_lens = NULL;
desc = NULL;
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
+ if (GNUNET_CONFIGURATION_have_value (cfg,
+ service_name,
+ "DISABLEV6"))
{
if (GNUNET_SYSERR ==
(disablev6 =
- GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
+ GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ service_name,
+ "DISABLEV6")))
return GNUNET_SYSERR;
}
else
if (! disablev6)
{
/* probe IPv6 support */
- desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+ desc = GNUNET_NETWORK_socket_create (PF_INET6,
+ SOCK_STREAM,
+ 0);
if (NULL == desc)
{
- if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+ if ((ENOBUFS == errno) ||
+ (ENOMEM == errno) ||
+ (ENFILE == errno) ||
(EACCES == errno))
{
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "socket");
return GNUNET_SYSERR;
}
LOG (GNUNET_ERROR_TYPE_INFO,
_("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
- service_name, STRERROR (errno));
+ service_name,
+ STRERROR (errno));
disablev6 = GNUNET_YES;
}
else
}
port = 0;
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
+ if (GNUNET_CONFIGURATION_have_value (cfg,
+ service_name,
+ "PORT"))
{
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
- "PORT", &port))
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ service_name,
+ "PORT",
+ &port))
{
LOG (GNUNET_ERROR_TYPE_ERROR,
_("Require valid port number for service `%s' in configuration!\n"),
}
}
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
+ if (GNUNET_CONFIGURATION_have_value (cfg,
+ service_name,
+ "BINDTO"))
{
GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
- "BINDTO", &hostname));
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ service_name,
+ "BINDTO",
+ &hostname));
}
else
hostname = NULL;
abstract = GNUNET_NO;
#ifdef AF_UNIX
if ((GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
+ GNUNET_CONFIGURATION_have_value (cfg,
+ service_name,
+ "UNIXPATH")) &&
(GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
- &unixpath)) &&
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ service_name,
+ "UNIXPATH",
+ &unixpath)) &&
(0 < strlen (unixpath)))
{
/* probe UNIX support */
if (strlen (unixpath) >= sizeof (s_un.sun_path))
{
LOG (GNUNET_ERROR_TYPE_WARNING,
- _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+ _("UNIXPATH `%s' too long, maximum length is %llu\n"),
+ unixpath,
(unsigned long long) sizeof (s_un.sun_path));
unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
LOG (GNUNET_ERROR_TYPE_INFO,
}
if (NULL != unixpath)
{
- desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+ desc = GNUNET_NETWORK_socket_create (AF_UNIX,
+ SOCK_STREAM,
+ 0);
if (NULL == desc)
{
- if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+ if ((ENOBUFS == errno) ||
+ (ENOMEM == errno) ||
+ (ENFILE == errno) ||
(EACCES == errno))
{
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "socket");
GNUNET_free_non_null (hostname);
GNUNET_free (unixpath);
return GNUNET_SYSERR;
}
if (0 == port)
{
- saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ saddrs = GNUNET_new_array (2,
+ struct sockaddr *);
+ saddrlens = GNUNET_new_array (2,
+ socklen_t);
+ add_unixpath (saddrs,
+ saddrlens,
+ unixpath,
+ abstract);
GNUNET_free_non_null (unixpath);
GNUNET_free_non_null (hostname);
*addrs = saddrs;
"Resolving `%s' since that is where `%s' will bind to.\n",
hostname,
service_name);
- memset (&hints, 0, sizeof (struct addrinfo));
+ memset (&hints,
+ 0,
+ sizeof (struct addrinfo));
if (disablev6)
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_TCP;
- if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+ if ((0 != (ret = getaddrinfo (hostname,
+ NULL,
+ &hints,
+ &res))) ||
(NULL == res))
{
LOG (GNUNET_ERROR_TYPE_ERROR,
while (NULL != (pos = next))
{
next = pos->ai_next;
- if ((disablev6) && (pos->ai_family == AF_INET6))
+ if ( (disablev6) &&
+ (pos->ai_family == AF_INET6) )
continue;
i++;
}
resi = i;
if (NULL != unixpath)
resi++;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ saddrs = GNUNET_new_array (resi + 1,
+ struct sockaddr *);
+ saddrlens = GNUNET_new_array (resi + 1,
+ socklen_t);
i = 0;
if (NULL != unixpath)
{
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ add_unixpath (saddrs,
+ saddrlens,
+ unixpath,
+ abstract);
i++;
}
next = res;
while (NULL != (pos = next))
{
next = pos->ai_next;
- if ((disablev6) && (AF_INET6 == pos->ai_family))
+ if ( (disablev6) &&
+ (AF_INET6 == pos->ai_family) )
continue;
- if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+ if ( (IPPROTO_TCP != pos->ai_protocol) &&
+ (0 != pos->ai_protocol) )
continue; /* not TCP */
- if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+ if ( (SOCK_STREAM != pos->ai_socktype) &&
+ (0 != pos->ai_socktype) )
continue; /* huh? */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
- service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Service `%s' will bind to `%s'\n",
+ service_name,
+ GNUNET_a2s (pos->ai_addr,
+ pos->ai_addrlen));
if (AF_INET == pos->ai_family)
{
GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
saddrlens[i] = pos->ai_addrlen;
saddrs[i] = GNUNET_malloc (saddrlens[i]);
- GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ GNUNET_memcpy (saddrs[i],
+ pos->ai_addr,
+ saddrlens[i]);
((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
}
else
GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
saddrlens[i] = pos->ai_addrlen;
saddrs[i] = GNUNET_malloc (saddrlens[i]);
- GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ GNUNET_memcpy (saddrs[i],
+ pos->ai_addr,
+ saddrlens[i]);
((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
}
i++;
if (NULL != unixpath)
resi++;
i = 0;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ saddrs = GNUNET_new_array (resi + 1,
+ struct sockaddr *);
+ saddrlens = GNUNET_new_array (resi + 1,
+ socklen_t);
if (NULL != unixpath)
{
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ add_unixpath (saddrs,
+ saddrlens,
+ unixpath,
+ abstract);
i++;
}
saddrlens[i] = sizeof (struct sockaddr_in);
resi = 2;
if (NULL != unixpath)
resi++;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ saddrs = GNUNET_new_array (resi + 1,
+ struct sockaddr *);
+ saddrlens = GNUNET_new_array (resi + 1,
+ socklen_t);
i = 0;
if (NULL != unixpath)
{
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ add_unixpath (saddrs,
+ saddrlens,
+ unixpath,
+ abstract);
i++;
}
saddrlens[i] = sizeof (struct sockaddr_in6);
* Read listen sockets from the parent process (ARM).
*
* @param sh service context to initialize
- * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
- * and #GNUNET_SYSERR on error.
+ * @return NULL-terminated array of sockets on success,
+ * NULL if not ok (must bind yourself)
*/
-static int
-receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sh)
+static struct GNUNET_NETWORK_Handle **
+receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh)
{
+ static struct GNUNET_NETWORK_Handle **lsocks;
const char *env_buf;
int fail;
uint64_t count;
HANDLE lsocks_pipe;
env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
- if ((NULL == env_buf) || (strlen (env_buf) <= 0))
- return GNUNET_NO;
+ if ( (NULL == env_buf) ||
+ (strlen (env_buf) <= 0) )
+ return NULL;
/* Using W32 API directly here, because this pipe will
* never be used outside of this function, and it's just too much of a bother
* to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
*/
- lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
- if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
- return GNUNET_NO;
+ lsocks_pipe = (HANDLE) strtoul (env_buf,
+ NULL,
+ 10);
+ if ( (0 == lsocks_pipe) ||
+ (INVALID_HANDLE_VALUE == lsocks_pipe))
+ return NULL;
fail = 1;
do
{
int fail2;
DWORD rd;
- ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
- if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
+ ret = ReadFile (lsocks_pipe,
+ &count,
+ sizeof (count),
+ &rd,
+ NULL);
+ if ( (0 == ret) ||
+ (sizeof (count) != rd) ||
+ (0 == count) )
break;
- sh->lsocks =
- GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+ lsocks = GNUNET_new_array (count + 1,
+ struct GNUNET_NETWORK_Handle *);
fail2 = 1;
for (i = 0; i < count; i++)
uint64_t size;
SOCKET s;
- ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
- if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
+ ret = ReadFile (lsocks_pipe,
+ &size,
+ sizeof (size),
+ &rd,
+ NULL);
+ if ( (0 == ret) ||
+ (sizeof (size) != rd) ||
+ (sizeof (pi) != size) )
break;
- ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
- if ( (0 == ret) || (sizeof (pi) != rd))
+ ret = ReadFile (lsocks_pipe,
+ &pi,
+ sizeof (pi),
+ &rd,
+ NULL);
+ if ( (0 == ret) ||
+ (sizeof (pi) != rd))
break;
- s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
- sh->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
- if (NULL == sh->lsocks[i])
+ s = WSASocketA (pi.iAddressFamily,
+ pi.iSocketType,
+ pi.iProtocol,
+ &pi,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+ if (NULL == lsocks[i])
break;
else if (i == count - 1)
fail2 = 0;
}
if (fail2)
break;
- sh->lsocks[count] = NULL;
+ lsocks[count] = NULL;
fail = 0;
}
while (fail);
-
CloseHandle (lsocks_pipe);
if (fail)
{
LOG (GNUNET_ERROR_TYPE_ERROR,
_("Could not access a pre-bound socket, will try to bind myself\n"));
- for (i = 0; (i < count) && (NULL != sh->lsocks[i]); i++)
- GNUNET_break (0 == GNUNET_NETWORK_socket_close (sh->lsocks[i]));
- GNUNET_free_non_null (sh->lsocks);
- sh->lsocks = NULL;
- return GNUNET_NO;
+ for (i = 0; (i < count) && (NULL != lsocks[i]); i++)
+ GNUNET_break (0 == GNUNET_NETWORK_socket_close (lsocks[i]));
+ GNUNET_free (lsocks);
+ return NULL;
}
- return GNUNET_YES;
+ return lsocks;
}
#endif
port = 0;
break;
}
- sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
+ sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
+ SOCK_STREAM,
+ 0);
if (NULL == sock)
{
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "socket");
errno = 0;
return NULL;
}
/* bind the socket */
- if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
+ if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock,
+ server_addr,
+ socklen))
{
eno = errno;
if (EADDRINUSE != errno)
errno = eno;
return NULL;
}
- if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
+ if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock,
+ 5))
{
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
"listen");
}
-
-
/**
* Setup service handle
*
static int
setup_service (struct GNUNET_SERVICE_Handle *sh)
{
- struct GNUNET_TIME_Relative idleout;
int tolerant;
-
+ struct GNUNET_NETWORK_Handle **lsocks;
#ifndef MINGW
const char *nfds;
unsigned int cnt;
#endif
if (GNUNET_CONFIGURATION_have_value
- (sh->cfg, sh->service_name, "TOLERANT"))
+ (sh->cfg,
+ sh->service_name,
+ "TOLERANT"))
{
if (GNUNET_SYSERR ==
(tolerant =
- GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name,
+ GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
+ sh->service_name,
"TOLERANT")))
{
LOG (GNUNET_ERROR_TYPE_ERROR,
_("Specified value for `%s' of service `%s' is invalid\n"),
- "TOLERANT", sh->service_name);
+ "TOLERANT",
+ sh->service_name);
return GNUNET_SYSERR;
}
}
else
tolerant = GNUNET_NO;
+ lsocks = NULL;
#ifndef MINGW
errno = 0;
- if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
- (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
- (cnt + 4 < FD_SETSIZE))
+ if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+ (1 == SSCANF (nfds,
+ "%u",
+ &cnt)) &&
+ (cnt > 0) &&
+ (cnt < FD_SETSIZE) &&
+ (cnt + 4 < FD_SETSIZE) )
{
- sh->lsocks =
- GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
+ lsocks = GNUNET_new_array (cnt + 1,
+ struct GNUNET_NETWORK_Handle *);
while (0 < cnt--)
{
- flags = fcntl (3 + cnt, F_GETFD);
- if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
- (NULL ==
- (sh->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
+ flags = fcntl (3 + cnt,
+ F_GETFD);
+ if ( (flags < 0) ||
+ (0 != (flags & FD_CLOEXEC)) ||
+ (NULL ==
+ (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
{
LOG (GNUNET_ERROR_TYPE_ERROR,
- _
- ("Could not access pre-bound socket %u, will try to bind myself\n"),
+ _("Could not access pre-bound socket %u, will try to bind myself\n"),
(unsigned int) 3 + cnt);
cnt++;
- while (sh->lsocks[cnt] != NULL)
- GNUNET_break (0 == GNUNET_NETWORK_socket_close (sh->lsocks[cnt++]));
- GNUNET_free (sh->lsocks);
- sh->lsocks = NULL;
+ while (NULL != lsocks[cnt])
+ GNUNET_break (0 == GNUNET_NETWORK_socket_close (lsocks[cnt++]));
+ GNUNET_free (lsocks);
+ lsocks = NULL;
break;
}
}
unsetenv ("LISTEN_FDS");
}
#else
- if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+ if (NULL != getenv ("GNUNET_OS_READ_LSOCKS"))
{
- receive_sockets_from_parent (sh);
+ lsocks = receive_sockets_from_parent (sh);
putenv ("GNUNET_OS_READ_LSOCKS=");
}
#endif
- if (NULL != sh->lsocks)
+ if (NULL != lsocks)
{
/* listen only on inherited sockets if we have any */
- struct GNUNET_NETWORK_Handle **ls = sh->lsocks;
- for (; NULL != *ls; ls++)
+ struct GNUNET_NETWORK_Handle **ls;
+
+ for (ls = lsocks; NULL != *ls; ls++)
{
struct ServiceListenContext *slc;
slc = GNUNET_new (struct ServiceListenContext);
slc->listen_socket = *ls;
- GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
+ GNUNET_CONTAINER_DLL_insert (sh->slc_head,
+ sh->slc_tail,
+ slc);
}
- GNUNET_free_non_null (sh->lsocks);
+ GNUNET_free (lsocks);
}
else
{
socklen_t *addrlens;
int num;
- num = get_server_addresses (sh->service_name, sh->cfg,
- &addrs, &addrlens)));
+ num = get_server_addresses (sh->service_name,
+ sh->cfg,
+ &addrs,
+ &addrlens);
if (GNUNET_SYSERR == num)
return GNUNET_SYSERR;
struct ServiceListenContext *slc;
slc = GNUNET_new (struct ServiceListenContext);
- slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]);
+ slc->listen_socket = open_listen_socket (addrs[i],
+ addrlens[i]);
GNUNET_break (NULL != slc->listen_socket);
- GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
+ GNUNET_CONTAINER_DLL_insert (sh->slc_head,
+ sh->slc_tail,
+ slc);
}
}
sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
sh->match_uid =
- GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name,
+ GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
+ sh->service_name,
"UNIX_MATCH_UID");
sh->match_gid =
- GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name,
+ GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
+ sh->service_name,
"UNIX_MATCH_GID");
- process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
- process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
- process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
- process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
+ process_acl4 (&sh->v4_denied,
+ sh,
+ "REJECT_FROM");
+ process_acl4 (&sh->v4_allowed,
+ sh,
+ "ACCEPT_FROM");
+ process_acl6 (&sh->v6_denied,
+ sh,
+ "REJECT_FROM6");
+ process_acl6 (&sh->v6_allowed,
+ sh,
+ "ACCEPT_FROM6");
+ return GNUNET_OK;
+}
+
+/**
+ * Get the name of the user that'll be used
+ * to provide the service.
+ *
+ * @param sh service context
+ * @return value of the 'USERNAME' option
+ */
+static char *
+get_user_name (struct GNUNET_SERVICE_Handle *sh)
+{
+ char *un;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
+ sh->service_name,
+ "USERNAME",
+ &un))
+ return NULL;
+ return un;
+}
+
+
+/**
+ * Set user ID.
+ *
+ * @param sh service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+set_user_id (struct GNUNET_SERVICE_Handle *sh)
+{
+ char *user;
+
+ if (NULL == (user = get_user_name (sh)))
+ return GNUNET_OK; /* keep */
+#ifndef MINGW
+ struct passwd *pws;
+
+ errno = 0;
+ pws = getpwnam (user);
+ if (NULL == pws)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Cannot obtain information about user `%s': %s\n"),
+ user,
+ errno == 0 ? _("No such user") : STRERROR (errno));
+ GNUNET_free (user);
+ return GNUNET_SYSERR;
+ }
+ if ( (0 != setgid (pws->pw_gid)) ||
+ (0 != setegid (pws->pw_gid)) ||
+#if HAVE_INITGROUPS
+ (0 != initgroups (user,
+ pws->pw_gid)) ||
+#endif
+ (0 != setuid (pws->pw_uid)) ||
+ (0 != seteuid (pws->pw_uid)))
+ {
+ if ((0 != setregid (pws->pw_gid,
+ pws->pw_gid)) ||
+ (0 != setreuid (pws->pw_uid,
+ pws->pw_uid)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Cannot change user/group to `%s': %s\n"),
+ user,
+ STRERROR (errno));
+ GNUNET_free (user);
+ return GNUNET_SYSERR;
+ }
+ }
+#endif
+ GNUNET_free (user);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Get the name of the file where we will
+ * write the PID of the service.
+ *
+ * @param sh service context
+ * @return name of the file for the process ID
+ */
+static char *
+get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
+{
+ char *pif;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
+ sh->service_name,
+ "PIDFILE",
+ &pif))
+ return NULL;
+ return pif;
+}
+
+
+/**
+ * Delete the PID file that was created by our parent.
+ *
+ * @param sh service context
+ */
+static void
+pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
+{
+ char *pif = get_pid_file_name (sh);
+
+ if (NULL == pif)
+ return; /* no PID file */
+ if (0 != UNLINK (pif))
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
+ "unlink",
+ pif);
+ GNUNET_free (pif);
+}
+
+
+/**
+ * Detach from terminal.
+ *
+ * @param sh service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+detach_terminal (struct GNUNET_SERVICE_Handle *sh)
+{
+#ifndef MINGW
+ pid_t pid;
+ int nullfd;
+ int filedes[2];
+
+ if (0 != PIPE (filedes))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "pipe");
+ return GNUNET_SYSERR;
+ }
+ pid = fork ();
+ if (pid < 0)
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "fork");
+ return GNUNET_SYSERR;
+ }
+ if (0 != pid)
+ {
+ /* Parent */
+ char c;
+
+ GNUNET_break (0 == CLOSE (filedes[1]));
+ c = 'X';
+ if (1 != READ (filedes[0],
+ &c,
+ sizeof (char)))
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+ "read");
+ fflush (stdout);
+ switch (c)
+ {
+ case '.':
+ exit (0);
+ case 'I':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process failed to initialize\n"));
+ break;
+ case 'S':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process could not initialize server function\n"));
+ break;
+ case 'X':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process failed to report status\n"));
+ break;
+ }
+ exit (1); /* child reported error */
+ }
+ GNUNET_break (0 == CLOSE (0));
+ GNUNET_break (0 == CLOSE (1));
+ GNUNET_break (0 == CLOSE (filedes[0]));
+ nullfd = OPEN ("/dev/null",
+ O_RDWR | O_APPEND);
+ if (nullfd < 0)
+ return GNUNET_SYSERR;
+ /* set stdin/stdout to /dev/null */
+ if ( (dup2 (nullfd, 0) < 0) ||
+ (dup2 (nullfd, 1) < 0) )
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "dup2");
+ (void) CLOSE (nullfd);
+ return GNUNET_SYSERR;
+ }
+ (void) CLOSE (nullfd);
+ /* Detach from controlling terminal */
+ pid = setsid ();
+ if (-1 == pid)
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "setsid");
+ sh->ready_confirm_fd = filedes[1];
+#else
+ /* FIXME: we probably need to do something else
+ * elsewhere in order to fork the process itself... */
+ FreeConsole ();
+#endif
return GNUNET_OK;
}
const char *xdg;
char *logfile;
int do_daemonize;
- unsigned int i;
unsigned long long skew_offset;
unsigned long long skew_variance;
long long clock_offset;
- struct GNUNET_SERVICE_Context sh;
struct GNUNET_CONFIGURATION_Handle *cfg;
+ int ret;
+ int err;
struct GNUNET_GETOPT_CommandLineOption service_options[] = {
GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
sh.handlers = handlers;
/* setup subsystems */
- ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+ ret = GNUNET_GETOPT_run (service_name,
+ service_options,
+ argc,
+ argv);
if (GNUNET_SYSERR == ret)
goto shutdown;
if (GNUNET_NO == ret)
err = 0;
goto shutdown;
}
- if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
- HANDLE_ERROR;
+ if (GNUNET_OK != GNUNET_log_setup (service_name,
+ loglev,
+ logfile))
+ {
+ GNUNET_break (0);
+ goto shutdown;
+ }
if (NULL == opt_cfg_filename)
opt_cfg_filename = GNUNET_strdup (cfg_filename);
if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
{
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename))
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+ opt_cfg_filename))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Malformed configuration file `%s', exit ...\n"),
}
else
{
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+ NULL))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Malformed configuration, exit ...\n"));
goto shutdown;
}
- if (0 != strcmp (opt_cfg_filename, cfg_filename))
+ if (0 != strcmp (opt_cfg_filename,
+ cfg_filename))
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Could not access configuration file `%s'\n"),
opt_cfg_filename);
}
if (GNUNET_OK != setup_service (&sh))
goto shutdown;
- if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh)))
+ if ( (1 == do_daemonize) &&
+ (GNUNET_OK != detach_terminal (&sh)) )
{
GNUNET_break (0);
goto shutdown;
service_name,
opt_cfg_filename);
if ((GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (sh.cfg, "TESTING",
- "SKEW_OFFSET", &skew_offset)) &&
+ GNUNET_CONFIGURATION_get_value_number (sh.cfg,
+ "TESTING",
+ "SKEW_OFFSET",
+ &skew_offset)) &&
(GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (sh.cfg, "TESTING",
- "SKEW_VARIANCE", &skew_variance)))
+ GNUNET_CONFIGURATION_get_value_number (sh.cfg,
+ "TESTING",
+ "SKEW_VARIANCE",
+ &skew_variance)))
{
clock_offset = skew_offset - skew_variance;
GNUNET_TIME_set_offset (clock_offset);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Skewing clock by %dll ms\n",
+ clock_offset);
}
/* actually run service */
err = 0;
- GNUNET_SCHEDULER_run (&service_main, &sh);
+ GNUNET_SCHEDULER_run (&service_main,
+ &sh);
/* shutdown */
- if ((1 == do_daemonize) && (NULL != sh.server))
+ if (1 == do_daemonize)
pid_file_delete (&sh);
- GNUNET_free_non_null (sh.my_handlers);
shutdown:
if (-1 != sh.ready_confirm_fd)
char *counter;
if ( (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (sh.cfg, service_name,
+ GNUNET_CONFIGURATION_have_value (sh.cfg,
+ service_name,
"GAUGER_HEAP")) &&
(GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sh.cfg, service_name,
+ GNUNET_CONFIGURATION_get_value_string (sh.cfg,
+ service_name,
"GAUGER_HEAP",
&counter)) )
{
struct mallinfo mi;
mi = mallinfo ();
- GAUGER (service_name, counter, mi.usmblks, "blocks");
+ GAUGER (service_name,
+ counter,
+ mi.usmblks,
+ "blocks");
GNUNET_free (counter);
}
}
GNUNET_SPEEDUP_stop_ ();
GNUNET_CONFIGURATION_destroy (cfg);
- while (NULL != sh->slc_head)
+ while (NULL != sh.slc_head)
{
- struct ServiceListenContext *slc = sh->slc_head;
- sh->slc_head = slc->next;
+ struct ServiceListenContext *slc = sh.slc_head;
+
+ sh.slc_head = slc->next;
// FIXME: destroy slc
GNUNET_free (slc);
}
{
struct ServiceListenContext *slc;
- for (slc = slc_head; NULL != slc; slc = slc->next)
+ for (slc = sh->slc_head; NULL != slc; slc = slc->next)
{
if (NULL != slc->listen_task)
- {
- GNUNET_SCHEDULER_cancel (slc->listen_task);
- slc->listen_task = NULL;
- }
+ {
+ GNUNET_SCHEDULER_cancel (slc->listen_task);
+ slc->listen_task = NULL;
+ }
}
}
const struct GNUNET_MessageHeader *msg,
void *impl_state)
{
- struct GNUNET_SERVICE_Client *client = cls;
+ // struct GNUNET_SERVICE_Client *client = cls;
// FIXME 1: setup "client->send_task" for transmission.
// FIXME 2: I seriously hope we do not need to make a copy of `msg`!
service_mq_cancel (struct GNUNET_MQ_Handle *mq,
void *impl_state)
{
- struct GNUNET_SERVICE_Client *client = cls;
+ // struct GNUNET_SERVICE_Client *client = cls;
// FIXME: stop transmission! (must be possible, otherwise
// we must have told MQ that the message was sent!)
* the scope of this callback.
*
* @param cls closure with the `struct GNUNET_SERVICE_Client *`
- * @param client closure with the `struct GNUNET_SERVICE_Client *`
+ * @param client_cls closure with the `struct GNUNET_SERVICE_Client *`
* @param message the actual message
* @return #GNUNET_OK on success (always)
*/
static int
service_client_mst_cb (void *cls,
- void *client,
+ void *client_cls,
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_SERVICE_Client *client = cls;
client->mq);
GNUNET_MQ_set_handlers_closure (client->mq,
client->user_context);
- client->recv_task = GNUNET_SCHEDULER_add_read (client->sock,
- &service_client_recv,
- client);
+ client->recv_task
+ = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ client->sock,
+ &service_client_recv,
+ client);
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param add the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+ const struct in_addr *add)
+{
+ unsigned int i;
+
+ if (NULL == list)
+ return GNUNET_NO;
+ i = 0;
+ while ( (0 != list[i].network.s_addr) ||
+ (0 != list[i].netmask.s_addr) )
+ {
+ if ((add->s_addr & list[i].netmask.s_addr) ==
+ (list[i].network.s_addr & list[i].netmask.s_addr))
+ return GNUNET_YES;
+ i++;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param ip the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+ const struct in6_addr *ip)
+{
+ unsigned int i;
+ unsigned int j;
+ struct in6_addr zero;
+
+ if (NULL == list)
+ return GNUNET_NO;
+ memset (&zero,
+ 0,
+ sizeof (struct in6_addr));
+ i = 0;
+NEXT:
+ while (0 != memcmp (&zero,
+ &list[i].network,
+ sizeof (struct in6_addr)))
+ {
+ for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
+ if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
+ (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
+ {
+ i++;
+ goto NEXT;
+ }
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
}
accept_client (void *cls)
{
struct ServiceListenContext *slc = cls;
+ struct GNUNET_SERVICE_Handle *sh = slc->sh;
slc->listen_task = NULL;
while (1)
{
struct GNUNET_NETWORK_Handle *sock;
- struct sockaddr_in *v4;
- struct sockaddr_in6 *v6;
+ const struct sockaddr_in *v4;
+ const struct sockaddr_in6 *v6;
struct sockaddr_storage sa;
socklen_t addrlen;
int ok;
&addrlen);
if (NULL == sock)
break;
- switch (sa.sa_family)
+ switch (sa.ss_family)
{
case AF_INET:
GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
- v4 = (const struct sockaddr_in *) addr;
+ v4 = (const struct sockaddr_in *) &sa;
ok = ( ( (NULL == sh->v4_allowed) ||
(check_ipv4_listed (sh->v4_allowed,
- &i4->sin_addr))) &&
+ &v4->sin_addr))) &&
( (NULL == sh->v4_denied) ||
(! check_ipv4_listed (sh->v4_denied,
- &i4->sin_addr)) ) );
+ &v4->sin_addr)) ) );
break;
case AF_INET6:
GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
- v6 = (const struct sockaddr_in6 *) addr;
+ v6 = (const struct sockaddr_in6 *) &sa;
ok = ( ( (NULL == sh->v6_allowed) ||
(check_ipv6_listed (sh->v6_allowed,
- &i6->sin6_addr))) &&
+ &v6->sin6_addr))) &&
( (NULL == sh->v6_denied) ||
(! check_ipv6_listed (sh->v6_denied,
- &i6->sin6_addr)) ) );
+ &v6->sin6_addr)) ) );
break;
#ifndef WINDOWS
case AF_UNIX:
default:
LOG (GNUNET_ERROR_TYPE_WARNING,
_("Unknown address family %d\n"),
- addr->sa_family);
- return GNUNET_SYSERR;
+ sa.ss_family);
+ return;
}
if (! ok)
{
start_client (slc->sh,
sock);
}
- slc->listen_task = GNUNET_SCHEDULER_add_read (slc->listen_socket,
- &accept_client,
- slc);
+ slc->listen_task
+ = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ slc->listen_socket,
+ &accept_client,
+ slc);
}
{
struct ServiceListenContext *slc;
- for (slc = slc_head; NULL != slc; slc = slc->next)
+ for (slc = sh->slc_head; NULL != slc; slc = slc->next)
{
GNUNET_assert (NULL == slc->listen_task);
- slc->listen_task = GNUNET_SCHEDULER_add_read (slc->listen_socket,
- &accept_client,
- slc);
+ slc->listen_task
+ = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ slc->listen_socket,
+ &accept_client,
+ slc);
}
}
GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
{
c->is_monitor = GNUNET_YES;
- if ( (GNUNET_YES == sh->got_shutdown) &&
- (GNUNET_NO == have_non_monitor_clients (sh)) )
- GNUNET_SERVICE_shutdown (sh);
+ if ( (GNUNET_YES == c->sh->got_shutdown) &&
+ (GNUNET_NO == have_non_monitor_clients (c->sh)) )
+ GNUNET_SERVICE_shutdown (c->sh);
}