#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include "gnunet_transport_service.h"
-#include "plugin_transport.h"
+#include "gnunet_transport_plugin.h"
#include "transport.h"
-#define DEBUG_TCP GNUNET_YES
-#define DEBUG_TCP_NAT GNUNET_YES
-
+#define DEBUG_TCP GNUNET_NO
+#define DEBUG_TCP_NAT GNUNET_NO
+#define MULTIPLE_PEER_SESSIONS GNUNET_YES
/**
* How long until we give up on transmitting the welcome message?
*/
*/
int inbound;
+ /**
+ * Was this session created using NAT traversal?
+ */
+ int is_nat;
+
};
/**
* The process id of the server process (if behind NAT)
*/
- pid_t server_pid;
+ struct GNUNET_OS_Process *server_proc;
/**
* List of open TCP sessions.
return ret;
}
+#if !MULTIPLE_PEER_SESSIONS
+/**
+ * Find the session handle for the given client.
+ *
+ * @return NULL if no matching session exists
+ */
+static struct Session *
+find_session_by_id (struct Plugin *plugin,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct Session *ret;
+
+ ret = plugin->sessions;
+ while ((ret != NULL) && (0 != memcmp(peer, &ret->target, sizeof(struct GNUNET_PeerIdentity))))
+ ret = ret->next;
+ return ret;
+}
+#endif
+
/**
* Create a new session. Also queues a welcome message.
*
GNUNET_assert (client == NULL);
#if DEBUG_TCP
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Creating new session for peer `%4s'\n",
GNUNET_i2s (target));
#endif
ret = GNUNET_malloc (sizeof (struct Session));
ret->last_activity = GNUNET_TIME_absolute_get ();
ret->plugin = plugin;
+ ret->is_nat = is_nat;
if (is_nat != GNUNET_YES) /* If not a NAT WAIT conn, add it to global list */
{
ret->next = plugin->sessions;
ret = 0;
now = GNUNET_TIME_absolute_get ();
while ( (NULL != (pos = session->pending_messages_head)) &&
- (pos->timeout.value <= now.value) )
+ (pos->timeout.abs_value <= now.abs_value) )
{
GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
session->pending_messages_tail,
GNUNET_break (session->client != NULL);
if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (session->plugin->env->sched,
- session->receive_delay_task);
+ GNUNET_SCHEDULER_cancel (session->receive_delay_task);
if (session->client != NULL)
GNUNET_SERVER_receive_done (session->client,
GNUNET_SYSERR);
if ( (s1->expecting_welcome == GNUNET_YES) &&
(s2->expecting_welcome == GNUNET_NO) )
return s2;
- if (s1->last_activity.value < s2->last_activity.value)
+ if (s1->last_activity.abs_value < s2->last_activity.abs_value)
return s2;
- if (s1->last_activity.value > s2->last_activity.value)
+ if (s1->last_activity.abs_value > s2->last_activity.abs_value)
return s1;
if ( (GNUNET_YES == s1->inbound) &&
(GNUNET_NO == s2->inbound) )
char inet4[INET_ADDRSTRLEN];
char *address_as_string;
char *port_as_string;
- pid_t pid;
+ struct GNUNET_OS_Process *proc;
const struct sockaddr *sa = (const struct sockaddr *)addr;
#if DEBUG_TCP_NAT
#endif
/* Start the client process */
- pid = GNUNET_OS_start_process(NULL, NULL, "gnunet-nat-client", "gnunet-nat-client", plugin->external_address, address_as_string, port_as_string, NULL);
+ proc = GNUNET_OS_start_process(NULL, NULL, "gnunet-nat-client", "gnunet-nat-client", plugin->external_address, address_as_string, port_as_string, NULL);
GNUNET_free(address_as_string);
GNUNET_free(port_as_string);
- GNUNET_OS_process_wait (pid);
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_close (proc);
+ proc = NULL;
}
GNUNET_break (0);
break;
}
- if (session->inbound == GNUNET_YES)
- continue;
- if (addrlen != session->connect_alen)
+#if IGNORE_INBOUND
+ if (session->inbound == GNUNET_YES) /* FIXME: why do we ignore inbound sessions? */
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Ignoring inbound session\n");
+ continue;
+ }
+#endif
+ if ((addrlen != session->connect_alen) && (session->is_nat == GNUNET_NO))
continue;
- if (0 != memcmp (session->connect_addr,
+ if ((0 != memcmp (session->connect_addr,
addr,
- addrlen))
+ addrlen)) && (session->is_nat == GNUNET_NO))
continue;
cand_session = select_better_session (cand_session,
session);
return -1; /* NAT client only works with IPv4 addresses */
- if ( (plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) &&
+ if ((plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) &&
(GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)))
{
#if DEBUG_TCP_NAT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Found valid IPv4 NAT address!\n"));
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Found valid IPv4 NAT address (creating session)!\n"));
#endif
session = create_session (plugin,
target,
GNUNET_assert(GNUNET_CONTAINER_multihashmap_put(plugin->nat_wait_conns, &target->hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK);
#if DEBUG_TCP_NAT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Created NAT WAIT connection to `%4s' at `%s'\n",
GNUNET_i2s (target),
GNUNET_a2s (sb, sbs));
/* Only do one NAT punch attempt per peer identity */
return -1;
}
- sa = GNUNET_CONNECTION_create_from_sockaddr (plugin->env->sched,
- af, sb, sbs);
+ sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
if (sa == NULL)
{
#if DEBUG_TCP
GNUNET_NO);
return -1;
}
-#if DEBUG_TCP
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+#if DEBUG_TCP_NAT
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
GNUNET_i2s (target),
GNUNET_a2s (sb, sbs));
ppc->asc = asc;
ppc->asc_cls = asc_cls;
ppc->port = port;
- GNUNET_RESOLVER_hostname_get (plugin->env->sched,
- plugin->env->cfg,
+ GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
sb,
sbs,
!numeric, timeout, &append_port, ppc);
GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
{
#if DEBUG_TCP_NAT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Found address `%s' for incoming connection %p\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "handle_tcp_nat_probe Found address `%s' for incoming connection %p\n",
GNUNET_a2s (vaddr, alen),
client);
#endif
gettext_noop ("# TCP WELCOME messages received"),
1,
GNUNET_NO);
+#if MULTIPLE_PEER_SESSIONS
session = find_session_by_client (plugin, client);
+#else
+ session = find_session_by_id(plugin, &wm->clientIdentity);
+#endif
+
if (session == NULL)
{
GNUNET_SERVER_client_keep (client);
+#if DEBUG_TCP_NAT
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Received %s message from a `%4s/%p', creating session\n",
+ "WELCOME",
+ GNUNET_i2s (&wm->clientIdentity), client);
+#endif
session = create_session (plugin,
&wm->clientIdentity, client, GNUNET_NO);
session->inbound = GNUNET_YES;
if (GNUNET_OK ==
GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
{
-#if DEBUG_TCP
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+#if DEBUG_TCP_NAT
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Found address `%s' for incoming connection %p\n",
GNUNET_a2s (vaddr, alen),
client);
session->connect_addr = t6;
session->connect_alen = sizeof (struct IPv6TcpAddress);
}
+
GNUNET_free (vaddr);
}
else
#endif
process_pending_messages (session);
}
+ else
+ {
+#if DEBUG_TCP_NAT
+ if (GNUNET_OK ==
+ GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Found address `%s' (already have session) for incoming connection %p\n",
+ GNUNET_a2s (vaddr, alen),
+ client);
+ }
+#endif
+ }
+
+#if MULTIPLE_PEER_SESSIONS
if (session->expecting_welcome != GNUNET_YES)
{
GNUNET_break_op (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
+#endif
session->last_activity = GNUNET_TIME_absolute_get ();
session->expecting_welcome = GNUNET_NO;
GNUNET_SERVER_receive_done (client, GNUNET_OK);
NULL, 0,
session,
NULL, 0);
- if (delay.value == 0)
+ if (delay.rel_value == 0)
GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
else
session->receive_delay_task =
- GNUNET_SCHEDULER_add_delayed (session->plugin->env->sched,
- delay, &delayed_done, session);
+ GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
}
return;
}
session->last_activity = GNUNET_TIME_absolute_get ();
-#if DEBUG_TCP
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+#if DEBUG_TCP > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Passing %u bytes of type %u from `%4s' to transport service.\n",
(unsigned int) ntohs (message->size),
(unsigned int) ntohs (message->type),
session,
(GNUNET_YES == session->inbound) ? NULL : session->connect_addr,
(GNUNET_YES == session->inbound) ? 0 : session->connect_alen);
- if (delay.value == 0)
+ if (delay.rel_value == 0)
GNUNET_SERVER_receive_done (client, GNUNET_OK);
else
session->receive_delay_task =
- GNUNET_SCHEDULER_add_delayed (session->plugin->env->sched,
- delay, &delayed_done, session);
+ GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
}
else
{
plugin->server_read_task =
- GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
plugin->server_stdout_handle, &tcp_plugin_server_read, plugin);
return;
}
_("nat-server-read malformed address\n"), &mybuf, port);
plugin->server_read_task =
- GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
plugin->server_stdout_handle, &tcp_plugin_server_read, plugin);
return;
}
* We have received an ICMP response, ostensibly from a non-NAT'd peer
* that wants to connect to us! Send a message to establish a connection.
*/
- sock = GNUNET_CONNECTION_create_from_sockaddr (plugin->env->sched, AF_INET, (struct sockaddr *)&in_addr,
+ sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, (struct sockaddr *)&in_addr,
sizeof(in_addr));
if (sock == NULL)
{
plugin->server_read_task =
- GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
plugin->server_stdout_handle, &tcp_plugin_server_read, plugin);
return;
}
/*GNUNET_SERVER_connect_socket(plugin->server, sock);*/
plugin->server_read_task =
- GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
plugin->server_stdout_handle, &tcp_plugin_server_read, plugin);
}
tcp_transport_start_nat_server(struct Plugin *plugin)
{
- plugin->server_stdout = GNUNET_DISK_pipe(GNUNET_YES);
+ plugin->server_stdout = GNUNET_DISK_pipe(GNUNET_YES, GNUNET_NO, GNUNET_YES);
if (plugin->server_stdout == NULL)
return GNUNET_SYSERR;
"Starting gnunet-nat-server process cmd: %s %s\n", "gnunet-nat-server", plugin->internal_address);
#endif
/* Start the server process */
- plugin->server_pid = GNUNET_OS_start_process(NULL, plugin->server_stdout, "gnunet-nat-server", "gnunet-nat-server", plugin->internal_address, NULL);
- if (plugin->server_pid == GNUNET_SYSERR)
+ plugin->server_proc = GNUNET_OS_start_process(NULL, plugin->server_stdout, "gnunet-nat-server", "gnunet-nat-server", plugin->internal_address, NULL);
+ if (plugin->server_proc == NULL)
{
#if DEBUG_TCP_NAT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
plugin->server_read_task =
- GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
plugin->server_stdout_handle, &tcp_plugin_server_read, plugin);
return GNUNET_YES;
}
+
/**
* Return the actual path to a file found in the current
* PATH environment variable.
p = getenv ("PATH");
if (p == NULL)
- return NULL;
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("PATH environment variable is unset.\n"));
+ return NULL;
+ }
path = GNUNET_strdup (p); /* because we write on it */
buf = GNUNET_malloc (strlen (path) + 20);
pos = path;
- while (NULL != (end = strchr (pos, ':')))
+ while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
{
*end = '\0';
sprintf (buf, "%s/%s", pos, binary);
{
struct stat statbuf;
char *p;
+#ifdef MINGW
+ SOCKET rawsock;
+#endif
+#ifdef MINGW
+ char *binaryexe;
+ GNUNET_asprintf (&binaryexe, "%s.exe", binary);
+ p = get_path_from_PATH (binaryexe);
+ free (binaryexe);
+#else
p = get_path_from_PATH (binary);
+#endif
if (p == NULL)
- return GNUNET_NO;
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not find binary `%s' in PATH!\n"),
+ binary);
+ return GNUNET_NO;
+ }
if (0 != STAT (p, &statbuf))
{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("stat (%s) failed: %s\n"),
+ p,
+ STRERROR (errno));
GNUNET_free (p);
return GNUNET_SYSERR;
}
GNUNET_free (p);
+#ifndef MINGW
if ( (0 != (statbuf.st_mode & S_ISUID)) &&
(statbuf.st_uid == 0) )
return GNUNET_YES;
return GNUNET_NO;
+#else
+ rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (INVALID_SOCKET == rawsock)
+ {
+ DWORD err = GetLastError ();
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) have failed! GLE = %d\n", err);
+ return GNUNET_NO; /* not running as administrator */
+ }
+ closesocket (rawsock);
+ return GNUNET_YES;
+#endif
}
/**
struct sockaddr_in in_addr;
struct IPv4TcpAddress t4;
- service = GNUNET_SERVICE_start ("transport-tcp", env->sched, env->cfg);
+ service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);
if (service == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
}
- plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->sched,
- env->cfg,
+ plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->cfg,
AF_UNSPEC,
HOSTNAME_RESOLVE_TIMEOUT,
&process_hostname_ips,
if (plugin->behind_nat == GNUNET_YES)
{
- if (0 != PLIBC_KILL (plugin->server_pid, SIGTERM))
+ if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
- GNUNET_OS_process_wait (plugin->server_pid);
+ GNUNET_OS_process_wait (plugin->server_proc);
+ GNUNET_OS_process_close (plugin->server_proc);
+ plugin->server_proc = NULL;
}
GNUNET_free_non_null(plugin->bind_address);
GNUNET_free (plugin);