src/block/plugin_block_template.c
src/block/plugin_block_test.c
src/cadet/cadet_api.c
-src/cadet/cadet_api_new.c
-src/cadet/cadet_common.c
-src/cadet/cadet_path.c
src/cadet/cadet_test_lib.c
-src/cadet/cadet_test_lib_new.c
src/cadet/desirability_table.c
src/cadet/gnunet-cadet.c
src/cadet/gnunet-cadet-profiler.c
src/cadet/gnunet-service-cadet.c
src/cadet/gnunet-service-cadet_channel.c
src/cadet/gnunet-service-cadet_connection.c
+src/cadet/gnunet-service-cadet_core.c
src/cadet/gnunet-service-cadet_dht.c
src/cadet/gnunet-service-cadet_hello.c
-src/cadet/gnunet-service-cadet_local.c
-src/cadet/gnunet-service-cadet-new.c
-src/cadet/gnunet-service-cadet-new_channel.c
-src/cadet/gnunet-service-cadet-new_connection.c
-src/cadet/gnunet-service-cadet-new_core.c
-src/cadet/gnunet-service-cadet-new_dht.c
-src/cadet/gnunet-service-cadet-new_hello.c
-src/cadet/gnunet-service-cadet-new_paths.c
-src/cadet/gnunet-service-cadet-new_peer.c
-src/cadet/gnunet-service-cadet-new_tunnels.c
+src/cadet/gnunet-service-cadet_paths.c
src/cadet/gnunet-service-cadet_peer.c
-src/cadet/gnunet-service-cadet_tunnel.c
+src/cadet/gnunet-service-cadet_tunnels.c
src/consensus/consensus_api.c
src/consensus/gnunet-consensus-profiler.c
src/consensus/gnunet-service-consensus.c
src/fs/gnunet-service-fs_cadet_server.c
src/fs/gnunet-service-fs_cp.c
src/fs/gnunet-service-fs_indexing.c
-src/fs/gnunet-service-fs_lc.c
src/fs/gnunet-service-fs_pe.c
src/fs/gnunet-service-fs_pr.c
src/fs/gnunet-service-fs_push.c
src/transport/plugin_transport_udp.c
src/transport/plugin_transport_unix.c
src/transport/plugin_transport_wlan.c
+src/transport/tcp_connection_legacy.c
+src/transport/tcp_server_legacy.c
+src/transport/tcp_service_legacy.c
src/transport/transport_api_address_to_string.c
src/transport/transport_api_blacklist.c
src/transport/transport_api_core.c
src/util/common_logging.c
src/util/configuration.c
src/util/configuration_loader.c
-src/util/connection.c
src/util/container_bloomfilter.c
src/util/container_heap.c
src/util/container_meta_data.c
src/util/program.c
src/util/resolver_api.c
src/util/scheduler.c
-src/util/server.c
src/util/server_mst.c
src/util/server_nc.c
src/util/server_tc.c
-src/util/service.c
src/util/service_new.c
src/util/signal.c
src/util/socks.c
/**
* Is this a marker element?
*/
- uint8_t marker GNUNET_PACKED;
+ uint8_t marker;
/* rest: element data */
};
struct ConsensusSizeElement
{
- struct ConsensusElement ce GNUNET_PACKED;
+ struct ConsensusElement ce;
uint64_t size GNUNET_PACKED;
uint8_t sender_index;
struct ConsensusStuffedElement
{
- struct ConsensusElement ce GNUNET_PACKED;
+ struct ConsensusElement ce;
struct GNUNET_HashCode rand GNUNET_PACKED;
};
*/
static int
stdin_receiver (void *cls,
- void *client,
const struct GNUNET_MessageHeader *msg)
{
struct AudioMessage *audio;
ogg_sync_init (&oy);
}
+
static void
drain_callback (pa_stream*s, int success, void *userdata)
{
pa_threaded_mainloop_signal (m, 0);
}
+
/**
* The main function for the playback helper.
*
static unsigned long long toff;
char readbuf[MAXLINE];
- struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst;
+ struct GNUNET_MessageStreamTokenizer *stdin_mst;
char c;
ssize_t ret;
#ifdef DEBUG_READ_PURE_OGG
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
return 1;
}
- stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, NULL);
+ stdin_mst = GNUNET_MST_create (&stdin_receiver, NULL);
ogg_init ();
pa_init ();
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
}
else
#endif
- GNUNET_SERVER_mst_receive (stdin_mst, NULL,
- readbuf, ret,
- GNUNET_NO, GNUNET_NO);
+ GNUNET_MST_from_buffer (stdin_mst,
+ readbuf, ret,
+ GNUNET_NO, GNUNET_NO);
}
- GNUNET_SERVER_mst_destroy (stdin_mst);
+ GNUNET_MST_destroy (stdin_mst);
if (stream_out)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
* Function to process the audio from the record helper
*
* @param cls clsoure with our `struct Microphone`
- * @param client NULL
* @param msg the message from the helper
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
static int
process_record_messages (void *cls,
- void *client,
const struct GNUNET_MessageHeader *msg)
{
struct Microphone *mic = cls;
*/
struct GNUNET_MQ_Handle *mq;
+ /**
+ * Our message stream tokenizer (for encrypted payload).
+ */
+ struct GNUNET_MessageStreamTokenizer *mst;
+
/**
* PING message we transmit to the other peer.
*/
*/
static struct EphemeralKeyMessage current_ekm;
-/**
- * Our message stream tokenizer (for encrypted payload).
- */
-static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
-
/**
* DLL head.
*/
}
+/**
+ * Deliver P2P message to interested clients. Invokes send twice,
+ * once for clients that want the full message, and once for clients
+ * that only want the header
+ *
+ * @param cls the `struct GSC_KeyExchangeInfo`
+ * @param m the message
+ */
+static int
+deliver_message (void *cls,
+ const struct GNUNET_MessageHeader *m)
+{
+ struct GSC_KeyExchangeInfo *kx = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Decrypted message of type %d from %s\n",
+ ntohs (m->type),
+ GNUNET_i2s (kx->peer));
+ if (GNUNET_CORE_KX_STATE_UP != kx->status)
+ {
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop ("# PAYLOAD dropped (out of order)"),
+ 1,
+ GNUNET_NO);
+ return GNUNET_OK;
+ }
+ switch (ntohs (m->type))
+ {
+ case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
+ case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
+ GSC_SESSIONS_set_typemap (kx->peer, m);
+ return GNUNET_OK;
+ case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
+ GSC_SESSIONS_confirm_typemap (kx->peer, m);
+ return GNUNET_OK;
+ default:
+ GSC_CLIENTS_deliver_message (kx->peer,
+ m,
+ ntohs (m->size),
+ GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
+ GSC_CLIENTS_deliver_message (kx->peer,
+ m,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
+ }
+ return GNUNET_OK;
+}
+
+
/**
* Function called by transport to notify us that
* a peer connected to us (on the network level).
1,
GNUNET_NO);
kx = GNUNET_new (struct GSC_KeyExchangeInfo);
+ kx->mst = GNUNET_MST_create (&deliver_message,
+ kx);
kx->mq = mq;
kx->peer = pid;
kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
GNUNET_CONTAINER_DLL_remove (kx_head,
kx_tail,
kx);
+ GNUNET_MST_destroy (kx->mst);
GNUNET_free (kx);
}
}
-/**
- * Closure for #deliver_message()
- */
-struct DeliverMessageContext
-{
-
- /**
- * Key exchange context.
- */
- struct GSC_KeyExchangeInfo *kx;
-
- /**
- * Sender of the message.
- */
- const struct GNUNET_PeerIdentity *peer;
-};
-
-
/**
* We received an encrypted message. Check that it is
* well-formed (size-wise).
struct GNUNET_TIME_Absolute t;
struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
struct GNUNET_CRYPTO_AuthKey auth_key;
- struct DeliverMessageContext dmc;
uint16_t size = ntohs (m->header.size);
char buf[size] GNUNET_ALIGN;
gettext_noop ("# bytes of payload decrypted"),
size - sizeof (struct EncryptedMessage),
GNUNET_NO);
- dmc.kx = kx;
- dmc.peer = kx->peer;
if (GNUNET_OK !=
- GNUNET_SERVER_mst_receive (mst,
- &dmc,
- &buf[sizeof (struct EncryptedMessage)],
- size - sizeof (struct EncryptedMessage),
- GNUNET_YES,
- GNUNET_NO))
+ GNUNET_MST_from_buffer (kx->mst,
+ &buf[sizeof (struct EncryptedMessage)],
+ size - sizeof (struct EncryptedMessage),
+ GNUNET_YES,
+ GNUNET_NO))
GNUNET_break_op (0);
}
}
-/**
- * Deliver P2P message to interested clients. Invokes send twice,
- * once for clients that want the full message, and once for clients
- * that only want the header
- *
- * @param cls always NULL
- * @param client who sent us the message (struct GSC_KeyExchangeInfo)
- * @param m the message
- */
-static int
-deliver_message (void *cls,
- void *client,
- const struct GNUNET_MessageHeader *m)
-{
- struct DeliverMessageContext *dmc = client;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Decrypted message of type %d from %s\n",
- ntohs (m->type),
- GNUNET_i2s (dmc->peer));
- if (GNUNET_CORE_KX_STATE_UP != dmc->kx->status)
- {
- GNUNET_STATISTICS_update (GSC_stats,
- gettext_noop ("# PAYLOAD dropped (out of order)"),
- 1,
- GNUNET_NO);
- return GNUNET_OK;
- }
- switch (ntohs (m->type))
- {
- case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
- case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
- GSC_SESSIONS_set_typemap (dmc->peer, m);
- return GNUNET_OK;
- case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
- GSC_SESSIONS_confirm_typemap (dmc->peer, m);
- return GNUNET_OK;
- default:
- GSC_CLIENTS_deliver_message (dmc->peer,
- m,
- ntohs (m->size),
- GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
- GSC_CLIENTS_deliver_message (dmc->peer,
- m,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
- }
- return GNUNET_OK;
-}
-
-
/**
* Setup the message that links the ephemeral key to our persistent
* public key and generate the appropriate signature.
rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
&do_rekey,
NULL);
- mst = GNUNET_SERVER_mst_create (&deliver_message,
- NULL);
transport
= GNUNET_TRANSPORT_core_connect (GSC_cfg,
&GSC_my_identity,
GNUNET_free (my_private_key);
my_private_key = NULL;
}
- if (NULL != mst)
- {
- GNUNET_SERVER_mst_destroy (mst);
- mst = NULL;
- }
if (NULL != nc)
{
GNUNET_notification_context_destroy (nc);
* message is received by the tokenizer from the DNS hijack process.
*
* @param cls closure
- * @param client identification of the client
* @param message the actual message, a DNS request we should handle
*/
static int
-process_helper_messages (void *cls GNUNET_UNUSED, void *client,
+process_helper_messages (void *cls,
const struct GNUNET_MessageHeader *message)
{
uint16_t msize;
* Receive packets from the helper-process
*
* @param cls unused
- * @param client unsued
* @param message message received from helper
*/
static int
message_token (void *cls GNUNET_UNUSED,
- void *client GNUNET_UNUSED,
const struct GNUNET_MessageHeader *message)
{
const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun;
* Calls the scanner progress handler.
*
* @param cls the closure (directory scanner object)
- * @param client always NULL
* @param msg message from the helper process
*/
static int
process_helper_msgs (void *cls,
- void *client,
const struct GNUNET_MessageHeader *msg)
{
struct GNUNET_FS_DirScanner *ds = cls;
gnunet_common.h \
gnunet_constants.h \
gnunet_configuration_lib.h \
- gnunet_connection_lib.h \
gnunet_consensus_service.h \
gnunet_container_lib.h \
gnunet_conversation_service.h \
gnunet_scalarproduct_service.h \
gnunet_scheduler_lib.h \
gnunet_secretsharing_service.h \
- gnunet_server_lib.h \
gnunet_service_lib.h \
gnunet_set_service.h \
gnunet_signal_lib.h \
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @author Christian Grothoff
- *
- * @file include/gnunet_connection_lib.h
- * Basic, low-level TCP networking interface
- *
- * @defgroup connection Connection library
- * Basic, low-level TCP networking interface
- * @{
- */
-#ifndef GNUNET_CONNECTION_LIB_H
-#define GNUNET_CONNECTION_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. Actual value used
- * is this value divided by the number of address families.
- * Default is 5s.
- */
-#define GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
-
-/**
- * @brief handle for a network connection
- */
-struct GNUNET_CONNECTION_Handle;
-
-
-/**
- * Credentials for UNIX domain sockets.
- */
-struct GNUNET_CONNECTION_Credentials
-{
- /**
- * UID of the other end of the connection.
- */
- uid_t uid;
-
- /**
- * GID of the other end of the connection.
- */
- gid_t gid;
-};
-
-
-/**
- * Function to call for access control checks.
- *
- * @param cls closure
- * @param ucred credentials, if available, otherwise NULL
- * @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_CONNECTION_AccessCheck) (void *cls,
- const struct
- GNUNET_CONNECTION_Credentials *
- ucred,
- 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_CONNECTION_Receiver) (void *cls, const void *buf,
- size_t available,
- const struct sockaddr * addr,
- socklen_t addrlen, int errCode);
-
-/**
- * Set the persist option on this connection handle. Indicates
- * that the underlying socket or fd should never really be closed.
- * Used for indicating process death.
- *
- * @param connection the connection to set persistent
- */
-void
-GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection);
-
-/**
- * Disable the "CORK" feature for communication with the given socket,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages. Essentially
- * reduces the OS send buffers to zero.
- * Used to make sure that the last messages sent through the connection
- * reach the other side before the process is terminated.
- *
- * @param connection the connection to make flushing and blocking
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Create a connection 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 s socket to connect
- * @param serv_addr server address
- * @param addrlen length of server address
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
- const struct sockaddr *serv_addr,
- socklen_t addrlen);
-
-
-/**
- * Create a connection handle by boxing an existing OS socket. The OS
- * socket should henceforth be no longer used directly.
- * #GNUNET_CONNECTION_destroy() will close it.
- *
- * @param osSocket existing socket to box
- * @return the boxed socket handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket);
-
-
-/**
- * Create a connection handle by accepting on a listen socket. This
- * function may block if the listen socket has no connection ready.
- *
- * @param access_cb function to use to check if access is allowed
- * @param access_cb_cls closure for @a access_cb
- * @param lsock listen socket
- * @return the connection handle, NULL on error (for example, access refused)
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
- void *access_cb_cls,
- struct GNUNET_NETWORK_Handle *lsock);
-
-
-/**
- * Create a connection 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 cfg configuration to use
- * @param hostname name of the host to connect to
- * @param port port to connect to
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
- *cfg, const char *hostname,
- uint16_t port);
-
-
-/**
- * Create a connection handle by connecting to a UNIX domain service.
- * This function returns immediately, even if the connection has not
- * yet been established. This function only creates UNIX connections.
- *
- * @param cfg configuration to use
- * @param unixpath path to connect to)
- * @return the connection handle, NULL on systems without UNIX support
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
- GNUNET_CONFIGURATION_Handle
- *cfg, const char *unixpath);
-
-
-
-
-/**
- * Create a connection 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 af_family address family to use
- * @param serv_addr server address
- * @param addrlen length of server address
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_sockaddr (int af_family,
- const struct sockaddr *serv_addr,
- socklen_t addrlen);
-
-/**
- * Check if connection is valid (no fatal errors have happened so far).
- * Note that a connection that is still trying to connect is considered
- * valid.
- *
- * @param connection handle to check
- * @return GNUNET_YES if valid, GNUNET_NO otherwise
- */
-int
-GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param connection 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_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
- void **addr, size_t * addrlen);
-
-
-/**
- * Close the connection and free associated resources. There must
- * not be any pending requests for reading or writing to the
- * connection at this time.
- *
- * @param connection connection to destroy
- */
-void
-GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Receive data from the given connection. 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 connection at any given point in time (so do not
- * call receive again until the receiver callback has been invoked).
- *
- * @param connection connection 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
- */
-void
-GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CONNECTION_Receiver receiver,
- void *receiver_cls);
-
-
-/**
- * Cancel receive job on the given connection. Note that the
- * receiver callback must not have been called yet in order
- * for the cancellation to be valid.
- *
- * @param connection connection handle
- * @return closure of the original receiver callback closure
- */
-void *
-GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Function called to notify a client about the connection begin ready
- * to queue more data. @a buf will be NULL and @a size zero if the
- * connection was closed for writing in the meantime.
- *
- * @param cls closure
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to @a buf
- */
-typedef size_t
-(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
- size_t size,
- void *buf);
-
-
-/**
- * Opaque handle that can be used to cancel
- * a transmit-ready notification.
- */
-struct GNUNET_CONNECTION_TransmitHandle;
-
-/**
- * Ask the connection to call us once the specified number of bytes
- * are free in the transmission buffer. Will never call the @a notify
- * callback in this task, but always first go into the scheduler. Note that
- * this function will abort if "size" is greater than
- * #GNUNET_SERVER_MAX_MESSAGE_SIZE.
- *
- * Note that "notify" will be called either when enough
- * buffer space is available OR when the connection 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 connection 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 connection connection
- * @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_CONNECTION_TransmitHandle *
-GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
- size_t size,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CONNECTION_TransmitReadyNotify
- notify, void *notify_cls);
-
-
-/**
- * Cancel the specified transmission-ready
- * notification.
- *
- * @param th handle for notification to cancel
- */
-void
-GNUNET_CONNECTION_notify_transmit_ready_cancel (struct
- GNUNET_CONNECTION_TransmitHandle
- *th);
-
-
-/**
- * Create a connection to be proxied using a given connection.
- *
- * @param cph connection to proxy server
- * @return connection to be proxied
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph);
-
-
-/**
- * Activate proxied connection and destroy initial proxy handshake connection.
- * There must not be any pending requests for reading or writing to the
- * proxy hadshake connection at this time.
- *
- * @param proxied connection connection to proxy server
- */
-void
-GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CONNECTION_LIB_H */
-#endif
-
-/** @} */ /* end of group */
-
-/* end of gnunet_connection_lib.h */
#define GNUNET_HELPER_LIB_H
#include "gnunet_scheduler_lib.h"
-#include "gnunet_server_lib.h"
+#include "gnunet_mst_lib.h"
+
/**
* The handle to a helper process.
*
* @param cls the closure from GNUNET_HELPER_start()
*/
-typedef void (*GNUNET_HELPER_ExceptionCallback) (void *cls);
+typedef void
+(*GNUNET_HELPER_ExceptionCallback) (void *cls);
/**
GNUNET_HELPER_start (int with_control_pipe,
const char *binary_name,
char *const binary_argv[],
- GNUNET_SERVER_MessageTokenizerCallback cb,
+ GNUNET_MessageTokenizerCallback cb,
GNUNET_HELPER_ExceptionCallback exp_cb,
void *cb_cls);
#ifndef GNUNET_MQ_LIB_H
#define GNUNET_MQ_LIB_H
+#include "gnunet_scheduler_lib.h"
/**
* Allocate an envelope, with extra space allocated after the space needed
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009-2013 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @author Christian Grothoff
- *
- * @file
- * Library for building GNUnet network servers
-
- * @defgroup server Server library
- * Library for building GNUnet network servers
- *
- * Provides functions for a server that communicates with clients.
- *
- * @see [Documentation](https://gnunet.org/ipc)
- *
- * @{
- */
-
-#ifndef GNUNET_SERVER_LIB_H
-#define GNUNET_SERVER_LIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_common.h"
-#include "gnunet_connection_lib.h"
-
-
-/**
- * Largest supported message (to be precise, one byte more
- * than the largest possible message, so tests involving
- * this value should check for messages being smaller than
- * this value).
- */
-#define GNUNET_SERVER_MAX_MESSAGE_SIZE 65536
-
-/**
- * Smallest supported message.
- */
-#define GNUNET_SERVER_MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader)
-
-/**
- * @brief handle for a server
- */
-struct GNUNET_SERVER_Handle;
-
-/**
- * @brief opaque handle for a client of the server
- */
-struct GNUNET_SERVER_Client;
-
-/**
- * @brief opaque handle server returns for aborting transmission to a client.
- */
-struct GNUNET_SERVER_TransmitHandle;
-
-
-/**
- * Functions with this signature are called whenever a message is
- * received.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-typedef void
-(*GNUNET_SERVER_MessageCallback) (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Message handler. Each struct specifies how to handle on particular
- * type of message received.
- */
-struct GNUNET_SERVER_MessageHandler
-{
- /**
- * Function to call for messages of "type".
- */
- GNUNET_SERVER_MessageCallback callback;
-
- /**
- * Closure argument for @e callback.
- */
- void *callback_cls;
-
- /**
- * Type of the message this handler covers.
- */
- uint16_t type;
-
- /**
- * Expected size of messages of this type. Use 0 for
- * variable-size. If non-zero, messages of the given
- * type will be discarded (and the connection closed)
- * if they do not have the right size.
- */
- uint16_t expected_size;
-
-};
-
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param lsocks NULL-terminated array of listen sockets
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if #GNUNET_YES, connections sending messages of unknown type
- * will be closed
- * @return handle for the new server, NULL on error
- * (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
- void *access_cb_cls,
- struct GNUNET_NETWORK_Handle **lsocks,
- struct GNUNET_TIME_Relative idle_timeout,
- int require_found);
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param server_addr address toes listen on (including port), NULL terminated array
- * @param socklen lengths of respective @a server_addr
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if #GNUNET_YES, connections sending messages of unknown type
- * will be closed
- * @return handle for the new server, NULL on error
- * (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
- void *access_cb_cls,
- struct sockaddr *const *server_addr,
- const socklen_t *socklen,
- struct GNUNET_TIME_Relative idle_timeout,
- int require_found);
-
-
-/**
- * Suspend accepting connections from the listen socket temporarily.
- * Resume activity using #GNUNET_SERVER_resume.
- *
- * @param server server to stop accepting connections.
- */
-void
-GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Resume accepting connections from the listen socket.
- *
- * @param server server to resume accepting connections.
- */
-void
-GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Stop the listen socket and get ready to shutdown the server once
- * only clients marked using #GNUNET_SERVER_client_mark_monitor are
- * left.
- *
- * @param server server to stop listening on
- */
-void
-GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Free resources held by this server.
- *
- * @param server server to destroy
- */
-void
-GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Add additional handlers to an existing server.
- *
- * @param server the server to add handlers to
- * @param handlers array of message handlers for
- * incoming messages; the last entry must
- * have "NULL" for the "callback"; multiple
- * entries for the same type are allowed,
- * they will be called in order of occurence.
- * These handlers can be removed later;
- * the handlers array must exist until removed
- * (or server is destroyed).
- */
-void
-GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_SERVER_MessageHandler *handlers);
-
-
-/**
- * Notify us when the server has enough space to transmit
- * a message of the given size to the given client.
- *
- * @param client client to transmit message to
- * @param size requested amount of buffer space
- * @param timeout after how long should we give up (and call
- * notify with buf NULL and size 0)?
- * @param callback function to call when space is available
- * @param callback_cls closure for @a callback
- * @return non-NULL if the notify callback was queued; can be used
- * to cancel the request using
- * #GNUNET_SERVER_notify_transmit_ready_cancel.
- * NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_SERVER_TransmitHandle *
-GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
- size_t size,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CONNECTION_TransmitReadyNotify callback,
- void *callback_cls);
-
-
-/**
- * Abort transmission request.
- *
- * @param th request to abort
- */
-void
-GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
-
-
-/**
- * Set the 'monitor' flag on this client. Clients which have been
- * marked as 'monitors' won't prevent the server from shutting down
- * once #GNUNET_SERVER_stop_listening has been invoked. The idea is
- * that for "normal" clients we likely want to allow them to process
- * their requests; however, monitor-clients are likely to 'never'
- * disconnect during shutdown and thus will not be considered when
- * determining if the server should continue to exist after
- * #GNUNET_SERVER_destroy has been called.
- *
- * @param client the client to set the 'monitor' flag on
- */
-void
-GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Set the persistent flag on this client, used to setup client
- * connection to only be killed when the process of the service it's
- * connected to is actually dead. This API is used during shutdown
- * signalling within ARM, and it is not expected that typical users
- * of the API would need this function.
- *
- * @param client the client to set the persistent flag on
- */
-void
-GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Resume receiving from this client, we are done processing the
- * current request. This function must be called from within each
- * #GNUNET_SERVER_MessageCallback (or its respective continuations).
- *
- * @param client client we were processing a message of
- * @param success #GNUNET_OK to keep the connection open and
- * continue to receive
- * #GNUNET_NO to close the connection (normal behavior)
- * #GNUNET_SYSERR to close the connection (signal
- * serious error)
- */
-void
-GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
- int success);
-
-
-/**
- * Change the timeout for a particular client. Decreasing the timeout
- * may not go into effect immediately (only after the previous timeout
- * times out or activity happens on the socket).
- *
- * @param client the client to update
- * @param timeout new timeout for activities on the socket
- */
-void
-GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
- struct GNUNET_TIME_Relative timeout);
-
-
-/**
- * Return user context associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param size number of bytes in user context struct (for verification only)
- * @return pointer to user context
- */
-void *
-GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
- size_t size);
-
-
-/**
- * Set user context to be associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param ptr pointer to user context
- * @param size number of bytes in user context struct (for verification only)
- */
-void
-GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
- void *ptr,
- size_t size);
-
-
-/**
- * Return user context associated with the given client.
- *
- * @param client client to query
- * @param type expected return type (i.e. 'struct Foo')
- * @return pointer to user context of type 'type *'.
- */
-#define GNUNET_SERVER_client_get_user_context(client,type) \
- (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
-
-/**
- * Set user context to be associated with the given client.
- *
- * @param client client to query
- * @param value pointer to user context
- */
-#define GNUNET_SERVER_client_set_user_context(client,value) \
- GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
-
-
-/**
- * Disable the warning the server issues if a message is not acknowledged
- * in a timely fashion. Use this call if a client is intentionally delayed
- * for a while. Only applies to the current message.
- *
- * @param client client for which to disable the warning
- */
-void
-GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client
- *client);
-
-
-/**
- * Inject a message into the server, pretend it came
- * from the specified client. Delivery of the message
- * will happen instantly (if a handler is installed;
- * otherwise the call does nothing).
- *
- * @param server the server receiving the message
- * @param sender the "pretended" sender of the message
- * can be NULL!
- * @param message message to transmit
- * @return #GNUNET_OK if the message was OK and the
- * connection can stay open
- * #GNUNET_SYSERR if the connection to the
- * client should be shut down
- */
-int
-GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
- struct GNUNET_SERVER_Client *sender,
- const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Add a TCP socket-based connection to the set of handles managed by
- * this server. Use this function for outgoing (P2P) connections that
- * we initiated (and where this server should process incoming
- * messages).
- *
- * @param server the server to use
- * @param connection the connection to manage (client must
- * stop using this connection from now on)
- * @return the client handle
- */
-struct GNUNET_SERVER_Client *
-GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
- struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Notify the server that the given client handle should
- * be kept (keeps the connection up if possible, increments
- * the internal reference counter).
- *
- * @param client the client to keep
- */
-void
-GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Notify the server that the given client handle is no
- * longer required. Decrements the reference counter. If
- * that counter reaches zero an inactive connection maybe
- * closed.
- *
- * @param client the client to drop
- */
-void
-GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param client the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of @a addr
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
- void **addr, size_t *addrlen);
-
-
-/**
- * Functions with this signature are called whenever a client
- * is disconnected on the network level.
- *
- * @param cls closure
- * @param client identification of the client; NULL
- * for the last call when the server is destroyed
- */
-typedef void
-(*GNUNET_SERVER_DisconnectCallback) (void *cls,
- struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Functions with this signature are called whenever a client
- * is connected on the network level.
- *
- * @param cls closure
- * @param client identification of the client
- */
-typedef void
-(*GNUNET_SERVER_ConnectCallback) (void *cls,
- struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Ask the server to notify us whenever a client disconnects.
- * This function is called whenever the actual network connection
- * is closed; the reference count may be zero or larger than zero
- * at this point. If the server is destroyed before this
- * notification is explicitly cancelled, the 'callback' will
- * once be called with a 'client' argument of NULL to indicate
- * that the server itself is now gone (and that the callback
- * won't be called anymore and also can no longer be cancelled).
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_DisconnectCallback callback,
- void *callback_cls);
-
-
-/**
- * Ask the server to notify us whenever a client connects.
- * This function is called whenever the actual network connection
- * is opened. If the server is destroyed before this
- * notification is explicitly cancelled, the @a callback will
- * once be called with a 'client' argument of NULL to indicate
- * that the server itself is now gone (and that the callback
- * won't be called anymore and also can no longer be cancelled).
- *
- * @param server the server manageing the clients
- * @param callback function to call on sconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_ConnectCallback callback,
- void *callback_cls);
-
-
-/**
- * Ask the server to stop notifying us whenever a client disconnects.
- * Arguments must match exactly those given to
- * #GNUNET_SERVER_disconnect_notify. It is not necessary to call this
- * function during shutdown of the server; in fact, most applications
- * will never use this function.
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_DisconnectCallback callback,
- void *callback_cls);
-
-
-/**
- * Ask the server to stop notifying us whenever a client connects.
- * Arguments must match exactly those given to
- * #GNUNET_SERVER_connect_notify. It is not necessary to call this
- * function during shutdown of the server; in fact, most applications
- * will never use this function.
- *
- * @param server the server manageing the clients
- * @param callback function to call on connect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_ConnectCallback callback,
- void *callback_cls);
-
-
-/**
- * Ask the server to disconnect from the given client. This is the
- * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
- * except that it allows dropping of a client even when not handling a
- * message from that client.
- *
- * @param client the client to disconnect from
- */
-void
-GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Disable the "CORK" feature for communication with the given client,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages.
- *
- * @param client handle to the client
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * The tansmit context is the key datastructure for a conveniance API
- * used for transmission of complex results to the client followed
- * ONLY by signaling receive_done with success or error
- */
-struct GNUNET_SERVER_TransmitContext;
-
-
-/**
- * Create a new transmission context for the given client.
- *
- * @param client client to create the context for.
- * @return NULL on error
- */
-struct GNUNET_SERVER_TransmitContext *
-GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Append a message to the transmission context.
- * All messages in the context will be sent by
- * the #GNUNET_SERVER_transmit_context_run method.
- *
- * @param tc context to use
- * @param data what to append to the result message
- * @param length length of @a data
- * @param type type of the message
- */
-void
-GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext *tc,
- const void *data,
- size_t length, uint16_t type);
-
-
-/**
- * Append a message to the transmission context.
- * All messages in the context will be sent by
- * the transmit_context_run method.
- *
- * @param tc context to use
- * @param msg message to append
- */
-void
-GNUNET_SERVER_transmit_context_append_message (struct GNUNET_SERVER_TransmitContext *tc,
- const struct GNUNET_MessageHeader *msg);
-
-
-/**
- * Execute a transmission context. If there is an error in the
- * transmission, the receive_done method will be called with an error
- * code (#GNUNET_SYSERR), otherwise with #GNUNET_OK.
- *
- * @param tc transmission context to use
- * @param timeout when to time out and abort the transmission
- */
-void
-GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc,
- struct GNUNET_TIME_Relative timeout);
-
-
-/**
- * Destroy a transmission context. This function must not be called
- * after #GNUNET_SERVER_transmit_context_run.
- *
- * @param tc transmission context to destroy
- * @param success code to give to #GNUNET_SERVER_receive_done for
- * the client: #GNUNET_OK to keep the connection open and
- * continue to receive
- * #GNUNET_NO to close the connection (normal behavior)
- * #GNUNET_SYSERR to close the connection (signal
- * serious error)
- */
-void
-GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext *tc,
- int success);
-
-
-/**
- * The notification context is the key datastructure for a conveniance
- * API used for transmission of notifications to the client until the
- * client disconnects or is disconnected (or the notification context
- * is destroyed, in which case we disconnect these clients).
- * Essentially, all (notification) messages are queued up until the
- * client is able to read them.
- */
-struct GNUNET_SERVER_NotificationContext;
-
-
-/**
- * Create a new notification context.
- *
- * @param server server for which this function creates the context
- * @param queue_length maximum number of messages to keep in
- * the notification queue; optional messages are dropped
- * if the queue gets longer than this number of messages
- * @return handle to the notification context
- */
-struct GNUNET_SERVER_NotificationContext *
-GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
- unsigned int queue_length);
-
-
-/**
- * Destroy the context, force disconnect for all clients.
- *
- * @param nc context to destroy.
- */
-void
-GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc);
-
-
-/**
- * Add a client to the notification context.
- *
- * @param nc context to modify
- * @param client client to add
- */
-void
-GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
- struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Send a message to a particular client; must have
- * already been added to the notification context.
- *
- * @param nc context to modify
- * @param client client to transmit to
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-void
-GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *msg,
- int can_drop);
-
-
-/**
- * Send a message to all clients of this context.
- *
- * @param nc context to modify
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-void
-GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc,
- const struct GNUNET_MessageHeader *msg,
- int can_drop);
-
-
-/**
- * Return active number of subscribers in this context.
- *
- * @param nc context to query
- * @return number of current subscribers
- */
-unsigned int
-GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc);
-
-
-/**
- * Create a message queue for a server's client.
- *
- * @param client the client
- * @return the message queue
- */
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Handle to a message stream tokenizer.
- */
-struct GNUNET_SERVER_MessageStreamTokenizer;
-
-
-/**
- * Functions with this signature are called whenever a
- * complete message is received by the tokenizer.
- *
- * Do not call #GNUNET_SERVER_mst_destroy from within
- * the scope of this callback.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
- */
-typedef int
-(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
- void *client,
- const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Create a message stream tokenizer.
- *
- * @param cb function to call on completed messages
- * @param cb_cls closure for @a cb
- * @return handle to tokenizer
- */
-struct GNUNET_SERVER_MessageStreamTokenizer *
-GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
- void *cb_cls);
-
-
-/**
- * Add incoming data to the receive buffer and call the
- * callback for all complete messages.
- *
- * @param mst tokenizer to use
- * @param client_identity ID of client for which this is a buffer,
- * can be NULL (will be passed back to 'cb')
- * @param buf input data to add
- * @param size number of bytes in @a buf
- * @param purge should any excess bytes in the buffer be discarded
- * (i.e. for packet-based services like UDP)
- * @param one_shot only call callback once, keep rest of message in buffer
- * @return #GNUNET_OK if we are done processing (need more data)
- * #GNUNET_NO if one_shot was set and we have another message ready
- * #GNUNET_SYSERR if the data stream is corrupt
- */
-int
-GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
- void *client_identity,
- const char *buf, size_t size,
- int purge, int one_shot);
-
-
-/**
- * Destroys a tokenizer.
- *
- * @param mst tokenizer to destroy
- */
-void
-GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
-
-
-/**
- * Signature of a function to create a custom tokenizer.
- *
- * @param cls closure from #GNUNET_SERVER_set_callbacks
- * @param client handle to client the tokenzier will be used for
- * @return handle to custom tokenizer ('mst')
- */
-typedef void*
-(*GNUNET_SERVER_MstCreateCallback) (void *cls,
- struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Signature of a function to destroy a custom tokenizer.
- *
- * @param cls closure from #GNUNET_SERVER_set_callbacks
- * @param mst custom tokenizer handle
- */
-typedef void
-(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
- void *mst);
-
-
-/**
- * Signature of a function to receive data for a custom tokenizer.
- *
- * @param cls closure from #GNUNET_SERVER_set_callbacks
- * @param mst custom tokenizer handle
- * @param client_identity ID of client for which this is a buffer,
- * can be NULL (will be passed back to 'cb')
- * @param buf input data to add
- * @param size number of bytes in @a buf
- * @param purge should any excess bytes in the buffer be discarded
- * (i.e. for packet-based services like UDP)
- * @param one_shot only call callback once, keep rest of message in buffer
- * @return #GNUNET_OK if we are done processing (need more data)
- * #GNUNET_NO if one_shot was set and we have another message ready
- * #GNUNET_SYSERR if the data stream is corrupt
- */
-typedef int
-(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
- struct GNUNET_SERVER_Client *client,
- const char *buf,
- size_t size,
- int purge,
- int one_shot);
-
-
-/**
- * Change functions used by the server to tokenize the message stream.
- * (very rarely used).
- *
- * @param server server to modify
- * @param create new tokenizer initialization function
- * @param destroy new tokenizer destruction function
- * @param receive new tokenizer receive function
- * @param cls closure for @a create, @a receive and @a destroy
- */
-void
-GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_MstCreateCallback create,
- GNUNET_SERVER_MstDestroyCallback destroy,
- GNUNET_SERVER_MstReceiveCallback receive,
- void *cls);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_SERVER_LIB_H */
-#endif
-
-/** @} */ /* end of group server */
-
-/* end of gnunet_server_lib.h */
#endif
#include "gnunet_configuration_lib.h"
-#include "gnunet_server_lib.h"
#include "gnunet_mq_lib.h"
+/**
+ * Largest supported message (to be precise, one byte more
+ * than the largest possible message, so tests involving
+ * this value should check for messages being smaller than
+ * this value). NOTE: legacy name.
+ */
+#define GNUNET_SERVER_MAX_MESSAGE_SIZE 65536
/**
- * Function called by the service's run
- * method to run service-specific setup code.
- *
- * @param cls closure
- * @param server the initialized server
- * @param cfg configuration to use
+ * Smallest supported message. NOTE: legacy name.
*/
-typedef void
-(*GNUNET_SERVICE_Main) (void *cls,
- struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_CONFIGURATION_Handle *cfg);
+#define GNUNET_SERVER_MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader)
+
+/**
+ * Timeout we use on TCP connect before trying another
+ * result from the DNS resolver. Actual value used
+ * is this value divided by the number of address families.
+ * Default is 5s. NOTE: legacy name.
+ */
+#define GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
/**
};
-/**
- * Run a standard GNUnet service startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @param argc number of command line arguments in @a argv
- * @param argv command line arguments
- * @param service_name our service name
- * @param options service options
- * @param task main task of the service
- * @param task_cls closure for @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK
- * if we shutdown nicely
- * @deprecated
- */
-int
-GNUNET_SERVICE_run (int argc,
- char *const *argv,
- const char *service_name,
- enum GNUNET_SERVICE_Options options,
- GNUNET_SERVICE_Main task,
- void *task_cls);
/**
enum GNUNET_SERVICE_Options options);
-/**
- * Obtain the server used by a service. Note that the server must NOT
- * be destroyed by the caller.
- *
- * @param ctx the service context returned from the start function
- * @return handle to the server for this service, NULL if there is none
- * @deprecated
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx);
-
-
/**
* Get the NULL-terminated array of listen sockets for this service.
*
#include "gnunet_crypto_lib.h"
#include "gnunet_bandwidth_lib.h"
#include "gnunet_bio_lib.h"
-#include "gnunet_connection_lib.h"
#include "gnunet_client_lib.h"
#include "gnunet_container_lib.h"
#include "gnunet_getopt_lib.h"
#include "gnunet_plugin_lib.h"
#include "gnunet_program_lib.h"
#include "gnunet_protocols.h"
-#include "gnunet_server_lib.h"
#include "gnunet_service_lib.h"
#include "gnunet_signal_lib.h"
#include "gnunet_strings_lib.h"
libgnunetnatauto_la_SOURCES = \
nat_auto_api.c \
- nat_auto_api_test.c
+ nat_auto_api_test.c
libgnunetnatauto_la_LIBADD = \
$(top_builddir)/src/nat/libgnunetnatnew.la \
$(top_builddir)/src/util/libgnunetutil.la \
- $(GN_LIBINTL) @EXT_LIBS@
+ $(GN_LIBINTL) @EXT_LIBS@
libgnunetnatauto_la_LDFLAGS = \
$(GN_LIB_LDFLAGS) $(WINFLAGS) \
-version-info 0:0:0
$(LIBGCRYPT_LIBS) \
-lgcrypt \
$(GN_LIBINTL)
-
/*
This file is part of GNUnet.
- Copyright (C) 2011 GNUnet e.V.
+ Copyright (C) 2011, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
/**
- * Our server.
+ * Information we track per client.
*/
-static struct GNUNET_SERVER_Handle *server;
+struct ClientData
+{
+ /**
+ * Timeout task.
+ */
+ struct GNUNET_SCHEDULER_Task *tt;
+
+ /**
+ * Client handle.
+ */
+ struct GNUNET_SERVICE_Client *client;
+};
+
/**
* Our configuration.
* We've received a request to probe a NAT
* traversal. Do it.
*
- * @param cls unused
- * @param client handle to client (we always close)
+ * @param cls handle to client (we always close)
* @param msg message with details about what to test
*/
static void
-test (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *msg)
+handle_test (void *cls,
+ const struct GNUNET_NAT_AUTO_TestMessage *tm)
{
- const struct GNUNET_NAT_AUTO_TestMessage *tm;
+ struct ClientData *cd = cls;
uint16_t dport;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received test request\n");
- tm = (const struct GNUNET_NAT_AUTO_TestMessage *) msg;
dport = ntohs (tm->dport);
if (0 == dport)
try_anat (tm->dst_ipv4,
try_send_udp (tm->dst_ipv4,
dport,
tm->data);
- GNUNET_SERVER_receive_done (client,
- GNUNET_NO);
+ GNUNET_SERVICE_client_drop (cd->client);
}
/**
- * Task run during shutdown.
+ * Main function that will be run.
*
- * @param cls unused
+ * @param cls closure
+ * @param c configuration
+ * @param srv service handle
*/
static void
-shutdown_task (void *cls)
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_SERVICE_Handle *srv)
{
- GNUNET_SERVER_destroy (server);
- server = NULL;
+ cfg = c;
}
/**
- * Main function that will be run.
+ * Forcefully drops client after 1s.
*
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
+ * @param cls our `struct ClientData` of a client to drop
*/
static void
-run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
+force_timeout (void *cls)
{
- static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
- sizeof (struct GNUNET_NAT_AUTO_TestMessage)},
- {NULL, NULL, 0, 0}
- };
- unsigned int port;
- struct sockaddr_in in4;
- struct sockaddr_in6 in6;
-
- socklen_t slen[] = {
- sizeof (in4),
- sizeof (in6),
- 0
- };
- struct sockaddr *sa[] = {
- (struct sockaddr *) &in4,
- (struct sockaddr *) &in6,
- NULL
- };
+ struct ClientData *cd = cls;
- cfg = c;
- if ( (NULL == args[0]) ||
- (1 != SSCANF (args[0], "%u", &port)) ||
- (0 == port) ||
- (65536 <= port) )
- {
- FPRINTF (stderr,
- _("Please pass valid port number as the first argument! (got `%s')\n"),
- args[0]);
- return;
- }
- memset (&in4, 0, sizeof (in4));
- memset (&in6, 0, sizeof (in6));
- in4.sin_family = AF_INET;
- in4.sin_port = htons ((uint16_t) port);
- in6.sin6_family = AF_INET6;
- in6.sin6_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- in4.sin_len = sizeof (in4);
- in6.sin6_len = sizeof (in6);
-#endif
- server = GNUNET_SERVER_create (NULL,
- NULL,
- (struct sockaddr * const *) sa,
- slen,
- GNUNET_TIME_UNIT_SECONDS,
- GNUNET_YES);
- GNUNET_SERVER_add_handlers (server,
- handlers);
- GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
- NULL);
+ cd->tt = NULL;
+ GNUNET_SERVICE_client_drop (cd->client);
}
+
/**
- * Main function of gnunet-nat-server.
+ * Callback called when a client connects to the service.
*
- * @param argc number of command-line arguments
- * @param argv command line
- * @return 0 on success, -1 on error
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return our `struct ClientData`
*/
-int
-main (int argc, char *const argv[])
+static void *
+client_connect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *c,
+ struct GNUNET_MQ_Handle *mq)
{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_END
- };
-
- if (GNUNET_OK !=
- GNUNET_STRINGS_get_utf8_args (argc, argv,
- &argc, &argv))
- return 2;
-
- if (GNUNET_OK !=
- GNUNET_PROGRAM_run (argc,
- argv,
- "gnunet-nat-server [options] PORT",
- _("GNUnet NAT traversal test helper daemon"),
- options,
- &run,
- NULL))
- {
- GNUNET_free ((void*) argv);
- return 1;
- }
- GNUNET_free ((void*) argv);
- return 0;
+ struct ClientData *cd;
+
+ cd = GNUNET_new (struct ClientData);
+ cd->client = c;
+ cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &force_timeout,
+ cd);
+ return cd;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param c the client that disconnected
+ * @param internal_cls our `struct ClientData`
+ */
+static void
+client_disconnect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *c,
+ void *internal_cls)
+{
+ struct ClientData *cd = internal_cls;
+
+ if (NULL != cd->tt)
+ GNUNET_SCHEDULER_cancel (cd->tt);
+ GNUNET_free (cd);
}
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("nat-server",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_fixed_size (test,
+ GNUNET_MESSAGE_TYPE_NAT_TEST,
+ struct GNUNET_NAT_AUTO_TestMessage,
+ NULL),
+ GNUNET_MQ_handler_end ());
+
+
+#if defined(LINUX) && defined(__GLIBC__)
+#include <malloc.h>
+
+/**
+ * MINIMIZE heap size (way below 128k) since this process doesn't need much.
+ */
+void __attribute__ ((constructor))
+GNUNET_ARM_memory_init ()
+{
+ mallopt (M_TRIM_THRESHOLD, 4 * 1024);
+ mallopt (M_TOP_PAD, 1 * 1024);
+ malloc_trim (0);
+}
+#endif
+
+
+
+
/* end of gnunet-nat-server.c */
* @param client identification of the client
* @param message the actual message
*
- * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
*/
static int
-helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message)
+helper_mst (void *cls,
+ const struct GNUNET_MessageHeader *message)
{
struct GNUNET_TESTBED_ControllerProc *cp = cls;
const struct GNUNET_TESTBED_HelperReply *msg;
$(BT_BIN) \
gnunet-service-transport
+
+
bin_PROGRAMS = \
gnunet-transport \
gnunet-transport-certificate-creation
$(HTTP_API_TIMEOUT_TEST) \
$(HTTPS_API_TIMEOUT_TEST) \
$(WLAN_TIMEOUT_TEST) \
- $(BT_TIMEOUT_TEST)
+ $(BT_TIMEOUT_TEST)
if HAVE_GETOPT_BINARY
TESTS += \
test_transport_api_slow_ats
* type to the output forward and copy it to the buffer for stdout.
*
* @param cls the 'struct SendBuffer' to copy the converted message to
- * @param client unused
* @param hdr inbound message from the FIFO
*/
static int
-stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+stdin_send (void *cls,
+ const struct GNUNET_MessageHeader *hdr)
{
struct SendBuffer *write_pout = cls;
const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
* We read a full message from stdin. Copy it to our send buffer.
*
* @param cls the 'struct SendBuffer' to copy to
- * @param client unused
* @param hdr the message we received to copy to the buffer
*/
static int
-file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+file_in_send (void *cls,
+ const struct GNUNET_MessageHeader *hdr)
{
struct SendBuffer *write_std = cls;
uint16_t sendsize;
fd_set wfds;
struct timeval tv;
int retval;
- struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst = NULL;
- struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst = NULL;
+ struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
+ struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
int first;
write_std.pos = 0;
write_pout.size = 0;
write_pout.pos = 0;
- stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout);
- file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std);
+ stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
+ file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
/* Send 'random' mac address */
macaddr.mac[0] = 0x13;
}
else if (0 < readsize)
{
- GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize,
- GNUNET_NO, GNUNET_NO);
+ GNUNET_MST_from_buffer (stdin_mst,
+ readbuf, readsize,
+ GNUNET_NO, GNUNET_NO);
}
else
}
else if (0 < readsize)
{
- GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize,
- GNUNET_NO, GNUNET_NO);
+ GNUNET_MST_from_buffer (file_in_mst,
+ readbuf, readsize,
+ GNUNET_NO, GNUNET_NO);
}
else
{
end:
/* clean up */
if (NULL != stdin_mst)
- GNUNET_SERVER_mst_destroy (stdin_mst);
+ GNUNET_MST_destroy (stdin_mst);
if (NULL != file_in_mst)
- GNUNET_SERVER_mst_destroy (file_in_mst);
+ GNUNET_MST_destroy (file_in_mst);
if (NULL != fpout)
fclose (fpout);
/**
* Message stream tokenizer for incoming data
*/
- struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
+ struct GNUNET_MessageStreamTokenizer *msg_tk;
/**
* Session timeout task
GNUNET_TRANSPORT_SS_DONE);
if (NULL != s->msg_tk)
{
- GNUNET_SERVER_mst_destroy (s->msg_tk);
+ GNUNET_MST_destroy (s->msg_tk);
s->msg_tk = NULL;
}
GNUNET_HELLO_address_free (s->address);
* Callback for message stream tokenizer
*
* @param cls the session
- * @param client not used
* @param message the message received
* @return always #GNUNET_OK
*/
static int
client_receive_mst_cb (void *cls,
- void *client,
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_ATS_Session *s = cls;
return CURL_WRITEFUNC_PAUSE;
}
if (NULL == s->msg_tk)
- s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb,
- s);
- GNUNET_SERVER_mst_receive (s->msg_tk,
- s,
- stream,
- len,
- GNUNET_NO,
- GNUNET_NO);
+ s->msg_tk = GNUNET_MST_create (&client_receive_mst_cb,
+ s);
+ GNUNET_MST_from_buffer (s->msg_tk,
+ stream,
+ len,
+ GNUNET_NO,
+ GNUNET_NO);
return len;
}
/**
* Message stream tokenizer for incoming data
*/
- struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
+ struct GNUNET_MessageStreamTokenizer *msg_tk;
/**
* Client recv handle
}
if (NULL != s->msg_tk)
{
- GNUNET_SERVER_mst_destroy (s->msg_tk);
+ GNUNET_MST_destroy (s->msg_tk);
s->msg_tk = NULL;
}
GNUNET_HELLO_address_free (s->address);
* Callback called by MessageStreamTokenizer when a message has arrived
*
* @param cls current session as closure
- * @param client client
* @param message the message to be forwarded to transport service
* @return #GNUNET_OK
*/
static int
server_receive_mst_cb (void *cls,
- void *client,
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_ATS_Session *s = cls;
*upload_data_size);
if (s->msg_tk == NULL)
{
- s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s);
+ s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb,
+ s);
}
- GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, *upload_data_size,
- GNUNET_NO, GNUNET_NO);
+ GNUNET_MST_from_buffer (s->msg_tk,
+ upload_data,
+ *upload_data_size,
+ GNUNET_NO, GNUNET_NO);
server_mhd_connection_timeout (plugin, s,
- GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
- / 1000LL);
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
+ / 1000LL);
(*upload_data_size) = 0;
}
else
sc->session->server_recv = NULL;
if (NULL != sc->session->msg_tk)
{
- GNUNET_SERVER_mst_destroy (sc->session->msg_tk);
+ GNUNET_MST_destroy (sc->session->msg_tk);
sc->session->msg_tk = NULL;
}
}
return;
}
- plugin->nat
+ plugin->nat
= GNUNET_NAT_register (plugin->env->cfg,
"transport-http_server",
IPPROTO_TCP,
*/
#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
-GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * Opaque handle that can be used to cancel
+ * a transmit-ready notification.
+ */
+struct GNUNET_CONNECTION_TransmitHandle;
+
+/**
+ * @brief handle for a server
+ */
+struct GNUNET_SERVER_Handle;
+
+/**
+ * @brief opaque handle for a client of the server
+ */
+struct GNUNET_SERVER_Client;
+
+/**
+ * @brief opaque handle server returns for aborting transmission to a client.
+ */
+struct GNUNET_SERVER_TransmitHandle;
+
+/**
+ * @brief handle for a network connection
+ */
+struct GNUNET_CONNECTION_Handle;
+
+
+/**
+ * Function called to notify a client about the connection begin ready
+ * to queue more data. @a buf will be NULL and @a size zero if the
+ * connection was closed for writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in @a buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to @a buf
+ */
+typedef size_t
+(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
+ size_t size,
+ void *buf);
+
+/**
+ * Credentials for UNIX domain sockets.
+ */
+struct GNUNET_CONNECTION_Credentials
+{
+ /**
+ * UID of the other end of the connection.
+ */
+ uid_t uid;
+
+ /**
+ * GID of the other end of the connection.
+ */
+ gid_t gid;
+};
+
+
+/**
+ * Functions with this signature are called whenever a client
+ * is disconnected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client; NULL
+ * for the last call when the server is destroyed
+ */
+typedef void
+(*GNUNET_SERVER_DisconnectCallback) (void *cls,
+ struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Functions with this signature are called whenever a client
+ * is connected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+typedef void
+(*GNUNET_SERVER_ConnectCallback) (void *cls,
+ struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Function to call for access control checks.
+ *
+ * @param cls closure
+ * @param ucred credentials, if available, otherwise NULL
+ * @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_CONNECTION_AccessCheck) (void *cls,
+ const struct
+ GNUNET_CONNECTION_Credentials *
+ ucred,
+ 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_CONNECTION_Receiver) (void *cls, const void *buf,
+ size_t available,
+ const struct sockaddr * addr,
+ socklen_t addrlen, int errCode);
+
+
+
+/**
+ * Close the connection and free associated resources. There must
+ * not be any pending requests for reading or writing to the
+ * connection at this time.
+ *
+ * @param connection connection to destroy
+ */
+void
+GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
+
+
+/**
+ * Signature of a function to create a custom tokenizer.
+ *
+ * @param cls closure from #GNUNET_SERVER_set_callbacks
+ * @param client handle to client the tokenzier will be used for
+ * @return handle to custom tokenizer ('mst')
+ */
+typedef void*
+(*GNUNET_SERVER_MstCreateCallback) (void *cls,
+ struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Signature of a function to destroy a custom tokenizer.
+ *
+ * @param cls closure from #GNUNET_SERVER_set_callbacks
+ * @param mst custom tokenizer handle
+ */
+typedef void
+(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
+ void *mst);
+
+/**
+ * Signature of a function to receive data for a custom tokenizer.
+ *
+ * @param cls closure from #GNUNET_SERVER_set_callbacks
+ * @param mst custom tokenizer handle
+ * @param client_identity ID of client for which this is a buffer,
+ * can be NULL (will be passed back to 'cb')
+ * @param buf input data to add
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
+ * (i.e. for packet-based services like UDP)
+ * @param one_shot only call callback once, keep rest of message in buffer
+ * @return #GNUNET_OK if we are done processing (need more data)
+ * #GNUNET_NO if one_shot was set and we have another message ready
+ * #GNUNET_SYSERR if the data stream is corrupt
+ */
+typedef int
+(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
+ struct GNUNET_SERVER_Client *client,
+ const char *buf,
+ size_t size,
+ int purge,
+ int one_shot);
+/**
+ * Functions with this signature are called whenever a message is
+ * received.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+typedef void
+(*GNUNET_SERVER_MessageCallback) (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Message handler. Each struct specifies how to handle on particular
+ * type of message received.
+ */
+struct GNUNET_SERVER_MessageHandler
+{
+ /**
+ * Function to call for messages of "type".
+ */
+ GNUNET_SERVER_MessageCallback callback;
+
+ /**
+ * Closure argument for @e callback.
+ */
+ void *callback_cls;
+
+ /**
+ * Type of the message this handler covers.
+ */
+ uint16_t type;
+
+ /**
+ * Expected size of messages of this type. Use 0 for
+ * variable-size. If non-zero, messages of the given
+ * type will be discarded (and the connection closed)
+ * if they do not have the right size.
+ */
+ uint16_t expected_size;
+
+};
+
+/**
+ * Ask the server to disconnect from the given client. This is the
+ * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
+ * except that it allows dropping of a client even when not handling a
+ * message from that client.
+ *
+ * @param client the client to disconnect from
+ */
+void
+GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
+
+/**
+ * Return user context associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param size number of bytes in user context struct (for verification only)
+ * @return pointer to user context
+ */
+void *
+GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
+ size_t size);
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call #GNUNET_SERVER_mst_destroy from within
+ * the scope of this callback.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ */
+typedef int
+(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
+ void *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Create a message stream tokenizer.
+ *
+ * @param cb function to call on completed messages
+ * @param cb_cls closure for @a cb
+ * @return handle to tokenizer
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer *
+GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
+ void *cb_cls);
+
+/**
+ * Add incoming data to the receive buffer and call the
+ * callback for all complete messages.
+ *
+ * @param mst tokenizer to use
+ * @param client_identity ID of client for which this is a buffer,
+ * can be NULL (will be passed back to 'cb')
+ * @param buf input data to add
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
+ * (i.e. for packet-based services like UDP)
+ * @param one_shot only call callback once, keep rest of message in buffer
+ * @return #GNUNET_OK if we are done processing (need more data)
+ * #GNUNET_NO if one_shot was set and we have another message ready
+ * #GNUNET_SYSERR if the data stream is corrupt
+ */
+int
+GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
+ void *client_identity,
+ const char *buf, size_t size,
+ int purge, int one_shot);
+
+
+
+/**
+ * Destroys a tokenizer.
+ *
+ * @param mst tokenizer to destroy
+ */
+void
+GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
+
+
+/**
+ * Set user context to be associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param ptr pointer to user context
+ * @param size number of bytes in user context struct (for verification only)
+ */
+void
+GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
+ void *ptr,
+ size_t size);
+/**
+ * Return user context associated with the given client.
+ *
+ * @param client client to query
+ * @param type expected return type (i.e. 'struct Foo')
+ * @return pointer to user context of type 'type *'.
+ */
+#define GNUNET_SERVER_client_get_user_context(client,type) \
+ (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
+
+/**
+ * Set user context to be associated with the given client.
+ *
+ * @param client client to query
+ * @param value pointer to user context
+ */
+#define GNUNET_SERVER_client_set_user_context(client,value) \
+ GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
+
+
+
+/**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param client client to transmit message to
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ * notify with buf NULL and size 0)?
+ * @param callback function to call when space is available
+ * @param callback_cls closure for @a callback
+ * @return non-NULL if the notify callback was queued; can be used
+ * to cancel the request using
+ * #GNUNET_SERVER_notify_transmit_ready_cancel.
+ * NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_SERVER_TransmitHandle *
+GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
+ size_t size,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_CONNECTION_TransmitReadyNotify callback,
+ void *callback_cls);
+
+/**
+ * Abort transmission request.
+ *
+ * @param th request to abort
+ */
+void
+GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
+
+
+
+
+/**
+ * Notify the server that the given client handle should
+ * be kept (keeps the connection up if possible, increments
+ * the internal reference counter).
+ *
+ * @param client the client to keep
+ */
+void
+GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Notify the server that the given client handle is no
+ * longer required. Decrements the reference counter. If
+ * that counter reaches zero an inactive connection maybe
+ * closed.
+ *
+ * @param client the client to drop
+ */
+void
+GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Function called by the service's run
+ * method to run service-specific setup code.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+typedef void
+(*GNUNET_SERVICE_Main) (void *cls,
+ struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+
+/**
+ * Suspend accepting connections from the listen socket temporarily.
+ * Resume activity using #GNUNET_SERVER_resume.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
+
+/**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param client client to transmit message to
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ * notify with buf NULL and size 0)?
+ * @param callback function to call when space is available
+ * @param callback_cls closure for @a callback
+ * @return non-NULL if the notify callback was queued; can be used
+ * to cancel the request using
+ * #GNUNET_SERVER_notify_transmit_ready_cancel.
+ * NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_SERVER_TransmitHandle *
+GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
+ size_t size,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_CONNECTION_TransmitReadyNotify callback,
+ void *callback_cls);
+
+
+/**
+ * Add a TCP socket-based connection to the set of handles managed by
+ * this server. Use this function for outgoing (P2P) connections that
+ * we initiated (and where this server should process incoming
+ * messages).
+ *
+ * @param server the server to use
+ * @param connection the connection to manage (client must
+ * stop using this connection from now on)
+ * @return the client handle
+ */
+struct GNUNET_SERVER_Client *
+GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
+ struct GNUNET_CONNECTION_Handle *connection);
+
+
+/**
+ * Resume accepting connections from the listen socket.
+ *
+ * @param server server to resume accepting connections.
+ */
+void
+GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
+
+/**
+ * Free resources held by this server.
+ *
+ * @param server server to destroy
+ */
+void
+GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
+
+
+
+
+#include "tcp_connection_legacy.c"
+#include "tcp_server_mst_legacy.c"
+#include "tcp_server_legacy.c"
+#include "tcp_service_legacy.c"
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
/**
* Initial handshake message for a session.
*/
};
-/* begin of ancient copy-and-pasted code that should be
- specialized for TCP ...*/
-/**
- * Add the given UNIX domain path as an address to the
- * list (as the first entry).
- *
- * @param saddrs array to update
- * @param saddrlens where to store the address length
- * @param unixpath path to add
- * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
- * parameter is ignore on systems other than LINUX
- */
-static void
-add_unixpath (struct sockaddr **saddrs,
- socklen_t *saddrlens,
- const char *unixpath,
- int abstract)
-{
-#ifdef AF_UNIX
- struct sockaddr_un *un;
-
- un = GNUNET_new (struct sockaddr_un);
- un->sun_family = AF_UNIX;
- strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
-#ifdef LINUX
- if (GNUNET_YES == abstract)
- un->sun_path[0] = '\0';
-#endif
-#if HAVE_SOCKADDR_UN_SUN_LEN
- un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
- *saddrs = (struct sockaddr *) un;
- *saddrlens = sizeof (struct sockaddr_un);
-#else
- /* this function should never be called
- * unless AF_UNIX is defined! */
- GNUNET_assert (0);
-#endif
-}
-
-
/**
* Get the list of addresses that a server for the given service
* should bind to.
*/
struct GNUNET_PeerIdentity target;
+ /**
+ * Tokenizer for inbound messages.
+ */
+ struct GNUNET_MessageStreamTokenizer *mst;
+
/**
* Plugin this session belongs to.
*/
GNUNET_free (s->frag_ctx);
s->frag_ctx = NULL;
}
+ if (NULL != s->mst)
+ {
+ GNUNET_MST_destroy (s->mst);
+ s->mst = NULL;
+ }
GNUNET_free (s);
}
* Message tokenizer has broken up an incomming message. Pass it on
* to the service.
*
- * @param cls the `struct Plugin *`
- * @param client the `struct GNUNET_ATS_Session *`
+ * @param cls the `struct GNUNET_ATS_Session *`
* @param hdr the actual message
* @return #GNUNET_OK (always)
*/
static int
process_inbound_tokenized_messages (void *cls,
- void *client,
const struct GNUNET_MessageHeader *hdr)
{
- struct Plugin *plugin = cls;
- struct GNUNET_ATS_Session *session = client;
+ struct GNUNET_ATS_Session *session = cls;
+ struct Plugin *plugin = session->plugin;
if (GNUNET_YES == session->in_destroy)
return GNUNET_OK;
struct GNUNET_ATS_Session *s;
s = GNUNET_new (struct GNUNET_ATS_Session);
+ s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
+ s);
s->plugin = plugin;
s->address = GNUNET_HELLO_address_copy (address);
s->target = address->peer;
GNUNET_free (address);
s->rc++;
- GNUNET_SERVER_mst_receive (plugin->mst,
- s,
- (const char *) &msg[1],
- ntohs (msg->header.size) - sizeof(struct UDPMessage),
- GNUNET_YES,
- GNUNET_NO);
+ GNUNET_MST_from_buffer (s->mst,
+ (const char *) &msg[1],
+ ntohs (msg->header.size) - sizeof(struct UDPMessage),
+ GNUNET_YES,
+ GNUNET_NO);
s->rc--;
if ( (0 == s->rc) &&
(GNUNET_YES == s->in_destroy) )
p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
GNUNET_NO);
p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
- p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages,
- p);
GNUNET_BANDWIDTH_tracker_init (&p->tracker,
NULL,
NULL,
_("Failed to create UDP network sockets\n"));
GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
- GNUNET_SERVER_mst_destroy (p->mst);
if (NULL != p->nat)
GNUNET_NAT_unregister (p->nat);
GNUNET_free (p);
GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs);
plugin->defrag_ctxs = NULL;
}
- if (NULL != plugin->mst)
- {
- GNUNET_SERVER_mst_destroy (plugin->mst);
- plugin->mst = NULL;
- }
while (NULL != (udpw = plugin->ipv4_queue_head))
{
dequeue (plugin,
*/
struct GNUNET_SCHEDULER_Task *select_task_v6;
- /**
- * Tokenizer for inbound messages.
- */
- struct GNUNET_SERVER_MessageStreamTokenizer *mst;
-
/**
* Bandwidth tracker to limit global UDP traffic.
*/
* Handle to NAT traversal support.
*/
struct GNUNET_NAT_STUN_Handle *stun;
-
+
/**
* The read socket for IPv4
*/
*/
struct GNUNET_NETWORK_Handle *sockv6;
- /**
- * Tokenizer for inbound messages.
- */
- struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_mst;
-
/**
* Head of DLL of broadcast addresses
*/
*/
static int
broadcast_mst_cb (void *cls,
- void *client,
const struct GNUNET_MessageHeader *message)
{
- struct Plugin *plugin = cls;
- struct MstContext *mc = client;
+ struct MstContext *mc = cls;
+ struct Plugin *plugin = mc->plugin;
struct GNUNET_HELLO_Address *address;
const struct GNUNET_MessageHeader *hello;
const struct UDP_Beacon_Message *msg;
size_t udp_addr_len,
enum GNUNET_ATS_Network_Type network_type)
{
+ struct GNUNET_MessageStreamTokenizer *broadcast_mst;
struct MstContext mc;
+ broadcast_mst = GNUNET_MST_create (&broadcast_mst_cb,
+ &mc);
+ mc.plugin = plugin;
mc.udp_addr = udp_addr;
mc.udp_addr_len = udp_addr_len;
mc.ats_address_network_type = network_type;
- GNUNET_SERVER_mst_receive (plugin->broadcast_mst,
- &mc,
- buf, size,
- GNUNET_NO,
- GNUNET_NO);
+ GNUNET_MST_from_buffer (broadcast_mst,
+ buf, size,
+ GNUNET_NO,
+ GNUNET_NO);
+ GNUNET_MST_destroy (broadcast_mst);
}
return;
}
- /* always create tokenizers */
- plugin->broadcast_mst =
- GNUNET_SERVER_mst_create (&broadcast_mst_cb, plugin);
-
if (GNUNET_YES != plugin->enable_broadcasting)
return; /* We do not send, just receive */
GNUNET_free (p);
}
}
-
- /* Destroy MSTs */
- if (NULL != plugin->broadcast_mst)
- {
- GNUNET_SERVER_mst_destroy (plugin->broadcast_mst);
- plugin->broadcast_mst = NULL;
- }
}
/* end of plugin_transport_udp_broadcasting.c */
#include "gnunet_fragmentation_lib.h"
#include "gnunet_constants.h"
+
#if BUILD_WLAN
/* begin case wlan */
#define PLUGIN_NAME "wlan"
#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done
#define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__)
+
/**
* time out of a mac endpoint
*/
#error need to build wlan or bluetooth
#endif
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call #GNUNET_SERVER_mst_destroy from within
+ * the scope of this callback.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ */
+typedef int
+(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
+ void *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/* Include legacy message stream tokenizer that was removed from util (for now) */
+#include "tcp_server_mst_legacy.c"
+
+
/**
* Max size of packet (that we give to the WLAN driver for transmission)
*/
* Function used for to process the data from the suid process
*
* @param cls the plugin handle
- * @param client client that send the data (not used)
* @param hdr header of the GNUNET_MessageHeader
*/
static int
-handle_helper_message (void *cls, void *client,
+handle_helper_message (void *cls,
const struct GNUNET_MessageHeader *hdr)
{
struct Plugin *plugin = cls;
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009-2013 GNUnet e.V.
+
+ 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/connection.c
+ * @brief TCP connection management
+ * @author Christian Grothoff
+ *
+ * This code is rather complex. Only modify it if you
+ * 1) Have a NEW testcase showing that the new code
+ * is needed and correct
+ * 2) All EXISTING testcases pass with the new code
+ * These rules should apply in general, but for this
+ * module they are VERY, VERY important.
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_resolver_service.h"
+
+
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
+
+
+/**
+ * Transmission handle. There can only be one for each connection.
+ */
+struct GNUNET_CONNECTION_TransmitHandle
+{
+
+ /**
+ * Function to call if the send buffer has notify_size
+ * bytes available.
+ */
+ GNUNET_CONNECTION_TransmitReadyNotify notify_ready;
+
+ /**
+ * Closure for notify_ready.
+ */
+ void *notify_ready_cls;
+
+ /**
+ * Our connection handle.
+ */
+ struct GNUNET_CONNECTION_Handle *connection;
+
+ /**
+ * Timeout for receiving (in absolute time).
+ */
+ struct GNUNET_TIME_Absolute transmit_timeout;
+
+ /**
+ * Task called on timeout.
+ */
+ struct GNUNET_SCHEDULER_Task * timeout_task;
+
+ /**
+ * At what number of bytes available in the
+ * write buffer should the notify method be called?
+ */
+ size_t notify_size;
+
+};
+
+
+/**
+ * During connect, we try multiple possible IP addresses
+ * to find out which one might work.
+ */
+struct AddressProbe
+{
+
+ /**
+ * This is a linked list.
+ */
+ struct AddressProbe *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct AddressProbe *prev;
+
+ /**
+ * The address; do not free (allocated at the end of this struct).
+ */
+ const struct sockaddr *addr;
+
+ /**
+ * Underlying OS's socket.
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /**
+ * Connection for which we are probing.
+ */
+ struct GNUNET_CONNECTION_Handle *connection;
+
+ /**
+ * Lenth of addr.
+ */
+ socklen_t addrlen;
+
+ /**
+ * Task waiting for the connection to finish connecting.
+ */
+ struct GNUNET_SCHEDULER_Task * task;
+};
+
+
+/**
+ * @brief handle for a network connection
+ */
+struct GNUNET_CONNECTION_Handle
+{
+
+ /**
+ * Configuration to use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Linked list of sockets we are currently trying out
+ * (during connect).
+ */
+ struct AddressProbe *ap_head;
+
+ /**
+ * Linked list of sockets we are currently trying out
+ * (during connect).
+ */
+ struct AddressProbe *ap_tail;
+
+ /**
+ * Network address of the other end-point, may be NULL.
+ */
+ struct sockaddr *addr;
+
+ /**
+ * Pointer to the hostname if connection was
+ * created using DNS lookup, otherwise NULL.
+ */
+ char *hostname;
+
+ /**
+ * Underlying OS's socket, set to NULL after fatal errors.
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /**
+ * Function to call on data received, NULL if no receive is pending.
+ */
+ GNUNET_CONNECTION_Receiver receiver;
+
+ /**
+ * Closure for @e receiver.
+ */
+ void *receiver_cls;
+
+ /**
+ * Pointer to our write buffer.
+ */
+ char *write_buffer;
+
+ /**
+ * Current size of our @e write_buffer.
+ */
+ size_t write_buffer_size;
+
+ /**
+ * Current write-offset in @e write_buffer (where
+ * would we write next).
+ */
+ size_t write_buffer_off;
+
+ /**
+ * Current read-offset in @e write_buffer (how many
+ * bytes have already been sent).
+ */
+ size_t write_buffer_pos;
+
+ /**
+ * Length of @e addr.
+ */
+ socklen_t addrlen;
+
+ /**
+ * Read task that we may need to wait for.
+ */
+ struct GNUNET_SCHEDULER_Task *read_task;
+
+ /**
+ * Write task that we may need to wait for.
+ */
+ struct GNUNET_SCHEDULER_Task *write_task;
+
+ /**
+ * Handle to a pending DNS lookup request.
+ */
+ struct GNUNET_RESOLVER_RequestHandle *dns_active;
+
+ /**
+ * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready().
+ */
+ struct GNUNET_CONNECTION_TransmitHandle nth;
+
+ /**
+ * Timeout for receiving (in absolute time).
+ */
+ struct GNUNET_TIME_Absolute receive_timeout;
+
+ /**
+ * Maximum number of bytes to read (for receiving).
+ */
+ size_t max;
+
+ /**
+ * Port to connect to.
+ */
+ uint16_t port;
+
+ /**
+ * When shutdown, do not ever actually close the socket, but
+ * free resources. Only should ever be set if using program
+ * termination as a signal (because only then will the leaked
+ * socket be freed!)
+ */
+ int8_t persist;
+
+ /**
+ * Usually 0. Set to 1 if this handle is in use, and should
+ * #GNUNET_CONNECTION_destroy() be called right now, the action needs
+ * to be deferred by setting it to -1.
+ */
+ int8_t destroy_later;
+
+ /**
+ * Handle to subsequent connection after proxy handshake completes,
+ */
+ struct GNUNET_CONNECTION_Handle *proxy_handshake;
+
+};
+
+
+/**
+ * Set the persist option on this connection handle. Indicates
+ * that the underlying socket or fd should never really be closed.
+ * Used for indicating process death.
+ *
+ * @param connection the connection to set persistent
+ */
+void
+GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
+{
+ connection->persist = GNUNET_YES;
+}
+
+
+/**
+ * Disable the "CORK" feature for communication with the given connection,
+ * forcing the OS to immediately flush the buffer on transmission
+ * instead of potentially buffering multiple messages. Essentially
+ * reduces the OS send buffers to zero.
+ * Used to make sure that the last messages sent through the connection
+ * reach the other side before the process is terminated.
+ *
+ * @param connection the connection to make flushing and blocking
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
+{
+ return GNUNET_NETWORK_socket_disable_corking (connection->sock);
+}
+
+
+/**
+ * Create a connection handle by boxing an existing OS socket. The OS
+ * socket should henceforth be no longer used directly.
+ * #GNUNET_connection_destroy() will close it.
+ *
+ * @param osSocket existing socket to box
+ * @return the boxed connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
+{
+ struct GNUNET_CONNECTION_Handle *connection;
+
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+ connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+ connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+ connection->sock = osSocket;
+ return connection;
+}
+
+
+/**
+ * Create a connection handle by accepting on a listen socket. This
+ * function may block if the listen socket has no connection ready.
+ *
+ * @param access_cb function to use to check if access is allowed
+ * @param access_cb_cls closure for @a access_cb
+ * @param lsock listen socket
+ * @return the connection handle, NULL on error
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
+ void *access_cb_cls,
+ struct GNUNET_NETWORK_Handle *lsock)
+{
+ struct GNUNET_CONNECTION_Handle *connection;
+ char addr[128];
+ socklen_t addrlen;
+ struct GNUNET_NETWORK_Handle *sock;
+ int aret;
+ struct sockaddr_in *v4;
+ struct sockaddr_in6 *v6;
+ struct sockaddr *sa;
+ void *uaddr;
+#ifdef SO_PEERCRED
+ struct ucred uc;
+ socklen_t olen;
+#endif
+ struct GNUNET_CONNECTION_Credentials *gcp;
+#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
+ struct GNUNET_CONNECTION_Credentials gc;
+
+ gc.uid = 0;
+ gc.gid = 0;
+#endif
+
+ addrlen = sizeof (addr);
+ sock =
+ GNUNET_NETWORK_socket_accept (lsock,
+ (struct sockaddr *) &addr,
+ &addrlen);
+ if (NULL == sock)
+ {
+ if (EAGAIN != errno)
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
+ return NULL;
+ }
+ if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
+ {
+ GNUNET_break (0);
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+ return NULL;
+ }
+
+ sa = (struct sockaddr *) addr;
+ v6 = (struct sockaddr_in6 *) addr;
+ if ( (AF_INET6 == sa->sa_family) &&
+ (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) )
+ {
+ /* convert to V4 address */
+ v4 = GNUNET_new (struct sockaddr_in);
+ memset (v4, 0, sizeof (struct sockaddr_in));
+ v4->sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v4->sin_len = (u_char) sizeof (struct sockaddr_in);
+#endif
+ GNUNET_memcpy (&v4->sin_addr,
+ &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
+ sizeof (struct in_addr)],
+ sizeof (struct in_addr));
+ v4->sin_port = v6->sin6_port;
+ uaddr = v4;
+ addrlen = sizeof (struct sockaddr_in);
+ }
+ else
+ {
+ uaddr = GNUNET_malloc (addrlen);
+ GNUNET_memcpy (uaddr, addr, addrlen);
+ }
+ gcp = NULL;
+ if (AF_UNIX == sa->sa_family)
+ {
+#if HAVE_GETPEEREID
+ /* most BSDs */
+ if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock),
+ &gc.uid,
+ &gc.gid))
+ gcp = &gc;
+#else
+#ifdef SO_PEERCRED
+ /* largely traditional GNU/Linux */
+ olen = sizeof (uc);
+ if ( (0 ==
+ getsockopt (GNUNET_NETWORK_get_fd (sock),
+ SOL_SOCKET,
+ SO_PEERCRED,
+ &uc,
+ &olen)) &&
+ (olen == sizeof (uc)) )
+ {
+ gc.uid = uc.uid;
+ gc.gid = uc.gid;
+ gcp = &gc;
+ }
+#else
+#if HAVE_GETPEERUCRED
+ /* this is for Solaris 10 */
+ ucred_t *uc;
+
+ uc = NULL;
+ if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
+ {
+ gc.uid = ucred_geteuid (uc);
+ gc.gid = ucred_getegid (uc);
+ gcp = &gc;
+ }
+ ucred_free (uc);
+#endif
+#endif
+#endif
+ }
+
+ if ( (NULL != access_cb) &&
+ (GNUNET_YES != (aret = access_cb (access_cb_cls,
+ gcp,
+ uaddr,
+ addrlen))) )
+ {
+ if (GNUNET_NO == aret)
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Access denied to `%s'\n"),
+ GNUNET_a2s (uaddr,
+ addrlen));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_shutdown (sock,
+ SHUT_RDWR));
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+ GNUNET_free (uaddr);
+ return NULL;
+ }
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+ connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+ connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+ connection->addr = uaddr;
+ connection->addrlen = addrlen;
+ connection->sock = sock;
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Accepting connection from `%s': %p\n"),
+ GNUNET_a2s (uaddr,
+ addrlen),
+ connection);
+ return connection;
+}
+
+
+/**
+ * Obtain the network address of the other party.
+ *
+ * @param connection the client to get the address for
+ * @param addr where to store the address
+ * @param addrlen where to store the length of the @a addr
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
+ void **addr,
+ size_t *addrlen)
+{
+ if ((NULL == connection->addr) || (0 == connection->addrlen))
+ return GNUNET_NO;
+ *addr = GNUNET_malloc (connection->addrlen);
+ GNUNET_memcpy (*addr, connection->addr, connection->addrlen);
+ *addrlen = connection->addrlen;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Tell the receiver callback that we had an IO error.
+ *
+ * @param connection connection to signal error
+ * @param errcode error code to send
+ */
+static void
+signal_receive_error (struct GNUNET_CONNECTION_Handle *connection,
+ int errcode)
+{
+ GNUNET_CONNECTION_Receiver receiver;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Receive encounters error (%s), connection closed (%p)\n",
+ STRERROR (errcode),
+ connection);
+ GNUNET_assert (NULL != (receiver = connection->receiver));
+ connection->receiver = NULL;
+ receiver (connection->receiver_cls,
+ NULL,
+ 0,
+ connection->addr,
+ connection->addrlen,
+ errcode);
+}
+
+
+/**
+ * Tell the receiver callback that a timeout was reached.
+ *
+ * @param connection connection to signal for
+ */
+static void
+signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
+{
+ GNUNET_CONNECTION_Receiver receiver;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection signals timeout to receiver (%p)!\n",
+ connection);
+ GNUNET_assert (NULL != (receiver = connection->receiver));
+ connection->receiver = NULL;
+ receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
+}
+
+
+/**
+ * We failed to transmit data to the service, signal the error.
+ *
+ * @param connection handle that had trouble
+ * @param ecode error code (errno)
+ */
+static void
+signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection,
+ int ecode)
+{
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission encounterd error (%s), connection closed (%p)\n",
+ STRERROR (ecode),
+ connection);
+ if (NULL != connection->sock)
+ {
+ (void) GNUNET_NETWORK_socket_shutdown (connection->sock,
+ SHUT_RDWR);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (connection->sock));
+ connection->sock = NULL;
+ GNUNET_assert (NULL == connection->write_task);
+ }
+ if (NULL != connection->read_task)
+ {
+ /* send errors trigger read errors... */
+ GNUNET_SCHEDULER_cancel (connection->read_task);
+ connection->read_task = NULL;
+ signal_receive_timeout (connection);
+ return;
+ }
+ if (NULL == connection->nth.notify_ready)
+ return; /* nobody to tell about it */
+ notify = connection->nth.notify_ready;
+ connection->nth.notify_ready = NULL;
+ notify (connection->nth.notify_ready_cls,
+ 0,
+ NULL);
+}
+
+
+/**
+ * We've failed for good to establish a connection (timeout or
+ * no more addresses to try).
+ *
+ * @param connection the connection we tried to establish
+ */
+static void
+connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
+{
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
+ connection->hostname,
+ connection->port);
+ GNUNET_break (NULL == connection->ap_head);
+ GNUNET_break (NULL == connection->ap_tail);
+ GNUNET_break (GNUNET_NO == connection->dns_active);
+ GNUNET_break (NULL == connection->sock);
+ GNUNET_assert (NULL == connection->write_task);
+ GNUNET_assert (NULL == connection->proxy_handshake);
+
+ /* signal errors for jobs that used to wait on the connection */
+ connection->destroy_later = 1;
+ if (NULL != connection->receiver)
+ signal_receive_error (connection,
+ ECONNREFUSED);
+ if (NULL != connection->nth.notify_ready)
+ {
+ GNUNET_assert (NULL != connection->nth.timeout_task);
+ GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+ connection->nth.timeout_task = NULL;
+ signal_transmit_error (connection,
+ ECONNREFUSED);
+ }
+ if (-1 == connection->destroy_later)
+ {
+ /* do it now */
+ connection->destroy_later = 0;
+ GNUNET_CONNECTION_destroy (connection);
+ return;
+ }
+ connection->destroy_later = 0;
+}
+
+
+/**
+ * We are ready to transmit (or got a timeout).
+ *
+ * @param cls our connection handle
+ */
+static void
+transmit_ready (void *cls);
+
+
+/**
+ * This function is called once we either timeout or have data ready
+ * to read.
+ *
+ * @param cls connection to read from
+ */
+static void
+receive_ready (void *cls);
+
+
+/**
+ * We've succeeded in establishing a connection.
+ *
+ * @param connection the connection we tried to establish
+ */
+static void
+connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection to `%s' succeeded! (%p)\n",
+ GNUNET_a2s (connection->addr,
+ connection->addrlen),
+ connection);
+ /* trigger jobs that waited for the connection */
+ if (NULL != connection->receiver)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection succeeded, starting with receiving data (%p)\n",
+ connection);
+ GNUNET_assert (NULL == connection->read_task);
+ connection->read_task =
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+ (connection->receive_timeout),
+ connection->sock,
+ &receive_ready, connection);
+ }
+ if (NULL != connection->nth.notify_ready)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection succeeded, starting with sending data (%p)\n",
+ connection);
+ GNUNET_assert (connection->nth.timeout_task != NULL);
+ GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+ connection->nth.timeout_task = NULL;
+ GNUNET_assert (connection->write_task == NULL);
+ connection->write_task =
+ GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
+ (connection->nth.transmit_timeout), connection->sock,
+ &transmit_ready, connection);
+ }
+}
+
+
+/**
+ * Scheduler let us know that we're either ready to write on the
+ * socket OR connect timed out. Do the right thing.
+ *
+ * @param cls the `struct AddressProbe *` with the address that we are probing
+ */
+static void
+connect_probe_continuation (void *cls)
+{
+ struct AddressProbe *ap = cls;
+ struct GNUNET_CONNECTION_Handle *connection = ap->connection;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+ struct AddressProbe *pos;
+ int error;
+ socklen_t len;
+
+ GNUNET_assert (NULL != ap->sock);
+ GNUNET_CONTAINER_DLL_remove (connection->ap_head,
+ connection->ap_tail,
+ ap);
+ len = sizeof (error);
+ errno = 0;
+ error = 0;
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
+ (GNUNET_OK !=
+ GNUNET_NETWORK_socket_getsockopt (ap->sock,
+ SOL_SOCKET,
+ SO_ERROR,
+ &error,
+ &len)) ||
+ (0 != error) )
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (ap->sock));
+ GNUNET_free (ap);
+ if ( (NULL == connection->ap_head) &&
+ (GNUNET_NO == connection->dns_active) &&
+ (NULL == connection->proxy_handshake) )
+ connect_fail_continuation (connection);
+ return;
+ }
+ GNUNET_assert (NULL == connection->sock);
+ connection->sock = ap->sock;
+ GNUNET_assert (NULL == connection->addr);
+ connection->addr = GNUNET_malloc (ap->addrlen);
+ GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen);
+ connection->addrlen = ap->addrlen;
+ GNUNET_free (ap);
+ /* cancel all other attempts */
+ while (NULL != (pos = connection->ap_head))
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+ GNUNET_SCHEDULER_cancel (pos->task);
+ GNUNET_CONTAINER_DLL_remove (connection->ap_head,
+ connection->ap_tail,
+ pos);
+ GNUNET_free (pos);
+ }
+ connect_success_continuation (connection);
+}
+
+
+/**
+ * Try to establish a connection given the specified address.
+ * This function is called by the resolver once we have a DNS reply.
+ *
+ * @param cls our `struct GNUNET_CONNECTION_Handle *`
+ * @param addr address to try, NULL for "last call"
+ * @param addrlen length of @a addr
+ */
+static void
+try_connect_using_address (void *cls,
+ const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_CONNECTION_Handle *connection = cls;
+ struct AddressProbe *ap;
+ struct GNUNET_TIME_Relative delay;
+
+ if (NULL == addr)
+ {
+ connection->dns_active = NULL;
+ if ((NULL == connection->ap_head) &&
+ (NULL == connection->sock) &&
+ (NULL == connection->proxy_handshake))
+ connect_fail_continuation (connection);
+ return;
+ }
+ if (NULL != connection->sock)
+ return; /* already connected */
+ GNUNET_assert (NULL == connection->addr);
+ /* try to connect */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Trying to connect using address `%s:%u/%s:%u'\n",
+ connection->hostname,
+ connection->port,
+ GNUNET_a2s (addr, addrlen),
+ connection->port);
+ ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
+ ap->addr = (const struct sockaddr *) &ap[1];
+ GNUNET_memcpy (&ap[1], addr, addrlen);
+ ap->addrlen = addrlen;
+ ap->connection = connection;
+
+ switch (ap->addr->sa_family)
+ {
+ case AF_INET:
+ ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_free (ap);
+ return; /* not supported by us */
+ }
+ ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
+ SOCK_STREAM, 0);
+ if (NULL == ap->sock)
+ {
+ GNUNET_free (ap);
+ return; /* not supported by OS */
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Trying to connect to `%s' (%p)\n",
+ GNUNET_a2s (ap->addr, ap->addrlen),
+ connection);
+ if ((GNUNET_OK !=
+ GNUNET_NETWORK_socket_connect (ap->sock,
+ ap->addr,
+ ap->addrlen)) &&
+ (EINPROGRESS != errno))
+ {
+ /* maybe refused / unsupported address, try next */
+ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
+ GNUNET_free (ap);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
+ delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
+ if (NULL != connection->nth.notify_ready)
+ delay = GNUNET_TIME_relative_min (delay,
+ GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
+ if (NULL != connection->receiver)
+ delay = GNUNET_TIME_relative_min (delay,
+ GNUNET_TIME_absolute_get_remaining (connection->receive_timeout));
+ ap->task = GNUNET_SCHEDULER_add_write_net (delay,
+ ap->sock,
+ &connect_probe_continuation,
+ ap);
+}
+
+
+/**
+ * Create a connection 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 cfg configuration to use
+ * @param hostname name of the host to connect to
+ * @param port port to connect to
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *hostname,
+ uint16_t port)
+{
+ struct GNUNET_CONNECTION_Handle *connection;
+
+ GNUNET_assert (0 < strlen (hostname)); /* sanity check */
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+ connection->cfg = cfg;
+ connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+ connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+ connection->port = port;
+ connection->hostname = GNUNET_strdup (hostname);
+ connection->dns_active =
+ GNUNET_RESOLVER_ip_get (connection->hostname,
+ AF_UNSPEC,
+ GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+ &try_connect_using_address,
+ connection);
+ return connection;
+}
+
+
+/**
+ * Create a connection handle by connecting to a UNIX domain service.
+ * This function returns immediately, even if the connection has not
+ * yet been established. This function only creates UNIX connections.
+ *
+ * @param cfg configuration to use
+ * @param unixpath path to connect to
+ * @return the connection handle, NULL on systems without UNIX support
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *unixpath)
+{
+#ifdef AF_UNIX
+ struct GNUNET_CONNECTION_Handle *connection;
+ struct sockaddr_un *un;
+
+ GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
+ un = GNUNET_new (struct sockaddr_un);
+ un->sun_family = AF_UNIX;
+ strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+ {
+ int abstract;
+
+ abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ "TESTING",
+ "USE_ABSTRACT_SOCKETS");
+ if (GNUNET_YES == abstract)
+ un->sun_path[0] = '\0';
+ }
+#endif
+#if HAVE_SOCKADDR_UN_SUN_LEN
+ un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+ connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+ connection->cfg = cfg;
+ connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+ connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+ connection->port = 0;
+ connection->hostname = NULL;
+ connection->addr = (struct sockaddr *) un;
+ connection->addrlen = sizeof (struct sockaddr_un);
+ connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX,
+ SOCK_STREAM,
+ 0);
+ if (NULL == connection->sock)
+ {
+ GNUNET_free (connection->addr);
+ GNUNET_free (connection->write_buffer);
+ GNUNET_free (connection);
+ return NULL;
+ }
+ if ( (GNUNET_OK !=
+ GNUNET_NETWORK_socket_connect (connection->sock,
+ connection->addr,
+ connection->addrlen)) &&
+ (EINPROGRESS != errno) )
+ {
+ /* Just return; we expect everything to work eventually so don't fail HARD */
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (connection->sock));
+ connection->sock = NULL;
+ return connection;
+ }
+ connect_success_continuation (connection);
+ return connection;
+#else
+ return NULL;
+#endif
+}
+
+
+/**
+ * Create a connection 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 s socket to connect
+ * @param serv_addr server address
+ * @param addrlen length of @a serv_addr
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
+ const struct sockaddr *serv_addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_CONNECTION_Handle *connection;
+
+ if ( (GNUNET_OK !=
+ GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
+ (EINPROGRESS != errno) )
+ {
+ /* maybe refused / unsupported address, try next */
+ LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
+ "connect");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Attempt to connect to `%s' failed\n",
+ GNUNET_a2s (serv_addr,
+ addrlen));
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
+ return NULL;
+ }
+ connection = GNUNET_CONNECTION_create_from_existing (s);
+ connection->addr = GNUNET_malloc (addrlen);
+ GNUNET_memcpy (connection->addr, serv_addr, addrlen);
+ connection->addrlen = addrlen;
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Trying to connect to `%s' (%p)\n",
+ GNUNET_a2s (serv_addr, addrlen),
+ connection);
+ return connection;
+}
+
+
+/**
+ * Create a connection handle by creating a socket and
+ * (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 af_family address family to use
+ * @param serv_addr server address
+ * @param addrlen length of @a serv_addr
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_sockaddr (int af_family,
+ const struct sockaddr *serv_addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_NETWORK_Handle *s;
+
+ s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
+ if (NULL == s)
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+ "socket");
+ return NULL;
+ }
+ return GNUNET_CONNECTION_connect_socket (s,
+ serv_addr,
+ addrlen);
+}
+
+
+/**
+ * Check if connection is valid (no fatal errors have happened so far).
+ * Note that a connection that is still trying to connect is considered
+ * valid.
+ *
+ * @param connection connection to check
+ * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
+ */
+int
+GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
+{
+ if ((NULL != connection->ap_head) ||
+ (NULL != connection->dns_active) ||
+ (NULL != connection->proxy_handshake))
+ return GNUNET_YES; /* still trying to connect */
+ if ( (0 != connection->destroy_later) ||
+ (NULL == connection->sock) )
+ return GNUNET_NO;
+ return GNUNET_YES;
+}
+
+
+/**
+ * Close the connection and free associated resources. There must
+ * not be any pending requests for reading or writing to the
+ * connection at this time.
+ *
+ * @param connection connection to destroy
+ */
+void
+GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
+{
+ struct AddressProbe *pos;
+
+ if (0 != connection->destroy_later)
+ {
+ connection->destroy_later = -1;
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutting down connection (%p)\n",
+ connection);
+ GNUNET_assert (NULL == connection->nth.notify_ready);
+ GNUNET_assert (NULL == connection->receiver);
+ if (NULL != connection->write_task)
+ {
+ GNUNET_SCHEDULER_cancel (connection->write_task);
+ connection->write_task = NULL;
+ connection->write_buffer_off = 0;
+ }
+ if (NULL != connection->read_task)
+ {
+ GNUNET_SCHEDULER_cancel (connection->read_task);
+ connection->read_task = NULL;
+ }
+ if (NULL != connection->nth.timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+ connection->nth.timeout_task = NULL;
+ }
+ connection->nth.notify_ready = NULL;
+ if (NULL != connection->dns_active)
+ {
+ GNUNET_RESOLVER_request_cancel (connection->dns_active);
+ connection->dns_active = NULL;
+ }
+ if (NULL != connection->proxy_handshake)
+ {
+ /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
+ connection->proxy_handshake->destroy_later = -1;
+ connection->proxy_handshake = NULL; /* Not leaked ??? */
+ }
+ while (NULL != (pos = connection->ap_head))
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+ GNUNET_SCHEDULER_cancel (pos->task);
+ GNUNET_CONTAINER_DLL_remove (connection->ap_head,
+ connection->ap_tail,
+ pos);
+ GNUNET_free (pos);
+ }
+ if ( (NULL != connection->sock) &&
+ (GNUNET_YES != connection->persist) )
+ {
+ if ((GNUNET_OK !=
+ GNUNET_NETWORK_socket_shutdown (connection->sock,
+ SHUT_RDWR)) &&
+ (ENOTCONN != errno) &&
+ (ECONNRESET != errno) )
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+ "shutdown");
+ }
+ if (NULL != connection->sock)
+ {
+ if (GNUNET_YES != connection->persist)
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (connection->sock));
+ }
+ else
+ {
+ GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
+ * leak the socket in this special case) ... */
+ }
+ }
+ GNUNET_free_non_null (connection->addr);
+ GNUNET_free_non_null (connection->hostname);
+ GNUNET_free (connection->write_buffer);
+ GNUNET_free (connection);
+}
+
+
+/**
+ * This function is called once we either timeout
+ * or have data ready to read.
+ *
+ * @param cls connection to read from
+ */
+static void
+receive_ready (void *cls)
+{
+ struct GNUNET_CONNECTION_Handle *connection = cls;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+ char buffer[connection->max];
+ ssize_t ret;
+ GNUNET_CONNECTION_Receiver receiver;
+
+ connection->read_task = NULL;
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Receive from `%s' encounters error: timeout (%s, %p)\n",
+ GNUNET_a2s (connection->addr,
+ connection->addrlen),
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout),
+ GNUNET_YES),
+ connection);
+ signal_receive_timeout (connection);
+ return;
+ }
+ if (NULL == connection->sock)
+ {
+ /* connect failed for good */
+ signal_receive_error (connection, ECONNREFUSED);
+ return;
+ }
+ GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready,
+ connection->sock));
+RETRY:
+ ret = GNUNET_NETWORK_socket_recv (connection->sock,
+ buffer,
+ connection->max);
+ if (-1 == ret)
+ {
+ if (EINTR == errno)
+ goto RETRY;
+ signal_receive_error (connection, errno);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "receive_ready read %u/%u bytes from `%s' (%p)!\n",
+ (unsigned int) ret,
+ connection->max,
+ GNUNET_a2s (connection->addr,
+ connection->addrlen),
+ connection);
+ GNUNET_assert (NULL != (receiver = connection->receiver));
+ connection->receiver = NULL;
+ receiver (connection->receiver_cls,
+ buffer,
+ ret,
+ connection->addr,
+ connection->addrlen,
+ 0);
+}
+
+
+/**
+ * Receive data from the given connection. Note that this function
+ * will call @a receiver asynchronously using the scheduler. It will
+ * "immediately" return. Note that there MUST only be one active
+ * receive call per connection at any given point in time (so do not
+ * call receive again until the receiver callback has been invoked).
+ *
+ * @param connection connection 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 @a receiver
+ */
+void
+GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
+ size_t max,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_CONNECTION_Receiver receiver,
+ void *receiver_cls)
+{
+ GNUNET_assert ((NULL == connection->read_task) &&
+ (NULL == connection->receiver));
+ GNUNET_assert (NULL != receiver);
+ connection->receiver = receiver;
+ connection->receiver_cls = receiver_cls;
+ connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ connection->max = max;
+ if (NULL != connection->sock)
+ {
+ connection->read_task =
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+ (connection->receive_timeout),
+ connection->sock,
+ &receive_ready,
+ connection);
+ return;
+ }
+ if ((NULL == connection->dns_active) &&
+ (NULL == connection->ap_head) &&
+ (NULL == connection->proxy_handshake))
+ {
+ connection->receiver = NULL;
+ receiver (receiver_cls,
+ NULL, 0,
+ NULL, 0,
+ ETIMEDOUT);
+ return;
+ }
+}
+
+
+/**
+ * Cancel receive job on the given connection. Note that the
+ * receiver callback must not have been called yet in order
+ * for the cancellation to be valid.
+ *
+ * @param connection connection handle
+ * @return closure of the original receiver callback closure
+ */
+void *
+GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
+{
+ if (NULL != connection->read_task)
+ {
+ GNUNET_assert (connection ==
+ GNUNET_SCHEDULER_cancel (connection->read_task));
+ connection->read_task = NULL;
+ }
+ connection->receiver = NULL;
+ return connection->receiver_cls;
+}
+
+
+/**
+ * Try to call the transmit notify method (check if we do
+ * have enough space available first)!
+ *
+ * @param connection connection for which we should do this processing
+ * @return #GNUNET_YES if we were able to call notify
+ */
+static int
+process_notify (struct GNUNET_CONNECTION_Handle *connection)
+{
+ size_t used;
+ size_t avail;
+ size_t size;
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "process_notify is running\n");
+ GNUNET_assert (NULL == connection->write_task);
+ if (NULL == (notify = connection->nth.notify_ready))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "No one to notify\n");
+ return GNUNET_NO;
+ }
+ used = connection->write_buffer_off - connection->write_buffer_pos;
+ avail = connection->write_buffer_size - used;
+ size = connection->nth.notify_size;
+ if (size > avail)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Not enough buffer\n");
+ return GNUNET_NO;
+ }
+ connection->nth.notify_ready = NULL;
+ if (connection->write_buffer_size - connection->write_buffer_off < size)
+ {
+ /* need to compact */
+ memmove (connection->write_buffer,
+ &connection->write_buffer[connection->write_buffer_pos],
+ used);
+ connection->write_buffer_off -= connection->write_buffer_pos;
+ connection->write_buffer_pos = 0;
+ }
+ avail = connection->write_buffer_size - connection->write_buffer_off;
+ GNUNET_assert (avail >= size);
+ size =
+ notify (connection->nth.notify_ready_cls, avail,
+ &connection->write_buffer[connection->write_buffer_off]);
+ GNUNET_assert (size <= avail);
+ if (0 != size)
+ connection->write_buffer_off += size;
+ return GNUNET_YES;
+}
+
+
+/**
+ * Task invoked by the scheduler when a call to transmit
+ * is timing out (we never got enough buffer space to call
+ * the callback function before the specified timeout
+ * expired).
+ *
+ * This task notifies the client about the timeout.
+ *
+ * @param cls the `struct GNUNET_CONNECTION_Handle`
+ */
+static void
+transmit_timeout (void *cls)
+{
+ struct GNUNET_CONNECTION_Handle *connection = cls;
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ connection->nth.timeout_task = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
+ connection->hostname,
+ connection->port,
+ GNUNET_a2s (connection->addr,
+ connection->addrlen),
+ connection);
+ notify = connection->nth.notify_ready;
+ GNUNET_assert (NULL != notify);
+ connection->nth.notify_ready = NULL;
+ notify (connection->nth.notify_ready_cls,
+ 0,
+ NULL);
+}
+
+
+/**
+ * Task invoked by the scheduler when we failed to connect
+ * at the time of being asked to transmit.
+ *
+ * This task notifies the client about the error.
+ *
+ * @param cls the `struct GNUNET_CONNECTION_Handle`
+ */
+static void
+connect_error (void *cls)
+{
+ struct GNUNET_CONNECTION_Handle *connection = cls;
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
+ connection->nth.notify_size,
+ connection->hostname,
+ connection->port,
+ connection);
+ connection->write_task = NULL;
+ notify = connection->nth.notify_ready;
+ connection->nth.notify_ready = NULL;
+ notify (connection->nth.notify_ready_cls,
+ 0,
+ NULL);
+}
+
+
+/**
+ * We are ready to transmit (or got a timeout).
+ *
+ * @param cls our connection handle
+ */
+static void
+transmit_ready (void *cls)
+{
+ struct GNUNET_CONNECTION_Handle *connection = cls;
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+ ssize_t ret;
+ size_t have;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "transmit_ready running (%p).\n",
+ connection);
+ GNUNET_assert (NULL != connection->write_task);
+ connection->write_task = NULL;
+ GNUNET_assert (NULL == connection->nth.timeout_task);
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmit to `%s' fails, time out reached (%p).\n",
+ GNUNET_a2s (connection->addr,
+ connection->addrlen),
+ connection);
+ notify = connection->nth.notify_ready;
+ GNUNET_assert (NULL != notify);
+ connection->nth.notify_ready = NULL;
+ notify (connection->nth.notify_ready_cls, 0, NULL);
+ return;
+ }
+ GNUNET_assert (NULL != connection->sock);
+ if (NULL == tc->write_ready)
+ {
+ /* special circumstances (in particular, PREREQ_DONE after
+ * connect): not yet ready to write, but no "fatal" error either.
+ * Hence retry. */
+ goto SCHEDULE_WRITE;
+ }
+ if (! GNUNET_NETWORK_fdset_isset (tc->write_ready,
+ connection->sock))
+ {
+ GNUNET_assert (NULL == connection->write_task);
+ /* special circumstances (in particular, shutdown): not yet ready
+ * to write, but no "fatal" error either. Hence retry. */
+ goto SCHEDULE_WRITE;
+ }
+ GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
+ if ((NULL != connection->nth.notify_ready) &&
+ (connection->write_buffer_size < connection->nth.notify_size))
+ {
+ connection->write_buffer =
+ GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
+ connection->write_buffer_size = connection->nth.notify_size;
+ }
+ process_notify (connection);
+ have = connection->write_buffer_off - connection->write_buffer_pos;
+ if (0 == have)
+ {
+ /* no data ready for writing, terminate write loop */
+ return;
+ }
+ GNUNET_assert (have <= connection->write_buffer_size);
+ GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size);
+ GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
+RETRY:
+ ret =
+ GNUNET_NETWORK_socket_send (connection->sock,
+ &connection->write_buffer[connection->write_buffer_pos],
+ have);
+ if (-1 == ret)
+ {
+ if (EINTR == errno)
+ goto RETRY;
+ if (NULL != connection->write_task)
+ {
+ GNUNET_SCHEDULER_cancel (connection->write_task);
+ connection->write_task = NULL;
+ }
+ signal_transmit_error (connection, errno);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection transmitted %u/%u bytes to `%s' (%p)\n",
+ (unsigned int) ret,
+ have,
+ GNUNET_a2s (connection->addr,
+ connection->addrlen),
+ connection);
+ connection->write_buffer_pos += ret;
+ if (connection->write_buffer_pos == connection->write_buffer_off)
+ {
+ /* transmitted all pending data */
+ connection->write_buffer_pos = 0;
+ connection->write_buffer_off = 0;
+ }
+ if ( (0 == connection->write_buffer_off) &&
+ (NULL == connection->nth.notify_ready) )
+ return; /* all data sent! */
+ /* not done writing, schedule more */
+SCHEDULE_WRITE:
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Re-scheduling transmit_ready (more to do) (%p).\n",
+ connection);
+ have = connection->write_buffer_off - connection->write_buffer_pos;
+ GNUNET_assert ( (NULL != connection->nth.notify_ready) ||
+ (have > 0) );
+ if (NULL == connection->write_task)
+ connection->write_task =
+ GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
+ NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
+ GNUNET_TIME_absolute_get_remaining
+ (connection->nth.transmit_timeout),
+ connection->sock,
+ &transmit_ready, connection);
+}
+
+
+/**
+ * Ask the connection to call us once the specified number of bytes
+ * are free in the transmission buffer. Will never call the @a notify
+ * callback in this task, but always first go into the scheduler.
+ *
+ * @param connection connection
+ * @param size number of bytes to send
+ * @param timeout after how long should we give up (and call
+ * @a notify with buf NULL and size 0)?
+ * @param notify function to call
+ * @param notify_cls closure for @a notify
+ * @return non-NULL if the notify callback was queued,
+ * NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_CONNECTION_TransmitHandle *
+GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
+ size_t size,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_CONNECTION_TransmitReadyNotify notify,
+ void *notify_cls)
+{
+ if (NULL != connection->nth.notify_ready)
+ {
+ GNUNET_assert (0);
+ return NULL;
+ }
+ GNUNET_assert (NULL != notify);
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
+ GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
+ GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
+ connection->nth.notify_ready = notify;
+ connection->nth.notify_ready_cls = notify_cls;
+ connection->nth.connection = connection;
+ connection->nth.notify_size = size;
+ connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ GNUNET_assert (NULL == connection->nth.timeout_task);
+ if ((NULL == connection->sock) &&
+ (NULL == connection->ap_head) &&
+ (NULL == connection->dns_active) &&
+ (NULL == connection->proxy_handshake))
+ {
+ if (NULL != connection->write_task)
+ GNUNET_SCHEDULER_cancel (connection->write_task);
+ connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
+ connection);
+ return &connection->nth;
+ }
+ if (NULL != connection->write_task)
+ return &connection->nth; /* previous transmission still in progress */
+ if (NULL != connection->sock)
+ {
+ /* connected, try to transmit now */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Scheduling transmission (%p).\n",
+ connection);
+ connection->write_task =
+ GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
+ (connection->nth.transmit_timeout),
+ connection->sock,
+ &transmit_ready, connection);
+ return &connection->nth;
+ }
+ /* not yet connected, wait for connection */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
+ connection);
+ connection->nth.timeout_task =
+ GNUNET_SCHEDULER_add_delayed (timeout,
+ &transmit_timeout,
+ connection);
+ return &connection->nth;
+}
+
+
+/**
+ * Cancel the specified transmission-ready notification.
+ *
+ * @param th notification to cancel
+ */
+void
+GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
+{
+ GNUNET_assert (NULL != th->notify_ready);
+ th->notify_ready = NULL;
+ if (NULL != th->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ th->timeout_task = NULL;
+ }
+ if (NULL != th->connection->write_task)
+ {
+ GNUNET_SCHEDULER_cancel (th->connection->write_task);
+ th->connection->write_task = NULL;
+ }
+}
+
+
+/**
+ * Create a connection to be proxied using a given connection.
+ *
+ * @param cph connection to proxy server
+ * @return connection to be proxied
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph)
+{
+ struct GNUNET_CONNECTION_Handle *proxied = GNUNET_CONNECTION_create_from_existing (NULL);
+
+ proxied->proxy_handshake = cph;
+ return proxied;
+}
+
+
+/**
+ * Activate proxied connection and destroy initial proxy handshake connection.
+ * There must not be any pending requests for reading or writing to the
+ * proxy hadshake connection at this time.
+ *
+ * @param proxied connection connection to proxy server
+ */
+void
+GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
+{
+ struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
+
+ GNUNET_assert (NULL != cph);
+ GNUNET_assert (NULL == proxied->sock);
+ GNUNET_assert (NULL != cph->sock);
+ proxied->sock = cph->sock;
+ cph->sock = NULL;
+ GNUNET_CONNECTION_destroy (cph);
+ connect_success_continuation (proxied);
+}
+
+
+/* end of connection.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009-2013 GNUnet e.V.
+
+ 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/server.c
+ * @brief library for building GNUnet network servers
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
+
+
+/**
+ * List of arrays of message handlers.
+ */
+struct HandlerList
+{
+ /**
+ * This is a linked list.
+ */
+ struct HandlerList *next;
+
+ /**
+ * NULL-terminated array of handlers.
+ */
+ const struct GNUNET_SERVER_MessageHandler *handlers;
+};
+
+
+/**
+ * List of arrays of message handlers.
+ */
+struct NotifyList
+{
+ /**
+ * This is a doubly linked list.
+ */
+ struct NotifyList *next;
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct NotifyList *prev;
+
+ /**
+ * Function to call.
+ */
+ GNUNET_SERVER_DisconnectCallback callback;
+
+ /**
+ * Closure for callback.
+ */
+ void *callback_cls;
+};
+
+
+/**
+ * @brief handle for a server
+ */
+struct GNUNET_SERVER_Handle
+{
+ /**
+ * List of handlers for incoming messages.
+ */
+ struct HandlerList *handlers;
+
+ /**
+ * Head of list of our current clients.
+ */
+ struct GNUNET_SERVER_Client *clients_head;
+
+ /**
+ * Head of list of our current clients.
+ */
+ struct GNUNET_SERVER_Client *clients_tail;
+
+ /**
+ * Head of linked list of functions to call on disconnects by clients.
+ */
+ struct NotifyList *disconnect_notify_list_head;
+
+ /**
+ * Tail of linked list of functions to call on disconnects by clients.
+ */
+ struct NotifyList *disconnect_notify_list_tail;
+
+ /**
+ * Head of linked list of functions to call on connects by clients.
+ */
+ struct NotifyList *connect_notify_list_head;
+
+ /**
+ * Tail of linked list of functions to call on connects by clients.
+ */
+ struct NotifyList *connect_notify_list_tail;
+
+ /**
+ * Function to call for access control.
+ */
+ GNUNET_CONNECTION_AccessCheck access_cb;
+
+ /**
+ * Closure for @e access_cb.
+ */
+ void *access_cb_cls;
+
+ /**
+ * NULL-terminated array of sockets used to listen for new
+ * connections.
+ */
+ struct GNUNET_NETWORK_Handle **listen_sockets;
+
+ /**
+ * After how long should an idle connection time
+ * out (on write).
+ */
+ struct GNUNET_TIME_Relative idle_timeout;
+
+ /**
+ * Task scheduled to do the listening.
+ */
+ struct GNUNET_SCHEDULER_Task * listen_task;
+
+ /**
+ * Alternative function to create a MST instance.
+ */
+ GNUNET_SERVER_MstCreateCallback mst_create;
+
+ /**
+ * Alternative function to destroy a MST instance.
+ */
+ GNUNET_SERVER_MstDestroyCallback mst_destroy;
+
+ /**
+ * Alternative function to give data to a MST instance.
+ */
+ GNUNET_SERVER_MstReceiveCallback mst_receive;
+
+ /**
+ * Closure for 'mst_'-callbacks.
+ */
+ void *mst_cls;
+
+ /**
+ * Do we ignore messages of types that we do not understand or do we
+ * require that a handler is found (and if not kill the connection)?
+ */
+ int require_found;
+
+ /**
+ * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
+ * all non-monitor clients to disconnect before we call
+ * #GNUNET_SERVER_destroy. See test_monitor_clients(). Set to
+ * #GNUNET_SYSERR once the final destroy task has been scheduled
+ * (we cannot run it in the same task).
+ */
+ int in_soft_shutdown;
+};
+
+
+/**
+ * Handle server returns for aborting transmission to a client.
+ */
+struct GNUNET_SERVER_TransmitHandle
+{
+ /**
+ * Function to call to get the message.
+ */
+ GNUNET_CONNECTION_TransmitReadyNotify callback;
+
+ /**
+ * Closure for @e callback
+ */
+ void *callback_cls;
+
+ /**
+ * Active connection transmission handle.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *cth;
+
+};
+
+
+/**
+ * @brief handle for a client of the server
+ */
+struct GNUNET_SERVER_Client
+{
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct GNUNET_SERVER_Client *next;
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct GNUNET_SERVER_Client *prev;
+
+ /**
+ * Processing of incoming data.
+ */
+ void *mst;
+
+ /**
+ * Server that this client belongs to.
+ */
+ struct GNUNET_SERVER_Handle *server;
+
+ /**
+ * Client closure for callbacks.
+ */
+ struct GNUNET_CONNECTION_Handle *connection;
+
+ /**
+ * User context value, manipulated using
+ * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
+ */
+ void *user_context;
+
+ /**
+ * ID of task used to restart processing.
+ */
+ struct GNUNET_SCHEDULER_Task * restart_task;
+
+ /**
+ * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
+ */
+ struct GNUNET_SCHEDULER_Task * warn_task;
+
+ /**
+ * Time when the warn task was started.
+ */
+ struct GNUNET_TIME_Absolute warn_start;
+
+ /**
+ * Last activity on this socket (used to time it out
+ * if reference_count == 0).
+ */
+ struct GNUNET_TIME_Absolute last_activity;
+
+ /**
+ * Transmission handle we return for this client from
+ * #GNUNET_SERVER_notify_transmit_ready.
+ */
+ struct GNUNET_SERVER_TransmitHandle th;
+
+ /**
+ * After how long should an idle connection time
+ * out (on write).
+ */
+ struct GNUNET_TIME_Relative idle_timeout;
+
+ /**
+ * Number of external entities with a reference to
+ * this client object.
+ */
+ unsigned int reference_count;
+
+ /**
+ * Was processing if incoming messages suspended while
+ * we were still processing data already received?
+ * This is a counter saying how often processing was
+ * suspended (once per handler invoked).
+ */
+ unsigned int suspended;
+
+ /**
+ * Last size given when user context was initialized; used for
+ * sanity check.
+ */
+ size_t user_context_size;
+
+ /**
+ * Are we currently in the "process_client_buffer" function (and
+ * will hence restart the receive job on exit if suspended == 0 once
+ * we are done?). If this is set, then "receive_done" will
+ * essentially only decrement suspended; if this is not set, then
+ * "receive_done" may need to restart the receive process (either
+ * from the side-buffer or via select/recv).
+ */
+ int in_process_client_buffer;
+
+ /**
+ * We're about to close down this client.
+ */
+ int shutdown_now;
+
+ /**
+ * Are we currently trying to receive? (#GNUNET_YES if we are,
+ * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
+ * available in MST).
+ */
+ int receive_pending;
+
+ /**
+ * Persist the file handle for this client no matter what happens,
+ * force the OS to close once the process actually dies. Should only
+ * be used in special cases!
+ */
+ int persist;
+
+ /**
+ * Is this client a 'monitor' client that should not be counted
+ * when deciding on destroying the server during soft shutdown?
+ * (see also #GNUNET_SERVICE_start)
+ */
+ int is_monitor;
+
+ /**
+ * Type of last message processed (for warn_no_receive_done).
+ */
+ uint16_t warn_type;
+};
+
+
+
+/**
+ * Return user context associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param size number of bytes in user context struct (for verification only)
+ * @return pointer to user context
+ */
+void *
+GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
+ size_t size)
+{
+ if ((0 == client->user_context_size) &&
+ (NULL == client->user_context))
+ return NULL; /* never set */
+ GNUNET_assert (size == client->user_context_size);
+ return client->user_context;
+}
+
+
+/**
+ * Set user context to be associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param ptr pointer to user context
+ * @param size number of bytes in user context struct (for verification only)
+ */
+void
+GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
+ void *ptr,
+ size_t size)
+{
+ if (NULL == ptr)
+ {
+ client->user_context_size = 0;
+ client->user_context = ptr;
+ return;
+ }
+ client->user_context_size = size;
+ client->user_context = ptr;
+}
+
+
+/**
+ * Scheduler says our listen socket is ready. Process it!
+ *
+ * @param cls handle to our server for which we are processing the listen
+ * socket
+ */
+static void
+process_listen_socket (void *cls)
+{
+ struct GNUNET_SERVER_Handle *server = cls;
+ const struct GNUNET_SCHEDULER_TaskContext *tc;
+ struct GNUNET_CONNECTION_Handle *sock;
+ unsigned int i;
+
+ server->listen_task = NULL;
+ tc = GNUNET_SCHEDULER_get_task_context ();
+ for (i = 0; NULL != server->listen_sockets[i]; i++)
+ {
+ if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
+ server->listen_sockets[i]))
+ {
+ sock =
+ GNUNET_CONNECTION_create_from_accept (server->access_cb,
+ server->access_cb_cls,
+ server->listen_sockets[i]);
+ if (NULL != sock)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server accepted incoming connection.\n");
+ (void) GNUNET_SERVER_connect_socket (server,
+ sock);
+ }
+ }
+ }
+ /* listen for more! */
+ GNUNET_SERVER_resume (server);
+}
+
+
+/**
+ * Create and initialize a listen socket for the server.
+ *
+ * @param server_addr address to listen on
+ * @param socklen length of @a server_addr
+ * @return NULL on error, otherwise the listen socket
+ */
+static struct GNUNET_NETWORK_Handle *
+open_listen_socket (const struct sockaddr *server_addr,
+ socklen_t socklen)
+{
+ struct GNUNET_NETWORK_Handle *sock;
+ uint16_t port;
+ int eno;
+
+ switch (server_addr->sa_family)
+ {
+ case AF_INET:
+ port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
+ break;
+ case AF_INET6:
+ port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
+ break;
+ case AF_UNIX:
+ port = 0;
+ break;
+ default:
+ GNUNET_break (0);
+ port = 0;
+ break;
+ }
+ sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
+ if (NULL == sock)
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ errno = 0;
+ return NULL;
+ }
+ /* bind the socket */
+ if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
+ {
+ eno = errno;
+ if (EADDRINUSE != errno)
+ {
+ /* we don't log 'EADDRINUSE' here since an IPv4 bind may
+ * fail if we already took the port on IPv6; if both IPv4 and
+ * IPv6 binds fail, then our caller will log using the
+ * errno preserved in 'eno' */
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "bind");
+ if (0 != port)
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("`%s' failed for port %d (%s).\n"),
+ "bind",
+ port,
+ (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
+ eno = 0;
+ }
+ else
+ {
+ if (0 != port)
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("`%s' failed for port %d (%s): address already in use\n"),
+ "bind", port,
+ (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
+ else if (AF_UNIX == server_addr->sa_family)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("`%s' failed for `%s': address already in use\n"),
+ "bind",
+ GNUNET_a2s (server_addr, socklen));
+ }
+ }
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+ errno = eno;
+ return NULL;
+ }
+ if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "listen");
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+ errno = 0;
+ return NULL;
+ }
+ if (0 != port)
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server starts to listen on port %u.\n",
+ port);
+ return sock;
+}
+
+
+/**
+ * Create a new server.
+ *
+ * @param access_cb function for access control
+ * @param access_cb_cls closure for @a access_cb
+ * @param lsocks NULL-terminated array of listen sockets
+ * @param idle_timeout after how long should we timeout idle connections?
+ * @param require_found if #GNUNET_YES, connections sending messages of unknown type
+ * will be closed
+ * @return handle for the new server, NULL on error
+ * (typically, "port" already in use)
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
+ void *access_cb_cls,
+ struct GNUNET_NETWORK_Handle **lsocks,
+ struct GNUNET_TIME_Relative idle_timeout,
+ int require_found)
+{
+ struct GNUNET_SERVER_Handle *server;
+
+ server = GNUNET_new (struct GNUNET_SERVER_Handle);
+ server->idle_timeout = idle_timeout;
+ server->listen_sockets = lsocks;
+ server->access_cb = access_cb;
+ server->access_cb_cls = access_cb_cls;
+ server->require_found = require_found;
+ if (NULL != lsocks)
+ GNUNET_SERVER_resume (server);
+ return server;
+}
+
+
+/**
+ * Create a new server.
+ *
+ * @param access_cb function for access control
+ * @param access_cb_cls closure for @a access_cb
+ * @param server_addr address to listen on (including port), NULL terminated array
+ * @param socklen length of server_addr
+ * @param idle_timeout after how long should we timeout idle connections?
+ * @param require_found if YES, connections sending messages of unknown type
+ * will be closed
+ * @return handle for the new server, NULL on error
+ * (typically, "port" already in use)
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
+ void *access_cb_cls,
+ struct sockaddr *const *server_addr,
+ const socklen_t * socklen,
+ struct GNUNET_TIME_Relative idle_timeout,
+ int require_found)
+{
+ struct GNUNET_NETWORK_Handle **lsocks;
+ unsigned int i;
+ unsigned int j;
+ unsigned int k;
+ int seen;
+
+ i = 0;
+ while (NULL != server_addr[i])
+ i++;
+ if (i > 0)
+ {
+ lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
+ i = 0;
+ j = 0;
+ while (NULL != server_addr[i])
+ {
+ seen = 0;
+ for (k=0;k<i;k++)
+ if ( (socklen[k] == socklen[i]) &&
+ (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) )
+ {
+ seen = 1;
+ break;
+ }
+ if (0 != seen)
+ {
+ /* duplicate address, skip */
+ i++;
+ continue;
+ }
+ lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
+ if (NULL != lsocks[j])
+ j++;
+ i++;
+ }
+ if (0 == j)
+ {
+ if (0 != errno)
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
+ GNUNET_free (lsocks);
+ lsocks = NULL;
+ }
+ }
+ else
+ {
+ lsocks = NULL;
+ }
+ return GNUNET_SERVER_create_with_sockets (access_cb,
+ access_cb_cls,
+ lsocks,
+ idle_timeout,
+ require_found);
+}
+
+
+/**
+ * Set the 'monitor' flag on this client. Clients which have been
+ * marked as 'monitors' won't prevent the server from shutting down
+ * once '#GNUNET_SERVER_stop_listening()' has been invoked. The idea is
+ * that for "normal" clients we likely want to allow them to process
+ * their requests; however, monitor-clients are likely to 'never'
+ * disconnect during shutdown and thus will not be considered when
+ * determining if the server should continue to exist after
+ * #GNUNET_SERVER_destroy() has been called.
+ *
+ * @param client the client to set the 'monitor' flag on
+ */
+void
+GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Marking client as monitor!\n");
+ client->is_monitor = GNUNET_YES;
+}
+
+
+/**
+ * Helper function for #test_monitor_clients() to trigger
+ * #GNUNET_SERVER_destroy() after the stack has unwound.
+ *
+ * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
+ */
+static void
+do_destroy (void *cls)
+{
+ struct GNUNET_SERVER_Handle *server = cls;
+
+ GNUNET_SERVER_destroy (server);
+}
+
+
+/**
+ * Check if only 'monitor' clients are left. If so, destroy the
+ * server completely.
+ *
+ * @param server server to test for full shutdown
+ */
+static void
+test_monitor_clients (struct GNUNET_SERVER_Handle *server)
+{
+ struct GNUNET_SERVER_Client *client;
+
+ if (GNUNET_YES != server->in_soft_shutdown)
+ return;
+ for (client = server->clients_head; NULL != client; client = client->next)
+ if (GNUNET_NO == client->is_monitor)
+ return; /* not done yet */
+ server->in_soft_shutdown = GNUNET_SYSERR;
+ (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
+}
+
+
+/**
+ * Suspend accepting connections from the listen socket temporarily.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
+{
+ if (NULL != server->listen_task)
+ {
+ GNUNET_SCHEDULER_cancel (server->listen_task);
+ server->listen_task = NULL;
+ }
+}
+
+
+/**
+ * Resume accepting connections from the listen socket.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
+{
+ struct GNUNET_NETWORK_FDSet *r;
+ unsigned int i;
+
+ if (NULL == server->listen_sockets)
+ return;
+ if (NULL == server->listen_sockets[0])
+ return; /* nothing to do, no listen sockets! */
+ if (NULL == server->listen_sockets[1])
+ {
+ /* simplified method: no fd set needed; this is then much simpler
+ and much more efficient */
+ server->listen_task =
+ GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_PRIORITY_HIGH,
+ server->listen_sockets[0],
+ &process_listen_socket, server);
+ return;
+ }
+ r = GNUNET_NETWORK_fdset_create ();
+ i = 0;
+ while (NULL != server->listen_sockets[i])
+ GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
+ server->listen_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
+ GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
+ &process_listen_socket, server);
+ GNUNET_NETWORK_fdset_destroy (r);
+}
+
+
+/**
+ * Stop the listen socket and get ready to shutdown the server
+ * once only 'monitor' clients are left.
+ *
+ * @param server server to stop listening on
+ */
+void
+GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
+{
+ unsigned int i;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server in soft shutdown\n");
+ if (NULL != server->listen_task)
+ {
+ GNUNET_SCHEDULER_cancel (server->listen_task);
+ server->listen_task = NULL;
+ }
+ if (NULL != server->listen_sockets)
+ {
+ i = 0;
+ while (NULL != server->listen_sockets[i])
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
+ GNUNET_free (server->listen_sockets);
+ server->listen_sockets = NULL;
+ }
+ if (GNUNET_NO == server->in_soft_shutdown)
+ server->in_soft_shutdown = GNUNET_YES;
+ test_monitor_clients (server);
+}
+
+
+/**
+ * Free resources held by this server.
+ *
+ * @param server server to destroy
+ */
+void
+GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
+{
+ struct HandlerList *hpos;
+ struct NotifyList *npos;
+ unsigned int i;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server shutting down.\n");
+ if (NULL != server->listen_task)
+ {
+ GNUNET_SCHEDULER_cancel (server->listen_task);
+ server->listen_task = NULL;
+ }
+ if (NULL != server->listen_sockets)
+ {
+ i = 0;
+ while (NULL != server->listen_sockets[i])
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
+ GNUNET_free (server->listen_sockets);
+ server->listen_sockets = NULL;
+ }
+ while (NULL != server->clients_head)
+ GNUNET_SERVER_client_disconnect (server->clients_head);
+ while (NULL != (hpos = server->handlers))
+ {
+ server->handlers = hpos->next;
+ GNUNET_free (hpos);
+ }
+ while (NULL != (npos = server->disconnect_notify_list_head))
+ {
+ npos->callback (npos->callback_cls,
+ NULL);
+ GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
+ server->disconnect_notify_list_tail,
+ npos);
+ GNUNET_free (npos);
+ }
+ while (NULL != (npos = server->connect_notify_list_head))
+ {
+ npos->callback (npos->callback_cls,
+ NULL);
+ GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
+ server->connect_notify_list_tail,
+ npos);
+ GNUNET_free (npos);
+ }
+ GNUNET_free (server);
+}
+
+
+/**
+ * Add additional handlers to an existing server.
+ *
+ * @param server the server to add handlers to
+ * @param handlers array of message handlers for
+ * incoming messages; the last entry must
+ * have "NULL" for the "callback"; multiple
+ * entries for the same type are allowed,
+ * they will be called in order of occurence.
+ * These handlers can be removed later;
+ * the handlers array must exist until removed
+ * (or server is destroyed).
+ */
+void
+GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_SERVER_MessageHandler *handlers)
+{
+ struct HandlerList *p;
+
+ p = GNUNET_new (struct HandlerList);
+ p->handlers = handlers;
+ p->next = server->handlers;
+ server->handlers = p;
+}
+
+
+/**
+ * Change functions used by the server to tokenize the message stream.
+ * (very rarely used).
+ *
+ * @param server server to modify
+ * @param create new tokenizer initialization function
+ * @param destroy new tokenizer destruction function
+ * @param receive new tokenizer receive function
+ * @param cls closure for @a create, @a receive, @a destroy
+ */
+void
+GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_MstCreateCallback create,
+ GNUNET_SERVER_MstDestroyCallback destroy,
+ GNUNET_SERVER_MstReceiveCallback receive,
+ void *cls)
+{
+ server->mst_create = create;
+ server->mst_destroy = destroy;
+ server->mst_receive = receive;
+ server->mst_cls = cls;
+}
+
+
+/**
+ * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
+ *
+ * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
+ */
+static void
+warn_no_receive_done (void *cls)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+
+ GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
+ client->warn_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &warn_no_receive_done, client);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
+ (unsigned int) client->warn_type,
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
+ GNUNET_YES));
+}
+
+
+/**
+ * Disable the warning the server issues if a message is not acknowledged
+ * in a timely fashion. Use this call if a client is intentionally delayed
+ * for a while. Only applies to the current message.
+ *
+ * @param client client for which to disable the warning
+ */
+void
+GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
+{
+ if (NULL != client->warn_task)
+ {
+ GNUNET_SCHEDULER_cancel (client->warn_task);
+ client->warn_task = NULL;
+ }
+}
+
+
+/**
+ * Inject a message into the server, pretend it came
+ * from the specified client. Delivery of the message
+ * will happen instantly (if a handler is installed;
+ * otherwise the call does nothing).
+ *
+ * @param server the server receiving the message
+ * @param sender the "pretended" sender of the message
+ * can be NULL!
+ * @param message message to transmit
+ * @return #GNUNET_OK if the message was OK and the
+ * connection can stay open
+ * #GNUNET_SYSERR if the connection to the
+ * client should be shut down
+ */
+int
+GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
+ struct GNUNET_SERVER_Client *sender,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct HandlerList *pos;
+ const struct GNUNET_SERVER_MessageHandler *mh;
+ unsigned int i;
+ uint16_t type;
+ uint16_t size;
+ int found;
+
+ type = ntohs (message->type);
+ size = ntohs (message->size);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Received message of type %u and size %u from client\n",
+ type, size);
+ found = GNUNET_NO;
+ for (pos = server->handlers; NULL != pos; pos = pos->next)
+ {
+ i = 0;
+ while (pos->handlers[i].callback != NULL)
+ {
+ mh = &pos->handlers[i];
+ if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
+ {
+ if ((0 != mh->expected_size) && (mh->expected_size != size))
+ {
+#if GNUNET8_NETWORK_IS_DEAD
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Expected %u bytes for message of type %u, got %u\n",
+ mh->expected_size, mh->type, size);
+ GNUNET_break_op (0);
+#else
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Expected %u bytes for message of type %u, got %u\n",
+ mh->expected_size, mh->type, size);
+#endif
+ return GNUNET_SYSERR;
+ }
+ if (NULL != sender)
+ {
+ if ( (0 == sender->suspended) &&
+ (NULL == sender->warn_task) )
+ {
+ GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
+ sender->warn_start = GNUNET_TIME_absolute_get ();
+ sender->warn_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &warn_no_receive_done,
+ sender);
+ sender->warn_type = type;
+ }
+ sender->suspended++;
+ }
+ mh->callback (mh->callback_cls, sender, message);
+ found = GNUNET_YES;
+ }
+ i++;
+ }
+ }
+ if (GNUNET_NO == found)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Received message of unknown type %d\n", type);
+ if (GNUNET_YES == server->require_found)
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * We are receiving an incoming message. Process it.
+ *
+ * @param cls our closure (handle for the client)
+ * @param buf buffer with data received from network
+ * @param available number of bytes available in buf
+ * @param addr address of the sender
+ * @param addrlen length of @a addr
+ * @param errCode code indicating errors receiving, 0 for success
+ */
+static void
+process_incoming (void *cls,
+ const void *buf,
+ size_t available,
+ const struct sockaddr *addr,
+ socklen_t addrlen,
+ int errCode);
+
+
+/**
+ * Process messages from the client's message tokenizer until either
+ * the tokenizer is empty (and then schedule receiving more), or
+ * until some handler is not immediately done (then wait for restart_processing)
+ * or shutdown.
+ *
+ * @param client the client to process, RC must have already been increased
+ * using #GNUNET_SERVER_client_keep and will be decreased by one in this
+ * function
+ * @param ret #GNUNET_NO to start processing from the buffer,
+ * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
+ * #GNUNET_SYSERR if we should instantly abort due to error in a previous step
+ */
+static void
+process_mst (struct GNUNET_SERVER_Client *client,
+ int ret)
+{
+ while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
+ (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
+ {
+ if (GNUNET_OK == ret)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server re-enters receive loop, timeout: %s.\n",
+ GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
+ client->receive_pending = GNUNET_YES;
+ GNUNET_CONNECTION_receive (client->connection,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
+ client->idle_timeout,
+ &process_incoming,
+ client);
+ break;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server processes additional messages instantly.\n");
+ if (NULL != client->server->mst_receive)
+ ret =
+ client->server->mst_receive (client->server->mst_cls, client->mst,
+ client, NULL, 0, GNUNET_NO, GNUNET_YES);
+ else
+ ret =
+ GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
+ GNUNET_YES);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
+ ret, client->server,
+ client->shutdown_now,
+ client->suspended);
+ if (GNUNET_NO == ret)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server has more data pending but is suspended.\n");
+ client->receive_pending = GNUNET_SYSERR; /* data pending */
+ }
+ if ( (GNUNET_SYSERR == ret) ||
+ (GNUNET_YES == client->shutdown_now) )
+ GNUNET_SERVER_client_disconnect (client);
+}
+
+
+/**
+ * We are receiving an incoming message. Process it.
+ *
+ * @param cls our closure (handle for the client)
+ * @param buf buffer with data received from network
+ * @param available number of bytes available in buf
+ * @param addr address of the sender
+ * @param addrlen length of @a addr
+ * @param errCode code indicating errors receiving, 0 for success
+ */
+static void
+process_incoming (void *cls,
+ const void *buf,
+ size_t available,
+ const struct sockaddr *addr,
+ socklen_t addrlen,
+ int errCode)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+ struct GNUNET_SERVER_Handle *server = client->server;
+ struct GNUNET_TIME_Absolute end;
+ struct GNUNET_TIME_Absolute now;
+ int ret;
+
+ GNUNET_assert (GNUNET_YES == client->receive_pending);
+ client->receive_pending = GNUNET_NO;
+ now = GNUNET_TIME_absolute_get ();
+ end = GNUNET_TIME_absolute_add (client->last_activity,
+ client->idle_timeout);
+
+ if ( (NULL == buf) &&
+ (0 == available) &&
+ (NULL == addr) &&
+ (0 == errCode) &&
+ (GNUNET_YES != client->shutdown_now) &&
+ (NULL != server) &&
+ (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
+ (end.abs_value_us > now.abs_value_us) )
+ {
+ /* wait longer, timeout changed (i.e. due to us sending) */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Receive time out, but no disconnect due to sending (%p)\n",
+ client);
+ client->receive_pending = GNUNET_YES;
+ GNUNET_CONNECTION_receive (client->connection,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
+ GNUNET_TIME_absolute_get_remaining (end),
+ &process_incoming,
+ client);
+ return;
+ }
+ if ( (NULL == buf) ||
+ (0 == available) ||
+ (0 != errCode) ||
+ (NULL == server) ||
+ (GNUNET_YES == client->shutdown_now) ||
+ (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) )
+ {
+ /* other side closed connection, error connecting, etc. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to connect or other side closed connection (%p)\n",
+ client);
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server receives %u bytes from `%s'.\n",
+ (unsigned int) available,
+ GNUNET_a2s (addr, addrlen));
+ GNUNET_SERVER_client_keep (client);
+ client->last_activity = now;
+
+ if (NULL != server->mst_receive)
+ {
+ ret = client->server->mst_receive (client->server->mst_cls,
+ client->mst,
+ client,
+ buf,
+ available,
+ GNUNET_NO,
+ GNUNET_YES);
+ }
+ else if (NULL != client->mst)
+ {
+ ret =
+ GNUNET_SERVER_mst_receive (client->mst,
+ client,
+ buf,
+ available,
+ GNUNET_NO,
+ GNUNET_YES);
+ }
+ else
+ {
+ GNUNET_break (0);
+ return;
+ }
+ process_mst (client,
+ ret);
+ GNUNET_SERVER_client_drop (client);
+}
+
+
+/**
+ * Task run to start again receiving from the network
+ * and process requests.
+ *
+ * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
+ */
+static void
+restart_processing (void *cls)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+
+ GNUNET_assert (GNUNET_YES != client->shutdown_now);
+ client->restart_task = NULL;
+ if (GNUNET_NO == client->receive_pending)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
+ client->receive_pending = GNUNET_YES;
+ GNUNET_CONNECTION_receive (client->connection,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
+ client->idle_timeout,
+ &process_incoming,
+ client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server continues processing messages still in the buffer.\n");
+ GNUNET_SERVER_client_keep (client);
+ client->receive_pending = GNUNET_NO;
+ process_mst (client,
+ GNUNET_NO);
+ GNUNET_SERVER_client_drop (client);
+}
+
+
+/**
+ * This function is called whenever our inbound message tokenizer has
+ * received a complete message.
+ *
+ * @param cls closure (struct GNUNET_SERVER_Handle)
+ * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
+ * @param message the actual message
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ */
+static int
+client_message_tokenizer_callback (void *cls,
+ void *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_SERVER_Handle *server = cls;
+ struct GNUNET_SERVER_Client *sender = client;
+ int ret;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Tokenizer gives server message of type %u and size %u from client\n",
+ ntohs (message->type), ntohs (message->size));
+ sender->in_process_client_buffer = GNUNET_YES;
+ ret = GNUNET_SERVER_inject (server, sender, message);
+ sender->in_process_client_buffer = GNUNET_NO;
+ if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) )
+ {
+ GNUNET_SERVER_client_disconnect (sender);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Add a TCP socket-based connection to the set of handles managed by
+ * this server. Use this function for outgoing (P2P) connections that
+ * we initiated (and where this server should process incoming
+ * messages).
+ *
+ * @param server the server to use
+ * @param connection the connection to manage (client must
+ * stop using this connection from now on)
+ * @return the client handle
+ */
+struct GNUNET_SERVER_Client *
+GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
+ struct GNUNET_CONNECTION_Handle *connection)
+{
+ struct GNUNET_SERVER_Client *client;
+ struct NotifyList *n;
+
+ client = GNUNET_new (struct GNUNET_SERVER_Client);
+ client->connection = connection;
+ client->server = server;
+ client->last_activity = GNUNET_TIME_absolute_get ();
+ client->idle_timeout = server->idle_timeout;
+ GNUNET_CONTAINER_DLL_insert (server->clients_head,
+ server->clients_tail,
+ client);
+ if (NULL != server->mst_create)
+ client->mst =
+ server->mst_create (server->mst_cls, client);
+ else
+ client->mst =
+ GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
+ server);
+ GNUNET_assert (NULL != client->mst);
+ for (n = server->connect_notify_list_head; NULL != n; n = n->next)
+ n->callback (n->callback_cls, client);
+ client->receive_pending = GNUNET_YES;
+ GNUNET_CONNECTION_receive (client->connection,
+ GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
+ client->idle_timeout,
+ &process_incoming,
+ client);
+ return client;
+}
+
+
+/**
+ * Change the timeout for a particular client. Decreasing the timeout
+ * may not go into effect immediately (only after the previous timeout
+ * times out or activity happens on the socket).
+ *
+ * @param client the client to update
+ * @param timeout new timeout for activities on the socket
+ */
+void
+GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
+ struct GNUNET_TIME_Relative timeout)
+{
+ client->idle_timeout = timeout;
+}
+
+
+/**
+ * Notify the server that the given client handle should
+ * be kept (keeps the connection up if possible, increments
+ * the internal reference counter).
+ *
+ * @param client the client to keep
+ */
+void
+GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
+{
+ client->reference_count++;
+}
+
+
+/**
+ * Notify the server that the given client handle is no
+ * longer required. Decrements the reference counter. If
+ * that counter reaches zero an inactive connection maybe
+ * closed.
+ *
+ * @param client the client to drop
+ */
+void
+GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
+{
+ GNUNET_assert (client->reference_count > 0);
+ client->reference_count--;
+ if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
+ GNUNET_SERVER_client_disconnect (client);
+}
+
+
+/**
+ * Obtain the network address of the other party.
+ *
+ * @param client the client to get the address for
+ * @param addr where to store the address
+ * @param addrlen where to store the length of the @a addr
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
+ void **addr, size_t * addrlen)
+{
+ return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
+}
+
+
+/**
+ * Ask the server to notify us whenever a client disconnects.
+ * This function is called whenever the actual network connection
+ * is closed; the reference count may be zero or larger than zero
+ * at this point.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on disconnect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_DisconnectCallback callback,
+ void *callback_cls)
+{
+ struct NotifyList *n;
+
+ n = GNUNET_new (struct NotifyList);
+ n->callback = callback;
+ n->callback_cls = callback_cls;
+ GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
+ server->disconnect_notify_list_tail,
+ n);
+}
+
+
+/**
+ * Ask the server to notify us whenever a client connects.
+ * This function is called whenever the actual network connection
+ * is opened. If the server is destroyed before this
+ * notification is explicitly cancelled, the 'callback' will
+ * once be called with a 'client' argument of NULL to indicate
+ * that the server itself is now gone (and that the callback
+ * won't be called anymore and also can no longer be cancelled).
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on sconnect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_ConnectCallback callback,
+ void *callback_cls)
+{
+ struct NotifyList *n;
+ struct GNUNET_SERVER_Client *client;
+
+ n = GNUNET_new (struct NotifyList);
+ n->callback = callback;
+ n->callback_cls = callback_cls;
+ GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
+ server->connect_notify_list_tail,
+ n);
+ for (client = server->clients_head; NULL != client; client = client->next)
+ callback (callback_cls, client);
+}
+
+
+/**
+ * Ask the server to stop notifying us whenever a client connects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on connect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_DisconnectCallback callback,
+ void *callback_cls)
+{
+ struct NotifyList *pos;
+
+ for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
+ if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
+ break;
+ if (NULL == pos)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
+ server->disconnect_notify_list_tail,
+ pos);
+ GNUNET_free (pos);
+}
+
+
+/**
+ * Ask the server to stop notifying us whenever a client disconnects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on disconnect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_ConnectCallback callback,
+ void *callback_cls)
+{
+ struct NotifyList *pos;
+
+ for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
+ if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
+ break;
+ if (NULL == pos)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
+ server->connect_notify_list_tail,
+ pos);
+ GNUNET_free (pos);
+}
+
+
+/**
+ * Destroy the connection that is passed in via @a cls. Used
+ * as calling #GNUNET_CONNECTION_destroy from within a function
+ * that was itself called from within process_notify() of
+ * 'connection.c' is not allowed (see #2329).
+ *
+ * @param cls connection to destroy
+ */
+static void
+destroy_connection (void *cls)
+{
+ struct GNUNET_CONNECTION_Handle *connection = cls;
+
+ GNUNET_CONNECTION_destroy (connection);
+}
+
+
+/**
+ * Ask the server to disconnect from the given client.
+ * This is the same as returning #GNUNET_SYSERR from a message
+ * handler, except that it allows dropping of a client even
+ * when not handling a message from that client.
+ *
+ * @param client the client to disconnect from
+ */
+void
+GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
+{
+ struct GNUNET_SERVER_Handle *server = client->server;
+ struct NotifyList *n;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Client is being disconnected from the server.\n");
+ if (NULL != client->restart_task)
+ {
+ GNUNET_SCHEDULER_cancel (client->restart_task);
+ client->restart_task = NULL;
+ }
+ if (NULL != client->warn_task)
+ {
+ GNUNET_SCHEDULER_cancel (client->warn_task);
+ client->warn_task = NULL;
+ }
+ if (GNUNET_YES == client->receive_pending)
+ {
+ GNUNET_CONNECTION_receive_cancel (client->connection);
+ client->receive_pending = GNUNET_NO;
+ }
+ client->shutdown_now = GNUNET_YES;
+ client->reference_count++; /* make sure nobody else clean up client... */
+ if ( (NULL != client->mst) &&
+ (NULL != server) )
+ {
+ GNUNET_CONTAINER_DLL_remove (server->clients_head,
+ server->clients_tail,
+ client);
+ if (NULL != server->mst_destroy)
+ server->mst_destroy (server->mst_cls,
+ client->mst);
+ else
+ GNUNET_SERVER_mst_destroy (client->mst);
+ client->mst = NULL;
+ for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
+ n->callback (n->callback_cls,
+ client);
+ }
+ client->reference_count--;
+ if (client->reference_count > 0)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "RC of %p still positive, not destroying everything.\n",
+ client);
+ client->server = NULL;
+ return;
+ }
+ if (GNUNET_YES == client->in_process_client_buffer)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Still processing inputs of %p, not destroying everything.\n",
+ client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "RC of %p now zero, destroying everything.\n",
+ client);
+ if (GNUNET_YES == client->persist)
+ GNUNET_CONNECTION_persist_ (client->connection);
+ if (NULL != client->th.cth)
+ GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
+ (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
+ client->connection);
+ /* need to cancel again, as it might have been re-added
+ in the meantime (i.e. during callbacks) */
+ if (NULL != client->warn_task)
+ {
+ GNUNET_SCHEDULER_cancel (client->warn_task);
+ client->warn_task = NULL;
+ }
+ if (GNUNET_YES == client->receive_pending)
+ {
+ GNUNET_CONNECTION_receive_cancel (client->connection);
+ client->receive_pending = GNUNET_NO;
+ }
+ GNUNET_free (client);
+ /* we might be in soft-shutdown, test if we're done */
+ if (NULL != server)
+ test_monitor_clients (server);
+}
+
+
+/**
+ * Disable the "CORK" feature for communication with the given client,
+ * forcing the OS to immediately flush the buffer on transmission
+ * instead of potentially buffering multiple messages.
+ *
+ * @param client handle to the client
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
+{
+ return GNUNET_CONNECTION_disable_corking (client->connection);
+}
+
+
+/**
+ * Wrapper for transmission notification that calls the original
+ * callback and update the last activity time for our connection.
+ *
+ * @param cls the `struct GNUNET_SERVER_Client *`
+ * @param size number of bytes we can transmit
+ * @param buf where to copy the message
+ * @return number of bytes actually transmitted
+ */
+static size_t
+transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+ GNUNET_CONNECTION_TransmitReadyNotify callback;
+
+ client->th.cth = NULL;
+ callback = client->th.callback;
+ client->th.callback = NULL;
+ client->last_activity = GNUNET_TIME_absolute_get ();
+ return callback (client->th.callback_cls, size, buf);
+}
+
+
+/**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param client client to transmit message to
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ * notify with buf NULL and size 0)?
+ * @param callback function to call when space is available
+ * @param callback_cls closure for @a callback
+ * @return non-NULL if the notify callback was queued; can be used
+ * to cancel the request using
+ * #GNUNET_SERVER_notify_transmit_ready_cancel().
+ * NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_SERVER_TransmitHandle *
+GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
+ size_t size,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_CONNECTION_TransmitReadyNotify callback,
+ void *callback_cls)
+{
+ if (NULL != client->th.callback)
+ return NULL;
+ client->th.callback_cls = callback_cls;
+ client->th.callback = callback;
+ client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
+ timeout,
+ &transmit_ready_callback_wrapper,
+ client);
+ return &client->th;
+}
+
+
+/**
+ * Abort transmission request.
+ *
+ * @param th request to abort
+ */
+void
+GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
+{
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
+ th->cth = NULL;
+ th->callback = NULL;
+}
+
+
+/**
+ * Set the persistent flag on this client, used to setup client connection
+ * to only be killed when the service it's connected to is actually dead.
+ *
+ * @param client the client to set the persistent flag on
+ */
+void
+GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
+{
+ client->persist = GNUNET_YES;
+}
+
+
+/**
+ * Resume receiving from this client, we are done processing the
+ * current request. This function must be called from within each
+ * GNUNET_SERVER_MessageCallback (or its respective continuations).
+ *
+ * @param client client we were processing a message of
+ * @param success #GNUNET_OK to keep the connection open and
+ * continue to receive
+ * #GNUNET_NO to close the connection (normal behavior)
+ * #GNUNET_SYSERR to close the connection (signal
+ * serious error)
+ */
+void
+GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
+ int success)
+{
+ if (NULL == client)
+ return;
+ GNUNET_assert (client->suspended > 0);
+ client->suspended--;
+ if (GNUNET_OK != success)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GNUNET_SERVER_receive_done called with failure indication\n");
+ if ( (client->reference_count > 0) || (client->suspended > 0) )
+ client->shutdown_now = GNUNET_YES;
+ else
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
+ if (client->suspended > 0)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GNUNET_SERVER_receive_done called, but more clients pending\n");
+ return;
+ }
+ if (NULL != client->warn_task)
+ {
+ GNUNET_SCHEDULER_cancel (client->warn_task);
+ client->warn_task = NULL;
+ }
+ if (GNUNET_YES == client->in_process_client_buffer)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GNUNET_SERVER_receive_done called while still in processing loop\n");
+ return;
+ }
+ if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
+ {
+ GNUNET_SERVER_client_disconnect (client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
+ GNUNET_assert (NULL == client->restart_task);
+ client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
+ client);
+}
+
+
+/* end of server.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2010 GNUnet e.V.
+
+ 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/server_mst.c
+ * @brief convenience functions for handling inbound message buffers
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+
+#if HAVE_UNALIGNED_64_ACCESS
+#define ALIGN_FACTOR 4
+#else
+#define ALIGN_FACTOR 8
+#endif
+
+
+/**
+ * Handle to a message stream tokenizer.
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer
+{
+
+ /**
+ * Function to call on completed messages.
+ */
+ GNUNET_SERVER_MessageTokenizerCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Size of the buffer (starting at @e hdr).
+ */
+ size_t curr_buf;
+
+ /**
+ * How many bytes in buffer have we already processed?
+ */
+ size_t off;
+
+ /**
+ * How many bytes in buffer are valid right now?
+ */
+ size_t pos;
+
+ /**
+ * Beginning of the buffer. Typed like this to force alignment.
+ */
+ struct GNUNET_MessageHeader *hdr;
+
+};
+
+
+
+/**
+ * Create a message stream tokenizer.
+ *
+ * @param cb function to call on completed messages
+ * @param cb_cls closure for @a cb
+ * @return handle to tokenizer
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer *
+GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
+ void *cb_cls)
+{
+ struct GNUNET_SERVER_MessageStreamTokenizer *ret;
+
+ ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
+ ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE);
+ ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE;
+ ret->cb = cb;
+ ret->cb_cls = cb_cls;
+ return ret;
+}
+
+
+/**
+ * Add incoming data to the receive buffer and call the
+ * callback for all complete messages.
+ *
+ * @param mst tokenizer to use
+ * @param client_identity ID of client for which this is a buffer
+ * @param buf input data to add
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
+ * (i.e. for packet-based services like UDP)
+ * @param one_shot only call callback once, keep rest of message in buffer
+ * @return #GNUNET_OK if we are done processing (need more data)
+ * #GNUNET_NO if @a one_shot was set and we have another message ready
+ * #GNUNET_SYSERR if the data stream is corrupt
+ */
+int
+GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
+ void *client_identity,
+ const char *buf, size_t size,
+ int purge, int one_shot)
+{
+ const struct GNUNET_MessageHeader *hdr;
+ size_t delta;
+ uint16_t want;
+ char *ibuf;
+ int need_align;
+ unsigned long offset;
+ int ret;
+
+ GNUNET_assert (mst->off <= mst->pos);
+ GNUNET_assert (mst->pos <= mst->curr_buf);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server-mst receives %u bytes with %u bytes already in private buffer\n",
+ (unsigned int) size, (unsigned int) (mst->pos - mst->off));
+ ret = GNUNET_OK;
+ ibuf = (char *) mst->hdr;
+ while (mst->pos > 0)
+ {
+do_align:
+ GNUNET_assert (mst->pos >= mst->off);
+ if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
+ (0 != (mst->off % ALIGN_FACTOR)))
+ {
+ /* need to align or need more space */
+ mst->pos -= mst->off;
+ memmove (ibuf, &ibuf[mst->off], mst->pos);
+ mst->off = 0;
+ }
+ if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+ {
+ delta =
+ GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
+ (mst->pos - mst->off), size);
+ GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
+ mst->pos += delta;
+ buf += delta;
+ size -= delta;
+ }
+ if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+ {
+ if (purge)
+ {
+ mst->off = 0;
+ mst->pos = 0;
+ }
+ return GNUNET_OK;
+ }
+ hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+ want = ntohs (hdr->size);
+ if (want < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (mst->curr_buf - mst->off < want) &&
+ (mst->off > 0) )
+ {
+ /* can get more space by moving */
+ mst->pos -= mst->off;
+ memmove (ibuf, &ibuf[mst->off], mst->pos);
+ mst->off = 0;
+ }
+ if (mst->curr_buf < want)
+ {
+ /* need to get more space by growing buffer */
+ GNUNET_assert (0 == mst->off);
+ mst->hdr = GNUNET_realloc (mst->hdr, want);
+ ibuf = (char *) mst->hdr;
+ mst->curr_buf = want;
+ }
+ hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+ if (mst->pos - mst->off < want)
+ {
+ delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
+ GNUNET_assert (mst->pos + delta <= mst->curr_buf);
+ GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
+ mst->pos += delta;
+ buf += delta;
+ size -= delta;
+ }
+ if (mst->pos - mst->off < want)
+ {
+ if (purge)
+ {
+ mst->off = 0;
+ mst->pos = 0;
+ }
+ return GNUNET_OK;
+ }
+ if (one_shot == GNUNET_SYSERR)
+ {
+ /* cannot call callback again, but return value saying that
+ * we have another full message in the buffer */
+ ret = GNUNET_NO;
+ goto copy;
+ }
+ if (one_shot == GNUNET_YES)
+ one_shot = GNUNET_SYSERR;
+ mst->off += want;
+ if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
+ return GNUNET_SYSERR;
+ if (mst->off == mst->pos)
+ {
+ /* reset to beginning of buffer, it's free right now! */
+ mst->off = 0;
+ mst->pos = 0;
+ }
+ }
+ GNUNET_assert (0 == mst->pos);
+ while (size > 0)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server-mst has %u bytes left in inbound buffer\n",
+ (unsigned int) size);
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ break;
+ offset = (unsigned long) buf;
+ need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
+ if (GNUNET_NO == need_align)
+ {
+ /* can try to do zero-copy and process directly from original buffer */
+ hdr = (const struct GNUNET_MessageHeader *) buf;
+ want = ntohs (hdr->size);
+ if (want < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ mst->off = 0;
+ return GNUNET_SYSERR;
+ }
+ if (size < want)
+ break; /* or not: buffer incomplete, so copy to private buffer... */
+ if (one_shot == GNUNET_SYSERR)
+ {
+ /* cannot call callback again, but return value saying that
+ * we have another full message in the buffer */
+ ret = GNUNET_NO;
+ goto copy;
+ }
+ if (one_shot == GNUNET_YES)
+ one_shot = GNUNET_SYSERR;
+ if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
+ return GNUNET_SYSERR;
+ buf += want;
+ size -= want;
+ }
+ else
+ {
+ /* need to copy to private buffer to align;
+ * yes, we go a bit more spagetti than usual here */
+ goto do_align;
+ }
+ }
+copy:
+ if ((size > 0) && (!purge))
+ {
+ if (size + mst->pos > mst->curr_buf)
+ {
+ mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
+ ibuf = (char *) mst->hdr;
+ mst->curr_buf = size + mst->pos;
+ }
+ GNUNET_assert (size + mst->pos <= mst->curr_buf);
+ GNUNET_memcpy (&ibuf[mst->pos], buf, size);
+ mst->pos += size;
+ }
+ if (purge)
+ {
+ mst->off = 0;
+ mst->pos = 0;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Server-mst leaves %u bytes in private buffer\n",
+ (unsigned int) (mst->pos - mst->off));
+ return ret;
+}
+
+
+/**
+ * Destroys a tokenizer.
+ *
+ * @param mst tokenizer to destroy
+ */
+void
+GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
+{
+ GNUNET_free (mst->hdr);
+ GNUNET_free (mst);
+}
+
+
+
+/* end of server_mst.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009, 2012 GNUnet e.V.
+
+ 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/service.c
+ * @brief functions related to starting services
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_constants.h"
+#include "gnunet_resolver_service.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+#include "gauger.h"
+#endif
+
+
+/* ******************* access control ******************** */
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param add the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+ const struct in_addr *add)
+{
+ unsigned int i;
+
+ if (NULL == list)
+ return GNUNET_NO;
+ i = 0;
+ while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
+ {
+ if ((add->s_addr & list[i].netmask.s_addr) ==
+ (list[i].network.s_addr & list[i].netmask.s_addr))
+ return GNUNET_YES;
+ i++;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param ip the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+ const struct in6_addr *ip)
+{
+ unsigned int i;
+ unsigned int j;
+ struct in6_addr zero;
+
+ if (NULL == list)
+ return GNUNET_NO;
+ memset (&zero, 0, sizeof (struct in6_addr));
+ i = 0;
+NEXT:
+ while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
+ {
+ for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
+ if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
+ (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
+ {
+ i++;
+ goto NEXT;
+ }
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/* ****************** service struct ****************** */
+
+
+/**
+ * Context for "service_task".
+ */
+struct GNUNET_SERVICE_Context
+{
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Handle for the server.
+ */
+ struct GNUNET_SERVER_Handle *server;
+
+ /**
+ * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
+ * listen sockets.
+ */
+ struct sockaddr **addrs;
+
+ /**
+ * Name of our service.
+ */
+ const char *service_name;
+
+ /**
+ * Main service-specific task to run.
+ */
+ GNUNET_SERVICE_Main task;
+
+ /**
+ * Closure for @e task.
+ */
+ void *task_cls;
+
+ /**
+ * IPv4 addresses that are not allowed to connect.
+ */
+ struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
+
+ /**
+ * IPv6 addresses that are not allowed to connect.
+ */
+ struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
+
+ /**
+ * IPv4 addresses that are allowed to connect (if not
+ * set, all are allowed).
+ */
+ struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
+
+ /**
+ * IPv6 addresses that are allowed to connect (if not
+ * set, all are allowed).
+ */
+ struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
+
+ /**
+ * My (default) message handlers. Adjusted copy
+ * of "defhandlers".
+ */
+ struct GNUNET_SERVER_MessageHandler *my_handlers;
+
+ /**
+ * Array of the lengths of the entries in addrs.
+ */
+ socklen_t *addrlens;
+
+ /**
+ * NULL-terminated array of listen sockets we should take over.
+ */
+ struct GNUNET_NETWORK_Handle **lsocks;
+
+ /**
+ * Task ID of the shutdown task.
+ */
+ struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+ /**
+ * Idle timeout for server.
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Overall success/failure of the service start.
+ */
+ int ret;
+
+ /**
+ * If we are daemonizing, this FD is set to the
+ * pipe to the parent. Send '.' if we started
+ * ok, '!' if not. -1 if we are not daemonizing.
+ */
+ int ready_confirm_fd;
+
+ /**
+ * Do we close connections if we receive messages
+ * for which we have no handler?
+ */
+ int require_found;
+
+ /**
+ * Do we require a matching UID for UNIX domain socket connections?
+ * #GNUNET_NO means that the UID does not have to match (however,
+ * @e match_gid may still impose other access control checks).
+ */
+ int match_uid;
+
+ /**
+ * Do we require a matching GID for UNIX domain socket connections?
+ * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
+ * checking that the client's UID is in our group OR that the
+ * client's GID is our GID. If both "match_gid" and @e match_uid are
+ * #GNUNET_NO, all users on the local system have access.
+ */
+ int match_gid;
+
+ /**
+ * Our options.
+ */
+ enum GNUNET_SERVICE_Options options;
+
+};
+
+
+/* ****************** message handlers ****************** */
+
+/**
+ * Send a 'TEST' message back to the client.
+ *
+ * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
+ * @param size number of bytes available in 'buf'
+ * @param buf where to copy the message
+ * @return number of bytes written to 'buf'
+ */
+static size_t
+write_test (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+ struct GNUNET_MessageHeader *msg;
+
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return 0; /* client disconnected */
+ }
+ msg = (struct GNUNET_MessageHeader *) buf;
+ msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
+ msg->size = htons (sizeof (struct GNUNET_MessageHeader));
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+/**
+ * Handler for TEST message.
+ *
+ * @param cls closure (refers to service)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_test (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ /* simply bounce message back to acknowledge */
+ if (NULL ==
+ GNUNET_SERVER_notify_transmit_ready (client,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &write_test, client))
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Default handlers for all services. Will be copied and the
+ * "callback_cls" fields will be replaced with the specific service
+ * struct.
+ */
+static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
+ {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
+ sizeof (struct GNUNET_MessageHeader)},
+ {NULL, NULL, 0, 0}
+};
+
+
+/* ****************** service core routines ************** */
+
+
+/**
+ * Check if access to the service is allowed from the given address.
+ *
+ * @param cls closure
+ * @param uc credentials, if available, otherwise NULL
+ * @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).
+ */
+static int
+check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ struct GNUNET_SERVICE_Context *sctx = cls;
+ const struct sockaddr_in *i4;
+ const struct sockaddr_in6 *i6;
+ int ret;
+
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+ i4 = (const struct sockaddr_in *) addr;
+ ret = ((NULL == sctx->v4_allowed) ||
+ (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
+ ((NULL == sctx->v4_denied) ||
+ (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
+ break;
+ case AF_INET6:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+ i6 = (const struct sockaddr_in6 *) addr;
+ ret = ((NULL == sctx->v6_allowed) ||
+ (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
+ ((NULL == sctx->v6_denied) ||
+ (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
+ break;
+#ifndef WINDOWS
+ case AF_UNIX:
+ ret = GNUNET_OK; /* controlled using file-system ACL now */
+ break;
+#endif
+ default:
+ LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
+ addr->sa_family);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != ret)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Access from `%s' denied to service `%s'\n"),
+ GNUNET_a2s (addr, addrlen),
+ sctx->service_name);
+ }
+ return ret;
+}
+
+
+/**
+ * Get the name of the file where we will
+ * write the PID of the service.
+ *
+ * @param sctx service context
+ * @return name of the file for the process ID
+ */
+static char *
+get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *pif;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+ "PIDFILE", &pif))
+ return NULL;
+ return pif;
+}
+
+
+/**
+ * Parse an IPv4 access control list.
+ *
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ * no ACL configured)
+ */
+static int
+process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
+ struct GNUNET_SERVICE_Context *sctx,
+ const char *option)
+{
+ char *opt;
+
+ if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+ {
+ *ret = NULL;
+ return GNUNET_OK;
+ }
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+ sctx->service_name,
+ option, &opt));
+ if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
+ opt, sctx->service_name, option);
+ GNUNET_free (opt);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (opt);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse an IPv6 access control list.
+ *
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ * no ACL configured)
+ */
+static int
+process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
+ struct GNUNET_SERVICE_Context *sctx,
+ const char *option)
+{
+ char *opt;
+
+ if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+ {
+ *ret = NULL;
+ return GNUNET_OK;
+ }
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+ sctx->service_name,
+ option, &opt));
+ if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
+ opt, sctx->service_name, option);
+ GNUNET_free (opt);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (opt);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Add the given UNIX domain path as an address to the
+ * list (as the first entry).
+ *
+ * @param saddrs array to update
+ * @param saddrlens where to store the address length
+ * @param unixpath path to add
+ * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
+ * parameter is ignore on systems other than LINUX
+ */
+static void
+add_unixpath (struct sockaddr **saddrs,
+ socklen_t *saddrlens,
+ const char *unixpath,
+ int abstract)
+{
+#ifdef AF_UNIX
+ struct sockaddr_un *un;
+
+ un = GNUNET_new (struct sockaddr_un);
+ un->sun_family = AF_UNIX;
+ strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+ if (GNUNET_YES == abstract)
+ un->sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_UN_SUN_LEN
+ un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+ *saddrs = (struct sockaddr *) un;
+ *saddrlens = sizeof (struct sockaddr_un);
+#else
+ /* this function should never be called
+ * unless AF_UNIX is defined! */
+ GNUNET_assert (0);
+#endif
+}
+
+
+/**
+ * Get the list of addresses that a server for the given service
+ * should bind to.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration (which specifies the addresses)
+ * @param addrs set (call by reference) to an array of pointers to the
+ * addresses the server should bind to and listen on; the
+ * array will be NULL-terminated (on success)
+ * @param addr_lens set (call by reference) to an array of the lengths
+ * of the respective `struct sockaddr` struct in the @a addrs
+ * array (on success)
+ * @return number of addresses found on success,
+ * #GNUNET_SYSERR if the configuration
+ * did not specify reasonable finding information or
+ * if it specified a hostname that could not be resolved;
+ * #GNUNET_NO if the number of addresses configured is
+ * zero (in this case, `*addrs` and `*addr_lens` will be
+ * set to NULL).
+ */
+int
+GNUNET_SERVICE_get_server_addresses (const char *service_name,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct sockaddr ***addrs,
+ socklen_t ** addr_lens)
+{
+ int disablev6;
+ struct GNUNET_NETWORK_Handle *desc;
+ unsigned long long port;
+ char *unixpath;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ struct addrinfo *pos;
+ struct addrinfo *next;
+ unsigned int i;
+ int resi;
+ int ret;
+ int abstract;
+ struct sockaddr **saddrs;
+ socklen_t *saddrlens;
+ char *hostname;
+
+ *addrs = NULL;
+ *addr_lens = NULL;
+ desc = NULL;
+ if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
+ {
+ if (GNUNET_SYSERR ==
+ (disablev6 =
+ GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
+ return GNUNET_SYSERR;
+ }
+ else
+ disablev6 = GNUNET_NO;
+
+ if (! disablev6)
+ {
+ /* probe IPv6 support */
+ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+ if (NULL == desc)
+ {
+ if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+ (EACCES == errno))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ return GNUNET_SYSERR;
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
+ service_name, STRERROR (errno));
+ disablev6 = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+ desc = NULL;
+ }
+ }
+
+ port = 0;
+ if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
+ "PORT", &port))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Require valid port number for service `%s' in configuration!\n"),
+ service_name);
+ }
+ if (port > 65535)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Require valid port number for service `%s' in configuration!\n"),
+ service_name);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
+ "BINDTO", &hostname));
+ }
+ else
+ hostname = NULL;
+
+ unixpath = NULL;
+ abstract = GNUNET_NO;
+#ifdef AF_UNIX
+ if ((GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
+ &unixpath)) &&
+ (0 < strlen (unixpath)))
+ {
+ /* probe UNIX support */
+ struct sockaddr_un s_un;
+
+ if (strlen (unixpath) >= sizeof (s_un.sun_path))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+ (unsigned long long) sizeof (s_un.sun_path));
+ unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Using `%s' instead\n"),
+ unixpath);
+ }
+#ifdef LINUX
+ abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ "TESTING",
+ "USE_ABSTRACT_SOCKETS");
+ if (GNUNET_SYSERR == abstract)
+ abstract = GNUNET_NO;
+#endif
+ if ((GNUNET_YES != abstract)
+ && (GNUNET_OK !=
+ GNUNET_DISK_directory_create_for_file (unixpath)))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "mkdir",
+ unixpath);
+ }
+ if (NULL != unixpath)
+ {
+ desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+ if (NULL == desc)
+ {
+ if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+ (EACCES == errno))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+ GNUNET_free_non_null (hostname);
+ GNUNET_free (unixpath);
+ return GNUNET_SYSERR;
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
+ service_name,
+ STRERROR (errno));
+ GNUNET_free (unixpath);
+ unixpath = NULL;
+ }
+ else
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+ desc = NULL;
+ }
+ }
+#endif
+
+ if ((0 == port) && (NULL == unixpath))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
+ service_name);
+ GNUNET_free_non_null (hostname);
+ return GNUNET_SYSERR;
+ }
+ if (0 == port)
+ {
+ saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ GNUNET_free_non_null (unixpath);
+ GNUNET_free_non_null (hostname);
+ *addrs = saddrs;
+ *addr_lens = saddrlens;
+ return 1;
+ }
+
+ if (NULL != hostname)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Resolving `%s' since that is where `%s' will bind to.\n",
+ hostname,
+ service_name);
+ memset (&hints, 0, sizeof (struct addrinfo));
+ if (disablev6)
+ hints.ai_family = AF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+ (NULL == res))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to resolve `%s': %s\n"),
+ hostname,
+ gai_strerror (ret));
+ GNUNET_free (hostname);
+ GNUNET_free_non_null (unixpath);
+ return GNUNET_SYSERR;
+ }
+ next = res;
+ i = 0;
+ while (NULL != (pos = next))
+ {
+ next = pos->ai_next;
+ if ((disablev6) && (pos->ai_family == AF_INET6))
+ continue;
+ i++;
+ }
+ if (0 == i)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to find %saddress for `%s'.\n"),
+ disablev6 ? "IPv4 " : "",
+ hostname);
+ freeaddrinfo (res);
+ GNUNET_free (hostname);
+ GNUNET_free_non_null (unixpath);
+ return GNUNET_SYSERR;
+ }
+ resi = i;
+ if (NULL != unixpath)
+ resi++;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ i = 0;
+ if (NULL != unixpath)
+ {
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ i++;
+ }
+ next = res;
+ while (NULL != (pos = next))
+ {
+ next = pos->ai_next;
+ if ((disablev6) && (AF_INET6 == pos->ai_family))
+ continue;
+ if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+ continue; /* not TCP */
+ if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+ continue; /* huh? */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
+ service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+ if (AF_INET == pos->ai_family)
+ {
+ GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
+ saddrlens[i] = pos->ai_addrlen;
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+ GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ else
+ {
+ GNUNET_assert (AF_INET6 == pos->ai_family);
+ GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
+ saddrlens[i] = pos->ai_addrlen;
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+ GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+ }
+ i++;
+ }
+ GNUNET_free (hostname);
+ freeaddrinfo (res);
+ resi = i;
+ }
+ else
+ {
+ /* will bind against everything, just set port */
+ if (disablev6)
+ {
+ /* V4-only */
+ resi = 1;
+ if (NULL != unixpath)
+ resi++;
+ i = 0;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ if (NULL != unixpath)
+ {
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ i++;
+ }
+ saddrlens[i] = sizeof (struct sockaddr_in);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
+#endif
+ ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ else
+ {
+ /* dual stack */
+ resi = 2;
+ if (NULL != unixpath)
+ resi++;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ i = 0;
+ if (NULL != unixpath)
+ {
+ add_unixpath (saddrs, saddrlens, unixpath, abstract);
+ i++;
+ }
+ saddrlens[i] = sizeof (struct sockaddr_in6);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
+#endif
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+ i++;
+ saddrlens[i] = sizeof (struct sockaddr_in);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
+#endif
+ ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ }
+ GNUNET_free_non_null (unixpath);
+ *addrs = saddrs;
+ *addr_lens = saddrlens;
+ return resi;
+}
+
+
+#ifdef MINGW
+/**
+ * Read listen sockets from the parent process (ARM).
+ *
+ * @param sctx service context to initialize
+ * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
+ * and #GNUNET_SYSERR on error.
+ */
+static int
+receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
+{
+ const char *env_buf;
+ int fail;
+ uint64_t count;
+ uint64_t i;
+ HANDLE lsocks_pipe;
+
+ env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
+ if ((NULL == env_buf) || (strlen (env_buf) <= 0))
+ return GNUNET_NO;
+ /* Using W32 API directly here, because this pipe will
+ * never be used outside of this function, and it's just too much of a bother
+ * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
+ */
+ lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
+ if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
+ return GNUNET_NO;
+ fail = 1;
+ do
+ {
+ int ret;
+ int fail2;
+ DWORD rd;
+
+ ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
+ if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
+ break;
+ sctx->lsocks =
+ GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+
+ fail2 = 1;
+ for (i = 0; i < count; i++)
+ {
+ WSAPROTOCOL_INFOA pi;
+ uint64_t size;
+ SOCKET s;
+
+ ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
+ if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
+ break;
+ ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
+ if ( (0 == ret) || (sizeof (pi) != rd))
+ break;
+ s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
+ sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+ if (NULL == sctx->lsocks[i])
+ break;
+ else if (i == count - 1)
+ fail2 = 0;
+ }
+ if (fail2)
+ break;
+ sctx->lsocks[count] = NULL;
+ fail = 0;
+ }
+ while (fail);
+
+ CloseHandle (lsocks_pipe);
+
+ if (fail)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access a pre-bound socket, will try to bind myself\n"));
+ for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
+ GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
+ GNUNET_free_non_null (sctx->lsocks);
+ sctx->lsocks = NULL;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+#endif
+
+
+/**
+ * Setup addr, addrlen, idle_timeout
+ * based on configuration!
+ *
+ * Configuration may specify:
+ * - PORT (where to bind to for TCP)
+ * - UNIXPATH (where to bind to for UNIX domain sockets)
+ * - TIMEOUT (after how many ms does an inactive service timeout);
+ * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
+ * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
+ * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
+ * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
+ * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
+ * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
+ *
+ * @param sctx service context to initialize
+ * @return #GNUNET_OK if configuration succeeded
+ */
+static int
+setup_service (struct GNUNET_SERVICE_Context *sctx)
+{
+ struct GNUNET_TIME_Relative idleout;
+ int tolerant;
+
+#ifndef MINGW
+ const char *nfds;
+ unsigned int cnt;
+ int flags;
+#endif
+
+ if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
+ "TIMEOUT", &idleout))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Specified value for `%s' of service `%s' is invalid\n"),
+ "TIMEOUT", sctx->service_name);
+ return GNUNET_SYSERR;
+ }
+ sctx->timeout = idleout;
+ }
+ else
+ sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+
+ if (GNUNET_CONFIGURATION_have_value
+ (sctx->cfg, sctx->service_name, "TOLERANT"))
+ {
+ if (GNUNET_SYSERR ==
+ (tolerant =
+ GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+ "TOLERANT")))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Specified value for `%s' of service `%s' is invalid\n"),
+ "TOLERANT", sctx->service_name);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ tolerant = GNUNET_NO;
+
+#ifndef MINGW
+ errno = 0;
+ if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+ (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
+ (cnt + 4 < FD_SETSIZE))
+ {
+ sctx->lsocks =
+ GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
+ while (0 < cnt--)
+ {
+ flags = fcntl (3 + cnt, F_GETFD);
+ if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
+ (NULL ==
+ (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _
+ ("Could not access pre-bound socket %u, will try to bind myself\n"),
+ (unsigned int) 3 + cnt);
+ cnt++;
+ while (sctx->lsocks[cnt] != NULL)
+ GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
+ GNUNET_free (sctx->lsocks);
+ sctx->lsocks = NULL;
+ break;
+ }
+ }
+ unsetenv ("LISTEN_FDS");
+ }
+#else
+ if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+ {
+ receive_sockets_from_parent (sctx);
+ putenv ("GNUNET_OS_READ_LSOCKS=");
+ }
+#endif
+
+ if ((NULL == sctx->lsocks) &&
+ (GNUNET_SYSERR ==
+ GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
+ &sctx->addrs, &sctx->addrlens)))
+ return GNUNET_SYSERR;
+ sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
+ sctx->match_uid =
+ GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+ "UNIX_MATCH_UID");
+ sctx->match_gid =
+ GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+ "UNIX_MATCH_GID");
+ process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
+ process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
+ process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
+ process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Get the name of the user that'll be used
+ * to provide the service.
+ *
+ * @param sctx service context
+ * @return value of the 'USERNAME' option
+ */
+static char *
+get_user_name (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *un;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+ "USERNAME", &un))
+ return NULL;
+ return un;
+}
+
+
+/**
+ * Write PID file.
+ *
+ * @param sctx service context
+ * @param pid PID to write (should be equal to 'getpid()'
+ * @return #GNUNET_OK on success (including no work to be done)
+ */
+static int
+write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
+{
+ FILE *pidfd;
+ char *pif;
+ char *user;
+ char *rdir;
+ int len;
+
+ if (NULL == (pif = get_pid_file_name (sctx)))
+ return GNUNET_OK; /* no file desired */
+ user = get_user_name (sctx);
+ rdir = GNUNET_strdup (pif);
+ len = strlen (rdir);
+ while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
+ len--;
+ rdir[len] = '\0';
+ if (0 != ACCESS (rdir, F_OK))
+ {
+ /* we get to create a directory -- and claim it
+ * as ours! */
+ (void) GNUNET_DISK_directory_create (rdir);
+ if ((NULL != user) && (0 < strlen (user)))
+ GNUNET_DISK_file_change_owner (rdir, user);
+ }
+ if (0 != ACCESS (rdir, W_OK | X_OK))
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
+ GNUNET_free (rdir);
+ GNUNET_free_non_null (user);
+ GNUNET_free (pif);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (rdir);
+ pidfd = FOPEN (pif, "w");
+ if (NULL == pidfd)
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
+ GNUNET_free (pif);
+ GNUNET_free_non_null (user);
+ return GNUNET_SYSERR;
+ }
+ if (0 > FPRINTF (pidfd, "%u", pid))
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
+ GNUNET_break (0 == FCLOSE (pidfd));
+ if ((NULL != user) && (0 < strlen (user)))
+ GNUNET_DISK_file_change_owner (pif, user);
+ GNUNET_free_non_null (user);
+ GNUNET_free (pif);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Task run during shutdown. Stops the server/service.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Context`
+ */
+static void
+shutdown_task (void *cls)
+{
+ struct GNUNET_SERVICE_Context *service = cls;
+ struct GNUNET_SERVER_Handle *server = service->server;
+
+ service->shutdown_task = NULL;
+ if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
+ GNUNET_SERVER_stop_listening (server);
+ else
+ GNUNET_SERVER_destroy (server);
+}
+
+
+/**
+ * Initial task for the service.
+ *
+ * @param cls service context
+ */
+static void
+service_task (void *cls)
+{
+ struct GNUNET_SERVICE_Context *sctx = cls;
+ unsigned int i;
+
+ GNUNET_RESOLVER_connect (sctx->cfg);
+ if (NULL != sctx->lsocks)
+ sctx->server
+ = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+ sctx->timeout, sctx->require_found);
+ else
+ sctx->server
+ = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+ sctx->timeout, sctx->require_found);
+ if (NULL == sctx->server)
+ {
+ if (NULL != sctx->addrs)
+ for (i = 0; NULL != sctx->addrs[i]; i++)
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Failed to start `%s' at `%s'\n"),
+ sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+ sctx->ret = GNUNET_SYSERR;
+ return;
+ }
+#ifndef WINDOWS
+ if (NULL != sctx->addrs)
+ for (i = 0; NULL != sctx->addrs[i]; i++)
+ if ((AF_UNIX == sctx->addrs[i]->sa_family)
+ && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
+ GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
+ sctx->match_uid,
+ sctx->match_gid);
+#endif
+
+
+ if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
+ {
+ /* install a task that will kill the server
+ * process if the scheduler ever gets a shutdown signal */
+ sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ sctx);
+ }
+ sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+ GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+ i = 0;
+ while (NULL != sctx->my_handlers[i].callback)
+ sctx->my_handlers[i++].callback_cls = sctx;
+ GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+ if (-1 != sctx->ready_confirm_fd)
+ {
+ GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
+ GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
+ sctx->ready_confirm_fd = -1;
+ write_pid_file (sctx, getpid ());
+ }
+ if (NULL != sctx->addrs)
+ {
+ i = 0;
+ while (NULL != sctx->addrs[i])
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
+ sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+ i++;
+ }
+ }
+ sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
+}
+
+
+/**
+ * Detach from terminal.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+detach_terminal (struct GNUNET_SERVICE_Context *sctx)
+{
+#ifndef MINGW
+ pid_t pid;
+ int nullfd;
+ int filedes[2];
+
+ if (0 != PIPE (filedes))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
+ return GNUNET_SYSERR;
+ }
+ pid = fork ();
+ if (pid < 0)
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
+ return GNUNET_SYSERR;
+ }
+ if (0 != pid)
+ {
+ /* Parent */
+ char c;
+
+ GNUNET_break (0 == CLOSE (filedes[1]));
+ c = 'X';
+ if (1 != READ (filedes[0], &c, sizeof (char)))
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
+ fflush (stdout);
+ switch (c)
+ {
+ case '.':
+ exit (0);
+ case 'I':
+ LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
+ break;
+ case 'S':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process could not initialize server function\n"));
+ break;
+ case 'X':
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Service process failed to report status\n"));
+ break;
+ }
+ exit (1); /* child reported error */
+ }
+ GNUNET_break (0 == CLOSE (0));
+ GNUNET_break (0 == CLOSE (1));
+ GNUNET_break (0 == CLOSE (filedes[0]));
+ nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
+ if (nullfd < 0)
+ return GNUNET_SYSERR;
+ /* set stdin/stdout to /dev/null */
+ if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
+ {
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+ (void) CLOSE (nullfd);
+ return GNUNET_SYSERR;
+ }
+ (void) CLOSE (nullfd);
+ /* Detach from controlling terminal */
+ pid = setsid ();
+ if (-1 == pid)
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
+ sctx->ready_confirm_fd = filedes[1];
+#else
+ /* FIXME: we probably need to do something else
+ * elsewhere in order to fork the process itself... */
+ FreeConsole ();
+#endif
+ return GNUNET_OK;
+}
+
+
+/**
+ * Set user ID.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+set_user_id (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *user;
+
+ if (NULL == (user = get_user_name (sctx)))
+ return GNUNET_OK; /* keep */
+#ifndef MINGW
+ struct passwd *pws;
+
+ errno = 0;
+ pws = getpwnam (user);
+ if (NULL == pws)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Cannot obtain information about user `%s': %s\n"), user,
+ errno == 0 ? _("No such user") : STRERROR (errno));
+ GNUNET_free (user);
+ return GNUNET_SYSERR;
+ }
+ if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
+#if HAVE_INITGROUPS
+ (0 != initgroups (user, pws->pw_gid)) ||
+#endif
+ (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
+ {
+ if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
+ (0 != setreuid (pws->pw_uid, pws->pw_uid)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
+ user, STRERROR (errno));
+ GNUNET_free (user);
+ return GNUNET_SYSERR;
+ }
+ }
+#endif
+ GNUNET_free (user);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Delete the PID file that was created by our parent.
+ *
+ * @param sctx service context
+ */
+static void
+pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
+{
+ char *pif = get_pid_file_name (sctx);
+
+ if (NULL == pif)
+ return; /* no PID file */
+ if (0 != UNLINK (pif))
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
+ GNUNET_free (pif);
+}
+
+
+/**
+ * Run a standard GNUnet service startup sequence (initialize loggers
+ * and configuration, parse options).
+ *
+ * @param argc number of command line arguments
+ * @param argv command line arguments
+ * @param service_name our service name
+ * @param options service options
+ * @param task main task of the service
+ * @param task_cls closure for @a task
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK
+ * if we shutdown nicely
+ */
+int
+GNUNET_SERVICE_run (int argc, char *const *argv,
+ const char *service_name,
+ enum GNUNET_SERVICE_Options options,
+ GNUNET_SERVICE_Main task,
+ void *task_cls)
+{
+#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
+
+ int err;
+ int ret;
+ char *cfg_fn;
+ char *opt_cfg_fn;
+ char *loglev;
+ char *logfile;
+ int do_daemonize;
+ unsigned int i;
+ unsigned long long skew_offset;
+ unsigned long long skew_variance;
+ long long clock_offset;
+ struct GNUNET_SERVICE_Context sctx;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ const char *xdg;
+
+ struct GNUNET_GETOPT_CommandLineOption service_options[] = {
+ GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
+ {'d', "daemonize", NULL,
+ gettext_noop ("do daemonize (detach from terminal)"), 0,
+ GNUNET_GETOPT_set_one, &do_daemonize},
+ GNUNET_GETOPT_OPTION_HELP (NULL),
+ GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
+ GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
+ GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ err = 1;
+ do_daemonize = 0;
+ logfile = NULL;
+ loglev = NULL;
+ opt_cfg_fn = NULL;
+ xdg = getenv ("XDG_CONFIG_HOME");
+ if (NULL != xdg)
+ GNUNET_asprintf (&cfg_fn,
+ "%s%s%s",
+ xdg,
+ DIR_SEPARATOR_STR,
+ GNUNET_OS_project_data_get ()->config_file);
+ else
+ cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
+ memset (&sctx, 0, sizeof (sctx));
+ sctx.options = options;
+ sctx.ready_confirm_fd = -1;
+ sctx.ret = GNUNET_OK;
+ sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ sctx.task = task;
+ sctx.task_cls = task_cls;
+ sctx.service_name = service_name;
+ sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
+
+ /* setup subsystems */
+ ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+ if (GNUNET_SYSERR == ret)
+ goto shutdown;
+ if (GNUNET_NO == ret)
+ {
+ err = 0;
+ goto shutdown;
+ }
+ if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
+ HANDLE_ERROR;
+ if (NULL == opt_cfg_fn)
+ opt_cfg_fn = GNUNET_strdup (cfg_fn);
+ if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
+ {
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration file `%s', exit ...\n"),
+ opt_cfg_fn);
+ goto shutdown;
+ }
+ }
+ else
+ {
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed configuration, exit ...\n"));
+ goto shutdown;
+ }
+ if (0 != strcmp (opt_cfg_fn, cfg_fn))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access configuration file `%s'\n"),
+ opt_cfg_fn);
+ }
+ if (GNUNET_OK != setup_service (&sctx))
+ goto shutdown;
+ if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
+ HANDLE_ERROR;
+ if (GNUNET_OK != set_user_id (&sctx))
+ goto shutdown;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Service `%s' runs with configuration from `%s'\n",
+ service_name,
+ opt_cfg_fn);
+ if ((GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+ "SKEW_OFFSET", &skew_offset)) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+ "SKEW_VARIANCE", &skew_variance)))
+ {
+ clock_offset = skew_offset - skew_variance;
+ GNUNET_TIME_set_offset (clock_offset);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
+ }
+ /* actually run service */
+ err = 0;
+ GNUNET_SCHEDULER_run (&service_task, &sctx);
+ /* shutdown */
+ if ((1 == do_daemonize) && (NULL != sctx.server))
+ pid_file_delete (&sctx);
+ GNUNET_free_non_null (sctx.my_handlers);
+
+shutdown:
+ if (-1 != sctx.ready_confirm_fd)
+ {
+ if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
+ GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
+ }
+#if HAVE_MALLINFO
+ {
+ char *counter;
+
+ if ( (GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
+ "GAUGER_HEAP")) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
+ "GAUGER_HEAP",
+ &counter)) )
+ {
+ struct mallinfo mi;
+
+ mi = mallinfo ();
+ GAUGER (service_name, counter, mi.usmblks, "blocks");
+ GNUNET_free (counter);
+ }
+ }
+#endif
+ GNUNET_CONFIGURATION_destroy (cfg);
+ i = 0;
+ if (NULL != sctx.addrs)
+ while (NULL != sctx.addrs[i])
+ GNUNET_free (sctx.addrs[i++]);
+ GNUNET_free_non_null (sctx.addrs);
+ GNUNET_free_non_null (sctx.addrlens);
+ GNUNET_free_non_null (logfile);
+ GNUNET_free_non_null (loglev);
+ GNUNET_free (cfg_fn);
+ GNUNET_free_non_null (opt_cfg_fn);
+ GNUNET_free_non_null (sctx.v4_denied);
+ GNUNET_free_non_null (sctx.v6_denied);
+ GNUNET_free_non_null (sctx.v4_allowed);
+ GNUNET_free_non_null (sctx.v6_allowed);
+
+ return err ? GNUNET_SYSERR : sctx.ret;
+}
+
+
+/**
+ * Run a service startup sequence within an existing
+ * initialized system.
+ *
+ * @param service_name our service name
+ * @param cfg configuration to use
+ * @param options service options
+ * @return NULL on error, service handle
+ */
+struct GNUNET_SERVICE_Context *
+GNUNET_SERVICE_start (const char *service_name,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ enum GNUNET_SERVICE_Options options)
+{
+ int i;
+ struct GNUNET_SERVICE_Context *sctx;
+
+ sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
+ sctx->ready_confirm_fd = -1; /* no daemonizing */
+ sctx->ret = GNUNET_OK;
+ sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ sctx->service_name = service_name;
+ sctx->cfg = cfg;
+ sctx->options = options;
+
+ /* setup subsystems */
+ if (GNUNET_OK != setup_service (sctx))
+ {
+ GNUNET_SERVICE_stop (sctx);
+ return NULL;
+ }
+ if (NULL != sctx->lsocks)
+ sctx->server =
+ GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+ sctx->timeout, sctx->require_found);
+ else
+ sctx->server =
+ GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+ sctx->timeout, sctx->require_found);
+
+ if (NULL == sctx->server)
+ {
+ GNUNET_SERVICE_stop (sctx);
+ return NULL;
+ }
+#ifndef WINDOWS
+ if (NULL != sctx->addrs)
+ for (i = 0; NULL != sctx->addrs[i]; i++)
+ if ((AF_UNIX == sctx->addrs[i]->sa_family)
+ && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
+ GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
+ sctx->match_uid,
+ sctx->match_gid);
+#endif
+ sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+ GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+ i = 0;
+ while ((sctx->my_handlers[i].callback != NULL))
+ sctx->my_handlers[i++].callback_cls = sctx;
+ GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+ return sctx;
+}
+
+
+/**
+ * Obtain the server used by a service. Note that the server must NOT
+ * be destroyed by the caller.
+ *
+ * @param ctx the service context returned from the start function
+ * @return handle to the server for this service, NULL if there is none
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
+{
+ return ctx->server;
+}
+
+
+/**
+ * Get the NULL-terminated array of listen sockets for this service.
+ *
+ * @param ctx service context to query
+ * @return NULL if there are no listen sockets, otherwise NULL-terminated
+ * array of listen sockets.
+ */
+struct GNUNET_NETWORK_Handle *const*
+GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
+{
+ return ctx->lsocks;
+}
+
+
+/**
+ * Stop a service that was started with "GNUNET_SERVICE_start".
+ *
+ * @param sctx the service context returned from the start function
+ */
+void
+GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
+{
+ unsigned int i;
+
+#if HAVE_MALLINFO
+ {
+ char *counter;
+
+ if ( (GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
+ "GAUGER_HEAP")) &&
+ (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
+ "GAUGER_HEAP",
+ &counter)) )
+ {
+ struct mallinfo mi;
+
+ mi = mallinfo ();
+ GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
+ GNUNET_free (counter);
+ }
+ }
+#endif
+ if (NULL != sctx->shutdown_task)
+ {
+ GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
+ sctx->shutdown_task = NULL;
+ }
+ if (NULL != sctx->server)
+ GNUNET_SERVER_destroy (sctx->server);
+ GNUNET_free_non_null (sctx->my_handlers);
+ if (NULL != sctx->addrs)
+ {
+ i = 0;
+ while (NULL != sctx->addrs[i])
+ GNUNET_free (sctx->addrs[i++]);
+ GNUNET_free (sctx->addrs);
+ }
+ GNUNET_free_non_null (sctx->addrlens);
+ GNUNET_free_non_null (sctx->v4_denied);
+ GNUNET_free_non_null (sctx->v6_denied);
+ GNUNET_free_non_null (sctx->v4_allowed);
+ GNUNET_free_non_null (sctx->v6_allowed);
+ GNUNET_free (sctx);
+}
+
+
+/* end of service.c */
static int
-handle_helper_message (void *cls, void *client,
+handle_helper_message (void *cls,
const struct GNUNET_MessageHeader *hdr)
{
return GNUNET_OK;
common_logging.c \
configuration.c \
configuration_loader.c \
- connection.c \
container_bloomfilter.c \
container_heap.c \
container_meta_data.c \
program.c \
resolver_api.c resolver.h \
scheduler.c \
- server.c \
- server_mst.c \
- server_nc.c \
- server_tc.c \
- service.c \
service_new.c \
signal.c \
strings.c \
time.c \
- socks.c \
speedup.c speedup.h
libgnunetutil_la_LIBADD = \
endif
if HAVE_SSH_KEY
- SSH_USING_TESTS = test_socks.nc
+# SSH_USING_TESTS = test_socks.nc
endif
check_PROGRAMS = \
test_bio \
test_client.nc \
$(TEST_CLIENT_UNIX_NC) \
- $(SSH_USING_TESTS) \
test_common_allocation \
test_common_endian \
test_common_logging \
test_crypto_rsa \
test_disk \
test_getopt \
- test_connection.nc \
- test_connection_addressing.nc \
- test_connection_receive_cancel.nc \
- test_connection_timeout.nc \
- test_connection_timeout_no_connect.nc \
- test_connection_transmit_cancel.nc \
test_mq \
test_os_network \
test_peer \
test_resolver_api.nc \
test_scheduler \
test_scheduler_delay \
- test_server.nc \
- test_server_disconnect.nc \
- test_server_with_client.nc \
- test_server_mst_interrupt.nc \
- $(SERVER_CLIENT_UNIX) \
test_service \
test_strings \
test_strings_to_data \
test_connection_receive_cancel.log: test_connection_transmit_cancel.log
test_connection_timeout.log: test_connection_receive_cancel.log
test_resolver_api.log: test_connection_timeout.log
-test_server.log: test_resolver_api.log
-test_server_disconnect.log: test_server.log
-test_server_with_client.log: test_server_disconnect.log
-test_server_mst_interrupt.log: test_server_with_client.log
-test_client_unix.log: test_server_mst_interrupt.log
test_bio_SOURCES = \
test_bio.c
test_getopt_LDADD = \
libgnunetutil.la
-test_connection_nc_SOURCES = \
- test_connection.c
-test_connection_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_addressing_nc_SOURCES = \
- test_connection_addressing.c
-test_connection_addressing_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_receive_cancel_nc_SOURCES = \
- test_connection_receive_cancel.c
-test_connection_receive_cancel_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_timeout_nc_SOURCES = \
- test_connection_timeout.c
-test_connection_timeout_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_timeout_no_connect_nc_SOURCES = \
- test_connection_timeout_no_connect.c
-test_connection_timeout_no_connect_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_transmit_cancel_nc_SOURCES = \
- test_connection_transmit_cancel.c
-test_connection_transmit_cancel_nc_LDADD = \
- libgnunetutil.la
-
test_mq_SOURCES = \
test_mq.c
test_mq_LDADD = \
test_scheduler_delay_LDADD = \
libgnunetutil.la
-test_server_mst_interrupt_nc_SOURCES = \
- test_server_mst_interrupt.c
-test_server_mst_interrupt_nc_LDADD = \
- libgnunetutil.la
-
-test_server_nc_SOURCES = \
- test_server.c
-test_server_nc_LDADD = \
- libgnunetutil.la
-
-test_server_disconnect_nc_SOURCES = \
- test_server_disconnect.c
-test_server_disconnect_nc_LDADD = \
- libgnunetutil.la
-
-test_server_with_client_nc_SOURCES = \
- test_server_with_client.c
-test_server_with_client_nc_LDADD = \
- libgnunetutil.la
-
-test_server_with_client_unix_SOURCES = \
- test_server_with_client_unix.c
-test_server_with_client_unix_LDADD = \
- libgnunetutil.la
-
-
test_service_SOURCES = \
test_service.c
test_service_LDADD = \
test_strings_LDADD = \
libgnunetutil.la
-
test_strings_to_data_SOURCES = \
test_strings_to_data.c
test_strings_to_data_LDADD = \
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009-2013 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/connection.c
- * @brief TCP connection management
- * @author Christian Grothoff
- *
- * This code is rather complex. Only modify it if you
- * 1) Have a NEW testcase showing that the new code
- * is needed and correct
- * 2) All EXISTING testcases pass with the new code
- * These rules should apply in general, but for this
- * module they are VERY, VERY important.
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_resolver_service.h"
-
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-connection", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
-
-
-/**
- * Transmission handle. There can only be one for each connection.
- */
-struct GNUNET_CONNECTION_TransmitHandle
-{
-
- /**
- * Function to call if the send buffer has notify_size
- * bytes available.
- */
- GNUNET_CONNECTION_TransmitReadyNotify notify_ready;
-
- /**
- * Closure for notify_ready.
- */
- void *notify_ready_cls;
-
- /**
- * Our connection handle.
- */
- struct GNUNET_CONNECTION_Handle *connection;
-
- /**
- * Timeout for receiving (in absolute time).
- */
- struct GNUNET_TIME_Absolute transmit_timeout;
-
- /**
- * Task called on timeout.
- */
- struct GNUNET_SCHEDULER_Task * timeout_task;
-
- /**
- * At what number of bytes available in the
- * write buffer should the notify method be called?
- */
- size_t notify_size;
-
-};
-
-
-/**
- * During connect, we try multiple possible IP addresses
- * to find out which one might work.
- */
-struct AddressProbe
-{
-
- /**
- * This is a linked list.
- */
- struct AddressProbe *next;
-
- /**
- * This is a doubly-linked list.
- */
- struct AddressProbe *prev;
-
- /**
- * The address; do not free (allocated at the end of this struct).
- */
- const struct sockaddr *addr;
-
- /**
- * Underlying OS's socket.
- */
- struct GNUNET_NETWORK_Handle *sock;
-
- /**
- * Connection for which we are probing.
- */
- struct GNUNET_CONNECTION_Handle *connection;
-
- /**
- * Lenth of addr.
- */
- socklen_t addrlen;
-
- /**
- * Task waiting for the connection to finish connecting.
- */
- struct GNUNET_SCHEDULER_Task * task;
-};
-
-
-/**
- * @brief handle for a network connection
- */
-struct GNUNET_CONNECTION_Handle
-{
-
- /**
- * Configuration to use.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Linked list of sockets we are currently trying out
- * (during connect).
- */
- struct AddressProbe *ap_head;
-
- /**
- * Linked list of sockets we are currently trying out
- * (during connect).
- */
- struct AddressProbe *ap_tail;
-
- /**
- * Network address of the other end-point, may be NULL.
- */
- struct sockaddr *addr;
-
- /**
- * Pointer to the hostname if connection was
- * created using DNS lookup, otherwise NULL.
- */
- char *hostname;
-
- /**
- * Underlying OS's socket, set to NULL after fatal errors.
- */
- struct GNUNET_NETWORK_Handle *sock;
-
- /**
- * Function to call on data received, NULL if no receive is pending.
- */
- GNUNET_CONNECTION_Receiver receiver;
-
- /**
- * Closure for @e receiver.
- */
- void *receiver_cls;
-
- /**
- * Pointer to our write buffer.
- */
- char *write_buffer;
-
- /**
- * Current size of our @e write_buffer.
- */
- size_t write_buffer_size;
-
- /**
- * Current write-offset in @e write_buffer (where
- * would we write next).
- */
- size_t write_buffer_off;
-
- /**
- * Current read-offset in @e write_buffer (how many
- * bytes have already been sent).
- */
- size_t write_buffer_pos;
-
- /**
- * Length of @e addr.
- */
- socklen_t addrlen;
-
- /**
- * Read task that we may need to wait for.
- */
- struct GNUNET_SCHEDULER_Task *read_task;
-
- /**
- * Write task that we may need to wait for.
- */
- struct GNUNET_SCHEDULER_Task *write_task;
-
- /**
- * Handle to a pending DNS lookup request.
- */
- struct GNUNET_RESOLVER_RequestHandle *dns_active;
-
- /**
- * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready().
- */
- struct GNUNET_CONNECTION_TransmitHandle nth;
-
- /**
- * Timeout for receiving (in absolute time).
- */
- struct GNUNET_TIME_Absolute receive_timeout;
-
- /**
- * Maximum number of bytes to read (for receiving).
- */
- size_t max;
-
- /**
- * Port to connect to.
- */
- uint16_t port;
-
- /**
- * When shutdown, do not ever actually close the socket, but
- * free resources. Only should ever be set if using program
- * termination as a signal (because only then will the leaked
- * socket be freed!)
- */
- int8_t persist;
-
- /**
- * Usually 0. Set to 1 if this handle is in use, and should
- * #GNUNET_CONNECTION_destroy() be called right now, the action needs
- * to be deferred by setting it to -1.
- */
- int8_t destroy_later;
-
- /**
- * Handle to subsequent connection after proxy handshake completes,
- */
- struct GNUNET_CONNECTION_Handle *proxy_handshake;
-
-};
-
-
-/**
- * Set the persist option on this connection handle. Indicates
- * that the underlying socket or fd should never really be closed.
- * Used for indicating process death.
- *
- * @param connection the connection to set persistent
- */
-void
-GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
-{
- connection->persist = GNUNET_YES;
-}
-
-
-/**
- * Disable the "CORK" feature for communication with the given connection,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages. Essentially
- * reduces the OS send buffers to zero.
- * Used to make sure that the last messages sent through the connection
- * reach the other side before the process is terminated.
- *
- * @param connection the connection to make flushing and blocking
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
-{
- return GNUNET_NETWORK_socket_disable_corking (connection->sock);
-}
-
-
-/**
- * Create a connection handle by boxing an existing OS socket. The OS
- * socket should henceforth be no longer used directly.
- * #GNUNET_connection_destroy() will close it.
- *
- * @param osSocket existing socket to box
- * @return the boxed connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
-{
- struct GNUNET_CONNECTION_Handle *connection;
-
- connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
- connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
- connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
- connection->sock = osSocket;
- return connection;
-}
-
-
-/**
- * Create a connection handle by accepting on a listen socket. This
- * function may block if the listen socket has no connection ready.
- *
- * @param access_cb function to use to check if access is allowed
- * @param access_cb_cls closure for @a access_cb
- * @param lsock listen socket
- * @return the connection handle, NULL on error
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
- void *access_cb_cls,
- struct GNUNET_NETWORK_Handle *lsock)
-{
- struct GNUNET_CONNECTION_Handle *connection;
- char addr[128];
- socklen_t addrlen;
- struct GNUNET_NETWORK_Handle *sock;
- int aret;
- struct sockaddr_in *v4;
- struct sockaddr_in6 *v6;
- struct sockaddr *sa;
- void *uaddr;
-#ifdef SO_PEERCRED
- struct ucred uc;
- socklen_t olen;
-#endif
- struct GNUNET_CONNECTION_Credentials *gcp;
-#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
- struct GNUNET_CONNECTION_Credentials gc;
-
- gc.uid = 0;
- gc.gid = 0;
-#endif
-
- addrlen = sizeof (addr);
- sock =
- GNUNET_NETWORK_socket_accept (lsock,
- (struct sockaddr *) &addr,
- &addrlen);
- if (NULL == sock)
- {
- if (EAGAIN != errno)
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
- return NULL;
- }
- if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
- {
- GNUNET_break (0);
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
- return NULL;
- }
-
- sa = (struct sockaddr *) addr;
- v6 = (struct sockaddr_in6 *) addr;
- if ( (AF_INET6 == sa->sa_family) &&
- (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) )
- {
- /* convert to V4 address */
- v4 = GNUNET_new (struct sockaddr_in);
- memset (v4, 0, sizeof (struct sockaddr_in));
- v4->sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
- v4->sin_len = (u_char) sizeof (struct sockaddr_in);
-#endif
- GNUNET_memcpy (&v4->sin_addr,
- &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
- sizeof (struct in_addr)],
- sizeof (struct in_addr));
- v4->sin_port = v6->sin6_port;
- uaddr = v4;
- addrlen = sizeof (struct sockaddr_in);
- }
- else
- {
- uaddr = GNUNET_malloc (addrlen);
- GNUNET_memcpy (uaddr, addr, addrlen);
- }
- gcp = NULL;
- if (AF_UNIX == sa->sa_family)
- {
-#if HAVE_GETPEEREID
- /* most BSDs */
- if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock),
- &gc.uid,
- &gc.gid))
- gcp = &gc;
-#else
-#ifdef SO_PEERCRED
- /* largely traditional GNU/Linux */
- olen = sizeof (uc);
- if ( (0 ==
- getsockopt (GNUNET_NETWORK_get_fd (sock),
- SOL_SOCKET,
- SO_PEERCRED,
- &uc,
- &olen)) &&
- (olen == sizeof (uc)) )
- {
- gc.uid = uc.uid;
- gc.gid = uc.gid;
- gcp = &gc;
- }
-#else
-#if HAVE_GETPEERUCRED
- /* this is for Solaris 10 */
- ucred_t *uc;
-
- uc = NULL;
- if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
- {
- gc.uid = ucred_geteuid (uc);
- gc.gid = ucred_getegid (uc);
- gcp = &gc;
- }
- ucred_free (uc);
-#endif
-#endif
-#endif
- }
-
- if ( (NULL != access_cb) &&
- (GNUNET_YES != (aret = access_cb (access_cb_cls,
- gcp,
- uaddr,
- addrlen))) )
- {
- if (GNUNET_NO == aret)
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Access denied to `%s'\n"),
- GNUNET_a2s (uaddr,
- addrlen));
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_shutdown (sock,
- SHUT_RDWR));
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
- GNUNET_free (uaddr);
- return NULL;
- }
- connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
- connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
- connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
- connection->addr = uaddr;
- connection->addrlen = addrlen;
- connection->sock = sock;
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Accepting connection from `%s': %p\n"),
- GNUNET_a2s (uaddr,
- addrlen),
- connection);
- return connection;
-}
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param connection the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of the @a addr
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
- void **addr,
- size_t *addrlen)
-{
- if ((NULL == connection->addr) || (0 == connection->addrlen))
- return GNUNET_NO;
- *addr = GNUNET_malloc (connection->addrlen);
- GNUNET_memcpy (*addr, connection->addr, connection->addrlen);
- *addrlen = connection->addrlen;
- return GNUNET_OK;
-}
-
-
-/**
- * Tell the receiver callback that we had an IO error.
- *
- * @param connection connection to signal error
- * @param errcode error code to send
- */
-static void
-signal_receive_error (struct GNUNET_CONNECTION_Handle *connection,
- int errcode)
-{
- GNUNET_CONNECTION_Receiver receiver;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receive encounters error (%s), connection closed (%p)\n",
- STRERROR (errcode),
- connection);
- GNUNET_assert (NULL != (receiver = connection->receiver));
- connection->receiver = NULL;
- receiver (connection->receiver_cls,
- NULL,
- 0,
- connection->addr,
- connection->addrlen,
- errcode);
-}
-
-
-/**
- * Tell the receiver callback that a timeout was reached.
- *
- * @param connection connection to signal for
- */
-static void
-signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
-{
- GNUNET_CONNECTION_Receiver receiver;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection signals timeout to receiver (%p)!\n",
- connection);
- GNUNET_assert (NULL != (receiver = connection->receiver));
- connection->receiver = NULL;
- receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
-}
-
-
-/**
- * We failed to transmit data to the service, signal the error.
- *
- * @param connection handle that had trouble
- * @param ecode error code (errno)
- */
-static void
-signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection,
- int ecode)
-{
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission encounterd error (%s), connection closed (%p)\n",
- STRERROR (ecode),
- connection);
- if (NULL != connection->sock)
- {
- (void) GNUNET_NETWORK_socket_shutdown (connection->sock,
- SHUT_RDWR);
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (connection->sock));
- connection->sock = NULL;
- GNUNET_assert (NULL == connection->write_task);
- }
- if (NULL != connection->read_task)
- {
- /* send errors trigger read errors... */
- GNUNET_SCHEDULER_cancel (connection->read_task);
- connection->read_task = NULL;
- signal_receive_timeout (connection);
- return;
- }
- if (NULL == connection->nth.notify_ready)
- return; /* nobody to tell about it */
- notify = connection->nth.notify_ready;
- connection->nth.notify_ready = NULL;
- notify (connection->nth.notify_ready_cls,
- 0,
- NULL);
-}
-
-
-/**
- * We've failed for good to establish a connection (timeout or
- * no more addresses to try).
- *
- * @param connection the connection we tried to establish
- */
-static void
-connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
-{
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
- connection->hostname,
- connection->port);
- GNUNET_break (NULL == connection->ap_head);
- GNUNET_break (NULL == connection->ap_tail);
- GNUNET_break (GNUNET_NO == connection->dns_active);
- GNUNET_break (NULL == connection->sock);
- GNUNET_assert (NULL == connection->write_task);
- GNUNET_assert (NULL == connection->proxy_handshake);
-
- /* signal errors for jobs that used to wait on the connection */
- connection->destroy_later = 1;
- if (NULL != connection->receiver)
- signal_receive_error (connection,
- ECONNREFUSED);
- if (NULL != connection->nth.notify_ready)
- {
- GNUNET_assert (NULL != connection->nth.timeout_task);
- GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
- connection->nth.timeout_task = NULL;
- signal_transmit_error (connection,
- ECONNREFUSED);
- }
- if (-1 == connection->destroy_later)
- {
- /* do it now */
- connection->destroy_later = 0;
- GNUNET_CONNECTION_destroy (connection);
- return;
- }
- connection->destroy_later = 0;
-}
-
-
-/**
- * We are ready to transmit (or got a timeout).
- *
- * @param cls our connection handle
- */
-static void
-transmit_ready (void *cls);
-
-
-/**
- * This function is called once we either timeout or have data ready
- * to read.
- *
- * @param cls connection to read from
- */
-static void
-receive_ready (void *cls);
-
-
-/**
- * We've succeeded in establishing a connection.
- *
- * @param connection the connection we tried to establish
- */
-static void
-connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection to `%s' succeeded! (%p)\n",
- GNUNET_a2s (connection->addr,
- connection->addrlen),
- connection);
- /* trigger jobs that waited for the connection */
- if (NULL != connection->receiver)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection succeeded, starting with receiving data (%p)\n",
- connection);
- GNUNET_assert (NULL == connection->read_task);
- connection->read_task =
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
- (connection->receive_timeout),
- connection->sock,
- &receive_ready, connection);
- }
- if (NULL != connection->nth.notify_ready)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection succeeded, starting with sending data (%p)\n",
- connection);
- GNUNET_assert (connection->nth.timeout_task != NULL);
- GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
- connection->nth.timeout_task = NULL;
- GNUNET_assert (connection->write_task == NULL);
- connection->write_task =
- GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
- (connection->nth.transmit_timeout), connection->sock,
- &transmit_ready, connection);
- }
-}
-
-
-/**
- * Scheduler let us know that we're either ready to write on the
- * socket OR connect timed out. Do the right thing.
- *
- * @param cls the `struct AddressProbe *` with the address that we are probing
- */
-static void
-connect_probe_continuation (void *cls)
-{
- struct AddressProbe *ap = cls;
- struct GNUNET_CONNECTION_Handle *connection = ap->connection;
- const struct GNUNET_SCHEDULER_TaskContext *tc;
- struct AddressProbe *pos;
- int error;
- socklen_t len;
-
- GNUNET_assert (NULL != ap->sock);
- GNUNET_CONTAINER_DLL_remove (connection->ap_head,
- connection->ap_tail,
- ap);
- len = sizeof (error);
- errno = 0;
- error = 0;
- tc = GNUNET_SCHEDULER_get_task_context ();
- if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
- (GNUNET_OK !=
- GNUNET_NETWORK_socket_getsockopt (ap->sock,
- SOL_SOCKET,
- SO_ERROR,
- &error,
- &len)) ||
- (0 != error) )
- {
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (ap->sock));
- GNUNET_free (ap);
- if ( (NULL == connection->ap_head) &&
- (GNUNET_NO == connection->dns_active) &&
- (NULL == connection->proxy_handshake) )
- connect_fail_continuation (connection);
- return;
- }
- GNUNET_assert (NULL == connection->sock);
- connection->sock = ap->sock;
- GNUNET_assert (NULL == connection->addr);
- connection->addr = GNUNET_malloc (ap->addrlen);
- GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen);
- connection->addrlen = ap->addrlen;
- GNUNET_free (ap);
- /* cancel all other attempts */
- while (NULL != (pos = connection->ap_head))
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
- GNUNET_SCHEDULER_cancel (pos->task);
- GNUNET_CONTAINER_DLL_remove (connection->ap_head,
- connection->ap_tail,
- pos);
- GNUNET_free (pos);
- }
- connect_success_continuation (connection);
-}
-
-
-/**
- * Try to establish a connection given the specified address.
- * This function is called by the resolver once we have a DNS reply.
- *
- * @param cls our `struct GNUNET_CONNECTION_Handle *`
- * @param addr address to try, NULL for "last call"
- * @param addrlen length of @a addr
- */
-static void
-try_connect_using_address (void *cls,
- const struct sockaddr *addr,
- socklen_t addrlen)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
- struct AddressProbe *ap;
- struct GNUNET_TIME_Relative delay;
-
- if (NULL == addr)
- {
- connection->dns_active = NULL;
- if ((NULL == connection->ap_head) &&
- (NULL == connection->sock) &&
- (NULL == connection->proxy_handshake))
- connect_fail_continuation (connection);
- return;
- }
- if (NULL != connection->sock)
- return; /* already connected */
- GNUNET_assert (NULL == connection->addr);
- /* try to connect */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to connect using address `%s:%u/%s:%u'\n",
- connection->hostname,
- connection->port,
- GNUNET_a2s (addr, addrlen),
- connection->port);
- ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
- ap->addr = (const struct sockaddr *) &ap[1];
- GNUNET_memcpy (&ap[1], addr, addrlen);
- ap->addrlen = addrlen;
- ap->connection = connection;
-
- switch (ap->addr->sa_family)
- {
- case AF_INET:
- ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
- break;
- default:
- GNUNET_break (0);
- GNUNET_free (ap);
- return; /* not supported by us */
- }
- ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
- SOCK_STREAM, 0);
- if (NULL == ap->sock)
- {
- GNUNET_free (ap);
- return; /* not supported by OS */
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Trying to connect to `%s' (%p)\n",
- GNUNET_a2s (ap->addr, ap->addrlen),
- connection);
- if ((GNUNET_OK !=
- GNUNET_NETWORK_socket_connect (ap->sock,
- ap->addr,
- ap->addrlen)) &&
- (EINPROGRESS != errno))
- {
- /* maybe refused / unsupported address, try next */
- LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
- GNUNET_free (ap);
- return;
- }
- GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
- delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
- if (NULL != connection->nth.notify_ready)
- delay = GNUNET_TIME_relative_min (delay,
- GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
- if (NULL != connection->receiver)
- delay = GNUNET_TIME_relative_min (delay,
- GNUNET_TIME_absolute_get_remaining (connection->receive_timeout));
- ap->task = GNUNET_SCHEDULER_add_write_net (delay,
- ap->sock,
- &connect_probe_continuation,
- ap);
-}
-
-
-/**
- * Create a connection 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 cfg configuration to use
- * @param hostname name of the host to connect to
- * @param port port to connect to
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *hostname,
- uint16_t port)
-{
- struct GNUNET_CONNECTION_Handle *connection;
-
- GNUNET_assert (0 < strlen (hostname)); /* sanity check */
- connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
- connection->cfg = cfg;
- connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
- connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
- connection->port = port;
- connection->hostname = GNUNET_strdup (hostname);
- connection->dns_active =
- GNUNET_RESOLVER_ip_get (connection->hostname,
- AF_UNSPEC,
- GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
- &try_connect_using_address,
- connection);
- return connection;
-}
-
-
-/**
- * Create a connection handle by connecting to a UNIX domain service.
- * This function returns immediately, even if the connection has not
- * yet been established. This function only creates UNIX connections.
- *
- * @param cfg configuration to use
- * @param unixpath path to connect to
- * @return the connection handle, NULL on systems without UNIX support
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *unixpath)
-{
-#ifdef AF_UNIX
- struct GNUNET_CONNECTION_Handle *connection;
- struct sockaddr_un *un;
-
- GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
- un = GNUNET_new (struct sockaddr_un);
- un->sun_family = AF_UNIX;
- strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
-#ifdef LINUX
- {
- int abstract;
-
- abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "TESTING",
- "USE_ABSTRACT_SOCKETS");
- if (GNUNET_YES == abstract)
- un->sun_path[0] = '\0';
- }
-#endif
-#if HAVE_SOCKADDR_UN_SUN_LEN
- un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
- connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
- connection->cfg = cfg;
- connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
- connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
- connection->port = 0;
- connection->hostname = NULL;
- connection->addr = (struct sockaddr *) un;
- connection->addrlen = sizeof (struct sockaddr_un);
- connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX,
- SOCK_STREAM,
- 0);
- if (NULL == connection->sock)
- {
- GNUNET_free (connection->addr);
- GNUNET_free (connection->write_buffer);
- GNUNET_free (connection);
- return NULL;
- }
- if ( (GNUNET_OK !=
- GNUNET_NETWORK_socket_connect (connection->sock,
- connection->addr,
- connection->addrlen)) &&
- (EINPROGRESS != errno) )
- {
- /* Just return; we expect everything to work eventually so don't fail HARD */
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (connection->sock));
- connection->sock = NULL;
- return connection;
- }
- connect_success_continuation (connection);
- return connection;
-#else
- return NULL;
-#endif
-}
-
-
-/**
- * Create a connection 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 s socket to connect
- * @param serv_addr server address
- * @param addrlen length of @a serv_addr
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
- const struct sockaddr *serv_addr,
- socklen_t addrlen)
-{
- struct GNUNET_CONNECTION_Handle *connection;
-
- if ( (GNUNET_OK !=
- GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
- (EINPROGRESS != errno) )
- {
- /* maybe refused / unsupported address, try next */
- LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
- "connect");
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Attempt to connect to `%s' failed\n",
- GNUNET_a2s (serv_addr,
- addrlen));
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
- return NULL;
- }
- connection = GNUNET_CONNECTION_create_from_existing (s);
- connection->addr = GNUNET_malloc (addrlen);
- GNUNET_memcpy (connection->addr, serv_addr, addrlen);
- connection->addrlen = addrlen;
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Trying to connect to `%s' (%p)\n",
- GNUNET_a2s (serv_addr, addrlen),
- connection);
- return connection;
-}
-
-
-/**
- * Create a connection handle by creating a socket and
- * (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 af_family address family to use
- * @param serv_addr server address
- * @param addrlen length of @a serv_addr
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_sockaddr (int af_family,
- const struct sockaddr *serv_addr,
- socklen_t addrlen)
-{
- struct GNUNET_NETWORK_Handle *s;
-
- s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
- if (NULL == s)
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
- "socket");
- return NULL;
- }
- return GNUNET_CONNECTION_connect_socket (s,
- serv_addr,
- addrlen);
-}
-
-
-/**
- * Check if connection is valid (no fatal errors have happened so far).
- * Note that a connection that is still trying to connect is considered
- * valid.
- *
- * @param connection connection to check
- * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
- */
-int
-GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
-{
- if ((NULL != connection->ap_head) ||
- (NULL != connection->dns_active) ||
- (NULL != connection->proxy_handshake))
- return GNUNET_YES; /* still trying to connect */
- if ( (0 != connection->destroy_later) ||
- (NULL == connection->sock) )
- return GNUNET_NO;
- return GNUNET_YES;
-}
-
-
-/**
- * Close the connection and free associated resources. There must
- * not be any pending requests for reading or writing to the
- * connection at this time.
- *
- * @param connection connection to destroy
- */
-void
-GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
-{
- struct AddressProbe *pos;
-
- if (0 != connection->destroy_later)
- {
- connection->destroy_later = -1;
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Shutting down connection (%p)\n",
- connection);
- GNUNET_assert (NULL == connection->nth.notify_ready);
- GNUNET_assert (NULL == connection->receiver);
- if (NULL != connection->write_task)
- {
- GNUNET_SCHEDULER_cancel (connection->write_task);
- connection->write_task = NULL;
- connection->write_buffer_off = 0;
- }
- if (NULL != connection->read_task)
- {
- GNUNET_SCHEDULER_cancel (connection->read_task);
- connection->read_task = NULL;
- }
- if (NULL != connection->nth.timeout_task)
- {
- GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
- connection->nth.timeout_task = NULL;
- }
- connection->nth.notify_ready = NULL;
- if (NULL != connection->dns_active)
- {
- GNUNET_RESOLVER_request_cancel (connection->dns_active);
- connection->dns_active = NULL;
- }
- if (NULL != connection->proxy_handshake)
- {
- /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
- connection->proxy_handshake->destroy_later = -1;
- connection->proxy_handshake = NULL; /* Not leaked ??? */
- }
- while (NULL != (pos = connection->ap_head))
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
- GNUNET_SCHEDULER_cancel (pos->task);
- GNUNET_CONTAINER_DLL_remove (connection->ap_head,
- connection->ap_tail,
- pos);
- GNUNET_free (pos);
- }
- if ( (NULL != connection->sock) &&
- (GNUNET_YES != connection->persist) )
- {
- if ((GNUNET_OK !=
- GNUNET_NETWORK_socket_shutdown (connection->sock,
- SHUT_RDWR)) &&
- (ENOTCONN != errno) &&
- (ECONNRESET != errno) )
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
- "shutdown");
- }
- if (NULL != connection->sock)
- {
- if (GNUNET_YES != connection->persist)
- {
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (connection->sock));
- }
- else
- {
- GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
- * leak the socket in this special case) ... */
- }
- }
- GNUNET_free_non_null (connection->addr);
- GNUNET_free_non_null (connection->hostname);
- GNUNET_free (connection->write_buffer);
- GNUNET_free (connection);
-}
-
-
-/**
- * This function is called once we either timeout
- * or have data ready to read.
- *
- * @param cls connection to read from
- */
-static void
-receive_ready (void *cls)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
- const struct GNUNET_SCHEDULER_TaskContext *tc;
- char buffer[connection->max];
- ssize_t ret;
- GNUNET_CONNECTION_Receiver receiver;
-
- connection->read_task = NULL;
- tc = GNUNET_SCHEDULER_get_task_context ();
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receive from `%s' encounters error: timeout (%s, %p)\n",
- GNUNET_a2s (connection->addr,
- connection->addrlen),
- GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout),
- GNUNET_YES),
- connection);
- signal_receive_timeout (connection);
- return;
- }
- if (NULL == connection->sock)
- {
- /* connect failed for good */
- signal_receive_error (connection, ECONNREFUSED);
- return;
- }
- GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready,
- connection->sock));
-RETRY:
- ret = GNUNET_NETWORK_socket_recv (connection->sock,
- buffer,
- connection->max);
- if (-1 == ret)
- {
- if (EINTR == errno)
- goto RETRY;
- signal_receive_error (connection, errno);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "receive_ready read %u/%u bytes from `%s' (%p)!\n",
- (unsigned int) ret,
- connection->max,
- GNUNET_a2s (connection->addr,
- connection->addrlen),
- connection);
- GNUNET_assert (NULL != (receiver = connection->receiver));
- connection->receiver = NULL;
- receiver (connection->receiver_cls,
- buffer,
- ret,
- connection->addr,
- connection->addrlen,
- 0);
-}
-
-
-/**
- * Receive data from the given connection. Note that this function
- * will call @a receiver asynchronously using the scheduler. It will
- * "immediately" return. Note that there MUST only be one active
- * receive call per connection at any given point in time (so do not
- * call receive again until the receiver callback has been invoked).
- *
- * @param connection connection 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 @a receiver
- */
-void
-GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
- size_t max,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CONNECTION_Receiver receiver,
- void *receiver_cls)
-{
- GNUNET_assert ((NULL == connection->read_task) &&
- (NULL == connection->receiver));
- GNUNET_assert (NULL != receiver);
- connection->receiver = receiver;
- connection->receiver_cls = receiver_cls;
- connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
- connection->max = max;
- if (NULL != connection->sock)
- {
- connection->read_task =
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
- (connection->receive_timeout),
- connection->sock,
- &receive_ready,
- connection);
- return;
- }
- if ((NULL == connection->dns_active) &&
- (NULL == connection->ap_head) &&
- (NULL == connection->proxy_handshake))
- {
- connection->receiver = NULL;
- receiver (receiver_cls,
- NULL, 0,
- NULL, 0,
- ETIMEDOUT);
- return;
- }
-}
-
-
-/**
- * Cancel receive job on the given connection. Note that the
- * receiver callback must not have been called yet in order
- * for the cancellation to be valid.
- *
- * @param connection connection handle
- * @return closure of the original receiver callback closure
- */
-void *
-GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
-{
- if (NULL != connection->read_task)
- {
- GNUNET_assert (connection ==
- GNUNET_SCHEDULER_cancel (connection->read_task));
- connection->read_task = NULL;
- }
- connection->receiver = NULL;
- return connection->receiver_cls;
-}
-
-
-/**
- * Try to call the transmit notify method (check if we do
- * have enough space available first)!
- *
- * @param connection connection for which we should do this processing
- * @return #GNUNET_YES if we were able to call notify
- */
-static int
-process_notify (struct GNUNET_CONNECTION_Handle *connection)
-{
- size_t used;
- size_t avail;
- size_t size;
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "process_notify is running\n");
- GNUNET_assert (NULL == connection->write_task);
- if (NULL == (notify = connection->nth.notify_ready))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "No one to notify\n");
- return GNUNET_NO;
- }
- used = connection->write_buffer_off - connection->write_buffer_pos;
- avail = connection->write_buffer_size - used;
- size = connection->nth.notify_size;
- if (size > avail)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Not enough buffer\n");
- return GNUNET_NO;
- }
- connection->nth.notify_ready = NULL;
- if (connection->write_buffer_size - connection->write_buffer_off < size)
- {
- /* need to compact */
- memmove (connection->write_buffer,
- &connection->write_buffer[connection->write_buffer_pos],
- used);
- connection->write_buffer_off -= connection->write_buffer_pos;
- connection->write_buffer_pos = 0;
- }
- avail = connection->write_buffer_size - connection->write_buffer_off;
- GNUNET_assert (avail >= size);
- size =
- notify (connection->nth.notify_ready_cls, avail,
- &connection->write_buffer[connection->write_buffer_off]);
- GNUNET_assert (size <= avail);
- if (0 != size)
- connection->write_buffer_off += size;
- return GNUNET_YES;
-}
-
-
-/**
- * Task invoked by the scheduler when a call to transmit
- * is timing out (we never got enough buffer space to call
- * the callback function before the specified timeout
- * expired).
- *
- * This task notifies the client about the timeout.
- *
- * @param cls the `struct GNUNET_CONNECTION_Handle`
- */
-static void
-transmit_timeout (void *cls)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- connection->nth.timeout_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
- connection->hostname,
- connection->port,
- GNUNET_a2s (connection->addr,
- connection->addrlen),
- connection);
- notify = connection->nth.notify_ready;
- GNUNET_assert (NULL != notify);
- connection->nth.notify_ready = NULL;
- notify (connection->nth.notify_ready_cls,
- 0,
- NULL);
-}
-
-
-/**
- * Task invoked by the scheduler when we failed to connect
- * at the time of being asked to transmit.
- *
- * This task notifies the client about the error.
- *
- * @param cls the `struct GNUNET_CONNECTION_Handle`
- */
-static void
-connect_error (void *cls)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
- connection->nth.notify_size,
- connection->hostname,
- connection->port,
- connection);
- connection->write_task = NULL;
- notify = connection->nth.notify_ready;
- connection->nth.notify_ready = NULL;
- notify (connection->nth.notify_ready_cls,
- 0,
- NULL);
-}
-
-
-/**
- * We are ready to transmit (or got a timeout).
- *
- * @param cls our connection handle
- */
-static void
-transmit_ready (void *cls)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
- GNUNET_CONNECTION_TransmitReadyNotify notify;
- const struct GNUNET_SCHEDULER_TaskContext *tc;
- ssize_t ret;
- size_t have;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "transmit_ready running (%p).\n",
- connection);
- GNUNET_assert (NULL != connection->write_task);
- connection->write_task = NULL;
- GNUNET_assert (NULL == connection->nth.timeout_task);
- tc = GNUNET_SCHEDULER_get_task_context ();
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Transmit to `%s' fails, time out reached (%p).\n",
- GNUNET_a2s (connection->addr,
- connection->addrlen),
- connection);
- notify = connection->nth.notify_ready;
- GNUNET_assert (NULL != notify);
- connection->nth.notify_ready = NULL;
- notify (connection->nth.notify_ready_cls, 0, NULL);
- return;
- }
- GNUNET_assert (NULL != connection->sock);
- if (NULL == tc->write_ready)
- {
- /* special circumstances (in particular, PREREQ_DONE after
- * connect): not yet ready to write, but no "fatal" error either.
- * Hence retry. */
- goto SCHEDULE_WRITE;
- }
- if (! GNUNET_NETWORK_fdset_isset (tc->write_ready,
- connection->sock))
- {
- GNUNET_assert (NULL == connection->write_task);
- /* special circumstances (in particular, shutdown): not yet ready
- * to write, but no "fatal" error either. Hence retry. */
- goto SCHEDULE_WRITE;
- }
- GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
- if ((NULL != connection->nth.notify_ready) &&
- (connection->write_buffer_size < connection->nth.notify_size))
- {
- connection->write_buffer =
- GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
- connection->write_buffer_size = connection->nth.notify_size;
- }
- process_notify (connection);
- have = connection->write_buffer_off - connection->write_buffer_pos;
- if (0 == have)
- {
- /* no data ready for writing, terminate write loop */
- return;
- }
- GNUNET_assert (have <= connection->write_buffer_size);
- GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size);
- GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
-RETRY:
- ret =
- GNUNET_NETWORK_socket_send (connection->sock,
- &connection->write_buffer[connection->write_buffer_pos],
- have);
- if (-1 == ret)
- {
- if (EINTR == errno)
- goto RETRY;
- if (NULL != connection->write_task)
- {
- GNUNET_SCHEDULER_cancel (connection->write_task);
- connection->write_task = NULL;
- }
- signal_transmit_error (connection, errno);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection transmitted %u/%u bytes to `%s' (%p)\n",
- (unsigned int) ret,
- have,
- GNUNET_a2s (connection->addr,
- connection->addrlen),
- connection);
- connection->write_buffer_pos += ret;
- if (connection->write_buffer_pos == connection->write_buffer_off)
- {
- /* transmitted all pending data */
- connection->write_buffer_pos = 0;
- connection->write_buffer_off = 0;
- }
- if ( (0 == connection->write_buffer_off) &&
- (NULL == connection->nth.notify_ready) )
- return; /* all data sent! */
- /* not done writing, schedule more */
-SCHEDULE_WRITE:
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Re-scheduling transmit_ready (more to do) (%p).\n",
- connection);
- have = connection->write_buffer_off - connection->write_buffer_pos;
- GNUNET_assert ( (NULL != connection->nth.notify_ready) ||
- (have > 0) );
- if (NULL == connection->write_task)
- connection->write_task =
- GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
- NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
- GNUNET_TIME_absolute_get_remaining
- (connection->nth.transmit_timeout),
- connection->sock,
- &transmit_ready, connection);
-}
-
-
-/**
- * Ask the connection to call us once the specified number of bytes
- * are free in the transmission buffer. Will never call the @a notify
- * callback in this task, but always first go into the scheduler.
- *
- * @param connection connection
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- * @a notify with buf NULL and size 0)?
- * @param notify function to call
- * @param notify_cls closure for @a notify
- * @return non-NULL if the notify callback was queued,
- * NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_CONNECTION_TransmitHandle *
-GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
- size_t size,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CONNECTION_TransmitReadyNotify notify,
- void *notify_cls)
-{
- if (NULL != connection->nth.notify_ready)
- {
- GNUNET_assert (0);
- return NULL;
- }
- GNUNET_assert (NULL != notify);
- GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
- GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
- GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
- GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
- connection->nth.notify_ready = notify;
- connection->nth.notify_ready_cls = notify_cls;
- connection->nth.connection = connection;
- connection->nth.notify_size = size;
- connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
- GNUNET_assert (NULL == connection->nth.timeout_task);
- if ((NULL == connection->sock) &&
- (NULL == connection->ap_head) &&
- (NULL == connection->dns_active) &&
- (NULL == connection->proxy_handshake))
- {
- if (NULL != connection->write_task)
- GNUNET_SCHEDULER_cancel (connection->write_task);
- connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
- connection);
- return &connection->nth;
- }
- if (NULL != connection->write_task)
- return &connection->nth; /* previous transmission still in progress */
- if (NULL != connection->sock)
- {
- /* connected, try to transmit now */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Scheduling transmission (%p).\n",
- connection);
- connection->write_task =
- GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
- (connection->nth.transmit_timeout),
- connection->sock,
- &transmit_ready, connection);
- return &connection->nth;
- }
- /* not yet connected, wait for connection */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
- connection);
- connection->nth.timeout_task =
- GNUNET_SCHEDULER_add_delayed (timeout,
- &transmit_timeout,
- connection);
- return &connection->nth;
-}
-
-
-/**
- * Cancel the specified transmission-ready notification.
- *
- * @param th notification to cancel
- */
-void
-GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
-{
- GNUNET_assert (NULL != th->notify_ready);
- th->notify_ready = NULL;
- if (NULL != th->timeout_task)
- {
- GNUNET_SCHEDULER_cancel (th->timeout_task);
- th->timeout_task = NULL;
- }
- if (NULL != th->connection->write_task)
- {
- GNUNET_SCHEDULER_cancel (th->connection->write_task);
- th->connection->write_task = NULL;
- }
-}
-
-
-/**
- * Create a connection to be proxied using a given connection.
- *
- * @param cph connection to proxy server
- * @return connection to be proxied
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph)
-{
- struct GNUNET_CONNECTION_Handle *proxied = GNUNET_CONNECTION_create_from_existing (NULL);
-
- proxied->proxy_handshake = cph;
- return proxied;
-}
-
-
-/**
- * Activate proxied connection and destroy initial proxy handshake connection.
- * There must not be any pending requests for reading or writing to the
- * proxy hadshake connection at this time.
- *
- * @param proxied connection connection to proxy server
- */
-void
-GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
-{
- struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
-
- GNUNET_assert (NULL != cph);
- GNUNET_assert (NULL == proxied->sock);
- GNUNET_assert (NULL != cph->sock);
- proxied->sock = cph->sock;
- cph->sock = NULL;
- GNUNET_CONNECTION_destroy (cph);
- connect_success_continuation (proxied);
-}
-
-
-/* end of connection.c */
*/
#include "platform.h"
#include "gnunet_util_lib.h"
+#include "gnunet_mst_lib.h"
/**
/**
* The Message-Tokenizer that tokenizes the messages comming from the helper
*/
- struct GNUNET_SERVER_MessageStreamTokenizer *mst;
+ struct GNUNET_MessageStreamTokenizer *mst;
/**
* The exception callback
}
/* purge MST buffer */
if (NULL != h->mst)
- (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO);
+ (void) GNUNET_MST_from_buffer (h->mst,
+ NULL, 0,
+ GNUNET_YES,
+ GNUNET_NO);
return ret;
}
h->fh_from_helper,
&helper_read, h);
if (GNUNET_SYSERR ==
- GNUNET_SERVER_mst_receive (h->mst,
- NULL,
- buf, t,
- GNUNET_NO, GNUNET_NO))
+ GNUNET_MST_from_buffer (h->mst,
+ buf, t,
+ GNUNET_NO,
+ GNUNET_NO))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Failed to parse inbound message from helper `%s'\n"),
GNUNET_HELPER_start (int with_control_pipe,
const char *binary_name,
char *const binary_argv[],
- GNUNET_SERVER_MessageTokenizerCallback cb,
+ GNUNET_MessageTokenizerCallback cb,
GNUNET_HELPER_ExceptionCallback exp_cb,
void *cb_cls)
{
h->binary_argv[c] = NULL;
h->cb_cls = cb_cls;
if (NULL != cb)
- h->mst = GNUNET_SERVER_mst_create (cb, h->cb_cls);
+ h->mst = GNUNET_MST_create (cb,
+ h->cb_cls);
h->exp_cb = exp_cb;
h->retry_back_off = 0;
start_helper (h);
GNUNET_free (sh);
}
if (NULL != h->mst)
- GNUNET_SERVER_mst_destroy (h->mst);
+ GNUNET_MST_destroy (h->mst);
GNUNET_free (h->binary_name);
for (c = 0; h->binary_argv[c] != NULL; c++)
GNUNET_free (h->binary_argv[c]);
}
-/**
- * Transmit a queued message to the session's client.
- *
- * @param cls consensus session
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to @a buf
- */
-static size_t
-transmit_queued (void *cls,
- size_t size,
- void *buf)
-{
- struct GNUNET_MQ_Handle *mq = cls;
- struct ServerClientSocketState *state = GNUNET_MQ_impl_state (mq);
- const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
- size_t msg_size;
-
- GNUNET_assert (NULL != buf);
- msg_size = ntohs (msg->size);
- GNUNET_assert (size >= msg_size);
- GNUNET_memcpy (buf, msg, msg_size);
- state->th = NULL;
-
- GNUNET_MQ_impl_send_continue (mq);
-
- return msg_size;
-}
-
-
-static void
-server_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
- void *impl_state)
-{
- struct ServerClientSocketState *state = impl_state;
-
- if (NULL != state->th)
- {
- GNUNET_SERVER_notify_transmit_ready_cancel (state->th);
- state->th = NULL;
- }
-
- GNUNET_assert (NULL != mq);
- GNUNET_assert (NULL != state);
- GNUNET_SERVER_client_drop (state->client);
- GNUNET_free (state);
-}
-
-
-static void
-server_client_send_impl (struct GNUNET_MQ_Handle *mq,
- const struct GNUNET_MessageHeader *msg,
- void *impl_state)
-{
- GNUNET_assert (NULL != mq);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending message of type %u and size %u\n",
- ntohs (msg->type), ntohs (msg->size));
-
- struct ServerClientSocketState *state = impl_state;
- state->th = GNUNET_SERVER_notify_transmit_ready (state->client,
- ntohs (msg->size),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &transmit_queued,
- mq);
-}
-
-
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client)
-{
- struct GNUNET_MQ_Handle *mq;
- struct ServerClientSocketState *scss;
-
- mq = GNUNET_new (struct GNUNET_MQ_Handle);
- scss = GNUNET_new (struct ServerClientSocketState);
- mq->impl_state = scss;
- scss->client = client;
- GNUNET_SERVER_client_keep (client);
- mq->send_impl = &server_client_send_impl;
- mq->destroy_impl = &server_client_destroy_impl;
- return mq;
-}
-
-
/**
* Associate the assoc_data in mq with a unique request id.
*
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009-2013 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/server.c
- * @brief library for building GNUnet network servers
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_protocols.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-server", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-server", syscall)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
-
-
-/**
- * List of arrays of message handlers.
- */
-struct HandlerList
-{
- /**
- * This is a linked list.
- */
- struct HandlerList *next;
-
- /**
- * NULL-terminated array of handlers.
- */
- const struct GNUNET_SERVER_MessageHandler *handlers;
-};
-
-
-/**
- * List of arrays of message handlers.
- */
-struct NotifyList
-{
- /**
- * This is a doubly linked list.
- */
- struct NotifyList *next;
-
- /**
- * This is a doubly linked list.
- */
- struct NotifyList *prev;
-
- /**
- * Function to call.
- */
- GNUNET_SERVER_DisconnectCallback callback;
-
- /**
- * Closure for callback.
- */
- void *callback_cls;
-};
-
-
-/**
- * @brief handle for a server
- */
-struct GNUNET_SERVER_Handle
-{
- /**
- * List of handlers for incoming messages.
- */
- struct HandlerList *handlers;
-
- /**
- * Head of list of our current clients.
- */
- struct GNUNET_SERVER_Client *clients_head;
-
- /**
- * Head of list of our current clients.
- */
- struct GNUNET_SERVER_Client *clients_tail;
-
- /**
- * Head of linked list of functions to call on disconnects by clients.
- */
- struct NotifyList *disconnect_notify_list_head;
-
- /**
- * Tail of linked list of functions to call on disconnects by clients.
- */
- struct NotifyList *disconnect_notify_list_tail;
-
- /**
- * Head of linked list of functions to call on connects by clients.
- */
- struct NotifyList *connect_notify_list_head;
-
- /**
- * Tail of linked list of functions to call on connects by clients.
- */
- struct NotifyList *connect_notify_list_tail;
-
- /**
- * Function to call for access control.
- */
- GNUNET_CONNECTION_AccessCheck access_cb;
-
- /**
- * Closure for @e access_cb.
- */
- void *access_cb_cls;
-
- /**
- * NULL-terminated array of sockets used to listen for new
- * connections.
- */
- struct GNUNET_NETWORK_Handle **listen_sockets;
-
- /**
- * After how long should an idle connection time
- * out (on write).
- */
- struct GNUNET_TIME_Relative idle_timeout;
-
- /**
- * Task scheduled to do the listening.
- */
- struct GNUNET_SCHEDULER_Task * listen_task;
-
- /**
- * Alternative function to create a MST instance.
- */
- GNUNET_SERVER_MstCreateCallback mst_create;
-
- /**
- * Alternative function to destroy a MST instance.
- */
- GNUNET_SERVER_MstDestroyCallback mst_destroy;
-
- /**
- * Alternative function to give data to a MST instance.
- */
- GNUNET_SERVER_MstReceiveCallback mst_receive;
-
- /**
- * Closure for 'mst_'-callbacks.
- */
- void *mst_cls;
-
- /**
- * Do we ignore messages of types that we do not understand or do we
- * require that a handler is found (and if not kill the connection)?
- */
- int require_found;
-
- /**
- * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
- * all non-monitor clients to disconnect before we call
- * #GNUNET_SERVER_destroy. See test_monitor_clients(). Set to
- * #GNUNET_SYSERR once the final destroy task has been scheduled
- * (we cannot run it in the same task).
- */
- int in_soft_shutdown;
-};
-
-
-/**
- * Handle server returns for aborting transmission to a client.
- */
-struct GNUNET_SERVER_TransmitHandle
-{
- /**
- * Function to call to get the message.
- */
- GNUNET_CONNECTION_TransmitReadyNotify callback;
-
- /**
- * Closure for @e callback
- */
- void *callback_cls;
-
- /**
- * Active connection transmission handle.
- */
- struct GNUNET_CONNECTION_TransmitHandle *cth;
-
-};
-
-
-/**
- * @brief handle for a client of the server
- */
-struct GNUNET_SERVER_Client
-{
-
- /**
- * This is a doubly linked list.
- */
- struct GNUNET_SERVER_Client *next;
-
- /**
- * This is a doubly linked list.
- */
- struct GNUNET_SERVER_Client *prev;
-
- /**
- * Processing of incoming data.
- */
- void *mst;
-
- /**
- * Server that this client belongs to.
- */
- struct GNUNET_SERVER_Handle *server;
-
- /**
- * Client closure for callbacks.
- */
- struct GNUNET_CONNECTION_Handle *connection;
-
- /**
- * User context value, manipulated using
- * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
- */
- void *user_context;
-
- /**
- * ID of task used to restart processing.
- */
- struct GNUNET_SCHEDULER_Task * restart_task;
-
- /**
- * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
- */
- struct GNUNET_SCHEDULER_Task * warn_task;
-
- /**
- * Time when the warn task was started.
- */
- struct GNUNET_TIME_Absolute warn_start;
-
- /**
- * Last activity on this socket (used to time it out
- * if reference_count == 0).
- */
- struct GNUNET_TIME_Absolute last_activity;
-
- /**
- * Transmission handle we return for this client from
- * #GNUNET_SERVER_notify_transmit_ready.
- */
- struct GNUNET_SERVER_TransmitHandle th;
-
- /**
- * After how long should an idle connection time
- * out (on write).
- */
- struct GNUNET_TIME_Relative idle_timeout;
-
- /**
- * Number of external entities with a reference to
- * this client object.
- */
- unsigned int reference_count;
-
- /**
- * Was processing if incoming messages suspended while
- * we were still processing data already received?
- * This is a counter saying how often processing was
- * suspended (once per handler invoked).
- */
- unsigned int suspended;
-
- /**
- * Last size given when user context was initialized; used for
- * sanity check.
- */
- size_t user_context_size;
-
- /**
- * Are we currently in the "process_client_buffer" function (and
- * will hence restart the receive job on exit if suspended == 0 once
- * we are done?). If this is set, then "receive_done" will
- * essentially only decrement suspended; if this is not set, then
- * "receive_done" may need to restart the receive process (either
- * from the side-buffer or via select/recv).
- */
- int in_process_client_buffer;
-
- /**
- * We're about to close down this client.
- */
- int shutdown_now;
-
- /**
- * Are we currently trying to receive? (#GNUNET_YES if we are,
- * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
- * available in MST).
- */
- int receive_pending;
-
- /**
- * Persist the file handle for this client no matter what happens,
- * force the OS to close once the process actually dies. Should only
- * be used in special cases!
- */
- int persist;
-
- /**
- * Is this client a 'monitor' client that should not be counted
- * when deciding on destroying the server during soft shutdown?
- * (see also #GNUNET_SERVICE_start)
- */
- int is_monitor;
-
- /**
- * Type of last message processed (for warn_no_receive_done).
- */
- uint16_t warn_type;
-};
-
-
-
-/**
- * Return user context associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param size number of bytes in user context struct (for verification only)
- * @return pointer to user context
- */
-void *
-GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
- size_t size)
-{
- if ((0 == client->user_context_size) &&
- (NULL == client->user_context))
- return NULL; /* never set */
- GNUNET_assert (size == client->user_context_size);
- return client->user_context;
-}
-
-
-/**
- * Set user context to be associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param ptr pointer to user context
- * @param size number of bytes in user context struct (for verification only)
- */
-void
-GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
- void *ptr,
- size_t size)
-{
- if (NULL == ptr)
- {
- client->user_context_size = 0;
- client->user_context = ptr;
- return;
- }
- client->user_context_size = size;
- client->user_context = ptr;
-}
-
-
-/**
- * Scheduler says our listen socket is ready. Process it!
- *
- * @param cls handle to our server for which we are processing the listen
- * socket
- */
-static void
-process_listen_socket (void *cls)
-{
- struct GNUNET_SERVER_Handle *server = cls;
- const struct GNUNET_SCHEDULER_TaskContext *tc;
- struct GNUNET_CONNECTION_Handle *sock;
- unsigned int i;
-
- server->listen_task = NULL;
- tc = GNUNET_SCHEDULER_get_task_context ();
- for (i = 0; NULL != server->listen_sockets[i]; i++)
- {
- if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
- server->listen_sockets[i]))
- {
- sock =
- GNUNET_CONNECTION_create_from_accept (server->access_cb,
- server->access_cb_cls,
- server->listen_sockets[i]);
- if (NULL != sock)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server accepted incoming connection.\n");
- (void) GNUNET_SERVER_connect_socket (server,
- sock);
- }
- }
- }
- /* listen for more! */
- GNUNET_SERVER_resume (server);
-}
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @param server_addr address to listen on
- * @param socklen length of @a server_addr
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket (const struct sockaddr *server_addr,
- socklen_t socklen)
-{
- struct GNUNET_NETWORK_Handle *sock;
- uint16_t port;
- int eno;
-
- switch (server_addr->sa_family)
- {
- case AF_INET:
- port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
- break;
- case AF_INET6:
- port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
- break;
- case AF_UNIX:
- port = 0;
- break;
- default:
- GNUNET_break (0);
- port = 0;
- break;
- }
- sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
- if (NULL == sock)
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
- errno = 0;
- return NULL;
- }
- /* bind the socket */
- if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
- {
- eno = errno;
- if (EADDRINUSE != errno)
- {
- /* we don't log 'EADDRINUSE' here since an IPv4 bind may
- * fail if we already took the port on IPv6; if both IPv4 and
- * IPv6 binds fail, then our caller will log using the
- * errno preserved in 'eno' */
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
- "bind");
- if (0 != port)
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("`%s' failed for port %d (%s).\n"),
- "bind",
- port,
- (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
- eno = 0;
- }
- else
- {
- if (0 != port)
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("`%s' failed for port %d (%s): address already in use\n"),
- "bind", port,
- (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
- else if (AF_UNIX == server_addr->sa_family)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("`%s' failed for `%s': address already in use\n"),
- "bind",
- GNUNET_a2s (server_addr, socklen));
- }
- }
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
- errno = eno;
- return NULL;
- }
- if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
- "listen");
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
- errno = 0;
- return NULL;
- }
- if (0 != port)
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server starts to listen on port %u.\n",
- port);
- return sock;
-}
-
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param lsocks NULL-terminated array of listen sockets
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if #GNUNET_YES, connections sending messages of unknown type
- * will be closed
- * @return handle for the new server, NULL on error
- * (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
- void *access_cb_cls,
- struct GNUNET_NETWORK_Handle **lsocks,
- struct GNUNET_TIME_Relative idle_timeout,
- int require_found)
-{
- struct GNUNET_SERVER_Handle *server;
-
- server = GNUNET_new (struct GNUNET_SERVER_Handle);
- server->idle_timeout = idle_timeout;
- server->listen_sockets = lsocks;
- server->access_cb = access_cb;
- server->access_cb_cls = access_cb_cls;
- server->require_found = require_found;
- if (NULL != lsocks)
- GNUNET_SERVER_resume (server);
- return server;
-}
-
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param server_addr address to listen on (including port), NULL terminated array
- * @param socklen length of server_addr
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if YES, connections sending messages of unknown type
- * will be closed
- * @return handle for the new server, NULL on error
- * (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
- void *access_cb_cls,
- struct sockaddr *const *server_addr,
- const socklen_t * socklen,
- struct GNUNET_TIME_Relative idle_timeout,
- int require_found)
-{
- struct GNUNET_NETWORK_Handle **lsocks;
- unsigned int i;
- unsigned int j;
- unsigned int k;
- int seen;
-
- i = 0;
- while (NULL != server_addr[i])
- i++;
- if (i > 0)
- {
- lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
- i = 0;
- j = 0;
- while (NULL != server_addr[i])
- {
- seen = 0;
- for (k=0;k<i;k++)
- if ( (socklen[k] == socklen[i]) &&
- (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) )
- {
- seen = 1;
- break;
- }
- if (0 != seen)
- {
- /* duplicate address, skip */
- i++;
- continue;
- }
- lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
- if (NULL != lsocks[j])
- j++;
- i++;
- }
- if (0 == j)
- {
- if (0 != errno)
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
- GNUNET_free (lsocks);
- lsocks = NULL;
- }
- }
- else
- {
- lsocks = NULL;
- }
- return GNUNET_SERVER_create_with_sockets (access_cb,
- access_cb_cls,
- lsocks,
- idle_timeout,
- require_found);
-}
-
-
-/**
- * Set the 'monitor' flag on this client. Clients which have been
- * marked as 'monitors' won't prevent the server from shutting down
- * once '#GNUNET_SERVER_stop_listening()' has been invoked. The idea is
- * that for "normal" clients we likely want to allow them to process
- * their requests; however, monitor-clients are likely to 'never'
- * disconnect during shutdown and thus will not be considered when
- * determining if the server should continue to exist after
- * #GNUNET_SERVER_destroy() has been called.
- *
- * @param client the client to set the 'monitor' flag on
- */
-void
-GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Marking client as monitor!\n");
- client->is_monitor = GNUNET_YES;
-}
-
-
-/**
- * Helper function for #test_monitor_clients() to trigger
- * #GNUNET_SERVER_destroy() after the stack has unwound.
- *
- * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
- */
-static void
-do_destroy (void *cls)
-{
- struct GNUNET_SERVER_Handle *server = cls;
-
- GNUNET_SERVER_destroy (server);
-}
-
-
-/**
- * Check if only 'monitor' clients are left. If so, destroy the
- * server completely.
- *
- * @param server server to test for full shutdown
- */
-static void
-test_monitor_clients (struct GNUNET_SERVER_Handle *server)
-{
- struct GNUNET_SERVER_Client *client;
-
- if (GNUNET_YES != server->in_soft_shutdown)
- return;
- for (client = server->clients_head; NULL != client; client = client->next)
- if (GNUNET_NO == client->is_monitor)
- return; /* not done yet */
- server->in_soft_shutdown = GNUNET_SYSERR;
- (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
-}
-
-
-/**
- * Suspend accepting connections from the listen socket temporarily.
- *
- * @param server server to stop accepting connections.
- */
-void
-GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
-{
- if (NULL != server->listen_task)
- {
- GNUNET_SCHEDULER_cancel (server->listen_task);
- server->listen_task = NULL;
- }
-}
-
-
-/**
- * Resume accepting connections from the listen socket.
- *
- * @param server server to stop accepting connections.
- */
-void
-GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
-{
- struct GNUNET_NETWORK_FDSet *r;
- unsigned int i;
-
- if (NULL == server->listen_sockets)
- return;
- if (NULL == server->listen_sockets[0])
- return; /* nothing to do, no listen sockets! */
- if (NULL == server->listen_sockets[1])
- {
- /* simplified method: no fd set needed; this is then much simpler
- and much more efficient */
- server->listen_task =
- GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_SCHEDULER_PRIORITY_HIGH,
- server->listen_sockets[0],
- &process_listen_socket, server);
- return;
- }
- r = GNUNET_NETWORK_fdset_create ();
- i = 0;
- while (NULL != server->listen_sockets[i])
- GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
- server->listen_task =
- GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
- GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
- &process_listen_socket, server);
- GNUNET_NETWORK_fdset_destroy (r);
-}
-
-
-/**
- * Stop the listen socket and get ready to shutdown the server
- * once only 'monitor' clients are left.
- *
- * @param server server to stop listening on
- */
-void
-GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
-{
- unsigned int i;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server in soft shutdown\n");
- if (NULL != server->listen_task)
- {
- GNUNET_SCHEDULER_cancel (server->listen_task);
- server->listen_task = NULL;
- }
- if (NULL != server->listen_sockets)
- {
- i = 0;
- while (NULL != server->listen_sockets[i])
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
- GNUNET_free (server->listen_sockets);
- server->listen_sockets = NULL;
- }
- if (GNUNET_NO == server->in_soft_shutdown)
- server->in_soft_shutdown = GNUNET_YES;
- test_monitor_clients (server);
-}
-
-
-/**
- * Free resources held by this server.
- *
- * @param server server to destroy
- */
-void
-GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
-{
- struct HandlerList *hpos;
- struct NotifyList *npos;
- unsigned int i;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server shutting down.\n");
- if (NULL != server->listen_task)
- {
- GNUNET_SCHEDULER_cancel (server->listen_task);
- server->listen_task = NULL;
- }
- if (NULL != server->listen_sockets)
- {
- i = 0;
- while (NULL != server->listen_sockets[i])
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
- GNUNET_free (server->listen_sockets);
- server->listen_sockets = NULL;
- }
- while (NULL != server->clients_head)
- GNUNET_SERVER_client_disconnect (server->clients_head);
- while (NULL != (hpos = server->handlers))
- {
- server->handlers = hpos->next;
- GNUNET_free (hpos);
- }
- while (NULL != (npos = server->disconnect_notify_list_head))
- {
- npos->callback (npos->callback_cls,
- NULL);
- GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
- server->disconnect_notify_list_tail,
- npos);
- GNUNET_free (npos);
- }
- while (NULL != (npos = server->connect_notify_list_head))
- {
- npos->callback (npos->callback_cls,
- NULL);
- GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
- server->connect_notify_list_tail,
- npos);
- GNUNET_free (npos);
- }
- GNUNET_free (server);
-}
-
-
-/**
- * Add additional handlers to an existing server.
- *
- * @param server the server to add handlers to
- * @param handlers array of message handlers for
- * incoming messages; the last entry must
- * have "NULL" for the "callback"; multiple
- * entries for the same type are allowed,
- * they will be called in order of occurence.
- * These handlers can be removed later;
- * the handlers array must exist until removed
- * (or server is destroyed).
- */
-void
-GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_SERVER_MessageHandler *handlers)
-{
- struct HandlerList *p;
-
- p = GNUNET_new (struct HandlerList);
- p->handlers = handlers;
- p->next = server->handlers;
- server->handlers = p;
-}
-
-
-/**
- * Change functions used by the server to tokenize the message stream.
- * (very rarely used).
- *
- * @param server server to modify
- * @param create new tokenizer initialization function
- * @param destroy new tokenizer destruction function
- * @param receive new tokenizer receive function
- * @param cls closure for @a create, @a receive, @a destroy
- */
-void
-GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_MstCreateCallback create,
- GNUNET_SERVER_MstDestroyCallback destroy,
- GNUNET_SERVER_MstReceiveCallback receive,
- void *cls)
-{
- server->mst_create = create;
- server->mst_destroy = destroy;
- server->mst_receive = receive;
- server->mst_cls = cls;
-}
-
-
-/**
- * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
- *
- * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
- */
-static void
-warn_no_receive_done (void *cls)
-{
- struct GNUNET_SERVER_Client *client = cls;
-
- GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
- client->warn_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &warn_no_receive_done, client);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
- (unsigned int) client->warn_type,
- GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
- GNUNET_YES));
-}
-
-
-/**
- * Disable the warning the server issues if a message is not acknowledged
- * in a timely fashion. Use this call if a client is intentionally delayed
- * for a while. Only applies to the current message.
- *
- * @param client client for which to disable the warning
- */
-void
-GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
-{
- if (NULL != client->warn_task)
- {
- GNUNET_SCHEDULER_cancel (client->warn_task);
- client->warn_task = NULL;
- }
-}
-
-
-/**
- * Inject a message into the server, pretend it came
- * from the specified client. Delivery of the message
- * will happen instantly (if a handler is installed;
- * otherwise the call does nothing).
- *
- * @param server the server receiving the message
- * @param sender the "pretended" sender of the message
- * can be NULL!
- * @param message message to transmit
- * @return #GNUNET_OK if the message was OK and the
- * connection can stay open
- * #GNUNET_SYSERR if the connection to the
- * client should be shut down
- */
-int
-GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
- struct GNUNET_SERVER_Client *sender,
- const struct GNUNET_MessageHeader *message)
-{
- struct HandlerList *pos;
- const struct GNUNET_SERVER_MessageHandler *mh;
- unsigned int i;
- uint16_t type;
- uint16_t size;
- int found;
-
- type = ntohs (message->type);
- size = ntohs (message->size);
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Received message of type %u and size %u from client\n",
- type, size);
- found = GNUNET_NO;
- for (pos = server->handlers; NULL != pos; pos = pos->next)
- {
- i = 0;
- while (pos->handlers[i].callback != NULL)
- {
- mh = &pos->handlers[i];
- if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
- {
- if ((0 != mh->expected_size) && (mh->expected_size != size))
- {
-#if GNUNET8_NETWORK_IS_DEAD
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Expected %u bytes for message of type %u, got %u\n",
- mh->expected_size, mh->type, size);
- GNUNET_break_op (0);
-#else
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Expected %u bytes for message of type %u, got %u\n",
- mh->expected_size, mh->type, size);
-#endif
- return GNUNET_SYSERR;
- }
- if (NULL != sender)
- {
- if ( (0 == sender->suspended) &&
- (NULL == sender->warn_task) )
- {
- GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
- sender->warn_start = GNUNET_TIME_absolute_get ();
- sender->warn_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &warn_no_receive_done,
- sender);
- sender->warn_type = type;
- }
- sender->suspended++;
- }
- mh->callback (mh->callback_cls, sender, message);
- found = GNUNET_YES;
- }
- i++;
- }
- }
- if (GNUNET_NO == found)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Received message of unknown type %d\n", type);
- if (GNUNET_YES == server->require_found)
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * We are receiving an incoming message. Process it.
- *
- * @param cls our closure (handle for the client)
- * @param buf buffer with data received from network
- * @param available number of bytes available in buf
- * @param addr address of the sender
- * @param addrlen length of @a addr
- * @param errCode code indicating errors receiving, 0 for success
- */
-static void
-process_incoming (void *cls,
- const void *buf,
- size_t available,
- const struct sockaddr *addr,
- socklen_t addrlen,
- int errCode);
-
-
-/**
- * Process messages from the client's message tokenizer until either
- * the tokenizer is empty (and then schedule receiving more), or
- * until some handler is not immediately done (then wait for restart_processing)
- * or shutdown.
- *
- * @param client the client to process, RC must have already been increased
- * using #GNUNET_SERVER_client_keep and will be decreased by one in this
- * function
- * @param ret #GNUNET_NO to start processing from the buffer,
- * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
- * #GNUNET_SYSERR if we should instantly abort due to error in a previous step
- */
-static void
-process_mst (struct GNUNET_SERVER_Client *client,
- int ret)
-{
- while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
- (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
- {
- if (GNUNET_OK == ret)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server re-enters receive loop, timeout: %s.\n",
- GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
- client->receive_pending = GNUNET_YES;
- GNUNET_CONNECTION_receive (client->connection,
- GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
- client->idle_timeout,
- &process_incoming,
- client);
- break;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server processes additional messages instantly.\n");
- if (NULL != client->server->mst_receive)
- ret =
- client->server->mst_receive (client->server->mst_cls, client->mst,
- client, NULL, 0, GNUNET_NO, GNUNET_YES);
- else
- ret =
- GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
- GNUNET_YES);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
- ret, client->server,
- client->shutdown_now,
- client->suspended);
- if (GNUNET_NO == ret)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server has more data pending but is suspended.\n");
- client->receive_pending = GNUNET_SYSERR; /* data pending */
- }
- if ( (GNUNET_SYSERR == ret) ||
- (GNUNET_YES == client->shutdown_now) )
- GNUNET_SERVER_client_disconnect (client);
-}
-
-
-/**
- * We are receiving an incoming message. Process it.
- *
- * @param cls our closure (handle for the client)
- * @param buf buffer with data received from network
- * @param available number of bytes available in buf
- * @param addr address of the sender
- * @param addrlen length of @a addr
- * @param errCode code indicating errors receiving, 0 for success
- */
-static void
-process_incoming (void *cls,
- const void *buf,
- size_t available,
- const struct sockaddr *addr,
- socklen_t addrlen,
- int errCode)
-{
- struct GNUNET_SERVER_Client *client = cls;
- struct GNUNET_SERVER_Handle *server = client->server;
- struct GNUNET_TIME_Absolute end;
- struct GNUNET_TIME_Absolute now;
- int ret;
-
- GNUNET_assert (GNUNET_YES == client->receive_pending);
- client->receive_pending = GNUNET_NO;
- now = GNUNET_TIME_absolute_get ();
- end = GNUNET_TIME_absolute_add (client->last_activity,
- client->idle_timeout);
-
- if ( (NULL == buf) &&
- (0 == available) &&
- (NULL == addr) &&
- (0 == errCode) &&
- (GNUNET_YES != client->shutdown_now) &&
- (NULL != server) &&
- (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
- (end.abs_value_us > now.abs_value_us) )
- {
- /* wait longer, timeout changed (i.e. due to us sending) */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receive time out, but no disconnect due to sending (%p)\n",
- client);
- client->receive_pending = GNUNET_YES;
- GNUNET_CONNECTION_receive (client->connection,
- GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
- GNUNET_TIME_absolute_get_remaining (end),
- &process_incoming,
- client);
- return;
- }
- if ( (NULL == buf) ||
- (0 == available) ||
- (0 != errCode) ||
- (NULL == server) ||
- (GNUNET_YES == client->shutdown_now) ||
- (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) )
- {
- /* other side closed connection, error connecting, etc. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to connect or other side closed connection (%p)\n",
- client);
- GNUNET_SERVER_client_disconnect (client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server receives %u bytes from `%s'.\n",
- (unsigned int) available,
- GNUNET_a2s (addr, addrlen));
- GNUNET_SERVER_client_keep (client);
- client->last_activity = now;
-
- if (NULL != server->mst_receive)
- {
- ret = client->server->mst_receive (client->server->mst_cls,
- client->mst,
- client,
- buf,
- available,
- GNUNET_NO,
- GNUNET_YES);
- }
- else if (NULL != client->mst)
- {
- ret =
- GNUNET_SERVER_mst_receive (client->mst,
- client,
- buf,
- available,
- GNUNET_NO,
- GNUNET_YES);
- }
- else
- {
- GNUNET_break (0);
- return;
- }
- process_mst (client,
- ret);
- GNUNET_SERVER_client_drop (client);
-}
-
-
-/**
- * Task run to start again receiving from the network
- * and process requests.
- *
- * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
- */
-static void
-restart_processing (void *cls)
-{
- struct GNUNET_SERVER_Client *client = cls;
-
- GNUNET_assert (GNUNET_YES != client->shutdown_now);
- client->restart_task = NULL;
- if (GNUNET_NO == client->receive_pending)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
- client->receive_pending = GNUNET_YES;
- GNUNET_CONNECTION_receive (client->connection,
- GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
- client->idle_timeout,
- &process_incoming,
- client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Server continues processing messages still in the buffer.\n");
- GNUNET_SERVER_client_keep (client);
- client->receive_pending = GNUNET_NO;
- process_mst (client,
- GNUNET_NO);
- GNUNET_SERVER_client_drop (client);
-}
-
-
-/**
- * This function is called whenever our inbound message tokenizer has
- * received a complete message.
- *
- * @param cls closure (struct GNUNET_SERVER_Handle)
- * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
- * @param message the actual message
- *
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
- */
-static int
-client_message_tokenizer_callback (void *cls,
- void *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_SERVER_Handle *server = cls;
- struct GNUNET_SERVER_Client *sender = client;
- int ret;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Tokenizer gives server message of type %u and size %u from client\n",
- ntohs (message->type), ntohs (message->size));
- sender->in_process_client_buffer = GNUNET_YES;
- ret = GNUNET_SERVER_inject (server, sender, message);
- sender->in_process_client_buffer = GNUNET_NO;
- if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) )
- {
- GNUNET_SERVER_client_disconnect (sender);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Add a TCP socket-based connection to the set of handles managed by
- * this server. Use this function for outgoing (P2P) connections that
- * we initiated (and where this server should process incoming
- * messages).
- *
- * @param server the server to use
- * @param connection the connection to manage (client must
- * stop using this connection from now on)
- * @return the client handle
- */
-struct GNUNET_SERVER_Client *
-GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
- struct GNUNET_CONNECTION_Handle *connection)
-{
- struct GNUNET_SERVER_Client *client;
- struct NotifyList *n;
-
- client = GNUNET_new (struct GNUNET_SERVER_Client);
- client->connection = connection;
- client->server = server;
- client->last_activity = GNUNET_TIME_absolute_get ();
- client->idle_timeout = server->idle_timeout;
- GNUNET_CONTAINER_DLL_insert (server->clients_head,
- server->clients_tail,
- client);
- if (NULL != server->mst_create)
- client->mst =
- server->mst_create (server->mst_cls, client);
- else
- client->mst =
- GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
- server);
- GNUNET_assert (NULL != client->mst);
- for (n = server->connect_notify_list_head; NULL != n; n = n->next)
- n->callback (n->callback_cls, client);
- client->receive_pending = GNUNET_YES;
- GNUNET_CONNECTION_receive (client->connection,
- GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
- client->idle_timeout,
- &process_incoming,
- client);
- return client;
-}
-
-
-/**
- * Change the timeout for a particular client. Decreasing the timeout
- * may not go into effect immediately (only after the previous timeout
- * times out or activity happens on the socket).
- *
- * @param client the client to update
- * @param timeout new timeout for activities on the socket
- */
-void
-GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
- struct GNUNET_TIME_Relative timeout)
-{
- client->idle_timeout = timeout;
-}
-
-
-/**
- * Notify the server that the given client handle should
- * be kept (keeps the connection up if possible, increments
- * the internal reference counter).
- *
- * @param client the client to keep
- */
-void
-GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
-{
- client->reference_count++;
-}
-
-
-/**
- * Notify the server that the given client handle is no
- * longer required. Decrements the reference counter. If
- * that counter reaches zero an inactive connection maybe
- * closed.
- *
- * @param client the client to drop
- */
-void
-GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
-{
- GNUNET_assert (client->reference_count > 0);
- client->reference_count--;
- if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
- GNUNET_SERVER_client_disconnect (client);
-}
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param client the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of the @a addr
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
- void **addr, size_t * addrlen)
-{
- return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
-}
-
-
-/**
- * Ask the server to notify us whenever a client disconnects.
- * This function is called whenever the actual network connection
- * is closed; the reference count may be zero or larger than zero
- * at this point.
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_DisconnectCallback callback,
- void *callback_cls)
-{
- struct NotifyList *n;
-
- n = GNUNET_new (struct NotifyList);
- n->callback = callback;
- n->callback_cls = callback_cls;
- GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
- server->disconnect_notify_list_tail,
- n);
-}
-
-
-/**
- * Ask the server to notify us whenever a client connects.
- * This function is called whenever the actual network connection
- * is opened. If the server is destroyed before this
- * notification is explicitly cancelled, the 'callback' will
- * once be called with a 'client' argument of NULL to indicate
- * that the server itself is now gone (and that the callback
- * won't be called anymore and also can no longer be cancelled).
- *
- * @param server the server manageing the clients
- * @param callback function to call on sconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_ConnectCallback callback,
- void *callback_cls)
-{
- struct NotifyList *n;
- struct GNUNET_SERVER_Client *client;
-
- n = GNUNET_new (struct NotifyList);
- n->callback = callback;
- n->callback_cls = callback_cls;
- GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
- server->connect_notify_list_tail,
- n);
- for (client = server->clients_head; NULL != client; client = client->next)
- callback (callback_cls, client);
-}
-
-
-/**
- * Ask the server to stop notifying us whenever a client connects.
- *
- * @param server the server manageing the clients
- * @param callback function to call on connect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_DisconnectCallback callback,
- void *callback_cls)
-{
- struct NotifyList *pos;
-
- for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
- if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
- break;
- if (NULL == pos)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
- server->disconnect_notify_list_tail,
- pos);
- GNUNET_free (pos);
-}
-
-
-/**
- * Ask the server to stop notifying us whenever a client disconnects.
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
- GNUNET_SERVER_ConnectCallback callback,
- void *callback_cls)
-{
- struct NotifyList *pos;
-
- for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
- if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
- break;
- if (NULL == pos)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
- server->connect_notify_list_tail,
- pos);
- GNUNET_free (pos);
-}
-
-
-/**
- * Destroy the connection that is passed in via @a cls. Used
- * as calling #GNUNET_CONNECTION_destroy from within a function
- * that was itself called from within process_notify() of
- * 'connection.c' is not allowed (see #2329).
- *
- * @param cls connection to destroy
- */
-static void
-destroy_connection (void *cls)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
-
- GNUNET_CONNECTION_destroy (connection);
-}
-
-
-/**
- * Ask the server to disconnect from the given client.
- * This is the same as returning #GNUNET_SYSERR from a message
- * handler, except that it allows dropping of a client even
- * when not handling a message from that client.
- *
- * @param client the client to disconnect from
- */
-void
-GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
-{
- struct GNUNET_SERVER_Handle *server = client->server;
- struct NotifyList *n;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Client is being disconnected from the server.\n");
- if (NULL != client->restart_task)
- {
- GNUNET_SCHEDULER_cancel (client->restart_task);
- client->restart_task = NULL;
- }
- if (NULL != client->warn_task)
- {
- GNUNET_SCHEDULER_cancel (client->warn_task);
- client->warn_task = NULL;
- }
- if (GNUNET_YES == client->receive_pending)
- {
- GNUNET_CONNECTION_receive_cancel (client->connection);
- client->receive_pending = GNUNET_NO;
- }
- client->shutdown_now = GNUNET_YES;
- client->reference_count++; /* make sure nobody else clean up client... */
- if ( (NULL != client->mst) &&
- (NULL != server) )
- {
- GNUNET_CONTAINER_DLL_remove (server->clients_head,
- server->clients_tail,
- client);
- if (NULL != server->mst_destroy)
- server->mst_destroy (server->mst_cls,
- client->mst);
- else
- GNUNET_SERVER_mst_destroy (client->mst);
- client->mst = NULL;
- for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
- n->callback (n->callback_cls,
- client);
- }
- client->reference_count--;
- if (client->reference_count > 0)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "RC of %p still positive, not destroying everything.\n",
- client);
- client->server = NULL;
- return;
- }
- if (GNUNET_YES == client->in_process_client_buffer)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Still processing inputs of %p, not destroying everything.\n",
- client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "RC of %p now zero, destroying everything.\n",
- client);
- if (GNUNET_YES == client->persist)
- GNUNET_CONNECTION_persist_ (client->connection);
- if (NULL != client->th.cth)
- GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
- (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
- client->connection);
- /* need to cancel again, as it might have been re-added
- in the meantime (i.e. during callbacks) */
- if (NULL != client->warn_task)
- {
- GNUNET_SCHEDULER_cancel (client->warn_task);
- client->warn_task = NULL;
- }
- if (GNUNET_YES == client->receive_pending)
- {
- GNUNET_CONNECTION_receive_cancel (client->connection);
- client->receive_pending = GNUNET_NO;
- }
- GNUNET_free (client);
- /* we might be in soft-shutdown, test if we're done */
- if (NULL != server)
- test_monitor_clients (server);
-}
-
-
-/**
- * Disable the "CORK" feature for communication with the given client,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages.
- *
- * @param client handle to the client
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
-{
- return GNUNET_CONNECTION_disable_corking (client->connection);
-}
-
-
-/**
- * Wrapper for transmission notification that calls the original
- * callback and update the last activity time for our connection.
- *
- * @param cls the `struct GNUNET_SERVER_Client *`
- * @param size number of bytes we can transmit
- * @param buf where to copy the message
- * @return number of bytes actually transmitted
- */
-static size_t
-transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
-{
- struct GNUNET_SERVER_Client *client = cls;
- GNUNET_CONNECTION_TransmitReadyNotify callback;
-
- client->th.cth = NULL;
- callback = client->th.callback;
- client->th.callback = NULL;
- client->last_activity = GNUNET_TIME_absolute_get ();
- return callback (client->th.callback_cls, size, buf);
-}
-
-
-/**
- * Notify us when the server has enough space to transmit
- * a message of the given size to the given client.
- *
- * @param client client to transmit message to
- * @param size requested amount of buffer space
- * @param timeout after how long should we give up (and call
- * notify with buf NULL and size 0)?
- * @param callback function to call when space is available
- * @param callback_cls closure for @a callback
- * @return non-NULL if the notify callback was queued; can be used
- * to cancel the request using
- * #GNUNET_SERVER_notify_transmit_ready_cancel().
- * NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_SERVER_TransmitHandle *
-GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
- size_t size,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CONNECTION_TransmitReadyNotify callback,
- void *callback_cls)
-{
- if (NULL != client->th.callback)
- return NULL;
- client->th.callback_cls = callback_cls;
- client->th.callback = callback;
- client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
- timeout,
- &transmit_ready_callback_wrapper,
- client);
- return &client->th;
-}
-
-
-/**
- * Abort transmission request.
- *
- * @param th request to abort
- */
-void
-GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
-{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
- th->cth = NULL;
- th->callback = NULL;
-}
-
-
-/**
- * Set the persistent flag on this client, used to setup client connection
- * to only be killed when the service it's connected to is actually dead.
- *
- * @param client the client to set the persistent flag on
- */
-void
-GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
-{
- client->persist = GNUNET_YES;
-}
-
-
-/**
- * Resume receiving from this client, we are done processing the
- * current request. This function must be called from within each
- * GNUNET_SERVER_MessageCallback (or its respective continuations).
- *
- * @param client client we were processing a message of
- * @param success #GNUNET_OK to keep the connection open and
- * continue to receive
- * #GNUNET_NO to close the connection (normal behavior)
- * #GNUNET_SYSERR to close the connection (signal
- * serious error)
- */
-void
-GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
- int success)
-{
- if (NULL == client)
- return;
- GNUNET_assert (client->suspended > 0);
- client->suspended--;
- if (GNUNET_OK != success)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GNUNET_SERVER_receive_done called with failure indication\n");
- if ( (client->reference_count > 0) || (client->suspended > 0) )
- client->shutdown_now = GNUNET_YES;
- else
- GNUNET_SERVER_client_disconnect (client);
- return;
- }
- if (client->suspended > 0)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GNUNET_SERVER_receive_done called, but more clients pending\n");
- return;
- }
- if (NULL != client->warn_task)
- {
- GNUNET_SCHEDULER_cancel (client->warn_task);
- client->warn_task = NULL;
- }
- if (GNUNET_YES == client->in_process_client_buffer)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GNUNET_SERVER_receive_done called while still in processing loop\n");
- return;
- }
- if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
- {
- GNUNET_SERVER_client_disconnect (client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
- GNUNET_assert (NULL == client->restart_task);
- client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
- client);
-}
-
-
-/* end of server.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2012 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/service.c
- * @brief functions related to starting services
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_protocols.h"
-#include "gnunet_constants.h"
-#include "gnunet_resolver_service.h"
-#include "speedup.h"
-
-#if HAVE_MALLINFO
-#include <malloc.h>
-#include "gauger.h"
-#endif
-
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-service", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-service", syscall)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
-
-
-/* ******************* access control ******************** */
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param add the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
- const struct in_addr *add)
-{
- unsigned int i;
-
- if (NULL == list)
- return GNUNET_NO;
- i = 0;
- while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
- {
- if ((add->s_addr & list[i].netmask.s_addr) ==
- (list[i].network.s_addr & list[i].netmask.s_addr))
- return GNUNET_YES;
- i++;
- }
- return GNUNET_NO;
-}
-
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param ip the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
- const struct in6_addr *ip)
-{
- unsigned int i;
- unsigned int j;
- struct in6_addr zero;
-
- if (NULL == list)
- return GNUNET_NO;
- memset (&zero, 0, sizeof (struct in6_addr));
- i = 0;
-NEXT:
- while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
- {
- for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
- if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
- (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
- {
- i++;
- goto NEXT;
- }
- return GNUNET_YES;
- }
- return GNUNET_NO;
-}
-
-
-/* ****************** service struct ****************** */
-
-
-/**
- * Context for "service_task".
- */
-struct GNUNET_SERVICE_Context
-{
- /**
- * Our configuration.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Handle for the server.
- */
- struct GNUNET_SERVER_Handle *server;
-
- /**
- * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
- * listen sockets.
- */
- struct sockaddr **addrs;
-
- /**
- * Name of our service.
- */
- const char *service_name;
-
- /**
- * Main service-specific task to run.
- */
- GNUNET_SERVICE_Main task;
-
- /**
- * Closure for @e task.
- */
- void *task_cls;
-
- /**
- * IPv4 addresses that are not allowed to connect.
- */
- struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
-
- /**
- * IPv6 addresses that are not allowed to connect.
- */
- struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
-
- /**
- * IPv4 addresses that are allowed to connect (if not
- * set, all are allowed).
- */
- struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
-
- /**
- * IPv6 addresses that are allowed to connect (if not
- * set, all are allowed).
- */
- struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
-
- /**
- * My (default) message handlers. Adjusted copy
- * of "defhandlers".
- */
- struct GNUNET_SERVER_MessageHandler *my_handlers;
-
- /**
- * Array of the lengths of the entries in addrs.
- */
- socklen_t *addrlens;
-
- /**
- * NULL-terminated array of listen sockets we should take over.
- */
- struct GNUNET_NETWORK_Handle **lsocks;
-
- /**
- * Task ID of the shutdown task.
- */
- struct GNUNET_SCHEDULER_Task *shutdown_task;
-
- /**
- * Idle timeout for server.
- */
- struct GNUNET_TIME_Relative timeout;
-
- /**
- * Overall success/failure of the service start.
- */
- int ret;
-
- /**
- * If we are daemonizing, this FD is set to the
- * pipe to the parent. Send '.' if we started
- * ok, '!' if not. -1 if we are not daemonizing.
- */
- int ready_confirm_fd;
-
- /**
- * Do we close connections if we receive messages
- * for which we have no handler?
- */
- int require_found;
-
- /**
- * Do we require a matching UID for UNIX domain socket connections?
- * #GNUNET_NO means that the UID does not have to match (however,
- * @e match_gid may still impose other access control checks).
- */
- int match_uid;
-
- /**
- * Do we require a matching GID for UNIX domain socket connections?
- * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
- * checking that the client's UID is in our group OR that the
- * client's GID is our GID. If both "match_gid" and @e match_uid are
- * #GNUNET_NO, all users on the local system have access.
- */
- int match_gid;
-
- /**
- * Our options.
- */
- enum GNUNET_SERVICE_Options options;
-
-};
-
-
-/* ****************** message handlers ****************** */
-
-/**
- * Send a 'TEST' message back to the client.
- *
- * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
- * @param size number of bytes available in 'buf'
- * @param buf where to copy the message
- * @return number of bytes written to 'buf'
- */
-static size_t
-write_test (void *cls, size_t size, void *buf)
-{
- struct GNUNET_SERVER_Client *client = cls;
- struct GNUNET_MessageHeader *msg;
-
- if (size < sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return 0; /* client disconnected */
- }
- msg = (struct GNUNET_MessageHeader *) buf;
- msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
- msg->size = htons (sizeof (struct GNUNET_MessageHeader));
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Handler for TEST message.
- *
- * @param cls closure (refers to service)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_test (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- /* simply bounce message back to acknowledge */
- if (NULL ==
- GNUNET_SERVER_notify_transmit_ready (client,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &write_test, client))
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Default handlers for all services. Will be copied and the
- * "callback_cls" fields will be replaced with the specific service
- * struct.
- */
-static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
- {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
- sizeof (struct GNUNET_MessageHeader)},
- {NULL, NULL, 0, 0}
-};
-
-
-/* ****************** service core routines ************** */
-
-
-/**
- * Check if access to the service is allowed from the given address.
- *
- * @param cls closure
- * @param uc credentials, if available, otherwise NULL
- * @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).
- */
-static int
-check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
- const struct sockaddr *addr, socklen_t addrlen)
-{
- struct GNUNET_SERVICE_Context *sctx = cls;
- const struct sockaddr_in *i4;
- const struct sockaddr_in6 *i6;
- int ret;
-
- switch (addr->sa_family)
- {
- case AF_INET:
- GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
- i4 = (const struct sockaddr_in *) addr;
- ret = ((NULL == sctx->v4_allowed) ||
- (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
- ((NULL == sctx->v4_denied) ||
- (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
- break;
- case AF_INET6:
- GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
- i6 = (const struct sockaddr_in6 *) addr;
- ret = ((NULL == sctx->v6_allowed) ||
- (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
- ((NULL == sctx->v6_denied) ||
- (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
- break;
-#ifndef WINDOWS
- case AF_UNIX:
- ret = GNUNET_OK; /* controlled using file-system ACL now */
- break;
-#endif
- default:
- LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
- addr->sa_family);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK != ret)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Access from `%s' denied to service `%s'\n"),
- GNUNET_a2s (addr, addrlen),
- sctx->service_name);
- }
- return ret;
-}
-
-
-/**
- * Get the name of the file where we will
- * write the PID of the service.
- *
- * @param sctx service context
- * @return name of the file for the process ID
- */
-static char *
-get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
-{
- char *pif;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
- "PIDFILE", &pif))
- return NULL;
- return pif;
-}
-
-
-/**
- * Parse an IPv4 access control list.
- *
- * @param ret location where to write the ACL (set)
- * @param sctx service context to use to get the configuration
- * @param option name of the ACL option to parse
- * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
- * no ACL configured)
- */
-static int
-process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
- struct GNUNET_SERVICE_Context *sctx,
- const char *option)
-{
- char *opt;
-
- if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
- {
- *ret = NULL;
- return GNUNET_OK;
- }
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
- sctx->service_name,
- option, &opt));
- if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
- opt, sctx->service_name, option);
- GNUNET_free (opt);
- return GNUNET_SYSERR;
- }
- GNUNET_free (opt);
- return GNUNET_OK;
-}
-
-
-/**
- * Parse an IPv6 access control list.
- *
- * @param ret location where to write the ACL (set)
- * @param sctx service context to use to get the configuration
- * @param option name of the ACL option to parse
- * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
- * no ACL configured)
- */
-static int
-process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
- struct GNUNET_SERVICE_Context *sctx,
- const char *option)
-{
- char *opt;
-
- if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
- {
- *ret = NULL;
- return GNUNET_OK;
- }
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
- sctx->service_name,
- option, &opt));
- if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
- opt, sctx->service_name, option);
- GNUNET_free (opt);
- return GNUNET_SYSERR;
- }
- GNUNET_free (opt);
- return GNUNET_OK;
-}
-
-
-/**
- * Add the given UNIX domain path as an address to the
- * list (as the first entry).
- *
- * @param saddrs array to update
- * @param saddrlens where to store the address length
- * @param unixpath path to add
- * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
- * parameter is ignore on systems other than LINUX
- */
-static void
-add_unixpath (struct sockaddr **saddrs,
- socklen_t *saddrlens,
- const char *unixpath,
- int abstract)
-{
-#ifdef AF_UNIX
- struct sockaddr_un *un;
-
- un = GNUNET_new (struct sockaddr_un);
- un->sun_family = AF_UNIX;
- strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
-#ifdef LINUX
- if (GNUNET_YES == abstract)
- un->sun_path[0] = '\0';
-#endif
-#if HAVE_SOCKADDR_UN_SUN_LEN
- un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
- *saddrs = (struct sockaddr *) un;
- *saddrlens = sizeof (struct sockaddr_un);
-#else
- /* this function should never be called
- * unless AF_UNIX is defined! */
- GNUNET_assert (0);
-#endif
-}
-
-
-/**
- * Get the list of addresses that a server for the given service
- * should bind to.
- *
- * @param service_name name of the service
- * @param cfg configuration (which specifies the addresses)
- * @param addrs set (call by reference) to an array of pointers to the
- * addresses the server should bind to and listen on; the
- * array will be NULL-terminated (on success)
- * @param addr_lens set (call by reference) to an array of the lengths
- * of the respective `struct sockaddr` struct in the @a addrs
- * array (on success)
- * @return number of addresses found on success,
- * #GNUNET_SYSERR if the configuration
- * did not specify reasonable finding information or
- * if it specified a hostname that could not be resolved;
- * #GNUNET_NO if the number of addresses configured is
- * zero (in this case, `*addrs` and `*addr_lens` will be
- * set to NULL).
- */
-int
-GNUNET_SERVICE_get_server_addresses (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct sockaddr ***addrs,
- socklen_t ** addr_lens)
-{
- int disablev6;
- struct GNUNET_NETWORK_Handle *desc;
- unsigned long long port;
- char *unixpath;
- struct addrinfo hints;
- struct addrinfo *res;
- struct addrinfo *pos;
- struct addrinfo *next;
- unsigned int i;
- int resi;
- int ret;
- int abstract;
- struct sockaddr **saddrs;
- socklen_t *saddrlens;
- char *hostname;
-
- *addrs = NULL;
- *addr_lens = NULL;
- desc = NULL;
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
- {
- if (GNUNET_SYSERR ==
- (disablev6 =
- GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
- return GNUNET_SYSERR;
- }
- else
- disablev6 = GNUNET_NO;
-
- if (! disablev6)
- {
- /* probe IPv6 support */
- desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
- if (NULL == desc)
- {
- if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
- (EACCES == errno))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
- return GNUNET_SYSERR;
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
- service_name, STRERROR (errno));
- disablev6 = GNUNET_YES;
- }
- else
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
- desc = NULL;
- }
- }
-
- port = 0;
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
- "PORT", &port))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Require valid port number for service `%s' in configuration!\n"),
- service_name);
- }
- if (port > 65535)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Require valid port number for service `%s' in configuration!\n"),
- service_name);
- return GNUNET_SYSERR;
- }
- }
-
- if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
- {
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
- "BINDTO", &hostname));
- }
- else
- hostname = NULL;
-
- unixpath = NULL;
- abstract = GNUNET_NO;
-#ifdef AF_UNIX
- if ((GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
- &unixpath)) &&
- (0 < strlen (unixpath)))
- {
- /* probe UNIX support */
- struct sockaddr_un s_un;
-
- if (strlen (unixpath) >= sizeof (s_un.sun_path))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
- (unsigned long long) sizeof (s_un.sun_path));
- unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Using `%s' instead\n"),
- unixpath);
- }
-#ifdef LINUX
- abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "TESTING",
- "USE_ABSTRACT_SOCKETS");
- if (GNUNET_SYSERR == abstract)
- abstract = GNUNET_NO;
-#endif
- if ((GNUNET_YES != abstract)
- && (GNUNET_OK !=
- GNUNET_DISK_directory_create_for_file (unixpath)))
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "mkdir",
- unixpath);
- }
- if (NULL != unixpath)
- {
- desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
- if (NULL == desc)
- {
- if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
- (EACCES == errno))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
- GNUNET_free_non_null (hostname);
- GNUNET_free (unixpath);
- return GNUNET_SYSERR;
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
- service_name,
- STRERROR (errno));
- GNUNET_free (unixpath);
- unixpath = NULL;
- }
- else
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
- desc = NULL;
- }
- }
-#endif
-
- if ((0 == port) && (NULL == unixpath))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
- service_name);
- GNUNET_free_non_null (hostname);
- return GNUNET_SYSERR;
- }
- if (0 == port)
- {
- saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- GNUNET_free_non_null (unixpath);
- GNUNET_free_non_null (hostname);
- *addrs = saddrs;
- *addr_lens = saddrlens;
- return 1;
- }
-
- if (NULL != hostname)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Resolving `%s' since that is where `%s' will bind to.\n",
- hostname,
- service_name);
- memset (&hints, 0, sizeof (struct addrinfo));
- if (disablev6)
- hints.ai_family = AF_INET;
- hints.ai_protocol = IPPROTO_TCP;
- if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
- (NULL == res))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to resolve `%s': %s\n"),
- hostname,
- gai_strerror (ret));
- GNUNET_free (hostname);
- GNUNET_free_non_null (unixpath);
- return GNUNET_SYSERR;
- }
- next = res;
- i = 0;
- while (NULL != (pos = next))
- {
- next = pos->ai_next;
- if ((disablev6) && (pos->ai_family == AF_INET6))
- continue;
- i++;
- }
- if (0 == i)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to find %saddress for `%s'.\n"),
- disablev6 ? "IPv4 " : "",
- hostname);
- freeaddrinfo (res);
- GNUNET_free (hostname);
- GNUNET_free_non_null (unixpath);
- return GNUNET_SYSERR;
- }
- resi = i;
- if (NULL != unixpath)
- resi++;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
- i = 0;
- if (NULL != unixpath)
- {
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- i++;
- }
- next = res;
- while (NULL != (pos = next))
- {
- next = pos->ai_next;
- if ((disablev6) && (AF_INET6 == pos->ai_family))
- continue;
- if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
- continue; /* not TCP */
- if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
- continue; /* huh? */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
- service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
- if (AF_INET == pos->ai_family)
- {
- GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
- saddrlens[i] = pos->ai_addrlen;
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
- GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
- ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
- }
- else
- {
- GNUNET_assert (AF_INET6 == pos->ai_family);
- GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
- saddrlens[i] = pos->ai_addrlen;
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
- GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
- ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
- }
- i++;
- }
- GNUNET_free (hostname);
- freeaddrinfo (res);
- resi = i;
- }
- else
- {
- /* will bind against everything, just set port */
- if (disablev6)
- {
- /* V4-only */
- resi = 1;
- if (NULL != unixpath)
- resi++;
- i = 0;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
- if (NULL != unixpath)
- {
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- i++;
- }
- saddrlens[i] = sizeof (struct sockaddr_in);
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
-#endif
- ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
- ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
- }
- else
- {
- /* dual stack */
- resi = 2;
- if (NULL != unixpath)
- resi++;
- saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
- saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
- i = 0;
- if (NULL != unixpath)
- {
- add_unixpath (saddrs, saddrlens, unixpath, abstract);
- i++;
- }
- saddrlens[i] = sizeof (struct sockaddr_in6);
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
-#endif
- ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
- ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
- i++;
- saddrlens[i] = sizeof (struct sockaddr_in);
- saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
- ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
-#endif
- ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
- ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
- }
- }
- GNUNET_free_non_null (unixpath);
- *addrs = saddrs;
- *addr_lens = saddrlens;
- return resi;
-}
-
-
-#ifdef MINGW
-/**
- * Read listen sockets from the parent process (ARM).
- *
- * @param sctx service context to initialize
- * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
- * and #GNUNET_SYSERR on error.
- */
-static int
-receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
-{
- const char *env_buf;
- int fail;
- uint64_t count;
- uint64_t i;
- HANDLE lsocks_pipe;
-
- env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
- if ((NULL == env_buf) || (strlen (env_buf) <= 0))
- return GNUNET_NO;
- /* Using W32 API directly here, because this pipe will
- * never be used outside of this function, and it's just too much of a bother
- * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
- */
- lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
- if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
- return GNUNET_NO;
- fail = 1;
- do
- {
- int ret;
- int fail2;
- DWORD rd;
-
- ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
- if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
- break;
- sctx->lsocks =
- GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
-
- fail2 = 1;
- for (i = 0; i < count; i++)
- {
- WSAPROTOCOL_INFOA pi;
- uint64_t size;
- SOCKET s;
-
- ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
- if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
- break;
- ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
- if ( (0 == ret) || (sizeof (pi) != rd))
- break;
- s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
- sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
- if (NULL == sctx->lsocks[i])
- break;
- else if (i == count - 1)
- fail2 = 0;
- }
- if (fail2)
- break;
- sctx->lsocks[count] = NULL;
- fail = 0;
- }
- while (fail);
-
- CloseHandle (lsocks_pipe);
-
- if (fail)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Could not access a pre-bound socket, will try to bind myself\n"));
- for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
- GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
- GNUNET_free_non_null (sctx->lsocks);
- sctx->lsocks = NULL;
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
-#endif
-
-
-/**
- * Setup addr, addrlen, idle_timeout
- * based on configuration!
- *
- * Configuration may specify:
- * - PORT (where to bind to for TCP)
- * - UNIXPATH (where to bind to for UNIX domain sockets)
- * - TIMEOUT (after how many ms does an inactive service timeout);
- * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
- * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
- * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
- * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
- * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
- * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
- *
- * @param sctx service context to initialize
- * @return #GNUNET_OK if configuration succeeded
- */
-static int
-setup_service (struct GNUNET_SERVICE_Context *sctx)
-{
- struct GNUNET_TIME_Relative idleout;
- int tolerant;
-
-#ifndef MINGW
- const char *nfds;
- unsigned int cnt;
- int flags;
-#endif
-
- if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
- "TIMEOUT", &idleout))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Specified value for `%s' of service `%s' is invalid\n"),
- "TIMEOUT", sctx->service_name);
- return GNUNET_SYSERR;
- }
- sctx->timeout = idleout;
- }
- else
- sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-
- if (GNUNET_CONFIGURATION_have_value
- (sctx->cfg, sctx->service_name, "TOLERANT"))
- {
- if (GNUNET_SYSERR ==
- (tolerant =
- GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
- "TOLERANT")))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Specified value for `%s' of service `%s' is invalid\n"),
- "TOLERANT", sctx->service_name);
- return GNUNET_SYSERR;
- }
- }
- else
- tolerant = GNUNET_NO;
-
-#ifndef MINGW
- errno = 0;
- if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
- (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
- (cnt + 4 < FD_SETSIZE))
- {
- sctx->lsocks =
- GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
- while (0 < cnt--)
- {
- flags = fcntl (3 + cnt, F_GETFD);
- if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
- (NULL ==
- (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _
- ("Could not access pre-bound socket %u, will try to bind myself\n"),
- (unsigned int) 3 + cnt);
- cnt++;
- while (sctx->lsocks[cnt] != NULL)
- GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
- GNUNET_free (sctx->lsocks);
- sctx->lsocks = NULL;
- break;
- }
- }
- unsetenv ("LISTEN_FDS");
- }
-#else
- if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
- {
- receive_sockets_from_parent (sctx);
- putenv ("GNUNET_OS_READ_LSOCKS=");
- }
-#endif
-
- if ((NULL == sctx->lsocks) &&
- (GNUNET_SYSERR ==
- GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
- &sctx->addrs, &sctx->addrlens)))
- return GNUNET_SYSERR;
- sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
- sctx->match_uid =
- GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
- "UNIX_MATCH_UID");
- sctx->match_gid =
- GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
- "UNIX_MATCH_GID");
- process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
- process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
- process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
- process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
-
- return GNUNET_OK;
-}
-
-
-/**
- * Get the name of the user that'll be used
- * to provide the service.
- *
- * @param sctx service context
- * @return value of the 'USERNAME' option
- */
-static char *
-get_user_name (struct GNUNET_SERVICE_Context *sctx)
-{
- char *un;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
- "USERNAME", &un))
- return NULL;
- return un;
-}
-
-
-/**
- * Write PID file.
- *
- * @param sctx service context
- * @param pid PID to write (should be equal to 'getpid()'
- * @return #GNUNET_OK on success (including no work to be done)
- */
-static int
-write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
-{
- FILE *pidfd;
- char *pif;
- char *user;
- char *rdir;
- int len;
-
- if (NULL == (pif = get_pid_file_name (sctx)))
- return GNUNET_OK; /* no file desired */
- user = get_user_name (sctx);
- rdir = GNUNET_strdup (pif);
- len = strlen (rdir);
- while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
- len--;
- rdir[len] = '\0';
- if (0 != ACCESS (rdir, F_OK))
- {
- /* we get to create a directory -- and claim it
- * as ours! */
- (void) GNUNET_DISK_directory_create (rdir);
- if ((NULL != user) && (0 < strlen (user)))
- GNUNET_DISK_file_change_owner (rdir, user);
- }
- if (0 != ACCESS (rdir, W_OK | X_OK))
- {
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
- GNUNET_free (rdir);
- GNUNET_free_non_null (user);
- GNUNET_free (pif);
- return GNUNET_SYSERR;
- }
- GNUNET_free (rdir);
- pidfd = FOPEN (pif, "w");
- if (NULL == pidfd)
- {
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
- GNUNET_free (pif);
- GNUNET_free_non_null (user);
- return GNUNET_SYSERR;
- }
- if (0 > FPRINTF (pidfd, "%u", pid))
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
- GNUNET_break (0 == FCLOSE (pidfd));
- if ((NULL != user) && (0 < strlen (user)))
- GNUNET_DISK_file_change_owner (pif, user);
- GNUNET_free_non_null (user);
- GNUNET_free (pif);
- return GNUNET_OK;
-}
-
-
-/**
- * Task run during shutdown. Stops the server/service.
- *
- * @param cls the `struct GNUNET_SERVICE_Context`
- */
-static void
-shutdown_task (void *cls)
-{
- struct GNUNET_SERVICE_Context *service = cls;
- struct GNUNET_SERVER_Handle *server = service->server;
-
- service->shutdown_task = NULL;
- if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
- GNUNET_SERVER_stop_listening (server);
- else
- GNUNET_SERVER_destroy (server);
-}
-
-
-/**
- * Initial task for the service.
- *
- * @param cls service context
- */
-static void
-service_task (void *cls)
-{
- struct GNUNET_SERVICE_Context *sctx = cls;
- unsigned int i;
-
- (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
- GNUNET_RESOLVER_connect (sctx->cfg);
- if (NULL != sctx->lsocks)
- sctx->server
- = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
- sctx->timeout, sctx->require_found);
- else
- sctx->server
- = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
- sctx->timeout, sctx->require_found);
- if (NULL == sctx->server)
- {
- if (NULL != sctx->addrs)
- for (i = 0; NULL != sctx->addrs[i]; i++)
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Failed to start `%s' at `%s'\n"),
- sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
- sctx->ret = GNUNET_SYSERR;
- return;
- }
-#ifndef WINDOWS
- if (NULL != sctx->addrs)
- for (i = 0; NULL != sctx->addrs[i]; i++)
- if ((AF_UNIX == sctx->addrs[i]->sa_family)
- && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
- GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
- sctx->match_uid,
- sctx->match_gid);
-#endif
-
-
- if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
- {
- /* install a task that will kill the server
- * process if the scheduler ever gets a shutdown signal */
- sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
- sctx);
- }
- sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
- GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
- i = 0;
- while (NULL != sctx->my_handlers[i].callback)
- sctx->my_handlers[i++].callback_cls = sctx;
- GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
- if (-1 != sctx->ready_confirm_fd)
- {
- GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
- GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
- sctx->ready_confirm_fd = -1;
- write_pid_file (sctx, getpid ());
- }
- if (NULL != sctx->addrs)
- {
- i = 0;
- while (NULL != sctx->addrs[i])
- {
- LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
- sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
- i++;
- }
- }
- sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
-}
-
-
-/**
- * Detach from terminal.
- *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-detach_terminal (struct GNUNET_SERVICE_Context *sctx)
-{
-#ifndef MINGW
- pid_t pid;
- int nullfd;
- int filedes[2];
-
- if (0 != PIPE (filedes))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
- return GNUNET_SYSERR;
- }
- pid = fork ();
- if (pid < 0)
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
- return GNUNET_SYSERR;
- }
- if (0 != pid)
- {
- /* Parent */
- char c;
-
- GNUNET_break (0 == CLOSE (filedes[1]));
- c = 'X';
- if (1 != READ (filedes[0], &c, sizeof (char)))
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
- fflush (stdout);
- switch (c)
- {
- case '.':
- exit (0);
- case 'I':
- LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
- break;
- case 'S':
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Service process could not initialize server function\n"));
- break;
- case 'X':
- LOG (GNUNET_ERROR_TYPE_INFO,
- _("Service process failed to report status\n"));
- break;
- }
- exit (1); /* child reported error */
- }
- GNUNET_break (0 == CLOSE (0));
- GNUNET_break (0 == CLOSE (1));
- GNUNET_break (0 == CLOSE (filedes[0]));
- nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
- if (nullfd < 0)
- return GNUNET_SYSERR;
- /* set stdin/stdout to /dev/null */
- if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
- {
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
- (void) CLOSE (nullfd);
- return GNUNET_SYSERR;
- }
- (void) CLOSE (nullfd);
- /* Detach from controlling terminal */
- pid = setsid ();
- if (-1 == pid)
- LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
- sctx->ready_confirm_fd = filedes[1];
-#else
- /* FIXME: we probably need to do something else
- * elsewhere in order to fork the process itself... */
- FreeConsole ();
-#endif
- return GNUNET_OK;
-}
-
-
-/**
- * Set user ID.
- *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-set_user_id (struct GNUNET_SERVICE_Context *sctx)
-{
- char *user;
-
- if (NULL == (user = get_user_name (sctx)))
- return GNUNET_OK; /* keep */
-#ifndef MINGW
- struct passwd *pws;
-
- errno = 0;
- pws = getpwnam (user);
- if (NULL == pws)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- _("Cannot obtain information about user `%s': %s\n"), user,
- errno == 0 ? _("No such user") : STRERROR (errno));
- GNUNET_free (user);
- return GNUNET_SYSERR;
- }
- if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
-#if HAVE_INITGROUPS
- (0 != initgroups (user, pws->pw_gid)) ||
-#endif
- (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
- {
- if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
- (0 != setreuid (pws->pw_uid, pws->pw_uid)))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
- user, STRERROR (errno));
- GNUNET_free (user);
- return GNUNET_SYSERR;
- }
- }
-#endif
- GNUNET_free (user);
- return GNUNET_OK;
-}
-
-
-/**
- * Delete the PID file that was created by our parent.
- *
- * @param sctx service context
- */
-static void
-pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
-{
- char *pif = get_pid_file_name (sctx);
-
- if (NULL == pif)
- return; /* no PID file */
- if (0 != UNLINK (pif))
- LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
- GNUNET_free (pif);
-}
-
-
-/**
- * Run a standard GNUnet service startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @param argc number of command line arguments
- * @param argv command line arguments
- * @param service_name our service name
- * @param options service options
- * @param task main task of the service
- * @param task_cls closure for @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK
- * if we shutdown nicely
- */
-int
-GNUNET_SERVICE_run (int argc, char *const *argv,
- const char *service_name,
- enum GNUNET_SERVICE_Options options,
- GNUNET_SERVICE_Main task,
- void *task_cls)
-{
-#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
-
- int err;
- int ret;
- char *cfg_fn;
- char *opt_cfg_fn;
- char *loglev;
- char *logfile;
- int do_daemonize;
- unsigned int i;
- unsigned long long skew_offset;
- unsigned long long skew_variance;
- long long clock_offset;
- struct GNUNET_SERVICE_Context sctx;
- struct GNUNET_CONFIGURATION_Handle *cfg;
- const char *xdg;
-
- struct GNUNET_GETOPT_CommandLineOption service_options[] = {
- GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
- {'d', "daemonize", NULL,
- gettext_noop ("do daemonize (detach from terminal)"), 0,
- GNUNET_GETOPT_set_one, &do_daemonize},
- GNUNET_GETOPT_OPTION_HELP (NULL),
- GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
- GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
- GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
- GNUNET_GETOPT_OPTION_END
- };
- err = 1;
- do_daemonize = 0;
- logfile = NULL;
- loglev = NULL;
- opt_cfg_fn = NULL;
- xdg = getenv ("XDG_CONFIG_HOME");
- if (NULL != xdg)
- GNUNET_asprintf (&cfg_fn,
- "%s%s%s",
- xdg,
- DIR_SEPARATOR_STR,
- GNUNET_OS_project_data_get ()->config_file);
- else
- cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
- memset (&sctx, 0, sizeof (sctx));
- sctx.options = options;
- sctx.ready_confirm_fd = -1;
- sctx.ret = GNUNET_OK;
- sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
- sctx.task = task;
- sctx.task_cls = task_cls;
- sctx.service_name = service_name;
- sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
-
- /* setup subsystems */
- ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
- if (GNUNET_SYSERR == ret)
- goto shutdown;
- if (GNUNET_NO == ret)
- {
- err = 0;
- goto shutdown;
- }
- if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
- HANDLE_ERROR;
- if (NULL == opt_cfg_fn)
- opt_cfg_fn = GNUNET_strdup (cfg_fn);
- if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
- {
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Malformed configuration file `%s', exit ...\n"),
- opt_cfg_fn);
- goto shutdown;
- }
- }
- else
- {
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Malformed configuration, exit ...\n"));
- goto shutdown;
- }
- if (0 != strcmp (opt_cfg_fn, cfg_fn))
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not access configuration file `%s'\n"),
- opt_cfg_fn);
- }
- if (GNUNET_OK != setup_service (&sctx))
- goto shutdown;
- if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
- HANDLE_ERROR;
- if (GNUNET_OK != set_user_id (&sctx))
- goto shutdown;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Service `%s' runs with configuration from `%s'\n",
- service_name,
- opt_cfg_fn);
- if ((GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
- "SKEW_OFFSET", &skew_offset)) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
- "SKEW_VARIANCE", &skew_variance)))
- {
- clock_offset = skew_offset - skew_variance;
- GNUNET_TIME_set_offset (clock_offset);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
- }
- /* actually run service */
- err = 0;
- GNUNET_SCHEDULER_run (&service_task, &sctx);
- /* shutdown */
- if ((1 == do_daemonize) && (NULL != sctx.server))
- pid_file_delete (&sctx);
- GNUNET_free_non_null (sctx.my_handlers);
-
-shutdown:
- if (-1 != sctx.ready_confirm_fd)
- {
- if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
- GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
- }
-#if HAVE_MALLINFO
- {
- char *counter;
-
- if ( (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
- "GAUGER_HEAP")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
- "GAUGER_HEAP",
- &counter)) )
- {
- struct mallinfo mi;
-
- mi = mallinfo ();
- GAUGER (service_name, counter, mi.usmblks, "blocks");
- GNUNET_free (counter);
- }
- }
-#endif
- GNUNET_SPEEDUP_stop_ ();
- GNUNET_CONFIGURATION_destroy (cfg);
- i = 0;
- if (NULL != sctx.addrs)
- while (NULL != sctx.addrs[i])
- GNUNET_free (sctx.addrs[i++]);
- GNUNET_free_non_null (sctx.addrs);
- GNUNET_free_non_null (sctx.addrlens);
- GNUNET_free_non_null (logfile);
- GNUNET_free_non_null (loglev);
- GNUNET_free (cfg_fn);
- GNUNET_free_non_null (opt_cfg_fn);
- GNUNET_free_non_null (sctx.v4_denied);
- GNUNET_free_non_null (sctx.v6_denied);
- GNUNET_free_non_null (sctx.v4_allowed);
- GNUNET_free_non_null (sctx.v6_allowed);
-
- return err ? GNUNET_SYSERR : sctx.ret;
-}
-
-
-/**
- * Run a service startup sequence within an existing
- * initialized system.
- *
- * @param service_name our service name
- * @param cfg configuration to use
- * @param options service options
- * @return NULL on error, service handle
- */
-struct GNUNET_SERVICE_Context *
-GNUNET_SERVICE_start (const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- enum GNUNET_SERVICE_Options options)
-{
- int i;
- struct GNUNET_SERVICE_Context *sctx;
-
- sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
- sctx->ready_confirm_fd = -1; /* no daemonizing */
- sctx->ret = GNUNET_OK;
- sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
- sctx->service_name = service_name;
- sctx->cfg = cfg;
- sctx->options = options;
-
- /* setup subsystems */
- if (GNUNET_OK != setup_service (sctx))
- {
- GNUNET_SERVICE_stop (sctx);
- return NULL;
- }
- if (NULL != sctx->lsocks)
- sctx->server =
- GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
- sctx->timeout, sctx->require_found);
- else
- sctx->server =
- GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
- sctx->timeout, sctx->require_found);
-
- if (NULL == sctx->server)
- {
- GNUNET_SERVICE_stop (sctx);
- return NULL;
- }
-#ifndef WINDOWS
- if (NULL != sctx->addrs)
- for (i = 0; NULL != sctx->addrs[i]; i++)
- if ((AF_UNIX == sctx->addrs[i]->sa_family)
- && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
- GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
- sctx->match_uid,
- sctx->match_gid);
-#endif
- sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
- GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
- i = 0;
- while ((sctx->my_handlers[i].callback != NULL))
- sctx->my_handlers[i++].callback_cls = sctx;
- GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
- return sctx;
-}
-
-
-/**
- * Obtain the server used by a service. Note that the server must NOT
- * be destroyed by the caller.
- *
- * @param ctx the service context returned from the start function
- * @return handle to the server for this service, NULL if there is none
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
-{
- return ctx->server;
-}
-
-
-/**
- * Get the NULL-terminated array of listen sockets for this service.
- *
- * @param ctx service context to query
- * @return NULL if there are no listen sockets, otherwise NULL-terminated
- * array of listen sockets.
- */
-struct GNUNET_NETWORK_Handle *const*
-GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
-{
- return ctx->lsocks;
-}
-
-
-/**
- * Stop a service that was started with "GNUNET_SERVICE_start".
- *
- * @param sctx the service context returned from the start function
- */
-void
-GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
-{
- unsigned int i;
-
-#if HAVE_MALLINFO
- {
- char *counter;
-
- if ( (GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
- "GAUGER_HEAP")) &&
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
- "GAUGER_HEAP",
- &counter)) )
- {
- struct mallinfo mi;
-
- mi = mallinfo ();
- GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
- GNUNET_free (counter);
- }
- }
-#endif
- if (NULL != sctx->shutdown_task)
- {
- GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
- sctx->shutdown_task = NULL;
- }
- if (NULL != sctx->server)
- GNUNET_SERVER_destroy (sctx->server);
- GNUNET_free_non_null (sctx->my_handlers);
- if (NULL != sctx->addrs)
- {
- i = 0;
- while (NULL != sctx->addrs[i])
- GNUNET_free (sctx->addrs[i++]);
- GNUNET_free (sctx->addrs);
- }
- GNUNET_free_non_null (sctx->addrlens);
- GNUNET_free_non_null (sctx->v4_denied);
- GNUNET_free_non_null (sctx->v6_denied);
- GNUNET_free_non_null (sctx->v4_allowed);
- GNUNET_free_non_null (sctx->v6_allowed);
- GNUNET_free (sctx);
-}
-
-
-/* end of service.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *asock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static size_t sofar;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return -1 on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
- const static int on = 1;
- struct sockaddr_in sa;
- struct GNUNET_NETWORK_Handle *desc;
-
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_port = htons (PORT);
- sa.sin_family = AF_INET;
- desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
- GNUNET_assert (desc != NULL);
- if (GNUNET_NETWORK_socket_setsockopt
- (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
- GNUNET_assert (GNUNET_OK ==
- GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
- sizeof (sa)));
- GNUNET_NETWORK_socket_listen (desc, 5);
- return desc;
-}
-
-static void
-receive_check (void *cls, const void *buf, size_t available,
- const struct sockaddr *addr, socklen_t addrlen, int errCode)
-{
- int *ok = cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive validates incoming data\n");
- GNUNET_assert (buf != NULL); /* no timeout */
- if (0 == memcmp (&"Hello World"[sofar], buf, available))
- sofar += available;
- if (sofar < 12)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive needs more data\n");
- GNUNET_CONNECTION_receive (asock, 1024,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
- cls);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n");
- *ok = 0;
- GNUNET_CONNECTION_destroy (asock);
- GNUNET_CONNECTION_destroy (csock);
- }
-}
-
-
-static void
-run_accept (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test accepts connection\n");
- asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
- GNUNET_assert (asock != NULL);
- GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n");
- GNUNET_CONNECTION_destroy (lsock);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Test asks to receive on accepted socket\n");
- GNUNET_CONNECTION_receive (asock, 1024,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
- cls);
-}
-
-
-static size_t
-make_hello (void *cls, size_t size, void *buf)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Test prepares to transmit on connect socket\n");
- GNUNET_assert (size >= 12);
- strcpy ((char *) buf, "Hello World");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n");
- return 12;
-}
-
-
-static void
-task (void *cls)
-{
- ls = open_listen_socket ();
- lsock = GNUNET_CONNECTION_create_from_existing (ls);
- GNUNET_assert (lsock != NULL);
- csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
- GNUNET_assert (csock != NULL);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n");
- GNUNET_assert (NULL !=
- GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
- GNUNET_TIME_UNIT_SECONDS,
- &make_hello, NULL));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n");
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept,
- cls);
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ok;
-
- GNUNET_log_setup ("test_connection",
- "WARNING",
- NULL);
-
- ok = 1;
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- GNUNET_SCHEDULER_run (&task, &ok);
- GNUNET_CONFIGURATION_destroy (cfg);
- return ok;
-}
-
-/* end of test_connection.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_addressing.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-
-#define PORT 12435
-
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *asock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static size_t sofar;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
- const static int on = 1;
- struct sockaddr_in sa;
- struct GNUNET_NETWORK_Handle *desc;
-
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = htons (PORT);
- desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
- GNUNET_assert (desc != 0);
- if (GNUNET_NETWORK_socket_setsockopt
- (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
- sizeof (sa)))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "bind");
- GNUNET_assert (0);
- }
- GNUNET_NETWORK_socket_listen (desc, 5);
- return desc;
-}
-
-
-static void
-receive_check (void *cls, const void *buf, size_t available,
- const struct sockaddr *addr, socklen_t addrlen, int errCode)
-{
- int *ok = cls;
-
- GNUNET_assert (buf != NULL); /* no timeout */
- if (0 == memcmp (&"Hello World"[sofar], buf, available))
- sofar += available;
- if (sofar < 12)
- {
- GNUNET_CONNECTION_receive (asock, 1024,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
- cls);
- }
- else
- {
- *ok = 0;
- GNUNET_CONNECTION_destroy (csock);
- GNUNET_CONNECTION_destroy (asock);
- }
-}
-
-
-static void
-run_accept (void *cls)
-{
- void *addr;
- size_t alen;
- struct sockaddr_in *v4;
- struct sockaddr_in expect;
-
- asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
- GNUNET_assert (asock != NULL);
- GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONNECTION_get_address (asock, &addr, &alen));
- GNUNET_assert (alen == sizeof (struct sockaddr_in));
- v4 = addr;
- memset (&expect, 0, sizeof (expect));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- expect.sin_len = sizeof (expect);
-#endif
- expect.sin_family = AF_INET;
- expect.sin_port = v4->sin_port;
- expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- GNUNET_assert (0 == memcmp (&expect, v4, alen));
- GNUNET_free (addr);
- GNUNET_CONNECTION_destroy (lsock);
- GNUNET_CONNECTION_receive (asock, 1024,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
- cls);
-}
-
-static size_t
-make_hello (void *cls, size_t size, void *buf)
-{
- GNUNET_assert (size >= 12);
- strcpy ((char *) buf, "Hello World");
- return 12;
-}
-
-
-static void
-task (void *cls)
-{
- struct sockaddr_in v4;
-
- ls = open_listen_socket ();
- lsock = GNUNET_CONNECTION_create_from_existing (ls);
- GNUNET_assert (lsock != NULL);
-
-#if HAVE_SOCKADDR_IN_SIN_LEN
- v4.sin_len = sizeof (v4);
-#endif
- v4.sin_family = AF_INET;
- v4.sin_port = htons (PORT);
- v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- csock =
- GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
- (const struct sockaddr *) &v4,
- sizeof (v4));
- GNUNET_assert (csock != NULL);
- GNUNET_assert (NULL !=
- GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
- GNUNET_TIME_UNIT_SECONDS,
- &make_hello, NULL));
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept,
- cls);
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ok;
-
- GNUNET_log_setup ("test_connection_addressing",
- "WARNING",
- NULL);
- ok = 1;
- GNUNET_SCHEDULER_run (&task, &ok);
- return ok;
-}
-
-/* end of test_connection_addressing.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_receive_cancel.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *asock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
- const static int on = 1;
- struct sockaddr_in sa;
- struct GNUNET_NETWORK_Handle *desc;
-
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = htons (PORT);
- desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
- GNUNET_assert (desc != NULL);
- if (GNUNET_NETWORK_socket_setsockopt
- (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "setsockopt");
- GNUNET_assert (GNUNET_OK ==
- GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
- sizeof (sa)));
- GNUNET_NETWORK_socket_listen (desc, 5);
- return desc;
-}
-
-
-static void
-dead_receive (void *cls,
- const void *buf,
- size_t available,
- const struct sockaddr *addr,
- socklen_t addrlen,
- int errCode)
-{
- GNUNET_assert (0);
-}
-
-
-static void
-run_accept_cancel (void *cls)
-{
- asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
- GNUNET_assert (asock != NULL);
- GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
- GNUNET_CONNECTION_destroy (lsock);
- GNUNET_CONNECTION_receive (asock, 1024,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 5),
- &dead_receive, cls);
-}
-
-
-static void
-receive_cancel_task (void *cls)
-{
- int *ok = cls;
-
- GNUNET_CONNECTION_receive_cancel (asock);
- GNUNET_CONNECTION_destroy (csock);
- GNUNET_CONNECTION_destroy (asock);
- *ok = 0;
-}
-
-
-static void
-task_receive_cancel (void *cls)
-{
- ls = open_listen_socket ();
- lsock = GNUNET_CONNECTION_create_from_existing (ls);
- GNUNET_assert (lsock != NULL);
- csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
- GNUNET_assert (csock != NULL);
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- ls,
- &run_accept_cancel,
- cls);
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &receive_cancel_task,
- cls);
-}
-
-
-/**
- * Main method, starts scheduler with task_timeout.
- */
-static int
-check_receive_cancel ()
-{
- int ok;
-
- ok = 1;
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_string (cfg,
- "resolver",
- "HOSTNAME",
- "localhost");
- GNUNET_SCHEDULER_run (&task_receive_cancel, &ok);
- GNUNET_CONFIGURATION_destroy (cfg);
- return ok;
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ret = 0;
-
- GNUNET_log_setup ("test_connection_receive_cancel", "WARNING", NULL);
- ret += check_receive_cancel ();
-
- return ret;
-}
-
-/* end of test_connection_receive_cancel.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_timeout.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
- const static int on = 1;
- struct sockaddr_in sa;
- struct GNUNET_NETWORK_Handle *desc;
-
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = htons (PORT);
- desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
- GNUNET_assert (desc != NULL);
- if (GNUNET_NETWORK_socket_setsockopt
- (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
- GNUNET_assert (GNUNET_OK ==
- GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
- sizeof (sa)));
- GNUNET_NETWORK_socket_listen (desc, 5);
- return desc;
-}
-
-
-static size_t
-send_kilo (void *cls, size_t size, void *buf)
-{
- int *ok = cls;
-
- if (size == 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the desired timeout!\n");
- GNUNET_assert (buf == NULL);
- *ok = 0;
- GNUNET_CONNECTION_destroy (lsock);
- GNUNET_CONNECTION_destroy (csock);
- return 0;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kilo to fill buffer.\n");
- GNUNET_assert (size >= 1024);
- memset (buf, 42, 1024);
-
- GNUNET_assert (NULL !=
- GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
- GNUNET_TIME_UNIT_SECONDS,
- &send_kilo, cls));
- return 1024;
-}
-
-
-static void
-task_timeout (void *cls)
-{
-
- ls = open_listen_socket ();
- lsock = GNUNET_CONNECTION_create_from_existing (ls);
- GNUNET_assert (lsock != NULL);
- csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
- GNUNET_assert (csock != NULL);
- GNUNET_assert (NULL !=
- GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
- GNUNET_TIME_UNIT_SECONDS,
- &send_kilo, cls));
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ok;
-
- GNUNET_log_setup ("test_connection_timeout",
- "WARNING",
- NULL);
-
- ok = 1;
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- GNUNET_SCHEDULER_run (&task_timeout, &ok);
- GNUNET_CONFIGURATION_destroy (cfg);
- return ok;
-}
-
-/* end of test_connection_timeout.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_timeout_no_connect.c
- * @brief tests for connection.c, doing timeout which connect failure
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 13425
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static size_t
-handle_timeout (void *cls, size_t size, void *buf)
-{
- int *ok = cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received timeout signal.\n");
- GNUNET_assert (size == 0);
- GNUNET_assert (buf == NULL);
- *ok = 0;
- return 0;
-}
-
-
-static void
-task_timeout (void *cls)
-{
- csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
- GNUNET_assert (csock != NULL);
- GNUNET_assert (NULL !=
- GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
- GNUNET_TIME_UNIT_SECONDS,
- &handle_timeout,
- cls));
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ok;
-
- GNUNET_log_setup ("test_connection_timeout_no_connect",
- "WARNING",
- NULL);
- ok = 1;
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- GNUNET_SCHEDULER_run (&task_timeout, &ok);
- GNUNET_CONFIGURATION_destroy (cfg);
- return ok;
-}
-
-/* end of test_connection_timeout_no_connect.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_transmit_cancel.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-static size_t
-not_run (void *cls, size_t size, void *buf)
-{
- GNUNET_assert (0);
- return 0;
-}
-
-
-static void
-task_transmit_cancel (void *cls)
-{
- int *ok = cls;
- struct GNUNET_CONNECTION_TransmitHandle *th;
- struct GNUNET_CONNECTION_Handle *csock;
-
- csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
- GNUNET_assert (csock != NULL);
- th = GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
- GNUNET_TIME_UNIT_MINUTES,
- ¬_run, cls);
- GNUNET_assert (NULL != th);
- GNUNET_CONNECTION_notify_transmit_ready_cancel (th);
- GNUNET_CONNECTION_destroy (csock);
- *ok = 0;
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ok;
-
- GNUNET_log_setup ("test_connection_transmit_cancel",
- "WARNING",
- NULL);
- ok = 1;
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok);
- GNUNET_CONFIGURATION_destroy (cfg);
- return ok;
-}
-
-/* end of test_connection_transmit_cancel.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2014, 2016 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server.c
- * @brief tests for server.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * TCP port to use for the server.
- */
-#define PORT 12435
-
-/**
- * Timeout to use for operations.
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
-
-/**
- * Test message type.
- */
-#define MY_TYPE 128
-
-/**
- * Test message type.
- */
-#define MY_TYPE2 129
-
-/**
- * Handle for the server.
- */
-static struct GNUNET_SERVER_Handle *server;
-
-/**
- * Handle for the client.
- */
-static struct GNUNET_MQ_Handle *mq;
-
-/**
- * Handle of the server for the client.
- */
-static struct GNUNET_SERVER_Client *argclient;
-
-/**
- * Our configuration.
- */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Number indiciating in which phase of the test we are.
- */
-static int ok;
-
-
-/**
- * Final task invoked to clean up.
- *
- * @param cls NULL
- */
-static void
-finish_up (void *cls)
-{
- GNUNET_assert (7 == ok);
- ok = 0;
- GNUNET_SERVER_destroy (server);
- GNUNET_MQ_destroy (mq);
- GNUNET_CONFIGURATION_destroy (cfg);
-}
-
-
-/**
- * The server has received the second message, initiate clean up.
- *
- * @param cls NULL
- * @param client client we got the message from
- * @param message the message
- */
-static void
-recv_fin_cb (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- GNUNET_assert (6 == ok);
- ok = 7;
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- GNUNET_SCHEDULER_add_now (&finish_up, NULL);
-}
-
-
-/**
- * We have received the reply from the server, check that we are at
- * the right stage and queue the next message to the server. Cleans
- * up #argclient.
- *
- * @param cls NULL
- * @param msg message we got from the server
- */
-static void
-handle_reply (void *cls,
- const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *m;
-
- GNUNET_assert (4 == ok);
- ok = 6;
- env = GNUNET_MQ_msg (m,
- MY_TYPE2);
- GNUNET_MQ_send (mq,
- env);
-}
-
-
-/**
- * Send a reply of type #MY_TYPE from the server to the client.
- * Checks that we are in the right phase and transmits the
- * reply. Cleans up #argclient state.
- *
- * @param cls NULL
- * @param size number of bytes we are allowed to send
- * @param buf where to copy the reply
- * @return number of bytes written to @a buf
- */
-static size_t
-reply_msg (void *cls,
- size_t size,
- void *buf)
-{
- struct GNUNET_MessageHeader msg;
-
- GNUNET_assert (3 == ok);
- ok = 4;
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
- msg.type = htons (MY_TYPE);
- msg.size = htons (sizeof (struct GNUNET_MessageHeader));
- GNUNET_memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader));
- GNUNET_assert (NULL != argclient);
- GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
- GNUNET_SERVER_client_drop (argclient);
- argclient = NULL;
- return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Function called whenever the server receives a message of
- * type #MY_TYPE. Checks that we are at the stage where
- * we expect the first message, then sends a reply. Stores
- * the handle to the client in #argclient.
- *
- * @param cls NULL
- * @param client client that sent the message
- * @param message the message we received
- */
-static void
-recv_cb (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- GNUNET_assert (2 == ok);
- ok = 3;
- argclient = client;
- GNUNET_SERVER_client_keep (argclient);
- GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size));
- GNUNET_assert (MY_TYPE == ntohs (message->type));
- GNUNET_assert (NULL !=
- GNUNET_SERVER_notify_transmit_ready (client,
- ntohs (message->size),
- TIMEOUT,
- &reply_msg,
- NULL));
-}
-
-
-/**
- * Message handlers for the server.
- */
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
- {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)},
- {NULL, NULL, 0, 0}
-};
-
-
-/**
- * Generic error handler, called with the appropriate error code and
- * the same closure specified at the creation of the message queue.
- * Not every message queue implementation supports an error handler.
- *
- * @param cls closure with the `struct GNUNET_STATISTICS_Handle *`
- * @param error error code
- */
-static void
-mq_error_handler (void *cls,
- enum GNUNET_MQ_Error error)
-{
- GNUNET_assert (0); /* should never happen */
-}
-
-
-/**
- * First task run by the scheduler. Initializes the server and
- * a client and asks for a transmission from the client to the
- * server.
- *
- * @param cls NULL
- */
-static void
-task (void *cls)
-{
- struct sockaddr_in sa;
- struct sockaddr *sap[2];
- socklen_t slens[2];
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
- struct GNUNET_MQ_MessageHandler chandlers[] = {
- GNUNET_MQ_hd_fixed_size (reply,
- MY_TYPE,
- struct GNUNET_MessageHeader,
- cls),
- GNUNET_MQ_handler_end ()
- };
-
- sap[0] = (struct sockaddr *) &sa;
- slens[0] = sizeof (sa);
- sap[1] = NULL;
- slens[1] = 0;
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = htons (PORT);
- server = GNUNET_SERVER_create (NULL, NULL,
- sap, slens,
- TIMEOUT, GNUNET_NO);
- GNUNET_assert (server != NULL);
- GNUNET_SERVER_add_handlers (server, handlers);
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_number (cfg,
- "test-server",
- "PORT",
- PORT);
- GNUNET_CONFIGURATION_set_value_string (cfg,
- "test-server",
- "HOSTNAME",
- "localhost");
- GNUNET_CONFIGURATION_set_value_string (cfg,
- "resolver",
- "HOSTNAME",
- "localhost");
- mq = GNUNET_CLIENT_connect (cfg,
- "test-server",
- chandlers,
- &mq_error_handler,
- NULL);
- GNUNET_assert (NULL != mq);
- ok = 2;
- env = GNUNET_MQ_msg (msg,
- MY_TYPE);
- GNUNET_MQ_send (mq,
- env);
-}
-
-
-/**
- * Runs the test.
- *
- * @param argc length of @a argv
- * @param argv command line arguments (ignored)
- * @return 0 on success, otherwise phase of failure
- */
-int
-main (int argc, char *argv[])
-{
- GNUNET_log_setup ("test_server",
- "WARNING",
- NULL);
- ok = 1;
- GNUNET_SCHEDULER_run (&task, &ok);
- return ok;
-}
-
-/* end of test_server.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2016 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_disconnect.c
- * @brief tests for server.c, specifically GNUNET_SERVER_client_disconnect
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-
-#define PORT 12435
-
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-#define MY_TYPE 128
-
-static struct GNUNET_SERVER_Handle *server;
-
-static struct GNUNET_MQ_Handle *mq;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static int ok;
-
-
-static void
-finish_up (void *cls)
-{
- GNUNET_assert (ok == 5);
- ok = 0;
- GNUNET_SERVER_destroy (server);
- GNUNET_MQ_destroy (mq);
- GNUNET_CONFIGURATION_destroy (cfg);
-}
-
-
-static void
-notify_disconnect (void *cls,
- struct GNUNET_SERVER_Client *clientarg)
-{
- if (NULL == clientarg)
- return;
- GNUNET_assert (ok == 4);
- ok = 5;
- GNUNET_SCHEDULER_add_now (&finish_up, NULL);
-}
-
-
-static void
-server_disconnect (void *cls)
-{
- struct GNUNET_SERVER_Client *argclient = cls;
-
- GNUNET_assert (ok == 3);
- ok = 4;
- GNUNET_SERVER_client_disconnect (argclient);
- GNUNET_SERVER_client_drop (argclient);
-}
-
-
-static void
-recv_cb (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- GNUNET_assert (ok == 2);
- ok = 3;
- GNUNET_SERVER_client_keep (client);
- GNUNET_SCHEDULER_add_now (&server_disconnect, client);
- GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size));
- GNUNET_assert (MY_TYPE == ntohs (message->type));
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
- {NULL, NULL, 0, 0}
-};
-
-
-static void
-task (void *cls)
-{
- struct sockaddr_in sa;
- struct sockaddr *sap[2];
- socklen_t slens[2];
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
-
- sap[0] = (struct sockaddr *) &sa;
- slens[0] = sizeof (sa);
- sap[1] = NULL;
- slens[1] = 0;
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = htons (PORT);
- server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO);
- GNUNET_assert (server != NULL);
- GNUNET_SERVER_add_handlers (server, handlers);
- GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, NULL);
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT);
- GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME",
- "localhost");
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- mq = GNUNET_CLIENT_connect (cfg,
- "test-server",
- NULL,
- NULL,
- NULL);
- GNUNET_assert (NULL != mq);
- ok = 2;
- env = GNUNET_MQ_msg (msg,
- MY_TYPE);
- GNUNET_MQ_send (mq,
- env);
-}
-
-
-/**
- * Main method, starts scheduler with task1,
- * checks that "ok" is correct at the end.
- */
-static int
-check ()
-{
- ok = 1;
- GNUNET_SCHEDULER_run (&task, &ok);
- return ok;
-}
-
-
-int
-main (int argc, char *argv[])
-{
- int ret = 0;
-
- GNUNET_log_setup ("test_server_disconnect", "WARNING", NULL);
- ret += check ();
-
- return ret;
-}
-
-/* end of test_server_disconnect.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2010 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_mst_interrupt.c
- * @brief test for interrupt message processing in server_mst.c
- */
-#include "platform.h"
-#include "gnunet_protocols.h"
-#include "gnunet_util_lib.h"
-
-static struct GNUNET_SERVER_MessageStreamTokenizer * mst;
-
-
-/* Callback destroying mst with data in buffer */
-static int
-mst_cb (void *cls, void *client,
- const struct GNUNET_MessageHeader * message)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MST gave me message, destroying\n");
- GNUNET_SERVER_mst_destroy (mst);
- return GNUNET_SYSERR;
-}
-
-
-int
-main (int argc, char *argv[])
-{
- struct GNUNET_PeerIdentity id;
- struct GNUNET_MessageHeader msg[2];
-
- GNUNET_log_setup ("test_server_mst_interrupt", "WARNING", NULL);
- memset (&id, 0, sizeof (id));
- msg[0].size = htons (sizeof (msg));
- msg[0].type = htons (sizeof (GNUNET_MESSAGE_TYPE_DUMMY));
- mst = GNUNET_SERVER_mst_create(mst_cb, NULL);
- GNUNET_SERVER_mst_receive (mst, &id,
- (const char *) &msg, 2 * sizeof (msg),
- GNUNET_NO, GNUNET_NO);
- /* If we reach this line, it did not crash */
- return 0;
-}
-
-/* end of test_server_mst_interrupt.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2016 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_with_client.c
- * @brief tests for server.c and client.c,
- * specifically disconnect_notify,
- * client_get_address and receive_done (resume processing)
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 22335
-
-#define MY_TYPE 128
-
-
-static struct GNUNET_SERVER_Handle *server;
-
-static struct GNUNET_MQ_Handle *mq;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static int ok;
-
-
-static void
-send_done (void *cls)
-{
- struct GNUNET_SERVER_Client *argclient = cls;
-
- GNUNET_assert (ok == 3);
- ok++;
- GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
-}
-
-
-static void
-recv_cb (void *cls,
- struct GNUNET_SERVER_Client *argclient,
- const struct GNUNET_MessageHeader *message)
-{
- void *addr;
- size_t addrlen;
- struct sockaddr_in sa;
- struct sockaddr_in *have;
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_SERVER_client_get_address (argclient,
- &addr,
- &addrlen));
-
- GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
- have = addr;
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = have->sin_port;
- sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- GNUNET_assert (0 == memcmp (&sa, addr, addrlen));
- GNUNET_free (addr);
- switch (ok)
- {
- case 2:
- ok++;
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_MILLISECONDS, 50),
- &send_done,
- argclient);
- break;
- case 4:
- ok++;
- GNUNET_MQ_destroy (mq);
- GNUNET_SERVER_receive_done (argclient,
- GNUNET_OK);
- break;
- default:
- GNUNET_assert (0);
- }
-
-}
-
-
-static void
-clean_up (void *cls)
-{
- GNUNET_SERVER_destroy (server);
- server = NULL;
- GNUNET_CONFIGURATION_destroy (cfg);
- cfg = NULL;
-}
-
-
-/**
- * Functions with this signature are called whenever a client
- * is disconnected on the network level.
- *
- * @param cls closure
- * @param client identification of the client
- */
-static void
-notify_disconnect (void *cls,
- struct GNUNET_SERVER_Client *client)
-{
- if (client == NULL)
- return;
- GNUNET_assert (ok == 5);
- ok = 0;
- GNUNET_SCHEDULER_add_now (&clean_up, NULL);
-}
-
-
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
- {NULL, NULL, 0, 0}
-};
-
-
-static void
-task (void *cls)
-{
- struct sockaddr_in sa;
- struct sockaddr *sap[2];
- socklen_t slens[2];
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
-
- sap[0] = (struct sockaddr *) &sa;
- slens[0] = sizeof (sa);
- sap[1] = NULL;
- slens[1] = 0;
- memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
- sa.sin_len = sizeof (sa);
-#endif
- sa.sin_family = AF_INET;
- sa.sin_port = htons (PORT);
- server =
- GNUNET_SERVER_create (NULL, NULL, sap, slens,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO);
- GNUNET_assert (server != NULL);
- handlers[0].callback_cls = cls;
- GNUNET_SERVER_add_handlers (server, handlers);
- GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls);
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT);
- GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost");
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- mq = GNUNET_CLIENT_connect (cfg,
- "test",
- NULL,
- NULL,
- NULL);
- GNUNET_assert (NULL != mq);
- ok = 2;
- env = GNUNET_MQ_msg (msg,
- MY_TYPE);
- GNUNET_MQ_send (mq,
- env);
- env = GNUNET_MQ_msg (msg,
- MY_TYPE);
- GNUNET_MQ_send (mq,
- env);
-}
-
-
-int
-main (int argc, char *argv[])
-{
- GNUNET_log_setup ("test_server_with_client",
- "WARNING",
- NULL);
- ok = 1;
- GNUNET_SCHEDULER_run (&task, NULL);
- return ok;
-}
-
-/* end of test_server_with_client.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2016 GNUnet e.V.
-
- 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 3, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_with_client_unix.c
- * @brief tests for server.c and client.c,
- * specifically disconnect_notify,
- * client_get_address and receive_done (resume processing)
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define MY_TYPE 128
-
-
-static struct GNUNET_SERVER_Handle *server;
-
-static struct GNUNET_MQ_Handle *mq;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static int ok;
-
-
-static void
-send_done (void *cls)
-{
- struct GNUNET_SERVER_Client *argclient = cls;
-
- GNUNET_assert (ok == 3);
- ok++;
- GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
-}
-
-
-static void
-recv_cb (void *cls,
- struct GNUNET_SERVER_Client *argclient,
- const struct GNUNET_MessageHeader *message)
-{
- switch (ok)
- {
- case 2:
- ok++;
- (void) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_MILLISECONDS, 50),
- &send_done,
- argclient);
- break;
- case 4:
- ok++;
- GNUNET_MQ_destroy (mq);
- GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
- break;
- default:
- GNUNET_assert (0);
- }
-
-}
-
-
-static void
-clean_up (void *cls)
-{
- GNUNET_SERVER_destroy (server);
- server = NULL;
- GNUNET_CONFIGURATION_destroy (cfg);
- cfg = NULL;
-}
-
-
-/**
- * Functions with this signature are called whenever a client
- * is disconnected on the network level.
- *
- * @param cls closure
- * @param client identification of the client
- */
-static void
-notify_disconnect (void *cls,
- struct GNUNET_SERVER_Client *client)
-{
- if (client == NULL)
- return;
- GNUNET_assert (ok == 5);
- ok = 0;
- (void) GNUNET_SCHEDULER_add_now (&clean_up, NULL);
-}
-
-
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
- {NULL, NULL, 0, 0}
-};
-
-
-static void
-task (void *cls)
-{
- struct sockaddr_un un;
- const char *unixpath = "/tmp/testsock";
- struct sockaddr *sap[2];
- socklen_t slens[2];
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
-
- memset (&un, 0, sizeof (un));
- un.sun_family = AF_UNIX;
- strncpy(un.sun_path, unixpath, sizeof (un.sun_path) - 1);
-#if HAVE_SOCKADDR_UN_SUN_LEN
- un.sun_len = (u_char) sizeof (un);
-#endif
-
- sap[0] = (struct sockaddr *) &un;
- slens[0] = sizeof (un);
- sap[1] = NULL;
- slens[1] = 0;
- server =
- GNUNET_SERVER_create (NULL, NULL, sap, slens,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO);
- GNUNET_assert (server != NULL);
- handlers[0].callback_cls = cls;
- GNUNET_SERVER_add_handlers (server, handlers);
- GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls);
- cfg = GNUNET_CONFIGURATION_create ();
-
- GNUNET_CONFIGURATION_set_value_string (cfg, "test", "UNIXPATH", unixpath);
- GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
- "localhost");
- mq = GNUNET_CLIENT_connect (cfg,
- "test",
- NULL,
- NULL,
- NULL);
- GNUNET_assert (NULL != mq);
- ok = 2;
- env = GNUNET_MQ_msg (msg,
- MY_TYPE);
- GNUNET_MQ_send (mq,
- env);
- env = GNUNET_MQ_msg (msg,
- MY_TYPE);
- GNUNET_MQ_send (mq,
- env);
-}
-
-
-int
-main (int argc, char *argv[])
-{
- GNUNET_log_setup ("test_server_with_client_unix",
- "WARNING",
- NULL);
- ok = 1;
- GNUNET_SCHEDULER_run (&task, NULL);
- return ok;
-}
-
-/* end of test_server_with_client_unix.c */
* and forward the packet.
*
* @param cls closure, NULL
- * @param client NULL
* @param message message we got from the client (VPN channel interface)
*/
static int
message_token (void *cls,
- void *client,
const struct GNUNET_MessageHeader *message)
{
const struct GNUNET_TUN_Layer2PacketHeader *tun;