src/include/gnunet_directories.h
src/hostlist/Makefile
src/peerinfo/Makefile
-src/resolver/Makefile
src/statistics/Makefile
src/template/Makefile
src/testing/Makefile
fragmentation \
hello \
peerinfo \
- resolver \
statistics \
datacache \
datastore \
* yet been established. This function only creates TCP connections.\r
*\r
* @param sched scheduler to use\r
+ * @param cfg configuration to use\r
* @param hostname name of the host to connect to\r
* @param port port to connect to\r
* @param maxbuf maximum write buffer size for the socket (use\r
* @return the socket handle\r
*/\r
struct GNUNET_CONNECTION_Handle\r
- *GNUNET_CONNECTION_create_from_connect (struct\r
- GNUNET_SCHEDULER_Handle\r
- *sched,\r
- const char *hostname,\r
- uint16_t port,\r
- size_t maxbuf);\r
+ *GNUNET_CONNECTION_create_from_connect (struct GNUNET_SCHEDULER_Handle *sched,\r
+ const struct GNUNET_CONFIGURATION_Handle *cfg,\r
+ const char *hostname,\r
+ uint16_t port,\r
+ size_t maxbuf);\r
\r
\r
\r
* @param timeout maximum amount of time to wait\r
* @param receiver function to call with received data\r
* @param receiver_cls closure for receiver\r
- * @return scheduler task ID used for receiving, GNUNET_SCHEDULER_NO_TASK on error\r
*/\r
-GNUNET_SCHEDULER_TaskIdentifier\r
+void\r
GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle\r
*sock, size_t max,\r
struct GNUNET_TIME_Relative timeout,\r
* for the cancellation to be valid.\r
*\r
* @param sock socket handle\r
- * @param task task identifier returned from the receive call\r
- * @return closure of the original receiver callback\r
+ * @return closure of the original receiver callback closure\r
*/\r
void *GNUNET_CONNECTION_receive_cancel (struct\r
- GNUNET_CONNECTION_Handle\r
- *sock,\r
- GNUNET_SCHEDULER_TaskIdentifier\r
- task);\r
+ GNUNET_CONNECTION_Handle\r
+ *sock);\r
\r
\r
/**\r
* @param hostname the hostname to resolve
* @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
* @param callback function to call with addresses
- * @param cls closure for callback
+ * @param callback_cls closure for callback
* @param timeout how long to try resolving
*/
void
const char *hostname,
int domain,
struct GNUNET_TIME_Relative timeout,
- GNUNET_RESOLVER_AddressCallback callback, void *cls);
+ GNUNET_RESOLVER_AddressCallback callback,
+ void *callback_cls);
/**
* @param timeout maximum amount of time to wait (use -1 for "forever")
* @param receiver function to call with received data
* @param receiver_cls closure for receiver
- * @return task identifier that can be used to cancel the receive,
- * GNUNET_SCHEDULER_NO_TASK should be returned
- * if the receiver function was already called
*/
-typedef GNUNET_SCHEDULER_TaskIdentifier
+typedef void
(*GNUNET_SERVER_ReceiveCallback) (void *cls,
size_t max,
struct GNUNET_TIME_Relative timeout,
* Cancel receive request.
*
* @param cls closure
- * @param ti task identifier from the receive callback
*/
-typedef void (*GNUNET_SERVER_ReceiveCancelCallback) (void *cls,
- GNUNET_SCHEDULER_TaskIdentifier
- ti);
+typedef void (*GNUNET_SERVER_ReceiveCancelCallback) (void *cls);
/**
plugin_transport_tcp.c
libgnunet_plugin_transport_tcp_la_LIBADD = \
$(top_builddir)/src/hello/libgnunethello.la \
- $(top_builddir)/src/resolver/libgnunetresolver.la \
$(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
$(top_builddir)/src/util/libgnunetutil.la
libgnunet_plugin_transport_tcp_la_LDFLAGS = \
plugin.c \
program.c \
pseudonym.c \
+ resolver_api.c \
scheduler.c \
server.c \
server_tc.c \
-version-info 4:0:0
+bin_PROGRAMS = \
+ gnunet-service-resolver
+
+gnunet_service_resolver_SOURCES = \
+ gnunet-service-resolver.c
+gnunet_service_resolver_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+
plugin_LTLIBRARIES = \
libgnunet_plugin_test.la
test_plugin \
test_program \
test_pseudonym \
+ test_resolver_api \
test_scheduler \
test_scheduler_delay \
test_server \
test_container_multihashmap.c
test_container_multihashmap_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la
-
+
test_container_heap_SOURCES = \
test_container_heap.c
test_container_heap_LDADD = \
test_pseudonym_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la
+test_resolver_api_SOURCES = \
+ test_resolver_api.c
+test_resolver_api_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
test_scheduler_SOURCES = \
test_scheduler.c
test_scheduler_LDADD = \
test_container_meta_data_image.jpg \
test_program_data.conf \
test_pseudonym_data.conf \
+ test_resolver_api_data.conf \
test_service_data.conf
*/
char *service_name;
- /**
- * ID of task used for receiving.
- */
- GNUNET_SCHEDULER_TaskIdentifier receiver_task;
-
/**
* Handler for current receiver task.
*/
*/
int msg_complete;
+ /**
+ * Are we currently busy doing receive-processing?
+ * GNUNET_YES if so, GNUNET_NO if not, GNUNET_SYSERR
+ * if the handle should be destroyed as soon as the
+ * receive processing is done.
+ */
+ int in_receive;
+
};
return NULL;
}
sock = GNUNET_CONNECTION_create_from_connect (sched,
+ cfg,
hostname,
port,
GNUNET_SERVER_MAX_MESSAGE_SIZE);
GNUNET_CONNECTION_destroy (sock->sock);
sock->sock = NULL;
sock->receiver_handler = NULL;
- GNUNET_SCHEDULER_add_after (sock->sched,
- GNUNET_YES,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sock->receiver_task, &finish_cleanup, sock);
+ if (sock->in_receive == GNUNET_YES)
+ sock->in_receive = GNUNET_SYSERR;
+ else
+ GNUNET_SCHEDULER_add_after (sock->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &finish_cleanup, sock);
}
/**
- * check if message is complete
+ * Check if message is complete
*/
static void
check_complete (struct GNUNET_CLIENT_Connection *conn)
struct GNUNET_TIME_Relative remaining;
GNUNET_assert (conn->msg_complete == GNUNET_NO);
- conn->receiver_task = GNUNET_SCHEDULER_NO_TASK;
-
+ if (GNUNET_SYSERR == conn->in_receive)
+ GNUNET_SCHEDULER_add_after (conn->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &finish_cleanup,
+ conn);
+ conn->in_receive = GNUNET_NO;
if ((available == 0) || (conn->sock == NULL) || (errCode != 0))
{
/* signal timeout! */
char mbuf[msize];
struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader*) mbuf;
+ if (GNUNET_SYSERR == sock->in_receive)
+ GNUNET_SCHEDULER_add_after (sock->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &finish_cleanup,
+ sock);
+ sock->in_receive = GNUNET_NO;
GNUNET_assert (GNUNET_YES == sock->msg_complete);
- sock->receiver_task = GNUNET_SCHEDULER_NO_TASK;
GNUNET_assert (sock->received_pos >= msize);
memcpy (msg, cmsg, msize);
memmove (sock->received_buf,
handler (handler_cls, NULL);
return;
}
- GNUNET_assert (sock->receiver_task ==
- GNUNET_SCHEDULER_NO_TASK);
sock->receiver_handler = handler;
sock->receiver_handler_cls = handler_cls;
sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ sock->in_receive = GNUNET_YES;
if (GNUNET_YES == sock->msg_complete)
- sock->receiver_task = GNUNET_SCHEDULER_add_after (sock->sched,
- GNUNET_YES,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK,
- &receive_task, sock);
+ GNUNET_SCHEDULER_add_after (sock->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &receive_task, sock);
else
- sock->receiver_task = GNUNET_CONNECTION_receive (sock->sock,
- GNUNET_SERVER_MAX_MESSAGE_SIZE,
- timeout,
- &receive_helper, sock);
+ GNUNET_CONNECTION_receive (sock->sock,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE,
+ timeout,
+ &receive_helper, sock);
}
#include "platform.h"
#include "gnunet_common.h"
#include "gnunet_connection_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_resolver_service.h"
#include "gnunet_scheduler_lib.h"
#define DEBUG_CONNECTION GNUNET_NO
+
/**
- * List of address families to give as hints to
- * getaddrinfo, in reverse order of preference.
+ * Possible functions to call after connect failed or succeeded.
*/
-static int address_families[] =
- { AF_INET, AF_INET6, AF_UNSPEC };
+enum ConnectContinuations
+ {
+ /**
+ * Call nothing.
+ */
+ CC_NONE = 0,
+
+ /**
+ * Call "receive_again".
+ */
+ CC_RECEIVE_AGAIN = 1,
+
+ /**
+ * Call "transmit_ready".
+ */
+ CC_TRANSMIT_READY = 2,
+
+ /**
+ * Call "destroy_continuation".
+ */
+ CC_DESTROY_CONTINUATION = 4
+ };
+
+/**
+ * Transmission handle. There can only be one for each connection.
+ */
struct GNUNET_CONNECTION_TransmitHandle
{
};
+
+/**
+ * During connect, we try multiple possible IP addresses
+ * to find out which one might work.
+ */
+struct AddressProbe
+{
+
+ /**
+ * This is a linked list.
+ */
+ struct AddressProbe *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct AddressProbe *prev;
+
+ /**
+ * The address; do not free (allocated at the end of this struct).
+ */
+ const struct sockaddr *addr;
+
+ /**
+ * Underlying OS's socket.
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /**
+ * Connection for which we are probing.
+ */
+ struct GNUNET_CONNECTION_Handle *h;
+
+ /**
+ * Lenth of addr.
+ */
+ socklen_t addrlen;
+
+ /**
+ * Task waiting for the socket to finish connecting.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+};
+
+
/**
* @brief handle for a network socket
*/
struct GNUNET_SCHEDULER_Handle *sched;
/**
- * Address information for connect (may be NULL).
+ * Configuration to use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Linked list of sockets we are currently trying out
+ * (during connect).
*/
- struct addrinfo *ai;
+ struct AddressProbe *ap_head;
/**
- * Index for the next struct addrinfo for connect attempts (may be NULL)
+ * Linked list of sockets we are currently trying out
+ * (during connect).
*/
- struct addrinfo *ai_pos;
+ struct AddressProbe *ap_tail;
/**
* Network address of the other end-point, may be NULL.
*/
char *hostname;
+ /**
+ * Underlying OS's socket, set to NULL after fatal errors.
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /**
+ * Function to call on data received, NULL if no receive is pending.
+ */
+ GNUNET_CONNECTION_Receiver receiver;
+
+ /**
+ * Closure for receiver.
+ */
+ void *receiver_cls;
+
/**
* Pointer to our write buffer.
*/
*/
socklen_t addrlen;
- /**
- * Offset in our address family list
- * that we used last.
- */
- int af_fam_offset;
-
- /**
- * Connect task that we may need to wait for.
- */
- GNUNET_SCHEDULER_TaskIdentifier connect_task;
-
/**
* Read task that we may need to wait for.
*/
struct GNUNET_CONNECTION_TransmitHandle nth;
/**
- * Underlying OS's socket, set to NULL after fatal errors.
- */
- struct GNUNET_NETWORK_Handle *sock;
-
- /**
- * Port to connect to.
+ * Timeout for receiving (in absolute time).
*/
- uint16_t port;
-
+ struct GNUNET_TIME_Absolute receive_timeout;
+
/**
- * Function to call on data received, NULL
- * if no receive is pending.
+ * Functions to call after connect failed or succeeded.
*/
- GNUNET_CONNECTION_Receiver receiver;
-
+ enum ConnectContinuations ccs;
+
/**
- * Closure for receiver.
+ * Maximum number of bytes to read (for receiving).
*/
- void *receiver_cls;
+ size_t max;
/**
- * Timeout for receiving (in absolute time).
+ * Are we still waiting for DNS replies (on connect)?
+ * GNUNET_YES if we are, GNUNET_NO if we are not waiting for DNS,
+ * GNUNET_SYSERR if destroying the handle was deferred due to
+ * a pending DNS lookup.
*/
- struct GNUNET_TIME_Absolute receive_timeout;
+ int dns_active;
/**
- * Maximum number of bytes to read
- * (for receiving).
+ * Port to connect to.
*/
- size_t max;
+ uint16_t port;
};
/**
- * Perform a DNS lookup for the hostname associated
- * with the current socket, iterating over the address
- * families as specified in the "address_families" array.
+ * It is time to re-try connecting.
+ *
+ * @param cls the handle for the connection that should be re-tried
+ * @param tc unused scheduler taks context
+ */
+static void
+retry_connect_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * This function is called after establishing a connection either has
+ * succeeded or timed out. Note that it is possible that the attempt
+ * timed out and that we're immediately retrying. If we are retrying,
+ * we need to wait again (or timeout); if we succeeded, we need to
+ * wait for data (or timeout).
*
- * @param sock the socket for which to do the lookup
+ * @param cls our connection handle
+ * @param tc task context describing why we are here
*/
static void
-try_lookup (struct GNUNET_CONNECTION_Handle *sock)
-{
- struct addrinfo hints;
- int ec;
+receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
- GNUNET_assert (0 < strlen (sock->hostname)); /* sanity check */
- while ( (sock->ai_pos == NULL) &&
- (sock->af_fam_offset > 0) )
- {
- if (sock->ai != NULL)
- freeaddrinfo (sock->ai);
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = address_families[--sock->af_fam_offset];
- hints.ai_socktype = SOCK_STREAM;
-#if 0
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("`%s' tries to resolve address family %d and hostname `%s:%u'\n"),
- "getaddrinfo",
- address_families[sock->af_fam_offset],
- sock->hostname,
- sock->port);
-#endif
- ec = getaddrinfo (sock->hostname, NULL, &hints, &sock->ai);
-#if 0
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("`%s' returned from resolving address family %d and hostname `%s:%u'\n"),
- "getaddrinfo",
- address_families[sock->af_fam_offset],
- sock->hostname,
- sock->port);
+
+/**
+ * Scheduler let us know that the connect task is finished (or was
+ * cancelled due to shutdown). Now really clean up.
+ *
+ * @param cls our "struct GNUNET_CONNECTION_Handle *"
+ * @param tc unused
+ */
+static void
+destroy_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+
+/**
+ * See if we are now connected. If not, wait longer for
+ * connect to succeed. If connected, we should be able
+ * to write now as well, unless we timed out.
+ *
+ * @param cls our connection handle
+ * @param tc task context describing why we are here
+ */
+static void
+transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * We've failed for good to establish a connection.
+ *
+ * @param h the connection we tried to establish
+ */
+static void
+connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
+{
+#if DEBUG_CONNECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
+ h->hostname,
+ h->port);
#endif
- if (0 != ec)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
- _("`%s' failed for address family %d and hostname `%s:%u': %s\n"),
- "getaddrinfo",
- address_families[sock->af_fam_offset],
- sock->hostname,
- sock->port,
- gai_strerror (ec));
- sock->ai = NULL;
- }
- sock->ai_pos = sock->ai;
+ /* connect failed / timed out */
+ GNUNET_break (h->ap_head == NULL);
+ GNUNET_break (h->ap_tail == NULL);
+ GNUNET_break (h->dns_active == GNUNET_NO);
+ GNUNET_break (h->sock == NULL);
+
+ /* FIXME: trigger delayed reconnect attempt... */
+ /* trigger jobs that used to wait on "connect_task" */
+ if (0 != (h->ccs & CC_RECEIVE_AGAIN))
+ {
+ h->ccs -= CC_RECEIVE_AGAIN;
+ h->read_task = GNUNET_SCHEDULER_add_after (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &receive_again,
+ h);
+ }
+ if (0 != (h->ccs & CC_TRANSMIT_READY))
+ {
+ h->ccs -= CC_TRANSMIT_READY;
+ h->write_task = GNUNET_SCHEDULER_add_after (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &transmit_ready,
+ h);
+ }
+ if (0 != (h->ccs & CC_DESTROY_CONTINUATION))
+ {
+ h->ccs -= CC_DESTROY_CONTINUATION;
+ GNUNET_SCHEDULER_add_continuation (h->sched,
+ GNUNET_NO,
+ &destroy_continuation,
+ h,
+ GNUNET_SCHEDULER_REASON_TIMEOUT);
}
}
/**
- * Initiate asynchronous TCP connect request.
+ * We've succeeded in establishing a connection.
*
- * @param sock what socket to connect
- * @return GNUNET_SYSERR error (no more addresses to try)
+ * @param h the connection we tried to establish
*/
-static int
-try_connect (struct GNUNET_CONNECTION_Handle *sock)
+static void
+connect_success_continuation (struct GNUNET_CONNECTION_Handle *h)
{
- struct GNUNET_NETWORK_Handle *s;
-
- if (sock->addr != NULL)
+#if DEBUG_CONNECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection to `%s' succeeded!\n",
+ GNUNET_a2s(h->addr, h->addrlen));
+#endif
+ /* trigger jobs that waited for the connection */
+ if (0 != (h->ccs & CC_RECEIVE_AGAIN))
{
- GNUNET_free (sock->addr);
- sock->addr = NULL;
- sock->addrlen = 0;
+ h->ccs -= CC_RECEIVE_AGAIN;
+ h->read_task = GNUNET_SCHEDULER_add_after (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ &receive_again,
+ h);
}
- while (1)
+ if (0 != (h->ccs & CC_TRANSMIT_READY))
{
- if (sock->ai_pos == NULL)
- try_lookup (sock);
- if (sock->ai_pos == NULL)
- {
- /* no more addresses to try, fatal! */
- return GNUNET_SYSERR;
- }
- switch (sock->ai_pos->ai_family)
- {
- case AF_INET:
- ((struct sockaddr_in *) sock->ai_pos->ai_addr)->sin_port =
- htons (sock->port);
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) sock->ai_pos->ai_addr)->sin6_port =
- htons (sock->port);
- break;
- default:
- sock->ai_pos = sock->ai_pos->ai_next;
- continue;
- }
- s = GNUNET_NETWORK_socket_socket (sock->ai_pos->ai_family, SOCK_STREAM, 0);
- if (s == NULL)
- {
- /* maybe unsupported address family, try next */
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "socket");
- sock->ai_pos = sock->ai_pos->ai_next;
- continue;
- }
-#ifndef MINGW
- if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (s))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "GNUNET_NETWORK_socket_set_inheritable");
-#endif
- if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (s, GNUNET_NO))
- {
- /* we'll treat this one as fatal */
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
- return GNUNET_SYSERR;
- }
-#if DEBUG_CONNECTION
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Trying to connect to `%s'\n"),
- GNUNET_a2s(sock->ai_pos->ai_addr,
- sock->ai_pos->ai_addrlen));
-#endif
- if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s,
- sock->ai_pos->ai_addr,
- sock->ai_pos->ai_addrlen)) && (errno != EINPROGRESS))
- {
- /* maybe refused / unsupported address, try next */
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect");
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
- sock->ai_pos = sock->ai_pos->ai_next;
- continue;
- }
- break;
+ h->ccs -= CC_TRANSMIT_READY;
+ h->write_task =
+ GNUNET_SCHEDULER_add_write_net (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_absolute_get_remaining (h->nth.transmit_timeout),
+ h->sock, &transmit_ready, h);
+ }
+ if (0 != (h->ccs & CC_DESTROY_CONTINUATION))
+ {
+ h->ccs -= CC_DESTROY_CONTINUATION;
+ GNUNET_SCHEDULER_add_continuation (h->sched,
+ GNUNET_NO,
+ &destroy_continuation,
+ h,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
}
- /* got one! copy address information! */
- sock->addrlen = sock->ai_pos->ai_addrlen;
- sock->addr = GNUNET_malloc (sock->addrlen);
- memcpy (sock->addr, sock->ai_pos->ai_addr, sock->addrlen);
- sock->ai_pos = sock->ai_pos->ai_next;
- sock->sock = s;
- return GNUNET_OK;
}
/**
- * Scheduler let us know that we're either ready to
- * write on the socket OR connect timed out. Do the
- * right thing.
+ * Scheduler let us know that we're either ready to write on the
+ * socket OR connect timed out. Do the right thing.
+ *
+ * @param ap the address we were probing
+ * @param tc success or failure info about the connect attempt.
*/
static void
-connect_continuation (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+connect_probe_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct GNUNET_CONNECTION_Handle *sock = cls;
- struct GNUNET_TIME_Relative delay;
+ struct AddressProbe *ap = cls;
+ struct GNUNET_CONNECTION_Handle *h = ap->h;
+ struct AddressProbe *pos;
+ int error;
unsigned int len;
- int error;
- GNUNET_assert (0 < strlen (sock->hostname)); /* sanity check */
- /* nobody needs to wait for us anymore... */
- sock->connect_task = GNUNET_SCHEDULER_NO_TASK;
- /* Note: write-ready does NOT mean connect succeeded,
- we need to use getsockopt to be sure */
+ GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, ap);
+
len = sizeof (error);
errno = 0;
error = 0;
- if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
- (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (sock->sock, SOL_SOCKET, SO_ERROR, &error, &len)) ||
- (error != 0) || (errno != 0))
+ if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
+ (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error, &len)) ||
+ (error != 0) || (errno != 0) )
+ {
+ GNUNET_NETWORK_socket_close (ap->sock);
+ GNUNET_free (ap);
+ if ( (NULL == h->ap_head) &&
+ (h->dns_active == GNUNET_NO) )
+ connect_fail_continuation (h);
+ return;
+ }
+ h->sock = ap->sock;
+ GNUNET_assert (h->addr == NULL);
+ h->addr = GNUNET_malloc (ap->addrlen);
+ memcpy (h->addr, ap->addr, ap->addrlen);
+ h->addrlen = ap->addrlen;
+ GNUNET_free (ap);
+ /* cancel all other attempts */
+ while (NULL != (pos = h->ap_head))
+ {
+ GNUNET_NETWORK_socket_close (pos->sock);
+ GNUNET_SCHEDULER_cancel (h->sched, pos->task);
+ GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, pos);
+ GNUNET_free (pos);
+ }
+ connect_success_continuation (h);
+}
+
+
+/**
+ * Scheduler let us know that the connect task is finished (or was
+ * cancelled due to shutdown). Now really clean up.
+ *
+ * @param cls our "struct GNUNET_CONNECTION_Handle *"
+ * @param tc unused
+ */
+static void
+destroy_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_CONNECTION_Handle *sock = cls;
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ if (sock->dns_active == GNUNET_YES)
+ {
+ sock->dns_active = GNUNET_SYSERR;
+ return;
+ }
+ if (0 != (sock->ccs & CC_TRANSMIT_READY))
+ {
+ sock->ccs |= CC_DESTROY_CONTINUATION;
+ return;
+ }
+ if (sock->write_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_add_after (sock->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ sock->write_task,
+ &destroy_continuation, sock);
+ return;
+ }
+ if (sock->sock != NULL)
{
#if DEBUG_CONNECTION
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to establish TCP connection to `%s:%u': %s\n",
- GNUNET_a2s(sock->addr, sock->addrlen),
- STRERROR (GNUNET_MAX (error, errno)));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket.\n");
#endif
- /* connect failed / timed out */
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
- sock->sock = NULL;
- if (GNUNET_SYSERR == try_connect (sock))
+ GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
+ }
+ if (0 != (sock->ccs & CC_RECEIVE_AGAIN))
+ {
+ sock->ccs |= CC_DESTROY_CONTINUATION;
+ return;
+ }
+ if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_add_after (sock->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ sock->read_task,
+ &destroy_continuation, sock);
+ return;
+ }
+ if (NULL != (notify = sock->nth.notify_ready))
+ {
+ sock->nth.notify_ready = NULL;
+ notify (sock->nth.notify_ready_cls, 0, NULL);
+ if (sock->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK)
{
- /* failed for good */
-#if DEBUG_CONNECTION
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
- sock->hostname,
- sock->port);
-#endif
- /* connect failed / timed out */
- GNUNET_break (sock->ai_pos == NULL);
- freeaddrinfo (sock->ai);
- sock->ai = NULL;
- return;
+ GNUNET_SCHEDULER_cancel (sock->sched, sock->nth.timeout_task);
+ sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
}
- delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
- if (sock->nth.notify_ready != NULL)
- delay = GNUNET_TIME_relative_min (delay,
- GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout));
- if (sock->receiver != NULL)
- delay = GNUNET_TIME_relative_min (delay,
- GNUNET_TIME_absolute_get_remaining (sock->receive_timeout));
- delay.value /= (1 + sock->af_fam_offset);
-#if DEBUG_CONNECTION
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Will try to connect to `%s' for %llu ms\n",
- GNUNET_a2s (sock->addr,
- sock->addrlen),
- delay.value);
-#endif
- sock->connect_task = GNUNET_SCHEDULER_add_write_net (tc->sched, GNUNET_NO, /* abort on shutdown */
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK,
- delay,
- sock->sock,
- &connect_continuation,
- sock);
+ }
+ if (sock->sock != NULL)
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
+ GNUNET_free_non_null (sock->addr);
+ GNUNET_free_non_null (sock->hostname);
+ GNUNET_free (sock);
+}
+
+
+/**
+ * Try to establish a socket connection given the specified address.
+ * This function is called by the resolver once we have a DNS reply.
+ *
+ * @param cls our "struct GNUNET_CONNECTION_Handle *"
+ * @param addr address to try, NULL for "last call"
+ * @param addrlen length of addr
+ */
+static void
+try_connect_using_address (void *cls,
+ const struct sockaddr * addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_CONNECTION_Handle *h = cls;
+ struct AddressProbe *ap;
+ struct GNUNET_TIME_Relative delay;
+
+ if (addr == NULL)
+ {
+ if (h->dns_active == GNUNET_SYSERR)
+ {
+ h->dns_active = GNUNET_NO;
+ GNUNET_SCHEDULER_add_after (h->sched,
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ h->read_task,
+ &destroy_continuation,
+ h);
+ return;
+ }
+ h->dns_active = GNUNET_NO;
+ if (NULL == h->ap_head)
+ connect_fail_continuation (h);
return;
}
- /* connect succeeded! clean up "ai" */
+ if (h->sock != NULL)
+ return; /* already connected */
+ if (h->dns_active == GNUNET_SYSERR)
+ return; /* already destroyed */
+ /* try to connect */
+ ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
+ ap->addr = (const struct sockaddr*) &ap[1];
+ memcpy (&ap[1], addr, addrlen);
+ ap->addrlen = addrlen;
+ ap->h = h;
+
+ switch (ap->addr->sa_family)
+ {
+ case AF_INET:
+ ((struct sockaddr_in *) ap->addr)->sin_port = htons (h->port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (h->port);
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_free (ap);
+ return; /* not supported by us */
+ }
+ ap->sock = GNUNET_NETWORK_socket_socket (ap->addr->sa_family, SOCK_STREAM, 0);
+ if (ap->sock == NULL)
+ {
+ GNUNET_free (ap);
+ return; /* not supported by OS */
+ }
+#ifndef MINGW
+ if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (ap->sock))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "GNUNET_NETWORK_socket_set_inheritable");
+#endif
+ if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (ap->sock, GNUNET_NO))
+ {
+ /* we might want to treat this one as fatal... */
+ GNUNET_break (0);
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
+ GNUNET_free (ap);
+ return;
+ }
#if DEBUG_CONNECTION
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connection to `%s' succeeded!\n",
- GNUNET_a2s(sock->addr, sock->addrlen));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Trying to connect to `%s'\n"),
+ GNUNET_a2s(ap->addr,
+ ap->addrlen));
#endif
- freeaddrinfo (sock->ai);
- sock->ai_pos = NULL;
- sock->ai = NULL;
+ if ( (GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock,
+ ap->addr,
+ ap->addrlen)) &&
+ (errno != EINPROGRESS))
+ {
+ /* maybe refused / unsupported address, try next */
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect");
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
+ GNUNET_free (ap);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_insert (h->ap_head, h->ap_tail, ap);
+ delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
+ if (h->nth.notify_ready != NULL)
+ delay = GNUNET_TIME_relative_min (delay,
+ GNUNET_TIME_absolute_get_remaining (h->nth.transmit_timeout));
+ if (h->receiver != NULL)
+ delay = GNUNET_TIME_relative_min (delay,
+ GNUNET_TIME_absolute_get_remaining (h->receive_timeout));
+ ap->task = GNUNET_SCHEDULER_add_write_net (h->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ delay,
+ ap->sock,
+ &connect_probe_continuation,
+ ap);
+}
+
+
+/**
+ * It is time to re-try connecting.
+ *
+ * @param cls the handle for the connection that should be re-tried
+ * @param tc unused scheduler taks context
+ */
+static void
+retry_connect_continuation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_CONNECTION_Handle *sock = cls;
+
+ sock->dns_active = GNUNET_YES;
+ GNUNET_RESOLVER_ip_get (sock->sched,
+ sock->cfg,
+ sock->hostname,
+ AF_UNSPEC,
+ GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+ &try_connect_using_address,
+ sock);
}
* yet been established. This function only creates TCP connections.
*
* @param sched scheduler to use
+ * @param cfg configuration to use
* @param hostname name of the host to connect to
* @param port port to connect to
* @param maxbuf maximum write buffer size for the socket (use
* @return the socket handle
*/
struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (struct GNUNET_SCHEDULER_Handle
- *sched, const char *hostname,
- uint16_t port, size_t maxbuf)
+GNUNET_CONNECTION_create_from_connect (struct GNUNET_SCHEDULER_Handle *sched,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *hostname,
+ uint16_t port, size_t maxbuf)
{
struct GNUNET_CONNECTION_Handle *ret;
GNUNET_assert (0 < strlen (hostname)); /* sanity check */
ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle) + maxbuf);
- ret->sock = NULL;
+ ret->cfg = cfg;
ret->sched = sched;
ret->write_buffer = (char *) &ret[1];
ret->write_buffer_size = maxbuf;
ret->port = port;
- ret->af_fam_offset = sizeof (address_families) / sizeof(address_families[0]);
ret->hostname = GNUNET_strdup (hostname);
- if (GNUNET_SYSERR == try_connect (ret))
- {
- if (NULL != ret->ai)
- freeaddrinfo (ret->ai);
- GNUNET_free (ret->hostname);
- GNUNET_free (ret);
- return NULL;
- }
- ret->connect_task = GNUNET_SCHEDULER_add_write_net (sched, GNUNET_NO, /* abort on shutdown */
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK,
- GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
- ret->sock,
- &connect_continuation, ret);
+ retry_connect_continuation (ret, NULL);
return ret;
-
}
int
GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock)
{
- if (sock->ai != NULL)
+ if ( (sock->ap_head != NULL) ||
+ (sock->dns_active == GNUNET_YES) )
return GNUNET_YES; /* still trying to connect */
return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES;
}
-/**
- * Scheduler let us know that the connect task is finished (or was
- * cancelled due to shutdown). Now really clean up.
- */
-static void
-destroy_continuation (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_CONNECTION_Handle *sock = cls;
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- if (sock->write_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_SCHEDULER_add_after (sock->sched,
- GNUNET_YES,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sock->write_task,
- &destroy_continuation, sock);
- return;
- }
- if (sock->sock != NULL)
- {
-#if DEBUG_CONNECTION
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket.\n");
-#endif
- GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
- }
- if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_SCHEDULER_add_after (sock->sched,
- GNUNET_YES,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sock->read_task,
- &destroy_continuation, sock);
- return;
- }
- if (NULL != (notify = sock->nth.notify_ready))
- {
- sock->nth.notify_ready = NULL;
- notify (sock->nth.notify_ready_cls, 0, NULL);
- if (sock->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_SCHEDULER_cancel (sock->sched, sock->nth.timeout_task);
- sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
- }
- }
- if (sock->sock != NULL)
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
- GNUNET_free_non_null (sock->addr);
- if (sock->ai != NULL)
- freeaddrinfo (sock->ai);
- GNUNET_free_non_null (sock->hostname);
- GNUNET_free (sock);
-}
-
-
/**
* Close the socket and free associated resources. Pending
* transmissions are simply dropped. A pending receive call will be
void
GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock)
{
- if (sock->write_buffer_off == 0)
- sock->ai_pos = NULL; /* if we're still trying to connect and have
- no message pending, stop trying! */
+ if ( (sock->write_buffer_off == 0) &&
+ (sock->dns_active == GNUNET_YES) )
+ {
+ sock->dns_active = GNUNET_SYSERR; /* if we're still trying to connect and have
+ no message pending, stop trying! */
+ return;
+ }
GNUNET_assert (sock->sched != NULL);
GNUNET_SCHEDULER_add_after (sock->sched,
GNUNET_YES,
GNUNET_SCHEDULER_PRIORITY_KEEP,
- sock->connect_task,
+ GNUNET_SCHEDULER_NO_TASK,
&destroy_continuation, sock);
}
+
/**
* Tell the receiver callback that a timeout was reached.
*/
* timed out and that we're immediately retrying. If we are retrying,
* we need to wait again (or timeout); if we succeeded, we need to
* wait for data (or timeout).
+ *
+ * @param cls our connection handle
+ * @param tc task context describing why we are here
*/
static void
receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
struct GNUNET_TIME_Absolute now;
sh->read_task = GNUNET_SCHEDULER_NO_TASK;
- if ((sh->sock == NULL) &&
- (sh->connect_task == GNUNET_SCHEDULER_NO_TASK))
+ if (sh->sock == NULL)
{
/* not connected and no longer trying */
#if DEBUG_CONNECTION
signal_timeout (sh);
return;
}
- if (sh->connect_task != GNUNET_SCHEDULER_NO_TASK)
- {
- /* connect was retried */
- sh->read_task = GNUNET_SCHEDULER_add_after (tc->sched,
- GNUNET_YES,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sh->connect_task,
- &receive_again, sh);
- return;
- }
+ GNUNET_assert (sh->sock != NULL);
/* connect succeeded, wait for data! */
sh->read_task = GNUNET_SCHEDULER_add_read_net (tc->sched,
- GNUNET_YES,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sh->connect_task,
- GNUNET_TIME_absolute_get_remaining
- (sh->receive_timeout),
- sh->sock, &receive_ready,
- sh);
+ GNUNET_YES,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_absolute_get_remaining
+ (sh->receive_timeout),
+ sh->sock,
+ &receive_ready,
+ sh);
}
* @param timeout maximum amount of time to wait (use -1 for "forever")
* @param receiver function to call with received data
* @param receiver_cls closure for receiver
- * @return scheduler task ID used for receiving, GNUNET_SCHEDULER_NO_TASK on error
*/
-GNUNET_SCHEDULER_TaskIdentifier
+void
GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock,
size_t max,
struct GNUNET_TIME_Relative timeout,
struct GNUNET_SCHEDULER_TaskContext tc;
GNUNET_assert ((sock->read_task == GNUNET_SCHEDULER_NO_TASK) &&
+ (0 == (sock->ccs & CC_RECEIVE_AGAIN)) &&
(sock->receiver == NULL));
sock->receiver = receiver;
sock->receiver_cls = receiver_cls;
sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
sock->max = max;
- memset (&tc, 0, sizeof (tc));
- tc.sched = sock->sched;
- tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE;
- receive_again (sock, &tc);
- return sock->read_task;
+ if (sock->sock != NULL)
+ {
+ memset (&tc, 0, sizeof (tc));
+ tc.sched = sock->sched;
+ tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE;
+ receive_again (sock, &tc);
+ return;
+ }
+ if ( (sock->dns_active != GNUNET_YES) &&
+ (sock->ap_head == NULL) )
+ {
+ receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
+ return;
+ }
+ sock->ccs += CC_RECEIVE_AGAIN;
}
* for the cancellation to be valid.
*
* @param sock socket handle
- * @param task task identifier returned from the receive call
- * @return closure of the original receiver callback
+ * @return closure of the original receiver callback closure
*/
void *
-GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock,
- GNUNET_SCHEDULER_TaskIdentifier task)
+GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock)
{
- GNUNET_assert (sock->read_task == task);
- GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->sched, task));
- sock->read_task = GNUNET_SCHEDULER_NO_TASK;
+ if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->sched,
+ sock->read_task));
+ sock->read_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ else
+ {
+ GNUNET_assert (0 != (sock->ccs & CC_RECEIVE_AGAIN));
+ sock->ccs -= CC_RECEIVE_AGAIN;
+ }
sock->receiver = NULL;
return sock->receiver_cls;
}
* See if we are now connected. If not, wait longer for
* connect to succeed. If connected, we should be able
* to write now as well, unless we timed out.
+ *
+ * @param cls our connection handle
+ * @param tc task context describing why we are here
*/
static void
transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
GNUNET_assert (sock->write_task != GNUNET_SCHEDULER_NO_TASK);
sock->write_task = GNUNET_SCHEDULER_NO_TASK;
- if (sock->connect_task != GNUNET_SCHEDULER_NO_TASK)
- {
- /* still waiting for connect */
- GNUNET_assert (sock->write_task ==
- GNUNET_SCHEDULER_NO_TASK);
- sock->write_task =
- GNUNET_SCHEDULER_add_delayed (tc->sched, GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sock->connect_task,
- GNUNET_TIME_UNIT_ZERO, &transmit_ready,
- sock);
- return;
- }
if ( (sock->sock == NULL) ||
( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) &&
(0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) &&
GNUNET_assert (notify != NULL);
GNUNET_assert (sock->write_buffer_size >= size);
- if ((sock->sock == NULL) &&
- (sock->connect_task == GNUNET_SCHEDULER_NO_TASK))
+ if ( (sock->sock == NULL) &&
+ (sock->ap_head == NULL) &&
+ (sock->dns_active != GNUNET_YES) )
{
#if DEBUG_CONNECTION
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
sock);
if (sock->write_task == GNUNET_SCHEDULER_NO_TASK)
{
- if (sock->connect_task == GNUNET_SCHEDULER_NO_TASK)
+ if (sock->sock != NULL)
sock->write_task = GNUNET_SCHEDULER_add_write_net (sock->sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK,
- GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout),
- sock->sock,
- &transmit_ready, sock);
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout),
+ sock->sock,
+ &transmit_ready, sock);
else
- sock->write_task = GNUNET_SCHEDULER_add_delayed (sock->sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- sock->connect_task,
- GNUNET_TIME_UNIT_ZERO,
- &transmit_ready, sock);
+ sock->ccs |= CC_TRANSMIT_READY;
}
return &sock->nth;
}
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2007, 2008, 2009 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
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file resolver/gnunet-service-resolver.c
+ * @brief code to do DNS resolution
+ * @author Christian Grothoff
+ */
+
+#include <stdlib.h>
+#include "platform.h"
+#include "gnunet_disk_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_service_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_strings_lib.h"
+#include "gnunet_time_lib.h"
+#include "resolver.h"
+
+
+struct IPCache
+{
+ struct IPCache *next;
+ char *addr;
+ struct sockaddr *sa;
+ struct GNUNET_TIME_Absolute last_refresh;
+ struct GNUNET_TIME_Absolute last_request;
+ unsigned int salen;
+};
+
+
+static struct IPCache *head;
+
+
+
+
+#if HAVE_GETNAMEINFO
+static void
+getnameinfo_resolve (struct IPCache *cache)
+{
+ char hostname[256];
+
+ if (0 == getnameinfo (cache->sa,
+ cache->salen,
+ hostname,
+ sizeof(hostname),
+ NULL, 0, 0))
+ cache->addr = GNUNET_strdup (hostname);
+}
+#endif
+
+
+#if HAVE_GETHOSTBYADDR
+static void
+gethostbyaddr_resolve (struct IPCache *cache)
+{
+ struct hostent *ent;
+
+ switch (cache->sa->sa_family)
+ {
+ case AF_INET:
+ ent = gethostbyaddr (&((struct sockaddr_in *) cache->sa)->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ break;
+ case AF_INET6:
+ ent = gethostbyaddr (&((struct sockaddr_in6 *) cache->sa)->sin6_addr,
+ sizeof (struct in6_addr), AF_INET6);
+ break;
+ default:
+ ent = NULL;
+ }
+ if (ent != NULL)
+ cache->addr = GNUNET_strdup (ent->h_name);
+}
+#endif
+
+
+static void
+cache_resolve (struct IPCache *cache)
+{
+#if HAVE_GETNAMEINFO
+ if (cache->addr == NULL)
+ getnameinfo_resolve (cache);
+#endif
+#if HAVE_GETHOSTBYADDR
+ if (cache->addr == NULL)
+ gethostbyaddr_resolve (cache);
+#endif
+}
+
+
+
+/**
+ * Get an IP address as a string (works for both IPv4 and IPv6). Note
+ * that the resolution happens asynchronously and that the first call
+ * may not immediately result in the FQN (but instead in a
+ * human-readable IP address).
+ *
+ * @param sa should be of type "struct sockaddr*"
+ */
+static void
+get_ip_as_string (struct GNUNET_SERVER_Client *client,
+ const struct sockaddr *sav, socklen_t salen)
+{
+ struct IPCache *cache;
+ struct IPCache *prev;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_SERVER_TransmitContext *tc;
+
+ if (salen < sizeof (struct sockaddr))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ now = GNUNET_TIME_absolute_get ();
+ cache = head;
+ prev = NULL;
+ while ((cache != NULL) &&
+ ((cache->salen != salen) || (0 != memcmp (cache->sa, sav, salen))))
+ {
+ if (GNUNET_TIME_absolute_get_duration (cache->last_request).value <
+ 60 * 60 * 1000)
+ {
+ if (prev != NULL)
+ {
+ prev->next = cache->next;
+ GNUNET_free_non_null (cache->addr);
+ GNUNET_free (cache->sa);
+ GNUNET_free (cache);
+ cache = prev->next;
+ }
+ else
+ {
+ head = cache->next;
+ GNUNET_free_non_null (cache->addr);
+ GNUNET_free (cache->sa);
+ GNUNET_free (cache);
+ cache = head;
+ }
+ continue;
+ }
+ prev = cache;
+ cache = cache->next;
+ }
+ if (cache != NULL)
+ {
+ cache->last_request = now;
+ if (GNUNET_TIME_absolute_get_duration (cache->last_request).value <
+ 60 * 60 * 1000)
+ {
+ GNUNET_free_non_null (cache->addr);
+ cache->addr = NULL;
+ cache->salen = 0;
+ cache_resolve (cache);
+ }
+ }
+ else
+ {
+ cache = GNUNET_malloc (sizeof (struct IPCache));
+ cache->next = head;
+ cache->salen = salen;
+ cache->sa = GNUNET_malloc (salen);
+ memcpy (cache->sa, sav, salen);
+ cache->last_request = GNUNET_TIME_absolute_get ();
+ cache->last_refresh = GNUNET_TIME_absolute_get ();
+ cache->addr = NULL;
+ cache_resolve (cache);
+ head = cache;
+ }
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ if (cache->addr != NULL)
+ GNUNET_SERVER_transmit_context_append (tc,
+ cache->addr,
+ strlen (cache->addr) + 1,
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+#if HAVE_GETADDRINFO
+static int
+getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc,
+ const char *hostname, int domain)
+{
+ int s;
+ struct addrinfo hints;
+ struct addrinfo *result;
+ struct addrinfo *pos;
+
+ memset (&hints, 0, sizeof (struct addrinfo));
+// FIXME in PlibC
+#ifndef MINGW
+ hints.ai_family = domain;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_STREAM; /* go for TCP */
+
+ if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Could not resolve `%s' (%s): %s\n"), hostname,
+ (domain ==
+ AF_INET) ? "IPv4" : ((domain ==
+ AF_INET6) ? "IPv6" : "any"),
+ gai_strerror (s));
+ if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) ||
+#ifndef MINGW
+ (s == EAI_SYSTEM)
+#else
+ // FIXME NILS
+ 1
+#endif
+ )
+ return GNUNET_NO; /* other function may still succeed */
+ return GNUNET_SYSERR;
+ }
+ if (result == NULL)
+ return GNUNET_SYSERR;
+ pos = result;
+ while (pos != NULL)
+ {
+ GNUNET_SERVER_transmit_context_append (tc,
+ result->ai_addr,
+ result->ai_addrlen,
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ pos = pos->ai_next;
+ }
+ freeaddrinfo (result);
+ return GNUNET_OK;
+}
+#endif
+
+#if HAVE_GETHOSTBYNAME2
+static int
+gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc,
+ const char *hostname, int domain)
+{
+ struct hostent *hp;
+ struct sockaddr_in a4;
+ struct sockaddr_in6 a6;
+ int ret1;
+ int ret2;
+
+ if (domain == AF_UNSPEC)
+ {
+ ret1 = gethostbyname2_resolve (tc, hostname, AF_INET);
+ ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6);
+ if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK))
+ return GNUNET_OK;
+ if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR))
+ return GNUNET_SYSERR;
+ return GNUNET_NO;
+ }
+ hp = gethostbyname2 (hostname, domain);
+ if (hp == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Could not find IP of host `%s': %s\n"),
+ hostname, hstrerror (h_errno));
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (hp->h_addrtype == domain);
+ if (domain == AF_INET)
+ {
+ GNUNET_assert (hp->h_length == sizeof (struct in_addr));
+ memset (&a4, 0, sizeof (a4));
+ a4.sin_family = AF_INET;
+ memcpy (&a4.sin_addr, hp->h_addr_list[0], hp->h_length);
+ GNUNET_SERVER_transmit_context_append (tc,
+ &a4,
+ sizeof (a4),
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ }
+ else
+ {
+ GNUNET_assert (hp->h_length == sizeof (struct in6_addr));
+ memset (&a6, 0, sizeof (a6));
+ a6.sin6_family = AF_INET6;
+ memcpy (&a6.sin6_addr, hp->h_addr_list[0], hp->h_length);
+ GNUNET_SERVER_transmit_context_append (tc,
+ &a6,
+ sizeof (a6),
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ }
+ return GNUNET_OK;
+}
+#endif
+
+#if HAVE_GETHOSTBYNAME
+static int
+gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc,
+ const char *hostname)
+{
+ struct hostent *hp;
+ struct sockaddr_in addr;
+
+ hp = GETHOSTBYNAME (hostname);
+ if (hp == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Could not find IP of host `%s': %s\n"),
+ hostname, hstrerror (h_errno));
+ return GNUNET_SYSERR;
+ }
+ if (hp->h_addrtype != AF_INET)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (hp->h_length == sizeof (struct in_addr));
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_family = AF_INET;
+ memcpy (&addr.sin_addr, hp->h_addr_list[0], hp->h_length);
+ GNUNET_SERVER_transmit_context_append (tc,
+ &addr,
+ sizeof (addr),
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ return GNUNET_OK;
+}
+#endif
+
+
+/**
+ * Convert a string to an IP address.
+ *
+ * @param client where to send the IP address
+ * @param hostname the hostname to resolve
+ * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
+ */
+static void
+get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
+ const char *hostname, int domain)
+{
+ int ret;
+ struct GNUNET_SERVER_TransmitContext *tc;
+
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ ret = GNUNET_NO;
+#if HAVE_GETADDRINFO
+ if (ret == GNUNET_NO)
+ ret = getaddrinfo_resolve (tc, hostname, domain);
+#endif
+#if HAVE_GETHOSTBYNAME2
+ if (ret == GNUNET_NO)
+ ret = gethostbyname2_resolve (tc, hostname, domain);
+#endif
+#if HAVE_GETHOSTBYNAME
+ if ((ret == GNUNET_NO) && ((domain == AF_UNSPEC) || (domain == PF_INET)))
+ gethostbyname_resolve (tc, hostname);
+#endif
+ GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+/**
+ * Handle GET-message.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_get (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ uint16_t msize;
+ const struct GNUNET_RESOLVER_GetMessage *msg;
+ const char *hostname;
+ uint16_t size;
+ int direction;
+ int domain;
+
+ msize = ntohs (message->size);
+ if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msg = (const struct GNUNET_RESOLVER_GetMessage *) message;
+ size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage);
+ direction = ntohl (msg->direction);
+ domain = ntohl (msg->domain);
+ if (direction == GNUNET_NO)
+ {
+ /* IP from hostname */
+ hostname = (const char *) &msg[1];
+ if (hostname[size - 1] != '\0')
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolver asked to look up `%s'.\n"), hostname);
+#endif
+ get_ip_from_hostname (client, hostname, domain);
+ }
+ else
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolver asked to look up IP address.\n"));
+#endif
+ get_ip_as_string (client, (const struct sockaddr *) &msg[1], size);
+ }
+}
+
+
+/**
+ * List of handlers for the messages understood by this
+ * service.
+ */
+static struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0},
+ {NULL, NULL, 0, 0}
+};
+
+
+/**
+ * Process resolver requests.
+ *
+ * @param cls closure
+ * @param sched scheduler to use
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+static void
+run (void *cls,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ GNUNET_SERVER_add_handlers (server, handlers);
+}
+
+
+/**
+ * The main function for the resolver service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ int ret;
+ struct IPCache *pos;
+
+ ret = (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc,
+ argv,
+ "resolver", &run, NULL, NULL, NULL)) ? 0 : 1;
+
+ while (head != NULL)
+ {
+ pos = head->next;
+ GNUNET_free_non_null (head->addr);
+ GNUNET_free (head->sa);
+ GNUNET_free (head);
+ head = pos;
+ }
+ return ret;
+}
+
+/* end of gnunet-service-resolver.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2009 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
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @author Christian Grothoff
+ * @file resolver/resolver.h
+ */
+#ifndef RESOLVER_H
+#define RESOLVER_H
+
+#include "gnunet_common.h"
+
+#define DEBUG_RESOLVER GNUNET_NO
+
+/**
+ * Request for the resolver. Followed by either
+ * the "struct sockaddr" or the 0-terminated hostname.
+ *
+ * The response will be one or more messages of type
+ * RESOLVER_RESPONSE, each with the message header
+ * immediately followed by the requested data
+ * (hostname or struct sockaddr, depending on direction).
+ * The last RESOLVER_RESPONSE will just be a header
+ * without any data (used to indicate the end of the list).
+ */
+struct GNUNET_RESOLVER_GetMessage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_STATISTICS_VALUE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * GNUNET_YES to get hostname from IP,
+ * GNUNET_NO to get IP from hostname.
+ */
+ int32_t direction GNUNET_PACKED;
+
+ /**
+ * Domain to use (AF_INET, AF_INET6 or AF_UNSPEC).
+ */
+ int32_t domain GNUNET_PACKED;
+
+};
+
+#endif
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2009 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
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file resolver/resolver_api.c
+ * @brief resolver for writing a tool
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_server_lib.h"
+#include "resolver.h"
+
+
+/**
+ * FIXME.
+ */
+struct GetAddressContext
+{
+
+ /**
+ * FIXME.
+ */
+ GNUNET_RESOLVER_AddressCallback callback;
+
+ /**
+ * Closure for "callback".
+ */
+ void *cls;
+
+ /**
+ * FIXME.
+ */
+ struct GNUNET_RESOLVER_GetMessage *msg;
+
+ /**
+ * FIXME.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * FIXME.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+};
+
+
+/**
+ * Possible hostnames for "loopback".
+ */
+static const char *loopback[] = {
+ "localhost",
+ "127.0.0.1",
+ "ip6-localnet",
+ "::1",
+ NULL
+};
+
+
+/**
+ * Check that the resolver service runs on localhost
+ * (or equivalent).
+ */
+static void
+check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *hostname;
+ unsigned int i;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "resolver",
+ "HOSTNAME",
+ &hostname))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Must specify `%s' for `%s' in configuration!\n"),
+ "HOSTNAME",
+ "resolver");
+ GNUNET_assert (0);
+ }
+ i = 0;
+ while (loopback[i] != NULL)
+ if (0 == strcmp (loopback[i++], hostname))
+ {
+ GNUNET_free (hostname);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Must specify `%s' for `%s' in configuration!\n"),
+ "localhost",
+ "resolver");
+ GNUNET_free (hostname);
+ GNUNET_assert (0);
+}
+
+
+/**
+ * Convert IP address to string without DNS resolution.
+ */
+static char *
+no_resolve (const struct sockaddr *sa, socklen_t salen)
+{
+ char *ret;
+ char inet4[INET_ADDRSTRLEN];
+ char inet6[INET6_ADDRSTRLEN];
+
+ if (salen < sizeof (struct sockaddr))
+ return NULL;
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (salen != sizeof (struct sockaddr_in))
+ return NULL;
+ inet_ntop (AF_INET,
+ &((struct sockaddr_in *) sa)->sin_addr,
+ inet4, INET_ADDRSTRLEN);
+ ret = GNUNET_strdup (inet4);
+ break;
+ case AF_INET6:
+ if (salen != sizeof (struct sockaddr_in6))
+ return NULL;
+ inet_ntop (AF_INET6,
+ &((struct sockaddr_in6 *) sa)->sin6_addr,
+ inet6, INET6_ADDRSTRLEN);
+ ret = GNUNET_strdup (inet6);
+ break;
+ default:
+ ret = NULL;
+ break;
+ }
+ return ret;
+}
+
+
+static void
+handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GetAddressContext *gac = cls;
+ uint16_t size;
+ const struct sockaddr *sa;
+ socklen_t salen;
+
+
+ if (msg == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Timeout trying to resolve hostname.\n"));
+ gac->callback (gac->cls, NULL, 0);
+ GNUNET_CLIENT_disconnect (gac->client);
+ GNUNET_free (gac);
+ return;
+ }
+ if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
+ {
+ GNUNET_break (0);
+ gac->callback (gac->cls, NULL, 0);
+ GNUNET_CLIENT_disconnect (gac->client);
+ GNUNET_free (gac);
+ return;
+ }
+
+ size = ntohs (msg->size);
+ if (size == sizeof (struct GNUNET_MessageHeader))
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Received end message resolving hostname.\n"));
+#endif
+ gac->callback (gac->cls, NULL, 0);
+ GNUNET_CLIENT_disconnect (gac->client);
+ GNUNET_free (gac);
+ return;
+ }
+ sa = (const struct sockaddr *) &msg[1];
+ salen = size - sizeof (struct GNUNET_MessageHeader);
+ if (salen < sizeof (struct sockaddr))
+ {
+ GNUNET_break (0);
+ gac->callback (gac->cls, NULL, 0);
+ GNUNET_CLIENT_disconnect (gac->client);
+ GNUNET_free (gac);
+ return;
+ }
+#if DEBUG_RESOLVER
+ {
+ char *ips = no_resolve (sa, salen);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), ips);
+ GNUNET_free (ips);
+ }
+#endif
+ gac->callback (gac->cls, sa, salen);
+ GNUNET_CLIENT_receive (gac->client,
+ &handle_address_response,
+ gac,
+ GNUNET_TIME_absolute_get_remaining (gac->timeout));
+}
+
+
+static size_t
+transmit_get_ip (void *cls, size_t size, void *buf)
+{
+ struct GetAddressContext *actx = cls;
+ uint16_t ms;
+
+ if (buf == NULL)
+ {
+ /* timeout / error */
+ GNUNET_free (actx->msg);
+ actx->callback (actx->cls, NULL, 0);
+ GNUNET_CLIENT_disconnect (actx->client);
+ GNUNET_free (actx);
+ return 0;
+ }
+ ms = ntohs (actx->msg->header.size);
+ GNUNET_assert (size >= ms);
+ memcpy (buf, actx->msg, ms);
+ GNUNET_free (actx->msg);
+ actx->msg = NULL;
+ GNUNET_CLIENT_receive (actx->client,
+ &handle_address_response,
+ actx,
+ GNUNET_TIME_absolute_get_remaining (actx->timeout));
+ return ms;
+}
+
+
+
+/**
+ * Convert a string to one or more IP addresses.
+ *
+ * @param sched scheduler to use
+ * @param cfg configuration to use
+ * @param hostname the hostname to resolve
+ * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
+ * @param callback function to call with addresses
+ * @param callback_cls closure for callback
+ * @param timeout how long to try resolving
+ */
+void
+GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *hostname,
+ int domain,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_RESOLVER_AddressCallback callback,
+ void *callback_cls)
+{
+ struct GNUNET_CLIENT_Connection *client;
+ struct GNUNET_RESOLVER_GetMessage *msg;
+ struct GetAddressContext *actx;
+ size_t slen;
+ unsigned int i;
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+
+ check_config (cfg);
+ i = 0;
+ while (loopback[i] != NULL)
+ if (0 == strcmp (loopback[i++], hostname))
+ {
+ memset (&v4, 0, sizeof(v4));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v4.sin_len = sizeof (v4);
+#endif
+ v4.sin_family = AF_INET;
+ v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ memset (&v6, 0, sizeof(v6));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v6.sin6_len = sizeof (v6);
+#endif
+ v6.sin6_family = AF_INET6;
+ v6.sin6_addr = in6addr_loopback;
+
+ switch (domain)
+ {
+ case AF_INET:
+ callback (callback_cls,
+ (const struct sockaddr*) &v4,
+ sizeof(v4));
+ break;
+ case AF_INET6:
+ callback (callback_cls,
+ (const struct sockaddr*) &v6,
+ sizeof(v6));
+ break;
+ case AF_UNSPEC:
+ callback (callback_cls,
+ (const struct sockaddr*) &v4,
+ sizeof(v4));
+ callback (callback_cls,
+ (const struct sockaddr*) &v6,
+ sizeof(v6));
+ break;
+ }
+ callback (callback_cls, NULL, 0);
+ return;
+ }
+ slen = strlen (hostname) + 1;
+ if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ callback (callback_cls, NULL, 0);
+ return;
+ }
+ client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
+ if (client == NULL)
+ {
+ callback (callback_cls, NULL, 0);
+ return;
+ }
+ msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
+ msg->header.size =
+ htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
+ msg->direction = htonl (GNUNET_NO);
+ msg->domain = htonl (domain);
+ memcpy (&msg[1], hostname, slen);
+ actx = GNUNET_malloc (sizeof (struct GetAddressContext));
+ actx->callback = callback;
+ actx->cls = callback_cls;
+ actx->client = client;
+ actx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ actx->msg = msg;
+
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolver requests DNS resolution of hostname `%s'.\n"),
+ hostname);
+#endif
+ if (NULL ==
+ GNUNET_CLIENT_notify_transmit_ready (client,
+ slen +
+ sizeof (struct
+ GNUNET_RESOLVER_GetMessage),
+ timeout, &transmit_get_ip, actx))
+ {
+ GNUNET_free (msg);
+ GNUNET_free (actx);
+ callback (callback_cls, NULL, 0);
+ GNUNET_CLIENT_disconnect (client);
+ return;
+ }
+}
+
+
+struct GetHostnameContext
+{
+ GNUNET_RESOLVER_HostnameCallback callback;
+ void *cls;
+ struct GNUNET_RESOLVER_GetMessage *msg;
+ struct GNUNET_CLIENT_Connection *client;
+ struct GNUNET_TIME_Absolute timeout;
+};
+
+
+static void
+handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GetHostnameContext *ghc = cls;
+ uint16_t size;
+ const char *hostname;
+
+ if (msg == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Timeout trying to resolve IP address.\n"));
+ ghc->callback (ghc->cls, NULL);
+ GNUNET_CLIENT_disconnect (ghc->client);
+ GNUNET_free (ghc);
+ return;
+ }
+ size = ntohs (msg->size);
+ if (size == sizeof (struct GNUNET_MessageHeader))
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Received end message resolving IP address.\n"));
+#endif
+ ghc->callback (ghc->cls, NULL);
+ GNUNET_CLIENT_disconnect (ghc->client);
+ GNUNET_free (ghc);
+ return;
+ }
+ hostname = (const char *) &msg[1];
+ if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
+ {
+ GNUNET_break (0);
+ ghc->callback (ghc->cls, NULL);
+ GNUNET_CLIENT_disconnect (ghc->client);
+ GNUNET_free (ghc);
+ return;
+ }
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolver returns `%s'.\n"), hostname);
+#endif
+ ghc->callback (ghc->cls, hostname);
+ GNUNET_CLIENT_receive (ghc->client,
+ &handle_hostname_response,
+ ghc,
+ GNUNET_TIME_absolute_get_remaining (ghc->timeout));
+}
+
+
+static size_t
+transmit_get_hostname (void *cls, size_t size, void *buf)
+{
+ struct GetHostnameContext *hctx = cls;
+ uint16_t msize;
+
+ if (buf == NULL)
+ {
+ GNUNET_free (hctx->msg);
+ hctx->callback (hctx->cls, NULL);
+ GNUNET_CLIENT_disconnect (hctx->client);
+ GNUNET_free (hctx);
+ return 0;
+ }
+ msize = ntohs (hctx->msg->header.size);
+ GNUNET_assert (size >= msize);
+ memcpy (buf, hctx->msg, msize);
+ GNUNET_free (hctx->msg);
+ hctx->msg = NULL;
+ GNUNET_CLIENT_receive (hctx->client,
+ &handle_hostname_response,
+ hctx,
+ GNUNET_TIME_absolute_get_remaining (hctx->timeout));
+ return msize;
+}
+
+
+
+
+/**
+ * Get an IP address as a string.
+ *
+ * @param sched scheduler to use
+ * @param cfg configuration to use
+ * @param sa host address
+ * @param salen length of host address
+ * @param do_resolve use GNUNET_NO to return numeric hostname
+ * @param timeout how long to try resolving
+ * @param callback function to call with hostnames
+ * @param cls closure for callback
+ */
+void
+GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct sockaddr *sa,
+ socklen_t salen,
+ int do_resolve,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_RESOLVER_HostnameCallback callback,
+ void *cls)
+{
+ char *result;
+ struct GNUNET_CLIENT_Connection *client;
+ struct GNUNET_RESOLVER_GetMessage *msg;
+ struct GetHostnameContext *hctx;
+
+ check_config (cfg);
+ if (GNUNET_NO == do_resolve)
+ {
+ result = no_resolve (sa, salen);
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolver returns `%s'.\n"), result);
+#endif
+ callback (cls, result);
+ if (result != NULL)
+ {
+ GNUNET_free (result);
+ callback (cls, NULL);
+ }
+ return;
+ }
+ if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ callback (cls, NULL);
+ return;
+ }
+ client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
+ if (client == NULL)
+ {
+ callback (cls, NULL);
+ return;
+ }
+ msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
+ msg->header.size =
+ htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
+ msg->direction = htonl (GNUNET_YES);
+ msg->domain = htonl (sa->sa_family);
+ memcpy (&msg[1], sa, salen);
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolver requests DNS resolution of IP address.\n"));
+#endif
+ hctx = GNUNET_malloc (sizeof (struct GetHostnameContext));
+ hctx->callback = callback;
+ hctx->cls = cls;
+ hctx->client = client;
+ hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ hctx->msg = msg;
+ if (NULL ==
+ GNUNET_CLIENT_notify_transmit_ready (client,
+ sizeof (struct
+ GNUNET_RESOLVER_GetMessage)
+ + salen, timeout,
+ &transmit_get_hostname, hctx))
+ {
+ GNUNET_free (msg);
+ callback (cls, NULL);
+ GNUNET_CLIENT_disconnect (client);
+ GNUNET_free (hctx);
+ }
+}
+
+/**
+ * Maximum supported length of hostname
+ */
+#define MAX_HOSTNAME 1024
+
+
+/**
+ * Resolve our hostname to an IP address.
+ *
+ * @param sched scheduler to use
+ * @param cfg configuration to use
+ * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
+ * @param callback function to call with addresses
+ * @param cls closure for callback
+ * @param timeout how long to try resolving
+ */
+void
+GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ int domain,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_RESOLVER_AddressCallback callback,
+ void *cls)
+{
+ char hostname[MAX_HOSTNAME];
+
+ check_config (cfg);
+ if (0 != gethostname (hostname, sizeof (hostname) - 1))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
+ GNUNET_ERROR_TYPE_BULK, "gethostname");
+ callback (cls, NULL, 0);
+ return;
+ }
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Resolving our hostname `%s'\n"), hostname);
+#endif
+ GNUNET_RESOLVER_ip_get (sched,
+ cfg, hostname, domain, timeout, callback, cls);
+}
+
+
+
+
+/* end of resolver_api.c */
*/
struct GNUNET_TIME_Absolute last_activity;
- /**
- * Current task identifier for the receive call
- * (or GNUNET_SCHEDULER_NO_TASK for none).
- */
- GNUNET_SCHEDULER_TaskIdentifier my_receive;
-
/**
* How many bytes in the "incoming_buffer" are currently
* valid? (starting at offset 0).
struct NotifyList *n;
unsigned int rc;
- GNUNET_assert (client->my_receive == GNUNET_SCHEDULER_NO_TASK);
rc = client->reference_count;
if (client->server != NULL)
{
const char *cbuf = buf;
size_t maxcpy;
- client->my_receive = GNUNET_SCHEDULER_NO_TASK;
if ((buf == NULL) ||
(available == 0) ||
(errCode != 0) ||
(GNUNET_YES != client->shutdown_now) && (client->server != NULL))
{
/* Finally, keep receiving! */
- client->my_receive = client->receive (client->client_closure,
- GNUNET_SERVER_MAX_MESSAGE_SIZE,
- server->idle_timeout,
- &process_incoming, client);
+ client->receive (client->client_closure,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE,
+ server->idle_timeout,
+ &process_incoming, client);
}
if (GNUNET_YES == client->shutdown_now)
shutdown_incoming_processing (client);
process_client_buffer (client);
if (0 == client->suspended)
- client->my_receive = client->receive (client->client_closure,
- GNUNET_SERVER_MAX_MESSAGE_SIZE,
- client->server->idle_timeout,
- &process_incoming, client);
+ client->receive (client->client_closure,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE,
+ client->server->idle_timeout,
+ &process_incoming, client);
}
client->last_activity = GNUNET_TIME_absolute_get ();
client->next = server->clients;
server->clients = client;
- client->my_receive = client->receive (client->client_closure,
- GNUNET_SERVER_MAX_MESSAGE_SIZE,
- server->idle_timeout,
- &process_incoming, client);
+ client->receive (client->client_closure,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE,
+ server->idle_timeout,
+ &process_incoming, client);
}
* @param timeout when should this operation time out
* @param receiver function to call for processing
* @param receiver_cls closure for receiver
- * @return task identifier that can be used to cancel the operation
*/
-static GNUNET_SCHEDULER_TaskIdentifier
+static void
sock_receive (void *cls,
size_t max,
struct GNUNET_TIME_Relative timeout,
GNUNET_CONNECTION_Receiver receiver, void *receiver_cls)
{
- return GNUNET_CONNECTION_receive (cls, max, timeout, receiver, receiver_cls);
+ GNUNET_CONNECTION_receive (cls, max, timeout, receiver, receiver_cls);
}
* Wrapper to cancel receiving from a socket.
*
* @param cls handle to the GNUNET_CONNECTION_Handle to cancel
- * @param ti task ID that was returned by GNUNET_CONNECTION_receive
*/
static void
-sock_receive_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti)
+sock_receive_cancel (void *cls)
{
- GNUNET_CONNECTION_receive_cancel (cls, ti);
+ GNUNET_CONNECTION_receive_cancel (cls);
}
{
if (client->server == NULL)
return; /* already disconnected */
- GNUNET_assert (client->my_receive != GNUNET_SCHEDULER_NO_TASK);
- client->receive_cancel (client->client_closure, client->my_receive);
- client->my_receive = GNUNET_SCHEDULER_NO_TASK;
+ client->receive_cancel (client->client_closure);
shutdown_incoming_processing (client);
}
GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT);
GNUNET_CONFIGURATION_set_value_string (cfg,
MYNAME, "HOSTNAME", "localhost");
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "resolver", "HOSTNAME", "localhost");
ok = 1;
GNUNET_SCHEDULER_run (&task, &ok);
GNUNET_CONFIGURATION_destroy (cfg);
#include "gnunet_scheduler_lib.h"
#include "gnunet_time_lib.h"
-#define VERBOSE GNUNET_NO
+#define VERBOSE GNUNET_YES
#define PORT 12435
static struct GNUNET_NETWORK_Handle *ls;
-
+static struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Create and initialize a listen socket for the server.
lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0);
GNUNET_assert (lsock != NULL);
csock = GNUNET_CONNECTION_create_from_connect (tc->sched,
- "localhost", PORT, 1024);
+ cfg,
+ "localhost", PORT, 1024);
GNUNET_assert (csock != NULL);
#if VERBOSE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n");
int ok;
ok = 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "resolver", "HOSTNAME", "localhost");
GNUNET_SCHEDULER_run (&task, &ok);
+ GNUNET_CONFIGURATION_destroy (cfg);
return ok;
}
static struct GNUNET_NETWORK_Handle *ls;
-static GNUNET_SCHEDULER_TaskIdentifier receive_task;
-
-
+static struct GNUNET_CONFIGURATION_Handle *cfg;
/**
GNUNET_assert (asock != NULL);
GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
GNUNET_CONNECTION_destroy (lsock);
- receive_task
- = GNUNET_CONNECTION_receive (asock,
- 1024,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive,
- cls);
+ GNUNET_CONNECTION_receive (asock,
+ 1024,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive,
+ cls);
}
receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
int *ok = cls;
- GNUNET_CONNECTION_receive_cancel (asock, receive_task);
+ GNUNET_CONNECTION_receive_cancel (asock);
GNUNET_CONNECTION_destroy (csock);
GNUNET_CONNECTION_destroy (asock);
*ok = 0;
ls = open_listen_socket ();
lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0);
GNUNET_assert (lsock != NULL);
- csock = GNUNET_CONNECTION_create_from_connect (tc->sched,
- "localhost", PORT, 1024);
+ csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg,
+ "localhost", PORT, 1024);
GNUNET_assert (csock != NULL);
GNUNET_SCHEDULER_add_read_net (tc->sched,
GNUNET_NO,
int ok;
ok = 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "resolver", "HOSTNAME", "localhost");
GNUNET_SCHEDULER_run (&task_receive_cancel, &ok);
+ GNUNET_CONFIGURATION_destroy (cfg);
return ok;
}
static struct GNUNET_NETWORK_Handle *ls;
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
/**
* Create and initialize a listen socket for the server.
ls = open_listen_socket ();
lsock = GNUNET_CONNECTION_create_from_existing (tc->sched, ls, 0);
GNUNET_assert (lsock != NULL);
- csock = GNUNET_CONNECTION_create_from_connect (tc->sched,
- "localhost", PORT, 1024);
+ csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg,
+ "localhost", PORT, 1024);
GNUNET_assert (csock != NULL);
GNUNET_assert (NULL !=
GNUNET_CONNECTION_notify_transmit_ready (csock,
int ok;
ok = 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "resolver", "HOSTNAME", "localhost");
GNUNET_SCHEDULER_run (&task_timeout, &ok);
+ GNUNET_CONFIGURATION_destroy (cfg);
return ok;
}
static struct GNUNET_CONNECTION_Handle *csock;
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
static size_t
handle_timeout (void *cls, size_t size, void *buf)
{
static void
task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- csock = GNUNET_CONNECTION_create_from_connect (tc->sched,
- "localhost", PORT, 1024);
+ csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg,
+ "localhost", PORT, 1024);
GNUNET_assert (csock != NULL);
GNUNET_assert (NULL !=
GNUNET_CONNECTION_notify_transmit_ready (csock,
int ok;
ok = 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "resolver", "HOSTNAME", "localhost");
GNUNET_SCHEDULER_run (&task_timeout, &ok);
+ GNUNET_CONFIGURATION_destroy (cfg);
return ok;
}
#define PORT 12435
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
static size_t
not_run (void *cls, size_t size, void *buf)
struct GNUNET_CONNECTION_TransmitHandle *th;
struct GNUNET_CONNECTION_Handle *csock;
- csock = GNUNET_CONNECTION_create_from_connect (tc->sched,
- "localhost", PORT, 1024);
+ csock = GNUNET_CONNECTION_create_from_connect (tc->sched, cfg,
+ "localhost", PORT, 1024);
GNUNET_assert (csock != NULL);
th = GNUNET_CONNECTION_notify_transmit_ready (csock,
12,
int ok;
ok = 1;
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "resolver", "HOSTNAME", "localhost");
GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok);
+ GNUNET_CONFIGURATION_destroy (cfg);
return ok;
}
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2009 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
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file resolver/test_resolver_api.c
+ * @brief testcase for resolver_api.c
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_resolver_service.h"
+#include "resolver.h"
+
+#define VERBOSE GNUNET_NO
+
+
+static void
+check_hostname (void *cls, const struct sockaddr *sa, socklen_t salen)
+{
+ int *ok = cls;
+
+ if (salen == 0)
+ {
+ (*ok) &= ~8;
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Got IP address `%s' for our host.\n"),
+ GNUNET_a2s (sa, salen));
+}
+
+
+static void
+check_localhost_num (void *cls, const char *hostname)
+{
+ int *ok = cls;
+ if (hostname == NULL)
+ return;
+ if (0 == strcmp (hostname, "127.0.0.1"))
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received correct hostname `%s'.\n", hostname);
+#endif
+ (*ok) &= ~4;
+ }
+ else
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received invalid hostname `%s'.\n", hostname);
+#endif
+ GNUNET_break (0);
+ }
+}
+
+static void
+check_localhost (void *cls, const char *hostname)
+{
+ int *ok = cls;
+ if (hostname == NULL)
+ return;
+ if (0 == strcmp (hostname, "localhost"))
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received correct hostname `%s'.\n", hostname);
+#endif
+ (*ok) &= ~2;
+ }
+ else
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received invalid hostname `%s'.\n", hostname);
+#endif
+ GNUNET_break (0);
+ }
+}
+
+static void
+check_127 (void *cls, const struct sockaddr *sa, socklen_t salen)
+{
+ int *ok = cls;
+ const struct sockaddr_in *sai = (const struct sockaddr_in *) sa;
+
+ if (sa == NULL)
+ return;
+ GNUNET_assert (sizeof (struct sockaddr_in) == salen);
+ if (sai->sin_addr.s_addr == htonl (INADDR_LOOPBACK))
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct address.\n");
+#endif
+ (*ok) &= ~1;
+ }
+ else
+ {
+#if DEBUG_RESOLVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received incorrect address.\n");
+#endif
+ GNUNET_break (0);
+ }
+}
+
+static void
+run (void *cls,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct sockaddr_in sa;
+ struct GNUNET_TIME_Relative timeout =
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+ 2500);
+ memset (&sa, 0, sizeof (sa));
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ GNUNET_RESOLVER_ip_get (sched,
+ cfg,
+ "localhost", AF_INET, timeout, &check_127, cls);
+ GNUNET_RESOLVER_hostname_get (sched,
+ cfg,
+ (const struct sockaddr *) &sa,
+ sizeof (struct sockaddr),
+ GNUNET_YES, timeout, &check_localhost, cls);
+ GNUNET_RESOLVER_hostname_get (sched,
+ cfg,
+ (const struct sockaddr *) &sa,
+ sizeof (struct sockaddr),
+ GNUNET_NO,
+ timeout, &check_localhost_num, cls);
+ GNUNET_RESOLVER_hostname_resolve (sched,
+ cfg,
+ AF_UNSPEC, timeout, &check_hostname, cls);
+}
+
+static int
+check ()
+{
+ int ok = 1 + 2 + 4 + 8;
+ pid_t pid;
+ char *const argv[] = { "test-resolver-api",
+ "-c",
+ "test_resolver_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ pid = GNUNET_OS_start_process ("gnunet-service-resolver",
+ "gnunet-service-resolver",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ "-c", "test_resolver_api_data.conf", NULL);
+ sleep (1);
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+ argv, "test-resolver-api", "nohelp",
+ options, &run, &ok);
+ if (0 != PLIBC_KILL (pid, SIGTERM))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ ok = 1;
+ }
+ GNUNET_OS_process_wait(pid);
+ if (ok != 0)
+ fprintf (stderr, "Missed some resolutions: %u\n", ok);
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_log_setup ("test-resolver-api",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+
+ return ret;
+}
+
+/* end of test_resolver_api.c */
--- /dev/null
+[PATHS]
+SERVICEHOME = /tmp/test-gnunetd-statistics/
+
+[resolver]
+PORT = 22354
+HOSTNAME = localhost
}
-static GNUNET_SCHEDULER_TaskIdentifier
+static GNUNET_SCHEDULER_TaskIdentifier ti;
+
+
+static void
my_receive (void *cls,
size_t max,
struct GNUNET_TIME_Relative timeout,
default:
GNUNET_assert (0);
}
- return ret;
+ ti = ret;
}
static void
-my_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti)
+my_cancel (void *cls)
{
GNUNET_SCHEDULER_cancel (sched, ti);
}
GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT);
GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME",
"localhost");
+ GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
+ "localhost");
client = GNUNET_CLIENT_connect (tc->sched, "test", cfg);
GNUNET_assert (client != NULL);
GNUNET_CLIENT_notify_transmit_ready (client,
GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT);
GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME",
"localhost");
+ GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
+ "localhost");
client = GNUNET_CLIENT_connect (tc->sched, "test", cfg);
GNUNET_assert (client != NULL);
GNUNET_CLIENT_notify_transmit_ready (client,
REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40;
HOSTNAME=::1
ALLOW_SHUTDOWN=YES
+
+[resolver]
+HOSTNAME=localhost