/*
This file is part of GNUnet.
- (C) 2009, 2012 Christian Grothoff (and other contributing authors)
+ (C) 2009-2013 Christian Grothoff (and other contributing authors)
GNUnet 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, or (at your
+ by the Free Software Foundation; either version 3, or (at your
option) any later version.
GNUnet is distributed in the hope that it will be useful, but
* These rules should apply in general, but for this
* module they are VERY, VERY important.
*/
-
#include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_connection_lib.h"
-#include "gnunet_container_lib.h"
+#include "gnunet_util_lib.h"
#include "gnunet_resolver_service.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_server_lib.h"
#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
* termination as a signal (because only then will the leaked
* socket be freed!)
*/
- int16_t persist;
+ int8_t persist;
+
+ /**
+ * Usually 0. Set to 1 if this handle is in used and should
+ * 'GNUNET_CONNECTION_destroy' be called right now, the action needs
+ * to be deferred by setting it to -1.
+ */
+ int8_t destroy_later;
};
{
struct GNUNET_CONNECTION_Handle *connection;
- connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
connection->sock = osSocket;
if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
{
/* convert to V4 address */
- v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
+ v4 = GNUNET_new (struct sockaddr_in);
memset (v4, 0, sizeof (struct sockaddr_in));
v4->sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
(GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen))))
{
if (GNUNET_NO == aret)
- LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"),
+ 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_free (uaddr);
return NULL;
}
- connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+ connection = GNUNET_new (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,
+ LOG (GNUNET_ERROR_TYPE_INFO,
_("Accepting connection from `%s': %p\n"),
GNUNET_a2s (uaddr, addrlen), connection);
return connection;
GNUNET_CONNECTION_Receiver receiver;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receive encounters error (%s), connection closed (%p)\n",
+ "Receive encounters error (%s), connection closed (%p)\n",
STRERROR (errcode),
connection);
GNUNET_assert (NULL != (receiver = connection->receiver));
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task);
/* signal errors for jobs that used to wait on the connection */
+ connection->destroy_later = 1;
if (NULL != connection->receiver)
signal_receive_error (connection, ECONNREFUSED);
if (NULL != connection->nth.notify_ready)
connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
signal_transmit_error (connection, ECONNREFUSED);
}
+ if (-1 == connection->destroy_later)
+ {
+ /* do it now */
+ connection->destroy_later = 0;
+ GNUNET_CONNECTION_destroy (connection);
+ return;
+ }
+ connection->destroy_later = 0;
}
static void
connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"Connection to `%s' succeeded! (%p)\n",
GNUNET_a2s (connection->addr, connection->addrlen), connection);
/* trigger jobs that waited for the connection */
if (NULL != connection->receiver)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection succeeded, starting with receiving data (%p)\n",
+ "Connection succeeded, starting with receiving data (%p)\n",
connection);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task);
connection->read_task =
GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
(connection->receive_timeout), connection->sock,
{
/* maybe refused / unsupported address, try next */
LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
-#if 0
- LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"),
- GNUNET_a2s (ap->addr, ap->addrlen), connection);
-#endif
GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
GNUNET_free (ap);
return;
struct GNUNET_CONNECTION_Handle *connection;
GNUNET_assert (0 < strlen (hostname)); /* sanity check */
- connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
connection->cfg = cfg;
connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
#ifdef AF_UNIX
struct GNUNET_CONNECTION_Handle *connection;
struct sockaddr_un *un;
- size_t slen;
GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
- un = GNUNET_malloc (sizeof (struct sockaddr_un));
+ un = GNUNET_new (struct sockaddr_un);
un->sun_family = AF_UNIX;
- slen = strlen (unixpath);
- if (slen >= sizeof (un->sun_path))
- slen = sizeof (un->sun_path) - 1;
- memcpy (un->sun_path, unixpath, slen);
- un->sun_path[slen] = '\0';
- slen = sizeof (struct sockaddr_un);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- un->sun_len = (u_char) slen;
+ strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+ {
+ int abstract;
+
+ abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING",
+ "USE_ABSTRACT_SOCKETS");
+ if (GNUNET_YES == abstract)
+ un->sun_path[0] = '\0';
+ }
#endif
-#if LINUX
- un->sun_path[0] = '\0';
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un->sun_len = (u_char) sizeof (struct sockaddr_un);
#endif
- connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
connection->cfg = cfg;
connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
connection->port = 0;
connection->hostname = NULL;
connection->addr = (struct sockaddr *) un;
- connection->addrlen = slen;
+ connection->addrlen = sizeof (struct sockaddr_un);
connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
if (NULL == connection->sock)
{
GNUNET_free (connection);
return NULL;
}
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen))
+ if ( (GNUNET_OK !=
+ GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen)) &&
+ (EINPROGRESS != errno) )
{
/* Just return; we expect everything to work eventually so don't fail HARD */
GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
{
struct AddressProbe *pos;
+ if (0 != connection->destroy_later)
+ {
+ connection->destroy_later = -1;
+ return;
+ }
LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection);
GNUNET_assert (NULL == connection->nth.notify_ready);
GNUNET_assert (NULL == connection->receiver);
if ( (NULL != connection->sock) &&
(GNUNET_YES != connection->persist) )
{
- if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) &&
- (ENOTCONN != errno) &&
+ if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) &&
+ (ENOTCONN != errno) &&
(ECONNRESET != errno) )
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");
}
if (NULL != connection->sock)
{
if (GNUNET_YES != connection->persist)
GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
else
- GNUNET_free (connection->sock); /* at least no memory leak (we deliberately
- * leak the socket in this special case) ... */
+ {
+ GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
+ * leak the socket in this special case) ... */
+ }
}
GNUNET_free_non_null (connection->addr);
GNUNET_free_non_null (connection->hostname);
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receive from `%s' encounters error: timeout (%p)\n",
+ "Receive from `%s' encounters error: timeout (%s, %p)\n",
GNUNET_a2s (connection->addr, connection->addrlen),
- GNUNET_TIME_absolute_get_duration (connection->receive_timeout).rel_value,
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout), GNUNET_YES),
connection);
signal_receive_timeout (connection);
return;
*
* @param connection connection handle
* @param max maximum number of bytes to read
- * @param timeout maximum amount of time to wait (use -1 for "forever")
+ * @param timeout maximum amount of time to wait
* @param receiver function to call with received data
* @param receiver_cls closure for receiver
*/
{
GNUNET_assert ((GNUNET_SCHEDULER_NO_TASK == connection->read_task) &&
(NULL == connection->receiver));
+ GNUNET_assert (NULL != receiver);
connection->receiver = receiver;
connection->receiver_cls = receiver_cls;
connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
}
if ((NULL == connection->dns_active) && (NULL == connection->ap_head))
{
+ connection->receiver = NULL;
receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
return;
}
void *
GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
{
- if (GNUNET_SCHEDULER_NO_TASK == connection->read_task)
+ if (GNUNET_SCHEDULER_NO_TASK != connection->read_task)
{
GNUNET_assert (connection == GNUNET_SCHEDULER_cancel (connection->read_task));
connection->read_task = GNUNET_SCHEDULER_NO_TASK;
size_t size;
GNUNET_CONNECTION_TransmitReadyNotify notify;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "process_notify is running\n");
+
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task);
if (NULL == (notify = connection->nth.notify_ready))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Noone to notify\n");
return GNUNET_NO;
+ }
used = connection->write_buffer_off - connection->write_buffer_pos;
avail = connection->write_buffer_size - used;
size = connection->nth.notify_size;
if (size > avail)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough buffer\n");
return GNUNET_NO;
+ }
connection->nth.notify_ready = NULL;
if (connection->write_buffer_size - connection->write_buffer_off < size)
{
return;
}
GNUNET_assert (NULL != connection->sock);
- if (NULL == tc->write_ready)
+ if (NULL == tc->write_ready)
{
/* special circumstances (in particular, PREREQ_DONE after
* connect): not yet ready to write, but no "fatal" error either.
connection->nth.notify_size = size;
connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task);
- if ((NULL == connection->sock) &&
+ if ((NULL == connection->sock) &&
(NULL == connection->ap_head) &&
(NULL == connection->dns_active))
{