*/
#define REASON_ERROR 3
+struct ForwardedConnection;
/**
*
*/
struct GNUNET_NETWORK_Handle *listeningSocket;
+ /**
+ *
+ */
+ struct ForwardedConnection *fc;
+
/**
* Task doing the accepting.
*/
* Have we ever successfully written data to the service?
*/
int first_write_done;
-};
+};
/**
* Array with the names of the services started by default.
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
-/**
- *
- */
-static struct GNUNET_SCHEDULER_Handle *scheduler;
-
/**
*
*/
#endif
if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (scheduler, fc->service_to_client_task);
+ GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
}
if (fc->armClientSocket != NULL)
#endif
if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (scheduler,
- fc->client_to_service_task);
+ GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
}
if (fc->armClientSocket != NULL)
"Closing forwarding connection (done with both directions)\n");
#endif
if (fc->start_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (scheduler,
- fc->start_task);
+ GNUNET_SCHEDULER_cancel (fc->start_task);
if ( (NULL != fc->armClientSocket) &&
(GNUNET_SYSERR ==
GNUNET_NETWORK_socket_close (fc->armClientSocket)) )
/**
- *
+ * Read data from the client and then forward it to the service.
+ *
+ * @param cls callback data, struct ForwardedConnection for the communication between client and service
+ * @param tc context
*/
static void
receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
/**
- *
+ * Receive service messages sent by the service and forward it to client
+ *
+ * @param cls callback data, struct ForwardedConnection for the communication between client and service
+ * @param tc scheduler context
*/
static void
receiveFromService (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
fc->armClientSocket))
{
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
+ GNUNET_SCHEDULER_add_write_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&forwardToClient, fc);
fc->service_to_client_bufferPos += numberOfBytesSent;
fc->service_to_client_bufferDataLength -= numberOfBytesSent;
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
+ GNUNET_SCHEDULER_add_write_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&forwardToClient,
return;
}
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&receiveFromService,
fc);
fc->armServiceSocket))
{
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
+ GNUNET_SCHEDULER_add_read_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&receiveFromService, fc);
if ( (fc->client_to_service_bufferDataLength > 0) &&
(fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) )
{
- GNUNET_SCHEDULER_cancel (scheduler,
- fc->client_to_service_task);
- fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
+ fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
}
fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
#if DEBUG_SERVICE_MANAGER
GNUNET_a2s (fc->listen_info->service_addr,
fc->listen_info->service_addr_len),
(unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
- rem).value);
+ rem).rel_value);
#endif
rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
fc->start_task
- = GNUNET_SCHEDULER_add_delayed (scheduler,
+ = GNUNET_SCHEDULER_add_delayed (
GNUNET_TIME_relative_min (fc->back_off,
rem),
&start_forwarding,
fc->service_to_client_bufferDataLength);
#endif
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
+ GNUNET_SCHEDULER_add_write_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&forwardToClient, fc);
fc->armServiceSocket))
{
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
+ GNUNET_SCHEDULER_add_write_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&forwardToService, fc);
if ( (fc->service_to_client_bufferDataLength == 0) &&
(fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
{
- GNUNET_SCHEDULER_cancel (scheduler,
- fc->service_to_client_task);
+ GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
}
fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
GNUNET_a2s (fc->listen_info->service_addr,
fc->listen_info->service_addr_len),
(unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
- rem).value);
+ rem).rel_value);
#endif
rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
fc->start_task
- = GNUNET_SCHEDULER_add_delayed (scheduler,
- GNUNET_TIME_relative_min (fc->back_off,
+ = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_min (fc->back_off,
rem),
&start_forwarding,
fc);
fc->client_to_service_bufferPos += numberOfBytesSent;
fc->client_to_service_bufferDataLength -= numberOfBytesSent;
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
+ GNUNET_SCHEDULER_add_write_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&forwardToService, fc);
return;
}
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&receiveFromClient, fc);
}
fc->armClientSocket))
{
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&receiveFromClient, fc);
return;
#endif
if (fc->armServiceSocket != NULL)
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
+ GNUNET_SCHEDULER_add_write_net (
GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&forwardToService, fc);
}
-/**
- *
- */
static void
-start_forwarding (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+fc_acceptConnection (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct ForwardedConnection *fc = cls;
- struct GNUNET_TIME_Relative rem;
+ struct ServiceListeningInfo *sli = cls;
+ struct ForwardedConnection *fc = sli->fc;
- fc->start_task = GNUNET_SCHEDULER_NO_TASK;
- if ( (NULL != tc) &&
- (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Unable to forward to service `%s': shutdown\n"),
- fc->listen_info->serviceName);
+ GNUNET_assert (GNUNET_OK == GNUNET_NETWORK_socket_close (sli->listeningSocket));
closeClientAndServiceSockets (fc, REASON_ERROR);
- return;
- }
- rem = GNUNET_TIME_absolute_get_remaining (fc->timeout);
- if (rem.value == 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Unable to forward to service `%s': timeout before connect\n"),
- fc->listen_info->serviceName);
- closeClientAndServiceSockets (fc, REASON_ERROR);
- return;
- }
- fc->armServiceSocket =
- GNUNET_NETWORK_socket_create (fc->listen_info->service_addr->sa_family,
- SOCK_STREAM, 0);
- if (NULL == fc->armServiceSocket)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _ ("Unable to start service `%s': %s\n"),
- fc->listen_info->serviceName,
- STRERROR (errno));
- closeClientAndServiceSockets (fc, REASON_ERROR);
- return;
- }
- if ( (GNUNET_SYSERR ==
- GNUNET_NETWORK_socket_connect (fc->armServiceSocket,
- fc->listen_info->service_addr,
- fc->listen_info->service_addr_len)) &&
- (errno != EINPROGRESS) )
- {
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (fc->armServiceSocket));
- fc->armServiceSocket = NULL;
- fc->back_off = GNUNET_TIME_relative_multiply (fc->back_off, 2);
- #if DEBUG_SERVICE_MANAGER
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to connected to service `%s' at `%s', will try again in %llu ms\n",
- fc->listen_info->serviceName,
- GNUNET_a2s (fc->listen_info->service_addr,
- fc->listen_info->service_addr_len),
- (unsigned long long) GNUNET_TIME_relative_min (fc->back_off,
- rem).value);
-#endif
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
- fc->start_task
- = GNUNET_SCHEDULER_add_delayed (scheduler,
- GNUNET_TIME_relative_min (fc->back_off,
- rem),
- &start_forwarding,
- fc);
+ GNUNET_free (sli);
return;
}
#if DEBUG_SERVICE_MANAGER
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Connected to service, now starting forwarding\n");
#endif
+ fc->armServiceSocket = sli->listeningSocket;
+ GNUNET_free (fc->listen_info->service_addr);
+ fc->listen_info->service_addr = sli->service_addr;
+ fc->listen_info->service_addr_len = sli->service_addr_len;
if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
{
if (fc->client_to_service_bufferDataLength == 0)
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&receiveFromClient, fc);
else
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&forwardToService, fc);
}
{
if (fc->service_to_client_bufferDataLength == 0)
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armServiceSocket,
&receiveFromService, fc);
else
fc->service_to_client_task =
- GNUNET_SCHEDULER_add_write_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&forwardToClient, fc);
}
+ GNUNET_free (sli);
+}
+
+
+static struct ServiceListeningInfo *
+service_try_to_connect (const struct sockaddr *addr,
+ int pf,
+ socklen_t addrlen,
+ struct ForwardedConnection *fc)
+{
+ struct GNUNET_NETWORK_Handle *sock;
+ struct ServiceListeningInfo *serviceListeningInfo;
+
+ sock = GNUNET_NETWORK_socket_create (pf, SOCK_STREAM, 0);
+ if (sock == NULL)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
+ return NULL;
+ }
+ if ( (GNUNET_SYSERR == GNUNET_NETWORK_socket_connect (sock, addr, addrlen)) &&
+ (errno != EINPROGRESS) )
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+ return NULL;
+ }
+ serviceListeningInfo = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+ serviceListeningInfo->serviceName = NULL;
+ serviceListeningInfo->service_addr = GNUNET_malloc (addrlen);
+ memcpy (serviceListeningInfo->service_addr,
+ addr,
+ addrlen);
+ serviceListeningInfo->service_addr_len = addrlen;
+ serviceListeningInfo->listeningSocket = sock;
+ serviceListeningInfo->fc = fc;
+ serviceListeningInfo->acceptTask =
+ GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ serviceListeningInfo->listeningSocket,
+ &fc_acceptConnection, serviceListeningInfo);
+ return serviceListeningInfo;
}
+/**
+ *
+ */
+static void
+start_forwarding (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ForwardedConnection *fc = cls;
+ struct ServiceListeningInfo *sc;
+ struct sockaddr_in target_ipv4;
+ struct sockaddr_in6 target_ipv6;
+ const struct sockaddr_in *v4;
+ const struct sockaddr_in6 *v6;
+ char listen_address[INET6_ADDRSTRLEN];
+
+ fc->start_task = GNUNET_SCHEDULER_NO_TASK;
+ if ( (NULL != tc) &&
+ (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Unable to forward to service `%s': shutdown\n"),
+ fc->listen_info->serviceName);
+ closeClientAndServiceSockets (fc, REASON_ERROR);
+ return;
+ }
+ if (0 == GNUNET_TIME_absolute_get_remaining (fc->timeout).rel_value)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Unable to forward to service `%s': timeout before connect\n"),
+ fc->listen_info->serviceName);
+ closeClientAndServiceSockets (fc, REASON_ERROR);
+ return;
+ }
+ switch (fc->listen_info->service_addr->sa_family)
+ {
+ case AF_UNSPEC:
+ GNUNET_break (0);
+ closeClientAndServiceSockets (fc, REASON_ERROR);
+ return;
+ case AF_INET:
+ v4 = (const struct sockaddr_in *) fc->listen_info->service_addr;
+ inet_ntop (fc->listen_info->service_addr->sa_family,
+ (const void *) &v4->sin_addr,
+ listen_address,
+ INET_ADDRSTRLEN);
+ if (0 == strncmp (listen_address, "0.0.0.0", 7))
+ {
+ /* connect to [::1] and 127.0.0.1 instead of [::] and 0.0.0.0 */
+ memset (&target_ipv4, 0, sizeof (target_ipv4));
+ inet_pton (AF_INET, "127.0.0.1", &target_ipv4.sin_addr);
+ target_ipv4.sin_family = AF_INET;
+ target_ipv4.sin_port = v4->sin_port;
+ v4 = &target_ipv4;
+ }
+ sc = service_try_to_connect ((const struct sockaddr*) v4,
+ PF_INET,
+ sizeof (struct sockaddr_in),
+ fc);
+ break;
+ case AF_INET6:
+ v6 = (struct sockaddr_in6 *)fc->listen_info->service_addr;
+ inet_ntop (fc->listen_info->service_addr->sa_family,
+ (const void *) &v6->sin6_addr,
+ listen_address,
+ INET6_ADDRSTRLEN);
+ if ( (strncmp (listen_address, "[::]:", 5) == 0) || (strncmp (listen_address, "::", 2) == 0) )
+ {
+ memset (&target_ipv6, 0, sizeof (target_ipv6));
+ target_ipv6.sin6_addr = in6addr_loopback;
+ target_ipv6.sin6_family = AF_INET6;
+ target_ipv6.sin6_port = v6->sin6_port;
+ v6 = &target_ipv6;
+ }
+ sc = service_try_to_connect ((const struct sockaddr*) v6,
+ PF_INET6,
+ sizeof (struct sockaddr_in6),
+ fc);
+ break;
+ case AF_UNIX:
+ sc = service_try_to_connect (fc->listen_info->service_addr,
+ PF_UNIX,
+ fc->listen_info->service_addr_len,
+ fc);
+ break;
+ default:
+ GNUNET_break (0);
+ closeClientAndServiceSockets (fc, REASON_ERROR);
+ return;
+ }
+ if (NULL == sc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _ ("Unable to start service `%s': %s\n"),
+ fc->listen_info->serviceName,
+ STRERROR (errno));
+ closeClientAndServiceSockets (fc, REASON_ERROR);
+ return;
+ }
+}
+
/**
*
(strcmp (pos->serviceName, serviceName) != 0) )
continue;
if (pos->acceptTask != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (scheduler, pos->acceptTask);
+ GNUNET_SCHEDULER_cancel (pos->acceptTask);
GNUNET_break (GNUNET_OK ==
GNUNET_NETWORK_socket_close (pos->listeningSocket));
GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
serviceListeningInfoList_tail,
serviceListeningInfo);
serviceListeningInfo->acceptTask =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
serviceListeningInfo->listeningSocket,
&acceptConnection,
serviceListeningInfo);
fc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_SERVICE_TIMEOUT);
fc->back_off = GNUNET_TIME_UNIT_MILLISECONDS;
fc->client_to_service_task =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
fc->armClientSocket,
&receiveFromClient, fc);
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
fc->start_task
- = GNUNET_SCHEDULER_add_now (scheduler,
- &start_forwarding,
+ = GNUNET_SCHEDULER_add_now (&start_forwarding,
fc);
}
GNUNET_free (pos->listeningSocket); /* deliberately no closing! */
GNUNET_free (pos->service_addr);
GNUNET_free (pos->serviceName);
- GNUNET_SCHEDULER_cancel (scheduler,
- pos->acceptTask);
+ GNUNET_SCHEDULER_cancel (pos->acceptTask);
GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head,
serviceListeningInfoList_tail,
pos);
sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
break;
case AF_UNIX:
+ if (strcmp(GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
+ return;
sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
break;
default:
if (GNUNET_NETWORK_socket_bind
(sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
serviceName,
GNUNET_a2s (sa, addr_len),
serviceListeningInfo->service_addr_len = addr_len;
serviceListeningInfo->listeningSocket = sock;
serviceListeningInfo->acceptTask =
- GNUNET_SCHEDULER_add_read_net (scheduler,
- GNUNET_TIME_UNIT_FOREVER_REL, sock,
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
&acceptConnection,
serviceListeningInfo);
GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head,
* Entry point to the Service Manager
*
* @param configurationHandle configuration to use to get services
- * @param sched scheduler to handle clients and services communications
*/
void
prepareServices (const struct GNUNET_CONFIGURATION_Handle
- *configurationHandle, struct GNUNET_SCHEDULER_Handle *sched)
+ *configurationHandle)
{
char *defaultServicesString;
- scheduler = sched;
cfg = configurationHandle;
/* Split the default services into a list */
if (GNUNET_OK ==