/** * Actually start the process for the given service. * * @param sl identifies service to start */ static void start_process (struct ServiceList *sl) { char *loprefix; char *options; char *optpos; char *optend; const char *next; int use_debug; char b; char *val; struct ServiceListeningInfo *sli; SOCKTYPE *lsocks; unsigned int ls; /* calculate listen socket list */ lsocks = NULL; ls = 0; for (sli = sl->listen_head; NULL != sli; sli = sli->next) { GNUNET_array_append (lsocks, ls, GNUNET_NETWORK_get_fd (sli->listen_socket)); if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_NO_TASK; } } #if WINDOWS GNUNET_array_append (lsocks, ls, INVALID_SOCKET); #else GNUNET_array_append (lsocks, ls, -1); #endif /* obtain configuration */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", &loprefix)) loprefix = GNUNET_strdup (prefix_command); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", &options)) { options = GNUNET_strdup (final_option); if (NULL == strstr (options, "%")) { /* replace '{}' with service name */ while (NULL != (optpos = strstr (options, "{}"))) { optpos[0] = '%'; optpos[1] = 's'; GNUNET_asprintf (&optpos, options, sl->name); GNUNET_free (options); options = optpos; } /* replace '$PATH' with value associated with "PATH" */ while (NULL != (optpos = strstr (options, "$"))) { optend = optpos + 1; while (isupper ((unsigned char) *optend)) optend++; b = *optend; if ('\0' == b) next = ""; else next = optend + 1; *optend = '\0'; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", optpos + 1, &val)) val = GNUNET_strdup (""); *optpos = '\0'; GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); GNUNET_free (options); GNUNET_free (val); options = optpos; } } } use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); /* actually start process */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service `%s' using binary `%s' and configuration `%s'\n", sl->name, sl->binary, sl->config); GNUNET_assert (NULL == sl->proc); if (GNUNET_YES == use_debug) sl->proc = do_start_process (sl->pipe_control, lsocks, loprefix, sl->binary, "-c", sl->config, "-L", "DEBUG", options, NULL); else sl->proc = do_start_process (sl->pipe_control, lsocks, loprefix, sl->binary, "-c", sl->config, options, NULL); if (sl->proc == NULL) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), sl->name); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name); /* clean up */ GNUNET_free (loprefix); GNUNET_free (options); GNUNET_array_grow (lsocks, ls, 0); }
/** * Create a connection handle by accepting on a listen socket. This * function may block if the listen socket has no connection ready. * * @param access function to use to check if access is allowed * @param access_cls closure for access * @param lsock listen socket * @return the connection handle, NULL on error */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle *lsock) { struct GNUNET_CONNECTION_Handle *connection; char addr[128]; socklen_t addrlen; struct GNUNET_NETWORK_Handle *sock; int aret; struct sockaddr_in *v4; struct sockaddr_in6 *v6; struct sockaddr *sa; void *uaddr; struct GNUNET_CONNECTION_Credentials *gcp; struct GNUNET_CONNECTION_Credentials gc; #ifdef SO_PEERCRED struct ucred uc; socklen_t olen; #endif addrlen = sizeof (addr); sock = GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen); if (NULL == sock) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept"); return NULL; } if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t))) { GNUNET_break (0); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); return NULL; } sa = (struct sockaddr *) addr; v6 = (struct sockaddr_in6 *) addr; if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr))) { /* convert to V4 address */ v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); memset (v4, 0, sizeof (struct sockaddr_in)); v4->sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4->sin_len = (u_char) sizeof (struct sockaddr_in); #endif memcpy (&v4->sin_addr, &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) - sizeof (struct in_addr)], sizeof (struct in_addr)); v4->sin_port = v6->sin6_port; uaddr = v4; addrlen = sizeof (struct sockaddr_in); } else { uaddr = GNUNET_malloc (addrlen); memcpy (uaddr, addr, addrlen); } gcp = NULL; gc.uid = 0; gc.gid = 0; if (AF_UNIX == sa->sa_family) { #if HAVE_GETPEEREID /* most BSDs */ if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid)) gcp = &gc; #else #ifdef SO_PEERCRED /* largely traditional GNU/Linux */ olen = sizeof (uc); if ((0 == getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc, &olen)) && (olen == sizeof (uc))) { gc.uid = uc.uid; gc.gid = uc.gid; gcp = &gc; } #else #if HAVE_GETPEERUCRED /* this is for Solaris 10 */ ucred_t *uc; uc = NULL; if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc)) { gc.uid = ucred_geteuid (uc); gc.gid = ucred_getegid (uc); gcp = &gc; } ucred_free (uc); #endif #endif #endif } if ((NULL != access) && (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen)))) { if (GNUNET_NO == aret) LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"), GNUNET_a2s (uaddr, addrlen)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (uaddr); return NULL; } connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->addr = uaddr; connection->addrlen = addrlen; connection->sock = sock; LOG (GNUNET_ERROR_TYPE_INFO, _("Accepting connection from `%s': %p\n"), GNUNET_a2s (uaddr, addrlen), connection); return connection; }
/** * Actually do the reading of a DNS packet from our UDP socket and see * if we have a valid, matching, pending request. * * @param rs request socket with callback details * @param dnsout socket to read from * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket) */ static int do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs, struct GNUNET_NETWORK_Handle *dnsout) { struct sockaddr_storage addr; socklen_t addrlen; struct GNUNET_TUN_DnsHeader *dns; ssize_t r; int len; #ifndef MINGW if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) { /* conservative choice: */ len = UINT16_MAX; } #else /* port the code above? */ len = UINT16_MAX; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving %d byte DNS reply\n", len); { unsigned char buf[len] GNUNET_ALIGN; addrlen = sizeof (addr); memset (&addr, 0, sizeof (addr)); r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf), (struct sockaddr*) &addr, &addrlen); if (-1 == r) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); GNUNET_NETWORK_socket_close (dnsout); return GNUNET_SYSERR; } if (sizeof (struct GNUNET_TUN_DnsHeader) > r) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Received DNS response that is too small (%u bytes)"), r); return GNUNET_NO; } dns = (struct GNUNET_TUN_DnsHeader *) buf; if ( (addrlen != rs->addrlen) || (0 != memcmp (&rs->addr, &addr, addrlen)) || (0 == GNUNET_TIME_absolute_get_remaining (rs->timeout).rel_value) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request timeout or invalid sender address; ignoring reply\n"); return GNUNET_NO; } if (NULL != rs->rc) rs->rc (rs->rc_cls, rs, dns, r); } return GNUNET_OK; }