From 2518cfc0a86865ebe4d0550e0013ed52a494231b Mon Sep 17 00:00:00 2001 From: Nils Durner Date: Sun, 23 Aug 2009 22:11:49 +0000 Subject: [PATCH] low level network API --- src/hostlist/hostlist-client.c | 17 +- src/hostlist/hostlist-server.c | 17 +- src/include/Makefile.am | 1 + src/include/gnunet_client_lib.h | 2 +- src/include/gnunet_connection_lib.h | 330 ++++++++++ src/include/gnunet_disk_lib.h | 25 +- src/include/gnunet_network_lib.h | 293 ++------- src/include/gnunet_scheduler_lib.h | 84 ++- src/include/gnunet_server_lib.h | 2 +- src/include/gnunet_transport_service.h | 2 +- src/include/gnunet_util_lib.h | 1 + src/transport/plugin_transport_http.c | 43 +- src/transport/plugin_transport_tcp.c | 2 +- src/transport/plugin_transport_template.c | 2 +- src/transport/plugin_transport_udp.c | 44 +- src/upnp/upnp.c | 6 +- src/upnp/upnp_init.c | 10 +- src/util/Makefile.am | 2 + src/util/disk.c | 170 +++++- src/util/disk.h | 53 ++ src/util/network.c | 181 ++---- src/util/scheduler.c | 281 +++++---- src/util/server.c | 99 +-- src/util/server_tc.c | 2 +- src/util/service.c | 16 +- src/util/sock.c | 678 +++++++++++++++++++++ src/util/test_network.c | 20 +- src/util/test_network_addressing.c | 24 +- src/util/test_network_receive_cancel.c | 24 +- src/util/test_network_timeout.c | 22 +- src/util/test_network_timeout_no_connect.c | 2 +- src/util/test_network_transmit_cancel.c | 2 +- src/util/test_scheduler.c | 24 +- src/util/test_service.c | 8 +- src/util/win.cc | 2 +- 35 files changed, 1845 insertions(+), 646 deletions(-) create mode 100644 src/include/gnunet_connection_lib.h create mode 100644 src/util/disk.h create mode 100644 src/util/sock.c diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c index 468c6b64c..cc24dc135 100644 --- a/src/hostlist/hostlist-client.c +++ b/src/hostlist/hostlist-client.c @@ -380,11 +380,17 @@ run_multi () fd_set ws; fd_set es; int max; + struct GNUNET_NETWORK_FDSet *grs; + struct GNUNET_NETWORK_FDSet *gws; + struct GNUNET_NETWORK_FDSet *ges; max = 0; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); + grs = GNUNET_NETWORK_fdset_create (); + gws = GNUNET_NETWORK_fdset_create (); + ges = GNUNET_NETWORK_fdset_create (); mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); if (mret != CURLM_OK) { @@ -395,17 +401,22 @@ run_multi () clean_up (); return; } + GNUNET_NETWORK_fdset_copy_native (grs, &rs, max); + GNUNET_NETWORK_fdset_copy_native (gws, &ws, max); + GNUNET_NETWORK_fdset_copy_native (ges, &es, max); current_task = GNUNET_SCHEDULER_add_select (sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_MINUTES, - max, - &rs, - &ws, + grs, + gws, &multi_ready, multi); + GNUNET_NETWORK_fdset_destroy (ges); + GNUNET_NETWORK_fdset_destroy (gws); + GNUNET_NETWORK_fdset_destroy (grs); } diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c index 5cc26c409..03e3c5d69 100644 --- a/src/hostlist/hostlist-server.c +++ b/src/hostlist/hostlist-server.c @@ -221,6 +221,9 @@ prepare_daemon () fd_set rs; fd_set ws; fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + struct GNUNET_NETWORK_FDSet *wes; int max; unsigned long long timeout; int haveto; @@ -229,6 +232,9 @@ prepare_daemon () FD_ZERO(&rs); FD_ZERO(&ws); FD_ZERO(&es); + wrs = GNUNET_NETWORK_fdset_create (); + wes = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); max = -1; GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, @@ -241,17 +247,22 @@ prepare_daemon () tv.value = (uint64_t) timeout; else tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max); + GNUNET_NETWORK_fdset_copy_native (wes, &es, max); hostlist_task = GNUNET_SCHEDULER_add_select (sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_SCHEDULER_NO_TASK, tv, - max, - &rs, - &ws, + wrs, + wws, &run_daemon, NULL); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + GNUNET_NETWORK_fdset_destroy (wes); } diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 201deeb4f..69954fd30 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -18,6 +18,7 @@ gnunetinclude_HEADERS = \ gnunet_constants.h \ gnunet_configuration_lib.h \ gnunet_container_lib.h \ + gnunet_connection_lib.h \ gnunet_core_service.h \ gnunet_crypto_lib.h \ gnunet_datacache_lib.h \ diff --git a/src/include/gnunet_client_lib.h b/src/include/gnunet_client_lib.h index b73691b79..eb75e8d1e 100644 --- a/src/include/gnunet_client_lib.h +++ b/src/include/gnunet_client_lib.h @@ -37,7 +37,7 @@ extern "C" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" diff --git a/src/include/gnunet_connection_lib.h b/src/include/gnunet_connection_lib.h new file mode 100644 index 000000000..bc4aeea9b --- /dev/null +++ b/src/include/gnunet_connection_lib.h @@ -0,0 +1,330 @@ +/* + 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 include/gnunet_connection_lib.h + * @brief basic, low-level TCP networking interface + * @author Christian Grothoff + */ +#ifndef GNUNET_NETWORK_LIB_H +#define GNUNET_NETWORK_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_network_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_time_lib.h" + +/** + * Timeout we use on TCP connect before trying another + * result from the DNS resolver. 5s. + */ +#define GNUNET_NETWORK_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) + +/** + * @brief handle for a network connection + */ +struct GNUNET_NETWORK_ConnectionHandle; + + +/** + * Function to call for access control checks. + * + * @param cls closure + * @param addr address + * @param addrlen length of address + * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR + * for unknown address family (will be denied). + */ +typedef int (*GNUNET_NETWORK_AccessCheck) (void *cls, + const struct sockaddr * addr, + socklen_t addrlen); + + +/** + * Callback function for data received from the network. Note that + * both "available" and "err" would be 0 if the read simply timed out. + * + * @param cls closure + * @param buf pointer to received data + * @param available number of bytes availabe in "buf", + * possibly 0 (on errors) + * @param addr address of the sender + * @param addrlen size of addr + * @param errCode value of errno (on errors receiving) + */ +typedef void (*GNUNET_NETWORK_Receiver) (void *cls, + const void *buf, + size_t available, + const struct sockaddr * addr, + socklen_t addrlen, int errCode); + + +/** + * Create a socket handle by boxing an existing OS socket. The OS + * socket should henceforth be no longer used directly. + * GNUNET_socket_destroy will close it. + * + * @param sched scheduler to use + * @param osSocket existing socket to box + * @param maxbuf maximum write buffer size for the socket (use + * 0 for sockets that need no write buffers, such as listen sockets) + * @return the boxed socket handle + */ +struct GNUNET_NETWORK_ConnectionHandle + *GNUNET_NETWORK_connection_create_from_existing (struct + GNUNET_SCHEDULER_Handle + *sched, + struct + GNUNET_NETWORK_Descriptor + *osSocket, size_t maxbuf); + + +/** + * Create a socket handle by accepting on a listen socket. This + * function may block if the listen socket has no connection ready. + * + * @param sched scheduler to use + * @param access function to use to check if access is allowed + * @param access_cls closure for access + * @param lsock listen socket + * @param maxbuf maximum write buffer size for the socket (use + * 0 for sockets that need no write buffers, such as listen sockets) + * @return the socket handle, NULL on error (for example, access refused) + */ +struct GNUNET_NETWORK_ConnectionHandle + *GNUNET_NETWORK_connection_create_from_accept (struct + GNUNET_SCHEDULER_Handle + *sched, + GNUNET_NETWORK_AccessCheck + access, void *access_cls, + struct + GNUNET_NETWORK_Descriptor + *lsock, size_t maxbuf); + + +/** + * Create a socket handle by (asynchronously) connecting to a host. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates TCP connections. + * + * @param sched scheduler 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 + * 0 for sockets that need no write buffers, such as listen sockets) + * @return the socket handle + */ +struct GNUNET_NETWORK_ConnectionHandle + *GNUNET_NETWORK_connection_create_from_connect (struct + GNUNET_SCHEDULER_Handle + *sched, + const char *hostname, + uint16_t port, + size_t maxbuf); + + + +/** + * Create a socket handle by (asynchronously) connecting to a host. + * This function returns immediately, even if the connection has not + * yet been established. This function only creates TCP connections. + * + * @param sched scheduler to use + * @param af_family address family to use + * @param serv_addr server address + * @param addrlen length of server address + * @param maxbuf maximum write buffer size for the socket (use + * 0 for sockets that need no write buffers, such as listen sockets) + * @return the socket handle + */ +struct GNUNET_NETWORK_ConnectionHandle + *GNUNET_NETWORK_connection_create_from_sockaddr (struct + GNUNET_SCHEDULER_Handle + *sched, int af_family, + const struct sockaddr + *serv_addr, + socklen_t addrlen, + size_t maxbuf); + +/** + * Check if socket is valid (no fatal errors have happened so far). + * Note that a socket that is still trying to connect is considered + * valid. + * + * @param sock socket to check + * @return GNUNET_YES if valid, GNUNET_NO otherwise + */ +int GNUNET_NETWORK_connection_check (struct GNUNET_NETWORK_ConnectionHandle + *sock); + + +/** + * Obtain the network address of the other party. + * + * @param sock the client to get the address for + * @param addr where to store the address + * @param addrlen where to store the length of the address + * @return GNUNET_OK on success + */ +int GNUNET_NETWORK_connection_get_address (struct + GNUNET_NETWORK_ConnectionHandle + *sock, void **addr, + size_t * addrlen); + +/** + * Close the socket and free associated resources. Pending + * transmissions are simply dropped. A pending receive call will be + * called with an error code of "EPIPE". + * + * @param sock socket to destroy + */ +void GNUNET_NETWORK_connection_destroy (struct GNUNET_NETWORK_ConnectionHandle + *sock); + + +/** + * Receive data from the given socket. Note that this function will + * call "receiver" asynchronously using the scheduler. It will + * "immediately" return. Note that there MUST only be one active + * receive call per socket at any given point in time (so do not + * call receive again until the receiver callback has been invoked). + * + * @param sock socket handle + * @param max maximum number of bytes to read + * @param timeout maximum amount of time to wait + * @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 +GNUNET_NETWORK_connection_receive (struct GNUNET_NETWORK_ConnectionHandle + *sock, size_t max, + struct GNUNET_TIME_Relative timeout, + GNUNET_NETWORK_Receiver receiver, + void *receiver_cls); + + +/** + * Cancel receive job on the given socket. Note that the + * receiver callback must not have been called yet in order + * 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 + */ +void *GNUNET_NETWORK_connection_receive_cancel (struct + GNUNET_NETWORK_ConnectionHandle + *sock, + GNUNET_SCHEDULER_TaskIdentifier + task); + + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +typedef size_t (*GNUNET_NETWORK_TransmitReadyNotify) (void *cls, + size_t size, void *buf); + + +/** + * Opaque handle that can be used to cancel + * a transmit-ready notification. + */ +struct GNUNET_NETWORK_TransmitHandle; + +/** + * Ask the socket to call us once the specified number of bytes + * are free in the transmission buffer. May call the notify + * method immediately if enough space is available. Note that + * this function will abort if "size" is greater than + * "maxbuf" (as specified when the socket handle was created). + * + * Note that "notify" will be called either when enough + * buffer space is available OR when the socket is destroyed. + * The size parameter given to notify is guaranteed to be + * larger or equal to size if the buffer is ready, or zero + * if the socket was destroyed (or at least closed for + * writing). Finally, any time before 'notify' is called, a + * client may call "notify_transmit_ready_cancel" to cancel + * the transmission request. + * + * Only one transmission request can be scheduled at the same + * time. Notify will be run with the same scheduler priority + * as that of the caller. + * + * @param sock socket + * @param size number of bytes to send + * @param timeout after how long should we give up (and call + * notify with buf NULL and size 0)? + * @param notify function to call when buffer space is available + * @param notify_cls closure for notify + * @return non-NULL if the notify callback was queued, + * NULL if we are already going to notify someone else (busy) + */ +struct GNUNET_NETWORK_TransmitHandle + *GNUNET_NETWORK_connection_notify_transmit_ready (struct + GNUNET_NETWORK_ConnectionHandle + *sock, size_t size, + struct + GNUNET_TIME_Relative + timeout, + GNUNET_NETWORK_TransmitReadyNotify + notify, void *notify_cls); + + +/** + * Cancel the specified transmission-ready + * notification. + * + * @param h handle for notification to cancel + */ +void +GNUNET_NETWORK_connection_notify_transmit_ready_cancel (struct + GNUNET_NETWORK_TransmitHandle + *h); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_NETWORK_LIB_H */ +#endif +/* end of gnunet_connection_lib.h */ diff --git a/src/include/gnunet_disk_lib.h b/src/include/gnunet_disk_lib.h index 49f2ece48..a5f279f05 100644 --- a/src/include/gnunet_disk_lib.h +++ b/src/include/gnunet_disk_lib.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) + (C) 2001, 2002, 2003, 2004, 2005, 2006, 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 @@ -76,6 +76,8 @@ enum GNUNET_DISK_Seek {GNUNET_SEEK_SET, GNUNET_SEEK_CUR, GNUNET_SEEK_END}; struct GNUNET_DISK_FileHandle; +struct GNUNET_DISK_PipeHandle; + /** * Get the number of blocks that are left on the partition that * contains the given file (for normal users). @@ -150,6 +152,19 @@ GNUNET_DISK_mktemp (const char *template); */ struct GNUNET_DISK_FileHandle *GNUNET_DISK_file_open (const char *fn, int flags, ...); +/** + * Creates an interprocess channel + * @param blocking creates an asynchronous pipe if set to GNUNET_NO + * @return handle to the new pipe, NULL on error + */ +struct GNUNET_DISK_PipeHandle *GNUNET_DISK_pipe (int blocking); + +/** + * Closes an interprocess channel + * @param p pipe + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p); /** * Close an open file. @@ -159,6 +174,14 @@ struct GNUNET_DISK_FileHandle *GNUNET_DISK_file_open (const char *fn, int flags, */ int GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h); +/** + * Get the handle to a particular pipe end + * @param p pipe + * @param n number of the end + */ +const struct GNUNET_DISK_FileHandle *GNUNET_DISK_pipe_handle (const struct + GNUNET_DISK_PipeHandle + *p, int n); /** * Read the contents of a binary file into a buffer. diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h index 68ca346e5..baba3aba8 100644 --- a/src/include/gnunet_network_lib.h +++ b/src/include/gnunet_network_lib.h @@ -20,11 +20,12 @@ /** * @file include/gnunet_network_lib.h - * @brief basic, low-level TCP networking interface - * @author Christian Grothoff + * @brief basic low-level networking interface + * @author Nils Durner */ -#ifndef GNUNET_NETWORK_LIB_H -#define GNUNET_NETWORK_LIB_H + +#ifndef GNUNET_NETWORK_LIB_H_ +#define GNUNET_NETWORK_LIB_H_ #ifdef __cplusplus extern "C" @@ -34,265 +35,102 @@ extern "C" #endif #endif -#include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" -/** - * Timeout we use on TCP connect before trying another - * result from the DNS resolver. 5s. - */ -#define GNUNET_NETWORK_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** - * @brief handle for a network connection + * @brief handle to a socket */ -struct GNUNET_NETWORK_ConnectionHandle; - +struct GNUNET_NETWORK_Descriptor; /** - * Function to call for access control checks. - * - * @param cls closure - * @param addr address - * @param addrlen length of address - * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR - * for unknown address family (will be denied). + * @brief collection of IO descriptors */ -typedef int (*GNUNET_NETWORK_AccessCheck) (void *cls, - const struct sockaddr * addr, - socklen_t addrlen); +struct GNUNET_NETWORK_FDSet; +struct GNUNET_DISK_FileHandle; -/** - * Callback function for data received from the network. Note that - * both "available" and "err" would be 0 if the read simply timed out. - * - * @param cls closure - * @param buf pointer to received data - * @param available number of bytes availabe in "buf", - * possibly 0 (on errors) - * @param addr address of the sender - * @param addrlen size of addr - * @param errCode value of errno (on errors receiving) - */ -typedef void (*GNUNET_NETWORK_Receiver) (void *cls, - const void *buf, - size_t available, - const struct sockaddr * addr, - socklen_t addrlen, int errCode); +struct GNUNET_NETWORK_Descriptor *GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Descriptor *desc, + struct sockaddr *address, + socklen_t *address_len); +int GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc, + const struct sockaddr *address, socklen_t address_len); -/** - * Create a socket handle by boxing an existing OS socket. The OS - * socket should henceforth be no longer used directly. - * GNUNET_socket_destroy will close it. - * - * @param sched scheduler to use - * @param osSocket existing socket to box - * @param maxbuf maximum write buffer size for the socket (use - * 0 for sockets that need no write buffers, such as listen sockets) - * @return the boxed socket handle - */ -struct GNUNET_NETWORK_ConnectionHandle - *GNUNET_NETWORK_connection_create_from_existing (struct GNUNET_SCHEDULER_Handle - *sched, int osSocket, - size_t maxbuf); +int GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Descriptor *desc); +int GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Descriptor *desc, + const struct sockaddr *address, socklen_t address_len); -/** - * Create a socket handle by accepting on a listen socket. This - * function may block if the listen socket has no connection ready. - * - * @param sched scheduler to use - * @param access function to use to check if access is allowed - * @param access_cls closure for access - * @param lsock listen socket - * @param maxbuf maximum write buffer size for the socket (use - * 0 for sockets that need no write buffers, such as listen sockets) - * @return the socket handle, NULL on error (for example, access refused) - */ -struct GNUNET_NETWORK_ConnectionHandle - *GNUNET_NETWORK_connection_create_from_accept (struct GNUNET_SCHEDULER_Handle - *sched, - GNUNET_NETWORK_AccessCheck - access, void *access_cls, - int lsock, size_t maxbuf); +int GNUNET_NETWORK_socket_getsockopt(const struct GNUNET_NETWORK_Descriptor *desc, int level, int optname, + void *optval, socklen_t *optlen); +int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Descriptor *desc, int backlog); -/** - * Create a socket handle by (asynchronously) connecting to a host. - * This function returns immediately, even if the connection has not - * yet been established. This function only creates TCP connections. - * - * @param sched scheduler 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 - * 0 for sockets that need no write buffers, such as listen sockets) - * @return the socket handle - */ -struct GNUNET_NETWORK_ConnectionHandle - *GNUNET_NETWORK_connection_create_from_connect (struct GNUNET_SCHEDULER_Handle - *sched, const char *hostname, - uint16_t port, size_t maxbuf); +ssize_t GNUNET_NETWORK_socket_read (const struct GNUNET_NETWORK_Descriptor *desc, void *buf, + size_t nbyte); +ssize_t GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Descriptor *desc, void *buffer, + size_t length, int flags); +int GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, + struct GNUNET_NETWORK_FDSet *wfds, struct GNUNET_NETWORK_FDSet *efds, + struct GNUNET_TIME_Relative timeout); /** - * Create a socket handle by (asynchronously) connecting to a host. - * This function returns immediately, even if the connection has not - * yet been established. This function only creates TCP connections. + * Set if a socket should use blocking or non-blocking IO. * - * @param sched scheduler to use - * @param af_family address family to use - * @param serv_addr server address - * @param addrlen length of server address - * @param maxbuf maximum write buffer size for the socket (use - * 0 for sockets that need no write buffers, such as listen sockets) - * @return the socket handle + * @return GNUNET_OK on success, GNUNET_SYSERR on error */ -struct GNUNET_NETWORK_ConnectionHandle - *GNUNET_NETWORK_connection_create_from_sockaddr (struct GNUNET_SCHEDULER_Handle - *sched, int af_family, - const struct sockaddr - *serv_addr, socklen_t addrlen, - size_t maxbuf); +int GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Descriptor *fd, int doBlock); -/** - * Check if socket is valid (no fatal errors have happened so far). - * Note that a socket that is still trying to connect is considered - * valid. - * - * @param sock socket to check - * @return GNUNET_YES if valid, GNUNET_NO otherwise - */ -int GNUNET_NETWORK_connection_check (struct GNUNET_NETWORK_ConnectionHandle *sock); +ssize_t GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Descriptor *desc, + const void *buffer, size_t length, int flags); +ssize_t GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Descriptor *desc, + const void *message, size_t length, int flags, + const struct sockaddr *dest_addr, + socklen_t dest_len); -/** - * Obtain the network address of the other party. - * - * @param sock the client to get the address for - * @param addr where to store the address - * @param addrlen where to store the length of the address - * @return GNUNET_OK on success - */ -int GNUNET_NETWORK_connection_get_address (struct GNUNET_NETWORK_ConnectionHandle - *sock, void **addr, size_t * addrlen); +int GNUNET_NETWORK_socket_setsockopt(struct GNUNET_NETWORK_Descriptor *fd, int level, int option_name, + const void *option_value, socklen_t option_len); -/** - * Close the socket and free associated resources. Pending - * transmissions are simply dropped. A pending receive call will be - * called with an error code of "EPIPE". - * - * @param sock socket to destroy - */ -void GNUNET_NETWORK_connection_destroy (struct GNUNET_NETWORK_ConnectionHandle *sock); +int GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Descriptor *desc, int how); +struct GNUNET_NETWORK_Descriptor *GNUNET_NETWORK_socket_socket (int domain, int type, int protocol); -/** - * Receive data from the given socket. Note that this function will - * call "receiver" asynchronously using the scheduler. It will - * "immediately" return. Note that there MUST only be one active - * receive call per socket at any given point in time (so do not - * call receive again until the receiver callback has been invoked). - * - * @param sock socket handle - * @param max maximum number of bytes to read - * @param timeout maximum amount of time to wait - * @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 -GNUNET_NETWORK_connection_receive (struct GNUNET_NETWORK_ConnectionHandle *sock, - size_t max, - struct GNUNET_TIME_Relative timeout, - GNUNET_NETWORK_Receiver receiver, void *receiver_cls); +ssize_t GNUNET_NETWORK_socket_write (const struct GNUNET_NETWORK_Descriptor *desc, + const void *buf, size_t nbyte); -/** - * Cancel receive job on the given socket. Note that the - * receiver callback must not have been called yet in order - * 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 - */ -void *GNUNET_NETWORK_connection_receive_cancel (struct GNUNET_NETWORK_ConnectionHandle *sock, - GNUNET_SCHEDULER_TaskIdentifier task); +void GNUNET_NETWORK_fdset_zero(struct GNUNET_NETWORK_FDSet *fds); +void GNUNET_NETWORK_fdset_set(struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Descriptor *desc); -/** - * Function called to notify a client about the socket - * begin ready to queue more data. "buf" will be - * NULL and "size" zero if the socket was closed for - * writing in the meantime. - * - * @param cls closure - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -typedef size_t (*GNUNET_NETWORK_TransmitReadyNotify) (void *cls, - size_t size, void *buf); +int GNUNET_NETWORK_fdset_isset(const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Descriptor *desc); +void GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, + const struct GNUNET_NETWORK_FDSet *src); -/** - * Opaque handle that can be used to cancel - * a transmit-ready notification. - */ -struct GNUNET_NETWORK_TransmitHandle; +void GNUNET_NETWORK_fdset_copy(struct GNUNET_NETWORK_FDSet *to, + const struct GNUNET_NETWORK_FDSet *from); -/** - * Ask the socket to call us once the specified number of bytes - * are free in the transmission buffer. May call the notify - * method immediately if enough space is available. Note that - * this function will abort if "size" is greater than - * "maxbuf" (as specified when the socket handle was created). - * - * Note that "notify" will be called either when enough - * buffer space is available OR when the socket is destroyed. - * The size parameter given to notify is guaranteed to be - * larger or equal to size if the buffer is ready, or zero - * if the socket was destroyed (or at least closed for - * writing). Finally, any time before 'notify' is called, a - * client may call "notify_transmit_ready_cancel" to cancel - * the transmission request. - * - * Only one transmission request can be scheduled at the same - * time. Notify will be run with the same scheduler priority - * as that of the caller. - * - * @param sock socket - * @param size number of bytes to send - * @param timeout after how long should we give up (and call - * notify with buf NULL and size 0)? - * @param notify function to call when buffer space is available - * @param notify_cls closure for notify - * @return non-NULL if the notify callback was queued, - * NULL if we are already going to notify someone else (busy) - */ -struct GNUNET_NETWORK_TransmitHandle - *GNUNET_NETWORK_connection_notify_transmit_ready (struct GNUNET_NETWORK_ConnectionHandle - *sock, size_t size, - struct GNUNET_TIME_Relative timeout, - GNUNET_NETWORK_TransmitReadyNotify - notify, void *notify_cls); +void GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, const fd_set *from, + int nfds); +void GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h); -/** - * Cancel the specified transmission-ready - * notification. - * - * @param h handle for notification to cancel - */ -void -GNUNET_NETWORK_connection_notify_transmit_ready_cancel (struct - GNUNET_NETWORK_TransmitHandle - *h); +int GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h); + +int GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, const struct GNUNET_NETWORK_FDSet *fds2); +struct GNUNET_NETWORK_FDSet *GNUNET_NETWORK_fdset_create (); + +void GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds); #if 0 /* keep Emacsens' auto-indent happy */ @@ -302,7 +140,4 @@ GNUNET_NETWORK_connection_notify_transmit_ready_cancel (struct } #endif - -/* ifndef GNUNET_NETWORK_LIB_H */ -#endif -/* end of gnunet_network_lib.h */ +#endif /* GNUNET_NETWORK_LIB_H_ */ diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h index d4013e630..86f709ed6 100644 --- a/src/include/gnunet_scheduler_lib.h +++ b/src/include/gnunet_scheduler_lib.h @@ -35,15 +35,15 @@ extern "C" #endif #endif -#include "gnunet_time_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_network_lib.h" /** * Opaque handle for the scheduling service. */ struct GNUNET_SCHEDULER_Handle; - /** * Opaque reference to a task. */ @@ -173,14 +173,14 @@ struct GNUNET_SCHEDULER_TaskContext * note that additional bits may be set * that were not in the original request */ - const fd_set *read_ready; + const struct GNUNET_NETWORK_FDSet *read_ready; /** * Set of file descriptors ready for writing; * note that additional bits may be set * that were not in the original request. */ - const fd_set *write_ready; + const struct GNUNET_NETWORK_FDSet *write_ready; }; @@ -345,12 +345,78 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_SCHEDULER_Handle *sched, * only valid until "main" is started! */ GNUNET_SCHEDULER_TaskIdentifier -GNUNET_SCHEDULER_add_read (struct GNUNET_SCHEDULER_Handle *sched, +GNUNET_SCHEDULER_add_read_net (struct GNUNET_SCHEDULER_Handle *sched, + int run_on_shutdown, + enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + struct GNUNET_TIME_Relative delay, + struct GNUNET_NETWORK_Descriptor *rfd, GNUNET_SCHEDULER_Task main, void *cls); + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for writing. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. + * + * @param sched scheduler to use + * @param run_on_shutdown run on shutdown? Set this + * argument to GNUNET_NO to skip this task if + * the user requested process termination. + * @param prio how important is this task? + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readyness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks. + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever" + * @param wfd write file-descriptor + * @param main main function of the task + * @param cls closure of task + * @return unique task identifier for the job + * only valid until "main" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_write_net (struct GNUNET_SCHEDULER_Handle *sched, + int run_on_shutdown, + enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + struct GNUNET_TIME_Relative delay, + struct GNUNET_NETWORK_Descriptor *wfd, GNUNET_SCHEDULER_Task main, void *cls); + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for reading. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. + * + * @param sched scheduler to use + * @param run_on_shutdown run on shutdown? Set this + * argument to GNUNET_NO to skip this task if + * the user requested process termination. + * @param prio how important is this task? + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readyness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks. + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever" + * @param rfd read file-descriptor + * @param main main function of the task + * @param cls closure of task + * @return unique task identifier for the job + * only valid until "main" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_file (struct GNUNET_SCHEDULER_Handle *sched, int run_on_shutdown, enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, - int rfd, GNUNET_SCHEDULER_Task main, void *cls); + struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_Task main, void *cls); /** @@ -378,12 +444,12 @@ GNUNET_SCHEDULER_add_read (struct GNUNET_SCHEDULER_Handle *sched, * only valid until "main" is started! */ GNUNET_SCHEDULER_TaskIdentifier -GNUNET_SCHEDULER_add_write (struct GNUNET_SCHEDULER_Handle *sched, +GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle *sched, int run_on_shutdown, enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, - int wfd, GNUNET_SCHEDULER_Task main, void *cls); + struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_Task main, void *cls); /** @@ -429,7 +495,7 @@ GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle *sched, GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, - int nfds, const fd_set * rs, const fd_set * ws, + const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws, GNUNET_SCHEDULER_Task main, void *cls); #if 0 /* keep Emacsens' auto-indent happy */ diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h index 82085ad0d..092bab40b 100644 --- a/src/include/gnunet_server_lib.h +++ b/src/include/gnunet_server_lib.h @@ -37,7 +37,7 @@ extern "C" #endif #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" diff --git a/src/include/gnunet_transport_service.h b/src/include/gnunet_transport_service.h index 037a247a2..385bf7cfb 100644 --- a/src/include/gnunet_transport_service.h +++ b/src/include/gnunet_transport_service.h @@ -37,7 +37,7 @@ extern "C" #include "gnunet_configuration_lib.h" #include "gnunet_crypto_lib.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" diff --git a/src/include/gnunet_util_lib.h b/src/include/gnunet_util_lib.h index 40686b189..fe382be3f 100644 --- a/src/include/gnunet_util_lib.h +++ b/src/include/gnunet_util_lib.h @@ -39,6 +39,7 @@ extern "C" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_configuration_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c index f7e06a9cd..78691852d 100644 --- a/src/transport/plugin_transport_http.c +++ b/src/transport/plugin_transport_http.c @@ -399,7 +399,7 @@ static int stat_connect_calls; */ static unsigned int http_requests_pending; -static int signal_pipe[2]; +static struct GNUNET_DISK_FileHandle signal_pipe[2]; static char *proxy; @@ -453,7 +453,7 @@ static void signal_select () { static char c; - WRITE (signal_pipe[1], &c, sizeof (c)); + GNUNET_DISK_file_write (signal_pipe[1], &c, sizeof (c)); } /** @@ -1747,8 +1747,10 @@ curl_runner (void *unused) fd_set rs; fd_set ws; fd_set es; + struct GNUNET_NETWORK_FDSet *hrs; + struct GNUNET_NETWORK_FDSet *hws; + struct GNUNET_NETWORK_FDSet *hes; int max; - struct timeval tv; int running; unsigned long long timeout; long ms; @@ -1761,6 +1763,11 @@ curl_runner (void *unused) GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "HTTP transport select thread started\n"); #endif + + hrs = GNUNET_net_fdset_create (); + hws = GNUNET_net_fdset_create (); + hes = GNUNET_net_fdset_create (); + while (GNUNET_YES == http_running) { max = 0; @@ -1793,16 +1800,20 @@ curl_runner (void *unused) have_tv = MHD_YES; } GNUNET_mutex_unlock (lock); - FD_SET (signal_pipe[0], &rs); - if (max < signal_pipe[0]) - max = signal_pipe[0]; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + + GNUNET_net_fdset_zero (hws); + GNUNET_net_fdset_zero (hrs); + GNUNET_net_fdset_zero (hes); + GNUNET_net_fdset_copy_native (hws, ws); + GNUNET_net_fdset_copy_native (hrs, rs); + GNUNET_net_fdset_copy_native (hes, es); + + GNUNET_net_fdset_handle_set (signal_pipe[0], hrs); if (stats != NULL) stats->change (stat_select_calls, 1); ret = - SELECT (max + 1, &rs, &ws, &es, (have_tv == MHD_YES) ? &tv : NULL); - if (ret == -1) + GNUNET_net_select (hrs, hws, hes, (have_tv == MHD_YES) ? timeout : GNUNET_TIME_UNIT_FOREVER_REL); + if (ret == GNUNET_SYSERR) { GNUNET_GE_LOG_STRERROR (coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | @@ -1819,8 +1830,8 @@ curl_runner (void *unused) } while ((mret == CURLM_CALL_MULTI_PERFORM) && (http_running == GNUNET_YES)); - if (FD_ISSET (signal_pipe[0], &rs)) - read (signal_pipe[0], buf, sizeof (buf)); + if (GNUNET_net_fdset_handle_isset (signal_pipe[0], hrs)) + GNUNET_DISK_file_read (signal_pipe[0], buf, sizeof (buf)); if ((mret != CURLM_OK) && (mret != CURLM_CALL_MULTI_PERFORM)) GNUNET_GE_LOG (coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER | @@ -1914,7 +1925,7 @@ startTransportServer () GNUNET_YES)) available_protocols |= VERSION_AVAILABLE_IPV6; } - if (0 != PIPE (signal_pipe)) + if (GNUNET_OK != GNUNET_DISK_pipe (signal_pipe, GNUNET_NO)) { MHD_stop_daemon (mhd_daemon); curl_multi_cleanup (curl_multi); @@ -1922,8 +1933,6 @@ startTransportServer () mhd_daemon = NULL; return GNUNET_SYSERR; } - GNUNET_pipe_make_nonblocking (coreAPI->ectx, signal_pipe[0]); - GNUNET_pipe_make_nonblocking (coreAPI->ectx, signal_pipe[1]); http_running = GNUNET_YES; curl_thread = GNUNET_thread_create (&curl_runner, NULL, 32 * 1024); if (curl_thread == NULL) @@ -1950,8 +1959,8 @@ stopTransportServer () signal_select (); GNUNET_thread_stop_sleep (curl_thread); GNUNET_thread_join (curl_thread, &unused); - CLOSE (signal_pipe[0]); - CLOSE (signal_pipe[1]); + GNUNET_DISK_close (signal_pipe[0]); + GNUNET_DISK_close (signal_pipe[1]); if (mhd_daemon != NULL) { MHD_stop_daemon (mhd_daemon); diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 764ef8b2f..2e174f80a 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -26,7 +26,7 @@ #include "platform.h" #include "gnunet_hello_lib.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_os_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_protocols.h" diff --git a/src/transport/plugin_transport_template.c b/src/transport/plugin_transport_template.c index bce4bbc52..6307092fc 100644 --- a/src/transport/plugin_transport_template.c +++ b/src/transport/plugin_transport_template.c @@ -26,7 +26,7 @@ #include "platform.h" #include "gnunet_protocols.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index ccaf9fbd1..c84b2bae7 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c @@ -267,31 +267,23 @@ udp_test_would_try (GNUNET_TSession * tsession, unsigned int size, * Create a UDP socket. If possible, use IPv6, otherwise * try IPv4. Update available_protocols accordingly. */ -static int +static struct GNUNET_NETWORK_Descriptor * udp_create_socket () { - int s; + struct GNUNET_NETWORK_Descriptor *desc; available_protocols = VERSION_AVAILABLE_NONE; - s = -1; + desc = NULL; if (GNUNET_YES != GNUNET_GC_get_configuration_value_yesno (cfg, "GNUNETD", "DISABLE-IPV6", GNUNET_YES)) { -#ifndef MINGW - s = SOCKET (PF_INET6, SOCK_DGRAM, 17); -#else - s = win_ols_socket (PF_INET6, SOCK_DGRAM, 17); -#endif + desc = GNUNET_net_socket (PF_INET6, SOCK_DGRAM, 17); } - if (s < 0) + if (NULL == desc) { -#ifndef MINGW - s = SOCKET (PF_INET, SOCK_DGRAM, 17); -#else - s = win_ols_socket (PF_INET, SOCK_DGRAM, 17); -#endif - if (s < 0) + desc = GNUNET_net_socket (PF_INET, SOCK_DGRAM, 17); + if (NULL == desc) { GNUNET_GE_LOG_STRERROR (coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | @@ -304,7 +296,7 @@ udp_create_socket () { available_protocols = VERSION_AVAILABLE_IPV6 | VERSION_AVAILABLE_IPV4; } - return s; + return desc; } /** @@ -424,7 +416,7 @@ udp_transport_server_start () struct sockaddr_in6 serverAddrv6; struct sockaddr *serverAddr; socklen_t addrlen; - int sock; + GNUNET_NETWORK_Descriptor *desc; const int on = 1; unsigned short port; @@ -433,10 +425,10 @@ udp_transport_server_start () port = get_port (); if (port != 0) { - sock = udp_create_socket (); - if (sock < 0) + desc = udp_create_socket (); + if (NULL == desc) return GNUNET_SYSERR; - if (SETSOCKOPT (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + if (GNUNET_net_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) { GNUNET_GE_DIE_STRERROR (coreAPI->ectx, GNUNET_GE_FATAL | GNUNET_GE_ADMIN | @@ -461,7 +453,7 @@ udp_transport_server_start () addrlen = sizeof (serverAddrv6); serverAddr = (struct sockaddr *) &serverAddrv6; } - if (BIND (sock, serverAddr, addrlen) < 0) + if (GNUNET_net_bind (desc, serverAddr, addrlen) < 0) { GNUNET_GE_LOG_STRERROR (coreAPI->ectx, GNUNET_GE_FATAL | GNUNET_GE_ADMIN | @@ -471,14 +463,14 @@ udp_transport_server_start () GNUNET_GE_IMMEDIATE, _("Failed to bind to %s port %d.\n"), MY_TRANSPORT_NAME, port); - if (0 != CLOSE (sock)) + if (0 != GNUNET_net_close (&desc)) GNUNET_GE_LOG_STRERROR (coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "close"); return GNUNET_SYSERR; } - selector = GNUNET_select_create ("udp", GNUNET_YES, coreAPI->ectx, load_monitor, sock, addrlen, 0, /* timeout */ + selector = GNUNET_select_create ("udp", GNUNET_YES, coreAPI->ectx, load_monitor, desc, addrlen, 0, /* timeout */ &select_message_handler, NULL, &select_accept_handler, @@ -489,8 +481,8 @@ udp_transport_server_start () if (selector == NULL) return GNUNET_SYSERR; } - sock = udp_create_socket (); - if (sock == -1) + desc = udp_create_socket (); + if (NULL == desc) { GNUNET_GE_LOG_STRERROR (coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | @@ -499,7 +491,7 @@ udp_transport_server_start () selector = NULL; return GNUNET_SYSERR; } - udp_sock = GNUNET_socket_create (coreAPI->ectx, load_monitor, sock); + udp_sock = GNUNET_socket_create (coreAPI->ectx, load_monitor, desc); GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL); return GNUNET_OK; } diff --git a/src/upnp/upnp.c b/src/upnp/upnp.c index 6dc4338a0..afc815b1f 100644 --- a/src/upnp/upnp.c +++ b/src/upnp/upnp.c @@ -104,7 +104,7 @@ typedef struct char *full_url; char *buf; unsigned int buf_len; - int sock; + struct GNUNET_NETWORK_Descriptor *sock; } UPnPDiscoveryData; static GaimUPnPControlInfo control_info = { @@ -543,7 +543,7 @@ gaim_upnp_parse_description (char *proxy, UPnPDiscoveryData * dd) } int -gaim_upnp_discover (struct GNUNET_CONFIGURATION_Handle *cfg, int sock) +gaim_upnp_discover (struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_NETWORK_Descriptor *sock) { char *proxy; socklen_t avail; @@ -613,7 +613,7 @@ gaim_upnp_discover (struct GNUNET_CONFIGURATION_Handle *cfg, int sock) /* try to read response */ do { - buf_len = recv (dd.sock, buf, sizeof (buf) - 1, 0); + buf_len = GNUNET_IO_recv (dd.sock, buf, sizeof (buf) - 1, 0); if (buf_len > 0) { buf[buf_len] = '\0'; diff --git a/src/upnp/upnp_init.c b/src/upnp/upnp_init.c index 3dc0d2b7c..8390494e5 100644 --- a/src/upnp/upnp_init.c +++ b/src/upnp/upnp_init.c @@ -50,7 +50,7 @@ static unsigned int maps_size; static struct GNUNET_ThreadHandle *discovery; -static int discovery_socket; +static struct GNUNET_NETWORK_Descriptor *discovery_socket; /** * Obtain the public/external IP address. @@ -84,8 +84,8 @@ kill_discovery () if (discovery != NULL) { - SHUTDOWN (discovery_socket, SHUT_RDWR); - CLOSE (discovery_socket); + GNUNET_IO_shutdown (discovery_socket, SHUT_RDWR); + GNUNET_IO_close (&discovery_socket); GNUNET_thread_join (discovery, &unused); discovery = NULL; } @@ -105,8 +105,8 @@ static void discover (void *unused) { kill_discovery (); - discovery_socket = SOCKET (PF_INET, SOCK_DGRAM, 0); - if (discovery_socket == -1) + discovery_socket = GNUNET_IO_socket (PF_INET, SOCK_DGRAM, 0); + if (NULL == discovery_socket) return; discovery = GNUNET_thread_create (&discover_thread, NULL, 1024 * 128); } diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 089e92018..46d1c3a7a 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -32,6 +32,7 @@ libgnunetutil_la_SOURCES = \ crypto_random.c \ crypto_rsa.c \ disk.c \ + disk.h \ getopt.c \ getopt_helpers.c \ network.c \ @@ -47,6 +48,7 @@ libgnunetutil_la_SOURCES = \ server_tc.c \ service.c \ signal.c \ + sock.c \ strings.c \ time.c \ $(WINSRC) diff --git a/src/util/disk.c b/src/util/disk.c index 08f14caf6..b9fad5477 100644 --- a/src/util/disk.c +++ b/src/util/disk.c @@ -31,6 +31,7 @@ #include "gnunet_disk_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_strings_lib.h" +#include "disk.h" #if LINUX || CYGWIN @@ -74,13 +75,9 @@ typedef struct int include_sym_links; } GetFileSizeData; -struct GNUNET_DISK_FileHandle +struct GNUNET_DISK_PipeHandle { -#if MINGW - HANDLE h; -#else - int fd; -#endif + struct GNUNET_DISK_FileHandle fd[2]; }; static int @@ -1390,4 +1387,165 @@ GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h) #endif } +/** + * Creates an interprocess channel + * @param blocking creates an asynchronous pipe if set to GNUNET_NO + * @return handle to the new pipe, NULL on error + */ +struct GNUNET_DISK_PipeHandle * +GNUNET_DISK_pipe (int blocking) +{ + struct GNUNET_DISK_PipeHandle *p; + int err; + + err = GNUNET_NO; + p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle)); + +#ifndef MINGW + int fd[2]; + int ret; + int flags; + + ret = pipe (fd); + if (ret != -1) + { + p->fd[0].fd = fd[0]; + p->fd[1].fd = fd[1]; + + if (!blocking) + { + flags = fcntl (fd[0], F_GETFL); + flags |= O_NONBLOCK; + ret = fcntl (fd[0], F_SETFL, flags); + if (ret != -1) + { + flags = fcntl (fd[1], F_GETFL); + flags |= O_NONBLOCK; + ret = fcntl (fd[1], F_SETFL, flags); + } + if (ret == -1) + { + GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "fcntl"); + close (fd[0]); + close (fd[1]); + err = GNUNET_YES; + } + } + } + else + err = GNUNET_YES; +#else + BOOL ret; + + ret = CreatePipe (&p->fd[0].h, &p->fd[1].h, NULL, 0); + if (ret) + { + if (!blocking) + { + DWORD mode; + + mode = PIPE_NOWAIT; + SetNamedPipeHandleState (p->fd[0].h, &mode, NULL, NULL); + SetNamedPipeHandleState (p->fd[1].h, &mode, NULL, NULL); + /* this always fails on Windows 95, so we don't care about error handling */ + } + } + else + err = GNUNET_YES; +#endif + + if (GNUNET_YES == err) + { + GNUNET_free (p); + p = NULL; + } + + return p; +} + +/** + * Closes an interprocess channel + * @param p pipe + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) +{ + int ret; + + ret = GNUNET_OK; + +#ifdef MINGW + if (!CloseHandle (p->fd[0].h)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } + + if (!CloseHandle (p->fd[1].h)) + { + SetErrnoFromWinError (GetLastError ()); + ret = GNUNET_SYSERR; + } +#else + { + int save; + + if (close (p->fd[0].fd) != -1) + { + ret = GNUNET_SYSERR; + save = errno; + } + else + save = 0; + + if (close (p->fd[1].fd) != -1) + { + ret = GNUNET_SYSERR; + } + else + errno = save; + } +#endif + GNUNET_free (p); + + return ret; +} + +/** + * Get the handle to a particular pipe end + * @param p pipe + * @param n number of the end + */ +const struct GNUNET_DISK_FileHandle * +GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, int n) +{ + return &p->fd[n]; +} + +/** + * Retrieve OS file handle + * @internal + * @param fh GNUnet file descriptor + * @param dst destination buffer + * @param dst_len length of dst + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int +GNUNET_internal_disk_file_handle (const struct GNUNET_DISK_FileHandle *fh, + void *dst, unsigned int dst_len) +{ +#ifdef MINGW + if (dst_len < sizeof (HANDLE)) + return GNUNET_SYSERR; + *((HANDLE *) dst) = fh->h; +#else + if (dst_len < sizeof(int)) + return GNUNET_SYSERR; + *((int *) dst) = fh->fd; +#endif + + return GNUNET_OK; +} + /* end of disk.c */ diff --git a/src/util/disk.h b/src/util/disk.h new file mode 100644 index 000000000..9857a0fed --- /dev/null +++ b/src/util/disk.h @@ -0,0 +1,53 @@ +/* + 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 util/disk.h + * @brief Internal DISK related helper functions + * @author Nils Durner + */ + + +#ifndef GNUNET_DISK_H_ +#define GNUNET_DISK_H_ + +#include "gnunet_disk_lib.h" + +struct GNUNET_DISK_FileHandle +{ +#ifdef MINGW + HANDLE h; +#else + int fd; +#endif +}; + +/** + * Retrieve OS file handle + * @internal + * @param fh GNUnet file descriptor + * @param dst destination buffer + * @param dst_len length of dst + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +int GNUNET_internal_disk_file_handle (const struct GNUNET_DISK_FileHandle *fh, + void *dst, unsigned int dst_len); + +#endif /* GNUNET_DISK_H_ */ diff --git a/src/util/network.c b/src/util/network.c index 3ee19cfb2..6d8b9f938 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -37,7 +37,7 @@ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #define DEBUG_NETWORK GNUNET_NO @@ -172,9 +172,9 @@ struct GNUNET_NETWORK_ConnectionHandle struct GNUNET_NETWORK_TransmitHandle nth; /** - * Underlying OS's socket, set to -1 after fatal errors. + * Underlying OS's socket, set to NULL after fatal errors. */ - int sock; + struct GNUNET_NETWORK_Descriptor *sock; /** * Port to connect to. @@ -219,7 +219,7 @@ struct GNUNET_NETWORK_ConnectionHandle */ struct GNUNET_NETWORK_ConnectionHandle * GNUNET_NETWORK_connection_create_from_existing (struct GNUNET_SCHEDULER_Handle - *sched, int osSocket, + *sched, struct GNUNET_NETWORK_Descriptor *osSocket, size_t maxbuf) { struct GNUNET_NETWORK_ConnectionHandle *ret; @@ -248,13 +248,13 @@ struct GNUNET_NETWORK_ConnectionHandle * GNUNET_NETWORK_connection_create_from_accept (struct GNUNET_SCHEDULER_Handle *sched, GNUNET_NETWORK_AccessCheck access, - void *access_cls, int lsock, + void *access_cls, struct GNUNET_NETWORK_Descriptor *lsock, size_t maxbuf) { struct GNUNET_NETWORK_ConnectionHandle *ret; char addr[32]; socklen_t addrlen; - int fd; + struct GNUNET_NETWORK_Descriptor *sock; int aret; struct sockaddr_in *v4; struct sockaddr_in6 *v6; @@ -262,22 +262,21 @@ GNUNET_NETWORK_connection_create_from_accept (struct GNUNET_SCHEDULER_Handle void *uaddr; addrlen = sizeof (addr); - fd = accept (lsock, (struct sockaddr *) &addr, &addrlen); - if (fd == -1) + sock = GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen); + if (NULL == sock) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept"); return NULL; } #ifndef MINGW - // FIXME NILS - if (0 != fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC)) + if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (sock)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "fcntl"); #endif if (addrlen > sizeof (addr)) { GNUNET_break (0); - GNUNET_break (0 == CLOSE (fd)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock)); return NULL; } @@ -310,8 +309,8 @@ GNUNET_NETWORK_connection_create_from_accept (struct GNUNET_SCHEDULER_Handle GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"), GNUNET_a2s(uaddr, addrlen)); - GNUNET_break (0 == SHUTDOWN (fd, SHUT_RDWR)); - GNUNET_break (0 == CLOSE (fd)); + GNUNET_break (0 == GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (uaddr); return NULL; } @@ -325,7 +324,7 @@ GNUNET_NETWORK_connection_create_from_accept (struct GNUNET_SCHEDULER_Handle ret->write_buffer_size = maxbuf; ret->addr = uaddr; ret->addrlen = addrlen; - ret->sock = fd; + ret->sock = sock; ret->sched = sched; return ret; } @@ -350,64 +349,6 @@ GNUNET_NETWORK_connection_get_address (struct GNUNET_NETWORK_ConnectionHandle *s return GNUNET_OK; } - -/** - * Set if a socket should use blocking or non-blocking IO. - * - * @return GNUNET_OK on success, GNUNET_SYSERR on error - */ -static int -socket_set_blocking (int handle, int doBlock) -{ -#if MINGW - u_long mode; - mode = !doBlock; -#if HAVE_PLIBC_FD - if (ioctlsocket (plibc_fd_get_handle (handle), FIONBIO, &mode) == - SOCKET_ERROR) - { - SetErrnoFromWinsockError (WSAGetLastError ()); - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket"); - return GNUNET_SYSERR; - } -#else - if (ioctlsocket (handle, FIONBIO, &mode) == SOCKET_ERROR) - { - SetErrnoFromWinsockError (WSAGetLastError ()); - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket"); - return GNUNET_SYSERR; - } -#endif - /* store the blocking mode */ -#if HAVE_PLIBC_FD - plibc_fd_set_blocking (handle, doBlock); -#else - __win_SetHandleBlockingMode (handle, doBlock); -#endif - return GNUNET_OK; - -#else - /* not MINGW */ - int flags = fcntl (handle, F_GETFL); - if (flags == -1) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl"); - return GNUNET_SYSERR; - } - if (doBlock) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - if (0 != fcntl (handle, F_SETFL, flags)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl"); - return GNUNET_SYSERR; - } - return GNUNET_OK; -#endif -} - - /** * Perform a DNS lookup for the hostname associated * with the current socket, iterating over the address @@ -448,7 +389,7 @@ try_lookup (struct GNUNET_NETWORK_ConnectionHandle *sock) static int try_connect (struct GNUNET_NETWORK_ConnectionHandle *sock) { - int s; + struct GNUNET_NETWORK_Descriptor *s; if (sock->addr != NULL) { @@ -479,8 +420,8 @@ try_connect (struct GNUNET_NETWORK_ConnectionHandle *sock) sock->ai_pos = sock->ai_pos->ai_next; continue; } - s = SOCKET (sock->ai_pos->ai_family, SOCK_STREAM, 0); - if (s == -1) + 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"); @@ -488,15 +429,14 @@ try_connect (struct GNUNET_NETWORK_ConnectionHandle *sock) continue; } #ifndef MINGW - // FIXME NILS - if (0 != fcntl (s, F_SETFD, fcntl (s, F_GETFD) | FD_CLOEXEC)) + if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (s)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "fcntl"); + "GNUNET_NETWORK_socket_set_inheritable"); #endif - if (GNUNET_SYSERR == socket_set_blocking (s, GNUNET_NO)) + if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (s, GNUNET_NO)) { /* we'll treat this one as fatal */ - GNUNET_break (0 == CLOSE (s)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (s)); return GNUNET_SYSERR; } #if DEBUG_NETWORK @@ -505,13 +445,13 @@ try_connect (struct GNUNET_NETWORK_ConnectionHandle *sock) GNUNET_a2s(sock->ai_pos->ai_addr, sock->ai_pos->ai_addrlen)); #endif - if ((0 != CONNECT (s, + if ((0 != 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 (0 == CLOSE (s)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (s)); sock->ai_pos = sock->ai_pos->ai_next; continue; } @@ -548,7 +488,7 @@ connect_continuation (void *cls, errno = 0; error = 0; if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || - (0 != getsockopt (sock->sock, SOL_SOCKET, SO_ERROR, &error, &len)) || + (0 != GNUNET_NETWORK_socket_getsockopt (sock->sock, SOL_SOCKET, SO_ERROR, &error, &len)) || (error != 0) || (errno != 0)) { #if DEBUG_NETWORK @@ -557,8 +497,8 @@ connect_continuation (void *cls, GNUNET_a2s(sock->addr, sock->addrlen)); #endif /* connect failed / timed out */ - GNUNET_break (0 == CLOSE (sock->sock)); - sock->sock = -1; + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock->sock)); + sock->sock = NULL; if (GNUNET_SYSERR == try_connect (sock)) { /* failed for good */ @@ -572,7 +512,7 @@ connect_continuation (void *cls, sock->ai = NULL; return; } - sock->connect_task = GNUNET_SCHEDULER_add_write (tc->sched, GNUNET_NO, /* abort on shutdown */ + sock->connect_task = GNUNET_SCHEDULER_add_write_net (tc->sched, GNUNET_NO, /* abort on shutdown */ GNUNET_SCHEDULER_PRIORITY_KEEP, GNUNET_SCHEDULER_NO_TASK, GNUNET_NETWORK_CONNECT_RETRY_TIMEOUT, @@ -613,7 +553,7 @@ GNUNET_NETWORK_connection_create_from_connect (struct GNUNET_SCHEDULER_Handle struct GNUNET_NETWORK_ConnectionHandle *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_ConnectionHandle) + maxbuf); - ret->sock = -1; + ret->sock = NULL; ret->sched = sched; ret->write_buffer = (char *) &ret[1]; ret->write_buffer_size = maxbuf; @@ -628,7 +568,7 @@ GNUNET_NETWORK_connection_create_from_connect (struct GNUNET_SCHEDULER_Handle GNUNET_free (ret); return NULL; } - ret->connect_task = GNUNET_SCHEDULER_add_write (sched, GNUNET_NO, /* abort on shutdown */ + ret->connect_task = GNUNET_SCHEDULER_add_write_net (sched, GNUNET_NO, /* abort on shutdown */ GNUNET_SCHEDULER_PRIORITY_KEEP, GNUNET_SCHEDULER_NO_TASK, GNUNET_NETWORK_CONNECT_RETRY_TIMEOUT, @@ -658,25 +598,28 @@ GNUNET_NETWORK_connection_create_from_sockaddr (struct GNUNET_SCHEDULER_Handle const struct sockaddr *serv_addr, socklen_t addrlen, size_t maxbuf) { - int s; + struct GNUNET_NETWORK_Descriptor *s; struct GNUNET_NETWORK_ConnectionHandle *ret; - s = SOCKET (af_family, SOCK_STREAM, 0); - if (s == -1) + s = GNUNET_NETWORK_socket_socket (af_family, SOCK_STREAM, 0); + if (s == NULL) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket"); return NULL; } #ifndef MINGW +#if 0 + // FIXME NILS if (0 != fcntl (s, F_SETFD, fcntl (s, F_GETFD) | FD_CLOEXEC)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "fcntl"); #endif - if (GNUNET_SYSERR == socket_set_blocking (s, GNUNET_NO)) +#endif + if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (s, GNUNET_NO)) { /* we'll treat this one as fatal */ - GNUNET_break (0 == CLOSE (s)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (s)); return NULL; } #if DEBUG_NETWORK @@ -684,11 +627,11 @@ GNUNET_NETWORK_connection_create_from_sockaddr (struct GNUNET_SCHEDULER_Handle _("Trying to connect to `%s'\n"), GNUNET_a2s(serv_addr, addrlen)); #endif - if ((0 != CONNECT (s, serv_addr, addrlen)) && (errno != EINPROGRESS)) + if ((0 != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) && (errno != EINPROGRESS)) { /* maybe refused / unsupported address, try next */ GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect"); - GNUNET_break (0 == CLOSE (s)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (s)); return NULL; } ret = GNUNET_NETWORK_connection_create_from_existing (sched, s, maxbuf); @@ -712,7 +655,7 @@ GNUNET_NETWORK_connection_check (struct GNUNET_NETWORK_ConnectionHandle *sock) { if (sock->ai != NULL) return GNUNET_YES; /* still trying to connect */ - return (sock->sock == -1) ? GNUNET_NO : GNUNET_YES; + return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES; } @@ -736,12 +679,12 @@ destroy_continuation (void *cls, &destroy_continuation, sock); return; } - if (sock->sock != -1) + if (sock->sock != NULL) { #if DEBUG_NETWORK GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down socket.\n"); #endif - SHUTDOWN (sock->sock, SHUT_RDWR); + GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); } if (sock->read_task != GNUNET_SCHEDULER_NO_TASK) { @@ -762,8 +705,8 @@ destroy_continuation (void *cls, sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; } } - if (sock->sock != -1) - GNUNET_break (0 == CLOSE (sock->sock)); + if (sock->sock != NULL) + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock->sock)); GNUNET_free_non_null (sock->addr); if (sock->ai != NULL) freeaddrinfo (sock->ai); @@ -850,7 +793,7 @@ receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) signal_timeout (sh); return; } - if (sh->sock == -1) + if (sh->sock == NULL) { /* connect failed for good */ #if DEBUG_NETWORK @@ -860,9 +803,9 @@ receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) signal_error (sh, ECONNREFUSED); return; } - GNUNET_assert (FD_ISSET (sh->sock, tc->read_ready)); + GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, sh->sock)); RETRY: - ret = RECV (sh->sock, buffer, sh->max, + ret = GNUNET_NETWORK_socket_recv (sh->sock, buffer, sh->max, #ifndef MINGW // FIXME MINGW MSG_DONTWAIT @@ -908,7 +851,7 @@ 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 == -1) && + if ((sh->sock == NULL) && (sh->connect_task == GNUNET_SCHEDULER_NO_TASK)) { /* not connected and no longer trying */ @@ -941,7 +884,7 @@ receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) return; } /* connect succeeded, wait for data! */ - sh->read_task = GNUNET_SCHEDULER_add_read (tc->sched, + sh->read_task = GNUNET_SCHEDULER_add_read_net (tc->sched, GNUNET_YES, GNUNET_SCHEDULER_PRIORITY_KEEP, sh->connect_task, @@ -1120,25 +1063,25 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) sock); return; } - if ( (sock->sock == -1) || + if ( (sock->sock == NULL) || ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) && (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) && - (!FD_ISSET (sock->sock, tc->write_ready))) ) + (!GNUNET_NETWORK_fdset_isset (tc->write_ready, sock->sock))) ) { #if DEBUG_NETWORK GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not satisfy pending transmission request, socket closed or connect failed.\n")); #endif - if (-1 != sock->sock) + if (NULL != sock->sock) { - SHUTDOWN (sock->sock, SHUT_RDWR); - GNUNET_break (0 == CLOSE (sock->sock)); - sock->sock = -1; + GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock->sock)); + sock->sock = NULL; } transmit_error (sock); return; /* connect failed for good, we're finished */ } - if ((tc->write_ready == NULL) || (!FD_ISSET (sock->sock, tc->write_ready))) + if ((tc->write_ready == NULL) || (!GNUNET_NETWORK_fdset_isset (tc->write_ready, sock->sock))) { /* special circumstances (in particular, PREREQ_DONE after connect): not yet ready to write, @@ -1154,7 +1097,7 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) return; } RETRY: - ret = SEND (sock->sock, + ret = GNUNET_NETWORK_socket_send (sock->sock, &sock->write_buffer[sock->write_buffer_pos], have, #ifndef MINGW @@ -1171,9 +1114,9 @@ RETRY: #if DEBUG_NETWORK GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send"); #endif - SHUTDOWN (sock->sock, SHUT_RDWR); - GNUNET_break (0 == CLOSE (sock->sock)); - sock->sock = -1; + GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock->sock)); + sock->sock = NULL; transmit_error (sock); return; } @@ -1197,7 +1140,7 @@ RETRY: SCHEDULE_WRITE: if (sock->write_task == GNUNET_SCHEDULER_NO_TASK) sock->write_task = - GNUNET_SCHEDULER_add_write (tc->sched, + GNUNET_SCHEDULER_add_write_net (tc->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_KEEP, GNUNET_SCHEDULER_NO_TASK, @@ -1232,7 +1175,7 @@ GNUNET_NETWORK_connection_notify_transmit_ready (struct GNUNET_NETWORK_Connectio GNUNET_assert (notify != NULL); GNUNET_assert (sock->write_buffer_size >= size); - if ((sock->sock == -1) && + if ((sock->sock == NULL) && (sock->connect_task == GNUNET_SCHEDULER_NO_TASK)) { #if DEBUG_NETWORK @@ -1261,7 +1204,7 @@ GNUNET_NETWORK_connection_notify_transmit_ready (struct GNUNET_NETWORK_Connectio if (sock->write_task == GNUNET_SCHEDULER_NO_TASK) { if (sock->connect_task == GNUNET_SCHEDULER_NO_TASK) - sock->write_task = GNUNET_SCHEDULER_add_write (sock->sched, + sock->write_task = GNUNET_SCHEDULER_add_write_net (sock->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_KEEP, GNUNET_SCHEDULER_NO_TASK, diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 0b5307290..69a5a83e1 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c @@ -55,7 +55,7 @@ struct Task * to reflect the set of file descriptors ready * for operation. */ - fd_set read_set; + struct GNUNET_NETWORK_FDSet *read_set; /** * Set of file descriptors this task is waiting @@ -63,7 +63,7 @@ struct Task * to reflect the set of file descriptors ready * for operation. */ - fd_set write_set; + struct GNUNET_NETWORK_FDSet *write_set; /** * Unique task identifier. @@ -93,11 +93,6 @@ struct Task */ enum GNUNET_SCHEDULER_Priority priority; - /** - * highest-numbered file descriptor in read_set or write_set plus one - */ - int nfds; - /** * Should this task be run on shutdown? */ @@ -170,33 +165,6 @@ check_priority (enum GNUNET_SCHEDULER_Priority p) } -/** - * Update the timeout value so that it is smaller than min. - */ -static void -update_timeout (struct timeval *tv, struct GNUNET_TIME_Relative min) -{ - if (((tv->tv_sec * 1000) + (tv->tv_usec / 1000)) > min.value) - { - tv->tv_sec = min.value / 1000; - tv->tv_usec = (min.value - tv->tv_sec * 1000) * 1000; - } -} - - -/** - * Set the given file descriptor bit in the given set and update max - * to the maximum of the existing max and fd+1. - */ -static void -set_fd (int fd, int *max, fd_set * set) -{ - if (*max <= fd) - *max = fd + 1; - FD_SET (fd, set); -} - - /** * Is a task with this identifier still pending? Also updates * "lowest_pending_id" as a side-effect (for faster checks in the @@ -247,14 +215,14 @@ is_pending (struct GNUNET_SCHEDULER_Handle *sched, */ static void update_sets (struct GNUNET_SCHEDULER_Handle *sched, - int *max, fd_set * rs, fd_set * ws, struct timeval *tv) + struct GNUNET_NETWORK_FDSet * rs, struct GNUNET_NETWORK_FDSet * ws, struct GNUNET_TIME_Relative *timeout) { - int i; struct Task *pos; pos = sched->pending; while (pos != NULL) { + if ((pos->prereq_id != GNUNET_SCHEDULER_NO_TASK) && (GNUNET_YES == is_pending (sched, pos->prereq_id))) { @@ -263,15 +231,16 @@ update_sets (struct GNUNET_SCHEDULER_Handle *sched, } if (pos->timeout.value != GNUNET_TIME_UNIT_FOREVER_ABS.value) - update_timeout (tv, - GNUNET_TIME_absolute_get_remaining (pos->timeout)); - for (i = 0; i < pos->nfds; i++) { - if (FD_ISSET (i, &pos->read_set)) - set_fd (i, max, rs); - if (FD_ISSET (i, &pos->write_set)) - set_fd (i, max, ws); + struct GNUNET_TIME_Relative to; + + to = GNUNET_TIME_absolute_get_remaining (pos->timeout); + if (timeout->value > to.value) + *timeout = to; } + + GNUNET_NETWORK_fdset_add (rs, pos->read_set); + GNUNET_NETWORK_fdset_add (ws, pos->write_set); pos = pos->next; } } @@ -286,18 +255,15 @@ update_sets (struct GNUNET_SCHEDULER_Handle *sched, * @return GNUNET_YES if there was some overlap */ static int -set_overlaps (const fd_set * ready, fd_set * want, int maxfd) +set_overlaps (const struct GNUNET_NETWORK_FDSet * ready, struct GNUNET_NETWORK_FDSet * want) { - int i; - - for (i = 0; i < maxfd; i++) - if (FD_ISSET (i, want) && FD_ISSET (i, ready)) - { - /* copy all over (yes, there maybe unrelated bits, - but this should not hurt well-written clients) */ - memcpy (want, ready, sizeof (fd_set)); - return GNUNET_YES; - } + if (GNUNET_NETWORK_fdset_overlap (ready, want)) + { + /* copy all over (yes, there maybe unrelated bits, + but this should not hurt well-written clients) */ + GNUNET_NETWORK_fdset_copy (want, ready); + return GNUNET_YES; + } return GNUNET_NO; } @@ -312,7 +278,7 @@ static int is_ready (struct GNUNET_SCHEDULER_Handle *sched, struct Task *task, struct GNUNET_TIME_Absolute now, - const fd_set * rs, const fd_set * ws) + const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws) { if ((GNUNET_NO == task->run_on_shutdown) && (GNUNET_YES == sched->shutdown)) return GNUNET_NO; @@ -322,10 +288,10 @@ is_ready (struct GNUNET_SCHEDULER_Handle *sched, if (now.value >= task->timeout.value) task->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && - (rs != NULL) && (set_overlaps (rs, &task->read_set, task->nfds))) + (rs != NULL) && (set_overlaps (rs, task->read_set))) task->reason |= GNUNET_SCHEDULER_REASON_READ_READY; if ((0 == (task->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && - (ws != NULL) && (set_overlaps (ws, &task->write_set, task->nfds))) + (ws != NULL) && (set_overlaps (ws, task->write_set))) task->reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; if (task->reason == 0) return GNUNET_NO; /* not ready */ @@ -357,7 +323,7 @@ queue_ready_task (struct GNUNET_SCHEDULER_Handle *handle, struct Task *task) */ static void check_ready (struct GNUNET_SCHEDULER_Handle *handle, - const fd_set * rs, const fd_set * ws) + const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws) { struct Task *pos; struct Task *prev; @@ -386,6 +352,19 @@ check_ready (struct GNUNET_SCHEDULER_Handle *handle, } +/** + * Destroy a task + */ +static void destroy_task (struct Task *t) +{ + if (t->read_set) + GNUNET_NETWORK_fdset_destroy (t->read_set); + if (t->write_set) + GNUNET_NETWORK_fdset_destroy (t->write_set); + GNUNET_free (t); +} + + /** * Run at least one task in the highest-priority queue that is not * empty. Keep running tasks until we are either no longer running @@ -420,10 +399,10 @@ run_ready (struct GNUNET_SCHEDULER_Handle *sched) GNUNET_assert (pos->priority == p); tc.sched = sched; tc.reason = pos->reason; - tc.read_ready = &pos->read_set; - tc.write_ready = &pos->write_set; + tc.read_ready = pos->read_set; + tc.write_ready = pos->write_set; pos->callback (pos->callback_cls, &tc); - GNUNET_free (pos); + destroy_task (pos); } while ((sched->pending == NULL) || (p == GNUNET_SCHEDULER_PRIORITY_URGENT)); } @@ -458,10 +437,9 @@ void GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls) { struct GNUNET_SCHEDULER_Handle sched; - fd_set rs; - fd_set ws; - int max; - struct timeval tv; + struct GNUNET_NETWORK_FDSet *rs; + struct GNUNET_NETWORK_FDSet *ws; + struct GNUNET_TIME_Relative timeout; int ret; struct GNUNET_SIGNAL_Context *shc_int; struct GNUNET_SIGNAL_Context *shc_term; @@ -470,6 +448,8 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls) struct Task *tpos; sig_shutdown = 0; + rs = GNUNET_NETWORK_fdset_create (); + ws = GNUNET_NETWORK_fdset_create (); #ifndef MINGW shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown); shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown); @@ -486,27 +466,24 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls) (!sig_shutdown) && ((sched.pending != NULL) || (sched.ready_count > 0))) { - FD_ZERO (&rs); - FD_ZERO (&ws); - max = 0; - tv.tv_sec = 0x7FFFFFFF; - tv.tv_usec = 0; + GNUNET_NETWORK_fdset_zero (rs); + GNUNET_NETWORK_fdset_zero (ws); + timeout = GNUNET_TIME_relative_get_forever(); if (sched.ready_count > 0) { /* no blocking, more work already ready! */ - tv.tv_sec = 0; - tv.tv_usec = 0; + timeout = GNUNET_TIME_relative_get_zero(); } - update_sets (&sched, &max, &rs, &ws, &tv); - ret = SELECT (max, &rs, &ws, NULL, &tv); - if (ret == -1) + update_sets (&sched, rs, ws, &timeout); + ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, GNUNET_TIME_relative_get_zero()); + if (ret == GNUNET_SYSERR) { if (errno == EINTR) continue; GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select"); break; } - check_ready (&sched, &rs, &ws); + check_ready (&sched, rs, ws); run_ready (&sched); } if (sig_shutdown) @@ -526,6 +503,8 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *cls) sched.pending = tpos->next; GNUNET_free (tpos); } + GNUNET_NETWORK_fdset_destroy (rs); + GNUNET_NETWORK_fdset_destroy (ws); } @@ -626,7 +605,7 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Handle *sched, else prev->next = t->next; ret = t->callback_cls; - GNUNET_free (t); + destroy_task (t); return ret; } @@ -688,7 +667,7 @@ GNUNET_SCHEDULER_add_after (struct GNUNET_SCHEDULER_Handle *sched, return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, prerequisite_task, GNUNET_TIME_UNIT_ZERO, - 0, NULL, NULL, main, cls); + NULL, NULL, main, cls); } @@ -726,7 +705,7 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_SCHEDULER_Handle * sched, { return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, prerequisite_task, delay, - 0, NULL, NULL, main, cls); + NULL, NULL, main, cls); } @@ -755,21 +734,24 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_SCHEDULER_Handle * sched, * only valid until "main" is started! */ GNUNET_SCHEDULER_TaskIdentifier -GNUNET_SCHEDULER_add_read (struct GNUNET_SCHEDULER_Handle * sched, +GNUNET_SCHEDULER_add_read_net (struct GNUNET_SCHEDULER_Handle * sched, int run_on_shutdown, enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, - int rfd, GNUNET_SCHEDULER_Task main, void *cls) + struct GNUNET_NETWORK_Descriptor *rfd, GNUNET_SCHEDULER_Task main, void *cls) { - fd_set rs; + struct GNUNET_NETWORK_FDSet *rs; + GNUNET_SCHEDULER_TaskIdentifier ret; - GNUNET_assert (rfd >= 0); - FD_ZERO (&rs); - FD_SET (rfd, &rs); - return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, + GNUNET_assert (rfd != NULL); + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set (rs, rfd); + ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, prerequisite_task, delay, - rfd + 1, &rs, NULL, main, cls); + rs, NULL, main, cls); + GNUNET_NETWORK_fdset_destroy (rs); + return ret; } @@ -798,21 +780,24 @@ GNUNET_SCHEDULER_add_read (struct GNUNET_SCHEDULER_Handle * sched, * only valid until "main" is started! */ GNUNET_SCHEDULER_TaskIdentifier -GNUNET_SCHEDULER_add_write (struct GNUNET_SCHEDULER_Handle * sched, +GNUNET_SCHEDULER_add_write_net (struct GNUNET_SCHEDULER_Handle * sched, int run_on_shutdown, enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, - int wfd, GNUNET_SCHEDULER_Task main, void *cls) + struct GNUNET_NETWORK_Descriptor *wfd, GNUNET_SCHEDULER_Task main, void *cls) { - fd_set ws; + struct GNUNET_NETWORK_FDSet *ws; + GNUNET_SCHEDULER_TaskIdentifier ret; - GNUNET_assert (wfd >= 0); - FD_ZERO (&ws); - FD_SET (wfd, &ws); - return GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, + GNUNET_assert (wfd != NULL); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set (ws, wfd); + ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, prerequisite_task, delay, - wfd + 1, NULL, &ws, main, cls); + NULL, ws, main, cls); + GNUNET_NETWORK_fdset_destroy (ws); + return ret; } @@ -844,7 +829,6 @@ GNUNET_SCHEDULER_add_write (struct GNUNET_SCHEDULER_Handle * sched, * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency * on completion of other tasks. * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever" - * @param nfds highest-numbered file descriptor in any of the two sets plus one * @param rs set of file descriptors we want to read (can be NULL) * @param ws set of file descriptors we want to write (can be NULL) * @param main main function of the task @@ -859,7 +843,7 @@ GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle * sched, GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, struct GNUNET_TIME_Relative delay, - int nfds, const fd_set * rs, const fd_set * ws, + const struct GNUNET_NETWORK_FDSet * rs, const struct GNUNET_NETWORK_FDSet * ws, GNUNET_SCHEDULER_Task main, void *cls) { struct Task *task; @@ -867,10 +851,12 @@ GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle * sched, task = GNUNET_malloc (sizeof (struct Task)); task->callback = main; task->callback_cls = cls; - if ((rs != NULL) && (nfds > 0)) - memcpy (&task->read_set, rs, sizeof (fd_set)); - if ((ws != NULL) && (nfds > 0)) - memcpy (&task->write_set, ws, sizeof (fd_set)); + task->read_set = GNUNET_NETWORK_fdset_create (); + if (rs != NULL) + GNUNET_NETWORK_fdset_copy (task->read_set, rs); + task->write_set = GNUNET_NETWORK_fdset_create (); + if (ws != NULL) + GNUNET_NETWORK_fdset_copy (task->write_set, ws); task->id = ++sched->last_id; task->prereq_id = prerequisite_task; task->timeout = GNUNET_TIME_relative_to_absolute (delay); @@ -878,11 +864,102 @@ GNUNET_SCHEDULER_add_select (struct GNUNET_SCHEDULER_Handle * sched, check_priority ((prio == GNUNET_SCHEDULER_PRIORITY_KEEP) ? sched->current_priority : prio); - task->nfds = nfds; task->run_on_shutdown = run_on_shutdown; task->next = sched->pending; sched->pending = task; return task->id; } +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for reading. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. + * + * @param sched scheduler to use + * @param run_on_shutdown run on shutdown? Set this + * argument to GNUNET_NO to skip this task if + * the user requested process termination. + * @param prio how important is this task? + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readyness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks. + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever" + * @param rfd read file-descriptor + * @param main main function of the task + * @param cls closure of task + * @return unique task identifier for the job + * only valid until "main" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_read_file (struct GNUNET_SCHEDULER_Handle * sched, + int run_on_shutdown, + enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + struct GNUNET_TIME_Relative delay, + struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_Task main, void *cls) +{ + struct GNUNET_NETWORK_FDSet *rs; + GNUNET_SCHEDULER_TaskIdentifier ret; + + GNUNET_assert (rfd != NULL); + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_handle_set (rs, rfd); + ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, + prerequisite_task, delay, + rs, NULL, main, cls); + GNUNET_NETWORK_fdset_destroy (rs); + return ret; +} + + +/** + * Schedule a new task to be run with a specified delay or when the + * specified file descriptor is ready for writing. The delay can be + * used as a timeout on the socket being ready. The task will be + * scheduled for execution once either the delay has expired or the + * socket operation is ready. + * + * @param sched scheduler to use + * @param run_on_shutdown run on shutdown? Set this + * argument to GNUNET_NO to skip this task if + * the user requested process termination. + * @param prio how important is this task? + * @param prerequisite_task run this task after the task with the given + * task identifier completes (and any of our other + * conditions, such as delay, read or write-readyness + * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency + * on completion of other tasks. + * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever" + * @param wfd write file-descriptor + * @param main main function of the task + * @param cls closure of task + * @return unique task identifier for the job + * only valid until "main" is started! + */ +GNUNET_SCHEDULER_TaskIdentifier +GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle * sched, + int run_on_shutdown, + enum GNUNET_SCHEDULER_Priority prio, + GNUNET_SCHEDULER_TaskIdentifier prerequisite_task, + struct GNUNET_TIME_Relative delay, + struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_Task main, void *cls) +{ + struct GNUNET_NETWORK_FDSet *ws; + GNUNET_SCHEDULER_TaskIdentifier ret; + + GNUNET_assert (wfd != NULL); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_handle_set (ws, wfd); + ret = GNUNET_SCHEDULER_add_select (sched, run_on_shutdown, prio, + prerequisite_task, delay, + NULL, ws, main, cls); + GNUNET_NETWORK_fdset_destroy (ws); + return ret; +} + + /* end of scheduler.c */ diff --git a/src/util/server.c b/src/util/server.c index d518cbeec..ff9ea993d 100644 --- a/src/util/server.c +++ b/src/util/server.c @@ -29,10 +29,11 @@ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" +#include "gnunet_disk_lib.h" #define DEBUG_SERVER GNUNET_NO @@ -124,13 +125,13 @@ struct GNUNET_SERVER_Handle /** * Pipe used to signal shutdown of the server. */ - int shutpipe[2]; + struct GNUNET_DISK_PipeHandle *shutpipe; /** * Socket used to listen for new connections. Set to * "-1" by GNUNET_SERVER_destroy to initiate shutdown. */ - int listen_socket; + struct GNUNET_NETWORK_Descriptor *listen_socket; /** * Set to GNUNET_YES if we are shutting down. @@ -280,9 +281,8 @@ destroy_server (struct GNUNET_SERVER_Handle *server) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n"); #endif - GNUNET_assert (server->listen_socket == -1); - GNUNET_break (0 == CLOSE (server->shutpipe[0])); - GNUNET_break (0 == CLOSE (server->shutpipe[1])); + GNUNET_assert (server->listen_socket == NULL); + GNUNET_break (GNUNET_YES == GNUNET_DISK_pipe_close (server->shutpipe)); while (server->clients != NULL) { pos = server->clients; @@ -314,21 +314,23 @@ process_listen_socket (void *cls, struct GNUNET_SERVER_Handle *server = cls; struct GNUNET_NETWORK_ConnectionHandle *sock; struct GNUNET_SERVER_Client *client; - fd_set r; + struct GNUNET_NETWORK_FDSet *r; + const struct GNUNET_DISK_FileHandle *shutpipe; if ((server->do_shutdown) || ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)) { /* shutdown was initiated */ - GNUNET_assert (server->listen_socket != -1); - GNUNET_break (0 == CLOSE (server->listen_socket)); - server->listen_socket = -1; + GNUNET_assert (server->listen_socket != NULL); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (server->listen_socket)); + server->listen_socket = NULL; if (server->do_shutdown) destroy_server (server); return; } - GNUNET_assert (FD_ISSET (server->listen_socket, tc->read_ready)); - GNUNET_assert (!FD_ISSET (server->shutpipe[0], tc->read_ready)); + shutpipe = GNUNET_DISK_pipe_handle (server->shutpipe, 0); + GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, server->listen_socket)); + GNUNET_assert (!GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, shutpipe)); sock = GNUNET_NETWORK_connection_create_from_accept (tc->sched, server->access, server->access_cls, @@ -345,30 +347,30 @@ process_listen_socket (void *cls, GNUNET_SERVER_client_drop (client); } /* listen for more! */ - FD_ZERO (&r); - FD_SET (server->listen_socket, &r); - FD_SET (server->shutpipe[0], &r); + r = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set (r, server->listen_socket); + GNUNET_NETWORK_fdset_handle_set (r, shutpipe); GNUNET_SCHEDULER_add_select (server->sched, GNUNET_YES, GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_MAX (server->listen_socket, - server->shutpipe[0]) + 1, &r, NULL, + r, NULL, &process_listen_socket, server); + GNUNET_NETWORK_fdset_destroy (r); } /** * Create and initialize a listen socket for the server. * - * @return -1 on error, otherwise the listen socket + * @return NULL on error, otherwise the listen socket */ -static int +static struct GNUNET_NETWORK_Descriptor * open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) { const static int on = 1; - int fd; + struct GNUNET_NETWORK_Descriptor *sock; uint16_t port; switch (serverAddr->sa_family) @@ -381,46 +383,45 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) break; default: GNUNET_break (0); - return -1; + return NULL; } - fd = SOCKET (serverAddr->sa_family, SOCK_STREAM, 0); - if (fd < 0) + sock = GNUNET_NETWORK_socket_socket (serverAddr->sa_family, SOCK_STREAM, 0); + if (NULL == sock) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); - return -1; + return NULL; } #ifndef MINGW - // FIXME NILS - if (0 != fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC)) + if (GNUNET_OK != GNUNET_NETWORK_socket_set_inheritable (sock)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "fcntl"); #endif - if (SETSOCKOPT (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + if (GNUNET_NETWORK_socket_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); /* bind the socket */ - if (BIND (fd, serverAddr, socklen) < 0) + if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) < 0) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("`%s' failed for port %d. Is the service already running?\n"), "bind", port); - GNUNET_break (0 == CLOSE (fd)); - return -1; + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock)); + return NULL; } - if (0 != LISTEN (fd, 5)) + if (0 != GNUNET_NETWORK_socket_listen (sock, 5)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); - GNUNET_break (0 == CLOSE (fd)); - return -1; + GNUNET_break (0 == GNUNET_NETWORK_socket_close (sock)); + return NULL; } #if DEBUG_SERVER GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server starts to listen on port %u.\n", port); #endif - return fd; + return sock; } @@ -451,20 +452,22 @@ GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched, idle_timeout, int require_found) { struct GNUNET_SERVER_Handle *ret; - int lsock; - fd_set r; + struct GNUNET_NETWORK_Descriptor *lsock; + struct GNUNET_NETWORK_FDSet *r; - lsock = -2; + lsock = NULL; // FIXME NILS: this was -2, does that have a special meaning? if (serverAddr != NULL) { lsock = open_listen_socket (serverAddr, socklen); - if (lsock == -1) + if (lsock == NULL) return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); - if (0 != PIPE (ret->shutpipe)) + ret->shutpipe = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileDescriptor *[2])); + if ((ret->shutpipe = GNUNET_DISK_pipe (GNUNET_NO)) == NULL) { - GNUNET_break (0 == CLOSE (lsock)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (lsock)); + GNUNET_free (ret->shutpipe); GNUNET_free (ret); return NULL; } @@ -475,19 +478,19 @@ GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched, ret->access = access; ret->access_cls = access_cls; ret->require_found = require_found; - if (lsock >= 0) + if (lsock != NULL) { - FD_ZERO (&r); - FD_SET (ret->listen_socket, &r); - FD_SET (ret->shutpipe[0], &r); + r = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set (r, ret->listen_socket); + GNUNET_NETWORK_fdset_handle_set (r, GNUNET_DISK_pipe_handle (ret->shutpipe, 0)); GNUNET_SCHEDULER_add_select (sched, GNUNET_YES, GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_MAX (ret->listen_socket, - ret->shutpipe[0]) + 1, &r, + r, NULL, &process_listen_socket, ret); + GNUNET_NETWORK_fdset_destroy (r); } return ret; } @@ -503,10 +506,10 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) GNUNET_assert (s->do_shutdown == GNUNET_NO); s->do_shutdown = GNUNET_YES; - if (s->listen_socket == -1) + if (s->listen_socket == NULL) destroy_server (s); else - GNUNET_break (1 == WRITE (s->shutpipe[1], &c, 1)); + GNUNET_break (1 == GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (s->shutpipe, 1), &c, 1)); } diff --git a/src/util/server_tc.c b/src/util/server_tc.c index dc51e1433..bffb892b1 100644 --- a/src/util/server_tc.c +++ b/src/util/server_tc.c @@ -27,7 +27,7 @@ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" diff --git a/src/util/service.c b/src/util/service.c index a976fab78..782c70fe9 100644 --- a/src/util/service.c +++ b/src/util/service.c @@ -813,9 +813,11 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) if (!disablev6) { + struct GNUNET_NETWORK_Descriptor *desc; + /* probe IPv6 support */ - ret = SOCKET (PF_INET6, SOCK_STREAM, 0); - if (ret == -1) + desc = GNUNET_NETWORK_socket_socket (PF_INET6, SOCK_STREAM, 0); + if (NULL == desc) { if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) @@ -823,18 +825,18 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; } - ret = SOCKET (PF_INET, SOCK_STREAM, 0); - if (ret != -1) + desc = GNUNET_NETWORK_socket_socket (PF_INET, SOCK_STREAM, 0); + if (NULL == desc) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), - sctx->serviceName, strerror (errno)); + sctx->serviceName, STRERROR (errno)); disablev6 = GNUNET_YES; } } - if (ret != -1) - GNUNET_break (0 == CLOSE (ret)); + if (NULL != desc) + GNUNET_break (0 == GNUNET_NETWORK_socket_close (desc)); } diff --git a/src/util/sock.c b/src/util/sock.c new file mode 100644 index 000000000..33b6df148 --- /dev/null +++ b/src/util/sock.c @@ -0,0 +1,678 @@ +/* + 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 util/sock.c + * @brief basic, low-level networking interface + * @author Nils Durner + */ + +#include "platform.h" +#include "gnunet_disk_lib.h" +#include "disk.h" +#include "gnunet_container_lib.h" + +#define DEBUG_SOCK GNUNET_NO + +struct GNUNET_NETWORK_Descriptor +{ + int fd; +}; + +struct GNUNET_NETWORK_FDSet +{ + /* socket descriptors */ + int nsds; + fd_set sds; +#ifdef WINDOWS + /* handles */ + struct GNUNET_CONTAINER_Vector *handles; +#endif +}; + +#ifndef FD_COPY +#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) +#endif + +struct GNUNET_NETWORK_Descriptor * +GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Descriptor *desc, + struct sockaddr *address, + socklen_t * address_len) +{ + struct GNUNET_NETWORK_Descriptor *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor)); + ret->fd = accept (desc->fd, address, address_len); +#ifdef MINGW + if (INVALID_SOCKET == ret->fd) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + +int +GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc, + const struct sockaddr *address, + socklen_t address_len) +{ + int ret; + + ret = bind (desc->fd, address, address_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + +/** + * Set if a socket should use blocking or non-blocking IO. + * + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Descriptor *fd, + int doBlock) +{ +#if MINGW + u_long mode; + mode = !doBlock; + if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR) + { + SetErrnoFromWinsockError (WSAGetLastError ()); + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket"); + return GNUNET_SYSERR; + } + return GNUNET_OK; + +#else + /* not MINGW */ + int flags = fcntl (fd->fd, F_GETFL); + if (flags == -1) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl"); + return GNUNET_SYSERR; + } + if (doBlock) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + if (0 != fcntl (fd->fd, F_SETFL, flags)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +#endif +} + +int +GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Descriptor *desc) +{ + int ret; +#ifdef MINGW + ret = closesocket (desc->fd); + if (SOCKET_ERROR != ret) + GNUNET_free (desc); + else + SetErrnoFromWinsockError (WSAGetLastError ()); +#else + ret = close (desc->fd); + if (-1 == ret) + { + GNUNET_free (desc); + } +#endif + + return ret; +} + +int +GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Descriptor *desc, + const struct sockaddr *address, + socklen_t address_len) +{ + int ret; + + ret = connect (desc->fd, address, address_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + +int +GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Descriptor *desc, + int level, int optname, void *optval, + socklen_t * optlen) +{ + int ret; + + ret = getsockopt (desc->fd, level, optname, optval, optlen); +#ifdef MINGW + if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR) + *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval)); + else if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + return ret; +} + +int +GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Descriptor *desc, + int backlog) +{ + int ret; + + ret = listen (desc->fd, backlog); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + return ret; +} + +ssize_t +GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Descriptor * desc, + void *buffer, size_t length, int flags) +{ + int ret; + + ret = recv (desc->fd, buffer, length, flags); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + return ret; +} + +ssize_t +GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Descriptor * desc, + const void *buffer, size_t length, int flags) +{ + int ret; + + ret = send (desc->fd, buffer, length, flags); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + return ret; +} + +ssize_t +GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Descriptor * desc, + const void *message, size_t length, int flags, + const struct sockaddr * dest_addr, + socklen_t dest_len) +{ + int ret; + + ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + return ret; +} + +int +GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Descriptor *fd, + int level, int option_name, + const void *option_value, + socklen_t option_len) +{ + int ret; + + ret = setsockopt (fd->fd, level, option_name, option_value, option_len); +#ifdef MINGW + if (SOCKET_ERROR == ret) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + return ret; +} + +struct GNUNET_NETWORK_Descriptor * +GNUNET_NETWORK_socket_socket (int domain, int type, int protocol) +{ + struct GNUNET_NETWORK_Descriptor *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor)); + ret->fd = socket (domain, type, protocol); +#ifdef MINGW + if (INVALID_SOCKET == ret->fd) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + if (ret->fd < 0) + { + GNUNET_free (ret); + ret = NULL; + } + + return ret; +} + +int +GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Descriptor *desc, + int how) +{ + int ret; + + ret = shutdown (desc->fd, how); +#ifdef MINGW + if (ret != 0) + SetErrnoFromWinsockError (WSAGetLastError ()); +#endif + + return ret; +} + +int +GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Descriptor + *desc) +{ +#ifdef MINGW + errno = ENOSYS; + return GNUNET_SYSERR; +#else + return fcntl (desc->fd, F_SETFD, + fcntl (desc->fd, + F_GETFD) | FD_CLOEXEC) == + 0 ? GNUNET_OK : GNUNET_SYSERR; +#endif +} + +void +GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds) +{ + FD_ZERO (&fds->sds); + fds->nsds = 0; +#ifdef MINGW + if (fds->handles) + GNUNET_CONTAINER_vector_destroy (fds->handles); + fds->handles = GNUNET_CONTAINER_vector_create (2); +#endif +} + +void +GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Descriptor *desc) +{ + FD_SET (desc->fd, &fds->sds); + + if (desc->fd + 1 > fds->nsds) + fds->nsds = desc->fd + 1; +} + +int +GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_NETWORK_Descriptor *desc) +{ + return FD_ISSET (desc->fd, &fds->sds); +} + +void +GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, + const struct GNUNET_NETWORK_FDSet *src) +{ + int nfds; + + for (nfds = src->nsds; nfds > 0; nfds--) + if (FD_ISSET (nfds, &src->sds)) + { + FD_SET (nfds, &dst->sds); + if (nfds + 1 > dst->nsds) + dst->nsds = nfds + 1; + } +} + +void +GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, + const struct GNUNET_NETWORK_FDSet *from) +{ + FD_COPY (&from->sds, &to->sds); + to->nsds = from->nsds; +#ifdef MINGW + void *obj; + + if (to->handles) + GNUNET_CONTAINER_vector_destroy (to->handles); + to->handles = GNUNET_CONTAINER_vector_create (2); + for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL; + obj = GNUNET_CONTAINER_vector_get_next (from->handles)) + { + GNUNET_CONTAINER_vector_insert_last (to->handles, obj); + } +#endif +} + +void +GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, + const fd_set * from, int nfds) +{ + FD_COPY (from, &to->sds); + to->nsds = nfds; +} + +void +GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h) +{ +#ifdef MINGW + HANDLE hw; + + GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE)); + GNUNET_CONTAINER_vector_insert_last (fds->handles, h); +#else + int fd; + + GNUNET_internal_disk_file_handle (h, &fd, sizeof (int)); + FD_SET (fd, &fds->sds); + if (fd + 1 > fds->nsds) + fds->nsds = fd + 1; +#endif +} + +int +GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, + const struct GNUNET_DISK_FileHandle *h) +{ +#ifdef MINGW + return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) != + (unsigned int) -1; +#else + return FD_ISSET (h->fd, &fds->sds); +#endif +} + +int +GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, + const struct GNUNET_NETWORK_FDSet *fds2) +{ + int nfds; + + nfds = fds1->nsds; + if (nfds < fds2->nsds) + nfds = fds2->nsds; + + for (; nfds >= 0; nfds--) + if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds)) + return GNUNET_YES; + + return GNUNET_NO; +} + +struct GNUNET_NETWORK_FDSet * +GNUNET_NETWORK_fdset_create () +{ + struct GNUNET_NETWORK_FDSet *fds; + + fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet)); +#ifdef MINGW + fds->handles = NULL; +#endif + GNUNET_NETWORK_fdset_zero (fds); + + return fds; +} + +void +GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) +{ +#ifdef MINGW + GNUNET_CONTAINER_vector_destroy (fds->handles); +#endif + GNUNET_free (fds); +} + +int +GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, + struct GNUNET_NETWORK_FDSet *wfds, + struct GNUNET_NETWORK_FDSet *efds, + const struct GNUNET_TIME_Relative timeout) +{ + int nfds; + + nfds = 0; + + if (rfds) + nfds = rfds->nsds; + if (wfds && wfds->nsds > nfds) + nfds = wfds->nsds; + if (efds && efds->nsds > nfds) + nfds = efds->nsds; + +#ifndef MINGW + struct timeval tv; + + tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value; + tv.tv_usec = (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value)) + / GNUNET_TIME_UNIT_MILLISECONDS.value; + + return select (nfds + 1, rfds ? &rfds->sds : NULL, wfds ? &wfds->sds : NULL, + efds ? &efds->sds : NULL, timeout.value + == GNUNET_TIME_UNIT_FOREVER_REL.value ? NULL : &tv); +#else + DWORD limit; + fd_set sock_read, sock_write, sock_except; + fd_set aread, awrite, aexcept; + int i; + struct timeval tvslice; + int retcode; + DWORD ms_total; + +#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) + + /* calculate how long we need to wait in milliseconds */ + if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value) + ms_total = INFINITE; + else + ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value; + + /* select() may be used as a portable way to sleep */ + if (!(rfds || wfds || efds)) + { + Sleep (ms_total); + + return 0; + } + + if (rfds) + sock_read = rfds->sds; + else + FD_ZERO(&sock_read); + + if (wfds) + sock_write = wfds->sds; + else + FD_ZERO(&sock_write); + + if (efds) + sock_except = efds->sds; + else + FD_ZERO(&sock_except); + + /* + if (rfds) + FD_COPY (&rfds->sds, &sock_read); + else + FD_ZERO(&sock_read); + + if (wfds) + FD_COPY (&wfds->sds, &sock_write); + else + FD_ZERO(&sock_write); + + if (efds) + FD_COPY (&efds->sds, &sock_except); + else + FD_ZERO(&sock_except); +*/ + + /* multiplex between winsock select() and waiting on the handles */ + + FD_ZERO (&aread); + FD_ZERO (&awrite); + FD_ZERO (&aexcept); + + limit = GetTickCount () + ms_total; + do + { + retcode = 0; + + if (nfds > 0) + { + /* overwrite the zero'd sets here; the select call + * will clear those that are not active */ + + FD_COPY (&sock_read, &aread); + FD_COPY (&sock_write, &awrite); + FD_COPY (&sock_except, &aexcept); + + tvslice.tv_sec = 0; + tvslice.tv_usec = 100000; + + if ((retcode = + select (nfds + 1, &aread, &awrite, &aexcept, + &tvslice)) == SOCKET_ERROR) + { + SetErrnoFromWinsockError (WSAGetLastError ()); + if (errno == ENOTSOCK) + errno = EBADF; + +#if DEBUG_SOCK + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select"); +#endif + + goto select_loop_end; + } + } + + /* Poll read pipes */ + if (rfds) + for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--) + { + DWORD dwBytes; + + if (!PeekNamedPipe + (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0, + NULL, &dwBytes, NULL)) + { + GNUNET_CONTAINER_vector_remove_at (rfds->handles, i); + + retcode = -1; + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_SOCK + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe"); +#endif + goto select_loop_end; + } + else if (dwBytes) + { + retcode++; + } + else + GNUNET_CONTAINER_vector_remove_at (rfds->handles, i); + } + + /* Poll for faulty pipes */ + if (efds) + for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--) + { + DWORD dwBytes; + + if (PeekNamedPipe + (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0, + NULL, &dwBytes, NULL)) + { + GNUNET_CONTAINER_vector_remove_at (efds->handles, i); + + retcode++; + } + } + + /* FIXME */ + if (wfds) + GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0); + + /* Check for closed sockets */ + for (i = 0; i < nfds; i++) + { + if (SAFE_FD_ISSET (i, &sock_read)) + { + struct sockaddr addr; + int len; + + if (getpeername (i, &addr, &len) == SOCKET_ERROR) + { + int err, len; + + len = sizeof (err); + if (getsockopt + (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0 + && err == WSAENOTCONN) + { + if (!SAFE_FD_ISSET (i, &aread)) + { + FD_SET (i, &aread); + retcode++; + } + } + } + } + } + + select_loop_end:; + } + while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit)); + + if (retcode != -1) + { + if (rfds) + { + GNUNET_NETWORK_fdset_zero (rfds); + GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode); + } + + if (wfds) + { + GNUNET_NETWORK_fdset_zero (wfds); + GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode); + } + + if (efds) + { + GNUNET_NETWORK_fdset_zero (efds); + GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode); + } + } + + return retcode; +#endif +} + +/* end of io.c */ diff --git a/src/util/test_network.c b/src/util/test_network.c index cb0656921..6f09c4fce 100644 --- a/src/util/test_network.c +++ b/src/util/test_network.c @@ -23,7 +23,7 @@ */ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" @@ -49,24 +49,24 @@ static int ls; * * @return -1 on error, otherwise the listen socket */ -static int +static struct GNUNET_NETWORK_Descriptor * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; - int fd; + struct GNUNET_NETWORK_Descriptor *desc; memset (&sa, 0, sizeof (sa)); sa.sin_port = htons (PORT); sa.sin_family = AF_INET; - fd = SOCKET (AF_INET, SOCK_STREAM, 0); - GNUNET_assert (fd >= 0); - if (SETSOCKOPT (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + desc = GNUNET_NETWORK_socket_socket (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != NULL); + if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); - GNUNET_assert (BIND (fd, &sa, sizeof (sa)) >= 0); - LISTEN (fd, 5); - return fd; + GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, &sa, sizeof (sa)) >= 0); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; } static void @@ -166,7 +166,7 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n"); #endif - GNUNET_SCHEDULER_add_read (tc->sched, + GNUNET_SCHEDULER_add_read_net (tc->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_SCHEDULER_NO_TASK, diff --git a/src/util/test_network_addressing.c b/src/util/test_network_addressing.c index aeb187634..a2682a733 100644 --- a/src/util/test_network_addressing.c +++ b/src/util/test_network_addressing.c @@ -23,7 +23,7 @@ */ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" @@ -40,32 +40,32 @@ static struct GNUNET_NETWORK_ConnectionHandle *lsock; static size_t sofar; -static int ls; +static struct GNUNET_NETWORK_Descriptor *ls; /** * Create and initialize a listen socket for the server. * - * @return -1 on error, otherwise the listen socket + * @return NULL on error, otherwise the listen socket */ -static int +static struct GNUNET_NETWORK_Descriptor * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; - int fd; + struct GNUNET_NETWORK_Descriptor *desc; memset (&sa, 0, sizeof (sa)); sa.sin_port = htons (PORT); - fd = SOCKET (AF_INET, SOCK_STREAM, 0); - GNUNET_assert (fd >= 0); - if (SETSOCKOPT (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + desc = GNUNET_NETWORK_socket_socket (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != 0); + if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); - GNUNET_assert (BIND (fd, &sa, sizeof (sa)) >= 0); - LISTEN (fd, 5); - return fd; + GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, &sa, sizeof (sa)) >= 0); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; } @@ -156,7 +156,7 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_TIME_UNIT_SECONDS, &make_hello, NULL)); GNUNET_NETWORK_connection_destroy (csock); - GNUNET_SCHEDULER_add_read (tc->sched, + GNUNET_SCHEDULER_add_read_net (tc->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_SCHEDULER_NO_TASK, diff --git a/src/util/test_network_receive_cancel.c b/src/util/test_network_receive_cancel.c index 51d8350af..1a3cb4866 100644 --- a/src/util/test_network_receive_cancel.c +++ b/src/util/test_network_receive_cancel.c @@ -23,7 +23,7 @@ */ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" @@ -38,7 +38,7 @@ static struct GNUNET_NETWORK_ConnectionHandle *asock; static struct GNUNET_NETWORK_ConnectionHandle *lsock; -static int ls; +static struct GNUNET_NETWORK_Descriptor *ls; static GNUNET_SCHEDULER_TaskIdentifier receive_task; @@ -48,25 +48,25 @@ static GNUNET_SCHEDULER_TaskIdentifier receive_task; /** * Create and initialize a listen socket for the server. * - * @return -1 on error, otherwise the listen socket + * @return NULL on error, otherwise the listen socket */ -static int +static struct GNUNET_NETWORK_Descriptor * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; - int fd; + struct GNUNET_NETWORK_Descriptor *desc; memset (&sa, 0, sizeof (sa)); sa.sin_port = htons (PORT); - fd = SOCKET (AF_INET, SOCK_STREAM, 0); - GNUNET_assert (fd >= 0); - if (SETSOCKOPT (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + desc = GNUNET_NETWORK_socket_socket (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != NULL); + if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); - GNUNET_assert (BIND (fd, &sa, sizeof (sa)) >= 0); - LISTEN (fd, 5); - return fd; + GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, &sa, sizeof (sa)) >= 0); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; } @@ -120,7 +120,7 @@ task_receive_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) csock = GNUNET_NETWORK_connection_create_from_connect (tc->sched, "localhost", PORT, 1024); GNUNET_assert (csock != NULL); - GNUNET_SCHEDULER_add_read (tc->sched, + GNUNET_SCHEDULER_add_read_net (tc->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_SCHEDULER_NO_TASK, diff --git a/src/util/test_network_timeout.c b/src/util/test_network_timeout.c index 1d8910842..442775463 100644 --- a/src/util/test_network_timeout.c +++ b/src/util/test_network_timeout.c @@ -23,7 +23,7 @@ */ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" @@ -35,31 +35,31 @@ static struct GNUNET_NETWORK_ConnectionHandle *csock; static struct GNUNET_NETWORK_ConnectionHandle *lsock; -static int ls; +static struct GNUNET_NETWORK_Descriptor *ls; /** * Create and initialize a listen socket for the server. * - * @return -1 on error, otherwise the listen socket + * @return NULL on error, otherwise the listen socket */ -static int +static struct GNUNET_NETWORK_Descriptor * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; - int fd; + struct GNUNET_NETWORK_Descriptor *desc; memset (&sa, 0, sizeof (sa)); sa.sin_port = htons (PORT); - fd = SOCKET (AF_INET, SOCK_STREAM, 0); - GNUNET_assert (fd >= 0); - if (SETSOCKOPT (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + desc = GNUNET_NETWORK_socket_socket (AF_INET, SOCK_STREAM, 0); + GNUNET_assert (desc != NULL); + if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); - GNUNET_assert (BIND (fd, &sa, sizeof (sa)) >= 0); - LISTEN (fd, 5); - return fd; + GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, &sa, sizeof (sa)) >= 0); + GNUNET_NETWORK_socket_listen (desc, 5); + return desc; } diff --git a/src/util/test_network_timeout_no_connect.c b/src/util/test_network_timeout_no_connect.c index 172a6991d..902edd2fa 100644 --- a/src/util/test_network_timeout_no_connect.c +++ b/src/util/test_network_timeout_no_connect.c @@ -23,7 +23,7 @@ */ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" diff --git a/src/util/test_network_transmit_cancel.c b/src/util/test_network_transmit_cancel.c index 7a67000a8..c46fecd22 100644 --- a/src/util/test_network_transmit_cancel.c +++ b/src/util/test_network_transmit_cancel.c @@ -23,7 +23,7 @@ */ #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" diff --git a/src/util/test_scheduler.c b/src/util/test_scheduler.c index d5a93ed7d..34def7b1e 100644 --- a/src/util/test_scheduler.c +++ b/src/util/test_scheduler.c @@ -25,6 +25,7 @@ #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" +#include "gnunet_disk_lib.h" #define VERBOSE GNUNET_NO @@ -55,7 +56,8 @@ task4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) (*ok) = 5; } -static int fds[2]; +struct GNUNET_DISK_PipeHandle *p; +static struct GNUNET_DISK_FileHandle *fds[2]; static void @@ -64,10 +66,9 @@ taskWrt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static char c; int *ok = cls; GNUNET_assert (6 == *ok); - GNUNET_assert (FD_ISSET (fds[1], tc->write_ready)); + GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->write_ready, fds[1])); (*ok) = 7; - GNUNET_assert (1 == WRITE (fds[1], &c, 1)); - GNUNET_break (0 == CLOSE (fds[1])); + GNUNET_assert (1 == GNUNET_DISK_file_write (fds[1], &c, 1)); } @@ -92,9 +93,8 @@ taskRd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static char c; int *ok = cls; GNUNET_assert (7 == *ok); - GNUNET_assert (FD_ISSET (fds[0], tc->read_ready)); - GNUNET_assert (1 == READ (fds[0], &c, 1)); - GNUNET_break (0 == CLOSE (fds[0])); + GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, fds[0])); + GNUNET_assert (1 == GNUNET_DISK_file_read (fds[0], &c, 1)); (*ok) = 8; GNUNET_SCHEDULER_add_after (tc->sched, GNUNET_NO, @@ -114,14 +114,17 @@ task5 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) int *ok = cls; GNUNET_assert (5 == *ok); (*ok) = 6; - GNUNET_assert (0 == PIPE (fds)); - GNUNET_SCHEDULER_add_read (tc->sched, + p = GNUNET_DISK_pipe (GNUNET_NO); + GNUNET_assert (NULL != p); + fds[0] = GNUNET_DISK_pipe_handle (p, 0); + fds[1] = GNUNET_DISK_pipe_handle (p, 1); + GNUNET_SCHEDULER_add_read_file (tc->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, GNUNET_TIME_UNIT_FOREVER_REL, fds[0], &taskRd, cls); - GNUNET_SCHEDULER_add_write (tc->sched, + GNUNET_SCHEDULER_add_write_file (tc->sched, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK, @@ -256,6 +259,7 @@ main (int argc, char *argv[]) ret += check (); ret += checkSignal (); ret += checkCancel (); + GNUNET_DISK_pipe_close (p); return ret; } diff --git a/src/util/test_service.c b/src/util/test_service.c index e8e3f8741..8e351deb3 100644 --- a/src/util/test_service.c +++ b/src/util/test_service.c @@ -300,7 +300,7 @@ int main (int argc, char *argv[]) { int ret = 0; - int s; + struct GNUNET_NETWORK_Descriptor *s; GNUNET_log_setup ("test-service", #if VERBOSE @@ -311,8 +311,8 @@ main (int argc, char *argv[]) NULL); ret += check (); ret += check (); - s = SOCKET (PF_INET6, SOCK_STREAM, 0); - if (s == -1) + s = GNUNET_NETWORK_socket_socket (PF_INET6, SOCK_STREAM, 0); + if (NULL == s) { if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) @@ -326,7 +326,7 @@ main (int argc, char *argv[]) } else { - GNUNET_break (0 == CLOSE (s)); + GNUNET_break (0 == GNUNET_NETWORK_socket_close (s)); ret += check6 (); ret += check6d (); /* with daemonization */ } diff --git a/src/util/win.cc b/src/util/win.cc index f3e4bd98c..8e71744d0 100644 --- a/src/util/win.cc +++ b/src/util/win.cc @@ -30,7 +30,7 @@ #include "winproc.h" #include "platform.h" #include "gnunet_common.h" -#include "gnunet_network_lib.h" +#include "gnunet_connection_lib.h" #include using namespace std; -- 2.25.1