aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan S. Evans <evans@in.tum.de>2010-01-19 13:23:04 +0000
committerNathan S. Evans <evans@in.tum.de>2010-01-19 13:23:04 +0000
commit71c69f178dd8ad00e917c8724c4f2417f8d9648f (patch)
treef2d68f75774acfc311f26b2a657dedc3be3e3ece /src
parent691f0bfb0a1cbd2a862c4707c40b35aba13c92f1 (diff)
downloadgnunet-71c69f178dd8ad00e917c8724c4f2417f8d9648f.tar.gz
gnunet-71c69f178dd8ad00e917c8724c4f2417f8d9648f.zip
moderate udp support, not really tested (:
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_network_lib.h26
-rw-r--r--src/include/gnunet_protocols.h9
-rw-r--r--src/include/gnunet_scheduler_lib.h4
-rw-r--r--src/transport/Makefile.am17
-rw-r--r--src/transport/plugin_transport_tcp.c6
-rw-r--r--src/transport/plugin_transport_udp.c1087
-rw-r--r--src/transport/test_plugin_transport_data_udp.conf24
-rw-r--r--src/transport/test_plugin_transport_udp.c358
-rw-r--r--src/util/network.c62
-rw-r--r--src/util/scheduler.c10
10 files changed, 1179 insertions, 424 deletions
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h
index 513787e08..71c8d4346 100644
--- a/src/include/gnunet_network_lib.h
+++ b/src/include/gnunet_network_lib.h
@@ -124,6 +124,27 @@ int GNUNET_NETWORK_socket_getsockopt(const struct GNUNET_NETWORK_Handle *desc, i
124int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, int backlog); 124int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, int backlog);
125 125
126/** 126/**
127 * How much data is available to be read on this descriptor?
128 * @param desc socket
129 */
130unsigned int
131GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * desc);
132
133/**
134 * Read data from a connected socket (always non-blocking).
135 * @param desc socket
136 * @param buffer buffer
137 * @param length length of buffer
138 * @param src_addr either the source to recv from, or all zeroes
139 * to be filled in by recvfrom
140 * @param addrlen length of the addr
141 */
142ssize_t
143GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc,
144 void *buffer, size_t length,
145 struct sockaddr *src_addr, socklen_t *addrlen);
146
147/**
127 * Read data from a connected socket (always non-blocking). 148 * Read data from a connected socket (always non-blocking).
128 * 149 *
129 * @param desc socket 150 * @param desc socket
@@ -248,6 +269,11 @@ void GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
248void GNUNET_NETWORK_fdset_copy(struct GNUNET_NETWORK_FDSet *to, 269void GNUNET_NETWORK_fdset_copy(struct GNUNET_NETWORK_FDSet *to,
249 const struct GNUNET_NETWORK_FDSet *from); 270 const struct GNUNET_NETWORK_FDSet *from);
250 271
272/*
273 * Return file descriptor for this network handle
274 */
275int
276GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc);
251/** 277/**
252 * Copy a native fd set 278 * Copy a native fd set
253 * @param to destination 279 * @param to destination
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 51442958c..cdf5d0df3 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -242,6 +242,15 @@ extern "C"
242 */ 242 */
243#define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA 43 243#define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA 43
244 244
245/*
246 * UDP Ping message
247 */
248#define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING 51
249
250/*
251 * UDP Pong message
252 */
253#define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG 52
245 254
246/** 255/**
247 * Initial setup message from core client to core. 256 * Initial setup message from core client to core.
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h
index 9ba4399ad..3205729a3 100644
--- a/src/include/gnunet_scheduler_lib.h
+++ b/src/include/gnunet_scheduler_lib.h
@@ -290,7 +290,7 @@ GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched,
290 * @param sched scheduler to use 290 * @param sched scheduler to use
291 * @param prerequisite_task run this task after the task with the given 291 * @param prerequisite_task run this task after the task with the given
292 * task identifier completes (and any of our other 292 * task identifier completes (and any of our other
293 * conditions, such as delay, read or write-readyness 293 * conditions, such as delay, read or write-readiness
294 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency 294 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
295 * on completion of other tasks (this will cause the task to run as 295 * on completion of other tasks (this will cause the task to run as
296 * soon as possible). 296 * soon as possible).
@@ -480,7 +480,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle *sched,
480 * @param prio how important is this task? 480 * @param prio how important is this task?
481 * @param prerequisite_task run this task after the task with the given 481 * @param prerequisite_task run this task after the task with the given
482 * task identifier completes (and any of our other 482 * task identifier completes (and any of our other
483 * conditions, such as delay, read or write-readyness 483 * conditions, such as delay, read or write-readiness
484 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency 484 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
485 * on completion of other tasks. 485 * on completion of other tasks.
486 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", 486 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever",
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index 02c346ef0..7d1f89a6e 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -48,6 +48,7 @@ gnunet_service_transport_LDADD = \
48 48
49plugin_LTLIBRARIES = \ 49plugin_LTLIBRARIES = \
50 libgnunet_plugin_transport_tcp.la \ 50 libgnunet_plugin_transport_tcp.la \
51 libgnunet_plugin_transport_udp.la \
51 libgnunet_plugin_transport_template.la 52 libgnunet_plugin_transport_template.la
52# TODO: add udp, http, nat, etc. 53# TODO: add udp, http, nat, etc.
53 54
@@ -67,10 +68,19 @@ libgnunet_plugin_transport_template_la_LIBADD = \
67libgnunet_plugin_transport_template_la_LDFLAGS = \ 68libgnunet_plugin_transport_template_la_LDFLAGS = \
68 $(GN_PLUGIN_LDFLAGS) 69 $(GN_PLUGIN_LDFLAGS)
69 70
71libgnunet_plugin_transport_udp_la_SOURCES = \
72 plugin_transport_udp.c
73libgnunet_plugin_transport_udp_la_LIBADD = \
74 $(top_builddir)/src/hello/libgnunethello.la \
75 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
76 $(top_builddir)/src/util/libgnunetutil.la
77libgnunet_plugin_transport_udp_la_LDFLAGS = \
78 $(GN_PLUGIN_LDFLAGS)
70 79
71check_PROGRAMS = \ 80check_PROGRAMS = \
72 test_transport_api \ 81 test_transport_api \
73 test_plugin_transport 82 test_plugin_transport \
83 test_plugin_transport_udp
74# TODO: add tests for tcp, udp, http, nat, etc. 84# TODO: add tests for tcp, udp, http, nat, etc.
75 85
76TESTS = $(check_PROGRAMS) 86TESTS = $(check_PROGRAMS)
@@ -88,6 +98,11 @@ test_plugin_transport_LDADD = \
88 $(top_builddir)/src/transport/libgnunettransport.la \ 98 $(top_builddir)/src/transport/libgnunettransport.la \
89 $(top_builddir)/src/util/libgnunetutil.la 99 $(top_builddir)/src/util/libgnunetutil.la
90 100
101test_plugin_transport_udp_SOURCES = \
102 test_plugin_transport_udp.c
103test_plugin_transport_udp_LDADD = \
104 $(top_builddir)/src/transport/libgnunettransport.la \
105 $(top_builddir)/src/util/libgnunetutil.la
91 106
92EXTRA_DIST = \ 107EXTRA_DIST = \
93 test_transport_api_data.conf \ 108 test_transport_api_data.conf \
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 8c5f79fd3..2694b3f1e 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -218,7 +218,7 @@ struct PendingMessage
218 218
219 /** 219 /**
220 * Continuation function to call once the message 220 * Continuation function to call once the message
221 * has been sent. Can be NULL if there is no 221 * has been sent. Can be NULL if there is no
222 * continuation to call. 222 * continuation to call.
223 */ 223 */
224 GNUNET_TRANSPORT_TransmitContinuation transmit_cont; 224 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
@@ -514,7 +514,7 @@ static void process_pending_messages (struct Session *session);
514 514
515/** 515/**
516 * Function called to notify a client about the socket 516 * Function called to notify a client about the socket
517 * begin ready to queue more data. "buf" will be 517 * being ready to queue more data. "buf" will be
518 * NULL and "size" zero if the socket was closed for 518 * NULL and "size" zero if the socket was closed for
519 * writing in the meantime. 519 * writing in the meantime.
520 * 520 *
@@ -1073,7 +1073,7 @@ session_try_connect (void *cls,
1073static void 1073static void
1074tcp_plugin_send (void *cls, 1074tcp_plugin_send (void *cls,
1075 const struct GNUNET_PeerIdentity *target, 1075 const struct GNUNET_PeerIdentity *target,
1076 unsigned int priority, 1076 unsigned int priority,
1077 const struct GNUNET_MessageHeader *msg, 1077 const struct GNUNET_MessageHeader *msg,
1078 struct GNUNET_TIME_Relative timeout, 1078 struct GNUNET_TIME_Relative timeout,
1079 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) 1079 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
index 624ca0933..d2839762e 100644
--- a/src/transport/plugin_transport_udp.c
+++ b/src/transport/plugin_transport_udp.c
@@ -22,15 +22,36 @@
22 * @file transport/plugin_transport_udp.c 22 * @file transport/plugin_transport_udp.c
23 * @brief Implementation of the UDP transport service 23 * @brief Implementation of the UDP transport service
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * @author Nathan Evans?
25 */ 26 */
26 27
28/* Notes for Nate:
29 * - Use simple network api to open ports and do select and whatnot.
30 * - For sending, just find session and send away!
31 * - All that is required is a simple linked list of known peers and
32 * how to send to them. Each will have a socket associated with it
33 * and that's pretty much it! May want to re-start over with 0.8
34 * code now that we have a better idea.
35 * - How often to do select loop? Do with a recall thing since we
36 * don't want to use cron jobs?
37 * - First thing, set up server which listens on a UDP port.
38 * - Use plugin->env->receive to notify server of message receipt
39 *
40 */
27#include "platform.h" 41#include "platform.h"
28#include "gnunet_util.h" 42#include "gnunet_hello_lib.h"
43#include "gnunet_connection_lib.h"
44#include "gnunet_os_lib.h"
45#include "gnunet_peerinfo_service.h"
29#include "gnunet_protocols.h" 46#include "gnunet_protocols.h"
30#include "gnunet_transport.h" 47#include "gnunet_resolver_service.h"
31#include "gnunet_stats_service.h" 48#include "gnunet_server_lib.h"
32#include "gnunet_upnp_service.h" 49#include "gnunet_service_lib.h"
33#include "ip.h" 50#include "gnunet_signatures.h"
51#include "gnunet_statistics_service.h"
52#include "gnunet_transport_service.h"
53#include "plugin_transport.h"
54#include "transport.h"
34 55
35#define DEBUG_UDP GNUNET_YES 56#define DEBUG_UDP GNUNET_YES
36 57
@@ -41,150 +62,200 @@
41#define MESSAGE_SIZE 1472 62#define MESSAGE_SIZE 1472
42 63
43/** 64/**
65 * Handle for request of hostname resolution, non-NULL if pending.
66 */
67static struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
68
69/**
44 * Message-Packet header. 70 * Message-Packet header.
45 */ 71 */
46typedef struct 72struct UDPMessage
47{ 73{
48 /** 74 /**
49 * size of the message, in bytes, including this header. 75 * size of the message, in bytes, including this header.
50 */ 76 */
51 GNUNET_MessageHeader header; 77 struct GNUNET_MessageHeader header;
52 78
53 /** 79 /**
54 * What is the identity of the sender (GNUNET_hash of public key) 80 * What is the identity of the sender (GNUNET_hash of public key)
55 */ 81 */
56 GNUNET_PeerIdentity sender; 82 struct GNUNET_PeerIdentity sender;
57 83
58} UDPMessage; 84};
59 85
60#define MY_TRANSPORT_NAME "UDP" 86/* Forward definition */
61#include "common.c" 87struct Plugin;
62 88
63/* *********** globals ************* */ 89/**
90 * Session handle for UDP connections.
91 */
92struct Session
93{
64 94
65static int stat_bytesReceived; 95 /**
96 * Stored in a linked list.
97 */
98 struct Session *next;
66 99
67static int stat_bytesSent; 100 /**
101 * Pointer to the global plugin struct.
102 */
103 struct Plugin *plugin;
68 104
69static int stat_bytesDropped; 105 /**
106 * To whom are we talking to (set to our identity
107 */
108 struct GNUNET_PeerIdentity target;
70 109
71static int stat_udpConnected; 110 /**
111 * Address of the other peer if WE initiated the connection
112 * (and hence can be sure what it is), otherwise NULL.
113 */
114 void *connect_addr;
72 115
73/** 116 /**
74 * thread that listens for inbound messages 117 * Length of connect_addr, can be 0.
75 */ 118 */
76static struct GNUNET_SelectHandle *selector; 119 size_t connect_alen;
77 120
78/** 121 /*
79 * the socket that we transmit all data with 122 * Random challenge number for validation
80 */ 123 */
81static struct GNUNET_SocketHandle *udp_sock; 124 int challenge;
82 125
83static struct GNUNET_LoadMonitor *load_monitor; 126 /*
127 * Have we received validation (performed ping/pong) from this peer?
128 */
129 unsigned int validated;
84 130
131};
85 132
86/** 133/**
87 * The socket of session has data waiting, process! 134 * Encapsulation of all of the state of the plugin.
88 *
89 * This function may only be called if the tcplock is
90 * already held by the caller.
91 */ 135 */
92static int 136struct Plugin
93select_message_handler (void *mh_cls,
94 struct GNUNET_SelectHandle *sh,
95 struct GNUNET_SocketHandle *sock,
96 void *sock_ctx, const GNUNET_MessageHeader * msg)
97{ 137{
98 unsigned int len; 138 /**
99 GNUNET_TransportPacket *mp; 139 * Our environment.
100 const UDPMessage *um; 140 */
141 struct GNUNET_TRANSPORT_PluginEnvironment *env;
101 142
102 len = ntohs (msg->size); 143 /**
103 if (len <= sizeof (UDPMessage)) 144 * List of open TCP sessions.
104 { 145 */
105 GNUNET_GE_LOG (coreAPI->ectx, 146 struct Session *sessions;
106 GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK,
107 _("Received malformed message via %s. Ignored.\n"),
108 "UDP");
109 return GNUNET_SYSERR;
110 }
111 um = (const UDPMessage *) msg;
112 mp = GNUNET_malloc (sizeof (GNUNET_TransportPacket));
113 mp->msg = GNUNET_malloc (len - sizeof (UDPMessage));
114 memcpy (mp->msg, &um[1], len - sizeof (UDPMessage));
115 mp->sender = um->sender;
116 mp->size = len - sizeof (UDPMessage);
117 mp->tsession = NULL;
118 coreAPI->receive (mp);
119 if (stats != NULL)
120 stats->change (stat_bytesReceived, len);
121 return GNUNET_OK;
122}
123 147
124static void * 148 /**
125select_accept_handler (void *ah_cls, 149 * Handle for the statistics service.
126 struct GNUNET_SelectHandle *sh, 150 */
127 struct GNUNET_SocketHandle *sock, 151 struct GNUNET_STATISTICS_Handle *statistics;
128 const void *addr, unsigned int addr_len)
129{
130 static int nonnullpointer;
131 152
132 if (GNUNET_NO != is_rejected_tester (addr, addr_len)) 153 /**
133 return NULL; 154 * Handle to the network service.
134 return &nonnullpointer; 155 */
135} 156 struct GNUNET_SERVICE_Context *service;
157
158 /**
159 * ID of task used to update our addresses when one expires.
160 */
161 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
162
163 /**
164 * ID of select task
165 */
166 GNUNET_SCHEDULER_TaskIdentifier select_task;
167
168 /**
169 * Port that we are actually listening on.
170 */
171 uint16_t open_port;
172
173 /**
174 * Port that the user said we would have visible to the
175 * rest of the world.
176 */
177 uint16_t adv_port;
178
179 /*
180 * FD Read set
181 */
182 struct GNUNET_NETWORK_FDSet * rs;
183
184};
136 185
137/** 186/**
138 * Select has been forced to close a connection. 187 * Message used to ask a peer to validate receipt (to check an address
139 * Free the associated context. 188 * from a HELLO). Followed by the address used. Note that the
189 * recipients response does not affirm that he has this address,
190 * only that he got the challenge message.
140 */ 191 */
141static void 192struct UDPPingMessage
142select_close_handler (void *ch_cls,
143 struct GNUNET_SelectHandle *sh,
144 struct GNUNET_SocketHandle *sock, void *sock_ctx)
145{ 193{
146 /* do nothing */ 194
147} 195 /**
196 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING
197 */
198 struct GNUNET_MessageHeader header;
199
200 /**
201 * Random challenge number (in network byte order).
202 */
203 uint32_t challenge GNUNET_PACKED;
204
205
206
207};
208
148 209
149/** 210/**
150 * Establish a connection to a remote node. 211 * Message used to validate a HELLO. The challenge is included in the
212 * confirmation to make matching of replies to requests possible. The
213 * signature signs the original challenge number, our public key, the
214 * sender's address (so that the sender can check that the address we
215 * saw is plausible for him and possibly detect a MiM attack) and a
216 * timestamp (to limit replay).<p>
151 * 217 *
152 * @param hello the hello-Message for the target node 218 * This message is followed by the address of the
153 * @param tsessionPtr the session handle that is to be set 219 * client that we are observing (which is part of what
154 * @param may_reuse are we allowed to re-use an existing connection (ignored for UDP) 220 * is being signed).
155 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
156 */ 221 */
157static int 222struct UDPPongMessage
158udp_connect (const GNUNET_MessageHello * hello,
159 GNUNET_TSession ** tsessionPtr, int may_reuse)
160{ 223{
161 GNUNET_TSession *tsession; 224 /**
162 225 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG
163 tsession = GNUNET_malloc (sizeof (GNUNET_TSession)); 226 */
164 memset (tsession, 0, sizeof (GNUNET_TSession)); 227 struct GNUNET_MessageHeader header;
165 tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello)); 228
166 memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello)); 229 /**
167 tsession->ttype = myAPI.protocol_number; 230 * Random challenge number (in network byte order).
168 tsession->peer = hello->senderIdentity; 231 */
169 *tsessionPtr = tsession; 232 uint32_t challenge GNUNET_PACKED;
170 if (stats != NULL) 233
171 stats->change (stat_udpConnected, 1); 234 /* Length of addr, appended to end of message */
172 return GNUNET_OK; 235 unsigned int addrlen;
173} 236};
237
238/* *********** globals ************* */
239
240/**
241 * the socket that we transmit all data with
242 */
243static struct GNUNET_NETWORK_Handle *udp_sock;
244
174 245
175/** 246/**
176 * A (core) Session is to be associated with a transport session. The 247 * A (core) Session is to be associated with a transport session. The
177 * transport service may want to know in order to call back on the 248 * transport service may want to know in order to call back on the
178 * core if the connection is being closed. 249 * core if the connection is being closed.
179 * 250 *
180 * @param tsession the session handle passed along 251 * @param session the session handle passed along
181 * from the call to receive that was made by the transport 252 * from the call to receive that was made by the transport
182 * layer 253 * layer
183 * @return GNUNET_OK if the session could be associated, 254 * @return GNUNET_OK if the session could be associated,
184 * GNUNET_SYSERR if not. 255 * GNUNET_SYSERR if not.
185 */ 256 */
186int 257int
187udp_associate (GNUNET_TSession * tsession) 258udp_associate (struct Session * session)
188{ 259{
189 return GNUNET_SYSERR; /* UDP connections can never be associated */ 260 return GNUNET_SYSERR; /* UDP connections can never be associated */
190} 261}
@@ -195,18 +266,12 @@ udp_associate (GNUNET_TSession * tsession)
195 * @param tsession the session that is closed 266 * @param tsession the session that is closed
196 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed 267 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
197 */ 268 */
198static int 269void
199udp_disconnect (GNUNET_TSession * tsession) 270udp_disconnect (void *cls,
271 const struct GNUNET_PeerIdentity *
272 target)
200{ 273{
201 if (tsession != NULL) 274 return;
202 {
203 if (tsession->internal != NULL)
204 GNUNET_free (tsession->internal);
205 GNUNET_free (tsession);
206 if (stats != NULL)
207 stats->change (stat_udpConnected, -1);
208 }
209 return GNUNET_OK;
210} 275}
211 276
212/** 277/**
@@ -214,385 +279,581 @@ udp_disconnect (GNUNET_TSession * tsession)
214 * restarted later! 279 * restarted later!
215 */ 280 */
216static int 281static int
217udp_transport_server_stop () 282udp_transport_server_stop (void *cls)
218{ 283{
219 GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL); 284 struct Plugin *plugin = cls;
220 if (selector != NULL) 285 GNUNET_assert (udp_sock != NULL);
286 if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
221 { 287 {
222 GNUNET_select_destroy (selector); 288 GNUNET_SCHEDULER_cancel (plugin->env->sched, plugin->select_task);
223 selector = NULL; 289 plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
224 } 290 }
225 GNUNET_socket_destroy (udp_sock); 291
292 GNUNET_NETWORK_socket_close (udp_sock);
226 udp_sock = NULL; 293 udp_sock = NULL;
227 return GNUNET_OK; 294 return GNUNET_OK;
228} 295}
229 296
297static struct Session *
298find_session(void *cls, struct Session * session_list, const struct GNUNET_PeerIdentity *peer)
299{
300 struct Plugin *plugin = cls;
301 struct Session *pos;
302 pos = session_list;
303
304 while (pos != NULL)
305 {
306 if (memcmp(peer, &pos->target, sizeof(struct GNUNET_PeerIdentity)) == 0)
307 return pos;
308 pos = pos->next;
309 }
310
311 return NULL;
312}
313
230/** 314/**
231 * Test if the transport would even try to send 315 * Function that can be used by the transport service to transmit
232 * a message of the given size and importance 316 * a message using the plugin.
233 * for the given session.<br>
234 * This function is used to check if the core should
235 * even bother to construct (and encrypt) this kind
236 * of message.
237 * 317 *
238 * @return GNUNET_YES if the transport would try (i.e. queue 318 * @param cls closure
239 * the message or call the OS to send), 319 * @param service_context value passed to the transport-service
240 * GNUNET_NO if the transport would just drop the message, 320 * to identify the neighbour
241 * GNUNET_SYSERR if the size/session is invalid 321 * @param target who should receive this message
322 * @param priority how important is the message
323 * @param msg the message to transmit
324 * @param timeout when should we time out (give up) if we can not transmit?
325 * @param cont continuation to call once the message has
326 * been transmitted (or if the transport is ready
327 * for the next transmission call; or if the
328 * peer disconnected...)
329 * @param cont_cls closure for cont
242 */ 330 */
243static int 331static void
244udp_test_would_try (GNUNET_TSession * tsession, unsigned int size, 332udp_plugin_send (void *cls,
245 int important) 333 const struct GNUNET_PeerIdentity *target,
334 unsigned int priority,
335 const struct GNUNET_MessageHeader *msg,
336 struct GNUNET_TIME_Relative timeout,
337 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
246{ 338{
247 const GNUNET_MessageHello *hello; 339 struct Plugin *plugin = cls;
340 struct Session *session;
341 struct UDPMessage *message;
342 int ssize;
343 size_t sent;
248 344
249 if (udp_sock == NULL) 345 session = find_session(plugin, plugin->sessions, target);
250 return GNUNET_SYSERR; 346
251 if (size == 0) 347 if ((session == NULL) || (udp_sock == NULL))
252 { 348 return;
253 GNUNET_GE_BREAK (coreAPI->ectx, 0); 349
254 return GNUNET_SYSERR; 350 /* Build the message to be sent */
255 } 351 message = GNUNET_malloc(sizeof(struct UDPMessage) + ntohs(msg->size));
256 if (size > myAPI.mtu) 352 ssize = sizeof(struct UDPMessage) + ntohs(msg->size);
353
354#if DEBUG_UDP
355 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
356 ("In udp_send, ssize is %d\n"), ssize);
357#endif
358 message->header.size = htons(ssize);
359 message->header.type = htons(0);
360 memcpy (&message->sender, plugin->env->my_identity, sizeof(struct GNUNET_PeerIdentity));
361 memcpy (&message[1], msg, ntohs (msg->size));
362
363 /* Actually send the message */
364 sent = GNUNET_NETWORK_socket_sendto (udp_sock, message, ssize, session->connect_addr,
365 session->connect_alen);
366
367 if (cont != NULL)
257 { 368 {
258 GNUNET_GE_BREAK (coreAPI->ectx, 0); 369 if (sent == GNUNET_SYSERR)
259 return GNUNET_SYSERR; 370 cont(cont_cls, target, GNUNET_SYSERR);
371 else
372 cont(cont_cls, target, GNUNET_OK);
260 } 373 }
261 hello = (const GNUNET_MessageHello *) tsession->internal; 374
262 if (hello == NULL) 375 return;
263 return GNUNET_SYSERR;
264 return GNUNET_YES;
265} 376}
266 377
267/** 378/**
268 * Create a UDP socket. If possible, use IPv6, otherwise 379 * We've received a PING from this peer via UDP.
269 * try IPv4. Update available_protocols accordingly. 380 * Send back our PONG.
381 *
382 * @param cls closure
383 * @param sender the Identity of the sender
384 * @param message the actual message
270 */ 385 */
271static struct GNUNET_NETWORK_Handle * 386static void
272udp_create_socket () 387handle_udp_ping (void *cls,
388 struct GNUNET_PeerIdentity *sender, struct sockaddr_storage * addr, size_t addrlen,
389 const struct GNUNET_MessageHeader *message)
273{ 390{
274 struct GNUNET_NETWORK_Handle *desc; 391 struct Plugin *plugin = cls;
275 392 struct Session *head = plugin->sessions;
276 available_protocols = VERSION_AVAILABLE_NONE; 393 const struct UDPPingMessage *ping = (const struct UDPPingMessage *)message;
277 desc = NULL; 394 struct UDPPongMessage *pong;
278 if (GNUNET_YES != 395 struct Session *found;
279 GNUNET_GC_get_configuration_value_yesno (cfg, "GNUNETD", "DISABLE-IPV6", 396
280 GNUNET_YES)) 397#if DEBUG_UDP
281 { 398 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
282 desc = GNUNET_net_socket (PF_INET6, SOCK_DGRAM, 17); 399 ("handling ping, challenge is %d\n"), ntohs(ping->challenge));
283 } 400#endif
284 if (NULL == desc) 401 found = find_session(plugin, head, sender);
285 { 402 if (found != NULL)
286 desc = GNUNET_net_socket (PF_INET, SOCK_DGRAM, 17);
287 if (NULL == desc)
288 {
289 GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
290 GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
291 GNUNET_GE_BULK, "socket");
292 return GNUNET_SYSERR;
293 }
294 available_protocols = VERSION_AVAILABLE_IPV4;
295 }
296 else
297 { 403 {
298 available_protocols = VERSION_AVAILABLE_IPV6 | VERSION_AVAILABLE_IPV4; 404 pong = GNUNET_malloc(sizeof(struct UDPPongMessage) + addrlen);
405 pong->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG);
406 pong->header.size = htons(sizeof(struct UDPPongMessage) + addrlen);
407 pong->challenge = ping->challenge;
408 memcpy(&pong[1], addr, addrlen);
409 pong->addrlen = htons(addrlen);
410
411 udp_plugin_send(plugin, sender, GNUNET_SCHEDULER_PRIORITY_DEFAULT, &pong->header, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30), NULL, NULL);
299 } 412 }
300 return desc; 413
414 return;
415
301} 416}
302 417
303/** 418/**
304 * Send a message to the specified remote node. 419 * We've received a PONG from this peer via UDP.
420 * Great. Call validate func if we haven't already
421 * received a PONG.
305 * 422 *
306 * @param tsession the GNUNET_MessageHello identifying the remote node 423 * @param cls closure
307 * @param message what to send 424 * @param client identification of the client
308 * @param size the size of the message 425 * @param message the actual message
309 * @param important is this message "important" to override typical transmit limits?
310 * @return GNUNET_SYSERR on error, GNUNET_OK on success
311 */ 426 */
312static int 427static void
313udp_send (GNUNET_TSession * tsession, 428handle_udp_pong (void *cls,
314 const void *message, const unsigned int size, int important) 429 struct GNUNET_PeerIdentity *sender,
430 const struct GNUNET_MessageHeader *message)
315{ 431{
316 const GNUNET_MessageHello *hello; 432 struct Plugin *plugin = cls;
317 const HostAddress *haddr; 433 const struct UDPPongMessage *pong = (struct UDPPongMessage *)message;
318 UDPMessage *mp; 434 struct Session *found;
319 struct sockaddr_in serverAddrv4; 435 unsigned int addr_len;
320 struct sockaddr_in6 serverAddrv6; 436 struct sockaddr_storage addr;
321 struct sockaddr *serverAddr; 437
322 socklen_t addrlen; 438#if DEBUG_UDP
323 unsigned short available; 439 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
324 int ok; 440 ("handling pong\n"));
325 int ssize; 441#endif
326 size_t sent; 442 found = find_session(plugin, plugin->sessions, sender);
327 443#if DEBUG_UDP
328 GNUNET_GE_ASSERT (NULL, tsession != NULL); 444 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
329 if (udp_sock == NULL) 445 ("found->challenge %d, pong->challenge %d\n"), found->challenge, ntohs(pong->challenge));
330 return GNUNET_SYSERR; 446#endif
331 if (size == 0) 447 if ((found != NULL) && (found->challenge == ntohs(pong->challenge)))
332 { 448 {
333 GNUNET_GE_BREAK (coreAPI->ectx, 0); 449 found->validated = GNUNET_YES;
334 return GNUNET_SYSERR; 450 addr_len = ntohs(pong->addrlen);
451#if DEBUG_UDP
452 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
453 ("found associated ping, addr is %u bytes\n"), addr_len);
454#endif
455 memcpy(&addr, &pong[1], addr_len);
456 plugin->env->notify_validation(plugin->env->cls, "udp", sender, ntohs(pong->challenge), (char *)&addr);
335 } 457 }
336 if (size > myAPI.mtu) 458 else
337 { 459 {
338 GNUNET_GE_BREAK (coreAPI->ectx, 0);
339 return GNUNET_SYSERR;
340 }
341 hello = (const GNUNET_MessageHello *) tsession->internal;
342 if (hello == NULL)
343 return GNUNET_SYSERR;
344 460
345 haddr = (const HostAddress *) &hello[1]; 461#if DEBUG_UDP
346 available = ntohs (haddr->availability) & available_protocols; 462 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
347 if (available == VERSION_AVAILABLE_NONE) 463 ("Session not found!\n"));
348 return GNUNET_SYSERR;
349 if (available == (VERSION_AVAILABLE_IPV4 | VERSION_AVAILABLE_IPV6))
350 {
351 if (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, 2) == 0)
352 available = VERSION_AVAILABLE_IPV4;
353 else
354 available = VERSION_AVAILABLE_IPV6;
355 }
356 ssize = size + sizeof (UDPMessage);
357 mp = GNUNET_malloc (ssize);
358 mp->header.size = htons (ssize);
359 mp->header.type = 0;
360 mp->sender = *(coreAPI->my_identity);
361 memcpy (&mp[1], message, size);
362 ok = GNUNET_SYSERR;
363
364 if ((available & VERSION_AVAILABLE_IPV4) > 0)
365 {
366 memset (&serverAddrv4, 0, sizeof (serverAddrv4));
367#if HAVE_SOCKADDR_IN_SIN_LEN
368 serverAddrv4.sin_len = sizeof (serverAddrv4);
369#endif 464#endif
370 serverAddrv4.sin_family = AF_INET;
371 serverAddrv4.sin_port = haddr->port;
372 memcpy (&serverAddrv4.sin_addr, &haddr->ipv4, sizeof (struct in_addr));
373 addrlen = sizeof (serverAddrv4);
374 serverAddr = (struct sockaddr *) &serverAddrv4;
375 } 465 }
376 else 466 return;
467}
468
469static void
470udp_plugin_select (void *cls,
471 const struct GNUNET_SCHEDULER_TaskContext *tc)
472{
473 struct Plugin *plugin = cls;
474 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500);
475 char * buf;
476 struct UDPMessage *msg;
477 const struct GNUNET_MessageHeader *hdr;
478 struct GNUNET_PeerIdentity *sender;
479 unsigned int buflen;
480 socklen_t fromlen;
481 struct sockaddr_storage addr;
482 ssize_t ret;
483
484 do
377 { 485 {
378 memset (&serverAddrv6, 0, sizeof (serverAddrv6)); 486 buflen = GNUNET_NETWORK_socket_recvfrom_amount(udp_sock);
379#if HAVE_SOCKADDR_IN_SIN_LEN 487
380 serverAddrv6.sin6_len = sizeof (serverAddrv6); 488#if DEBUG_UDP
489 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
490 ("we expect to read %u bytes\n"), buflen);
381#endif 491#endif
382 serverAddrv6.sin6_family = AF_INET; 492
383 serverAddrv6.sin6_port = haddr->port; 493 if (buflen == GNUNET_NO)
384 memcpy (&serverAddrv6.sin6_addr, &haddr->ipv6, 494 return;
385 sizeof (struct in6_addr)); 495
386 addrlen = sizeof (serverAddrv6); 496 buf = GNUNET_malloc(buflen);
387 serverAddr = (struct sockaddr *) &serverAddrv6; 497 fromlen = sizeof(addr);
388 } 498
389#ifndef MINGW 499#if DEBUG_UDP
390 if (GNUNET_YES == GNUNET_socket_send_to (udp_sock, 500 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
391 GNUNET_NC_NONBLOCKING, 501 ("src_addr_len is %u\n"), fromlen);
392 mp,
393 ssize, &sent,
394 (const char *) serverAddr,
395 addrlen))
396#else
397 sent =
398 win_ols_sendto (udp_sock, mp, ssize, (const char *) serverAddr, addrlen);
399 if (sent != SOCKET_ERROR)
400#endif 502#endif
401 { 503
402 ok = GNUNET_OK; 504 memset(&addr, 0, fromlen);
403 if (stats != NULL) 505 ret = GNUNET_NETWORK_socket_recvfrom(udp_sock, buf, buflen, (struct sockaddr *)&addr, &fromlen);
404 stats->change (stat_bytesSent, sent); 506
405 } 507#if DEBUG_UDP
406 else 508 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
407 { 509 ("socket_recv returned %u, src_addr_len is %u\n"), ret, fromlen);
408 if (stats != NULL) 510#endif
409 stats->change (stat_bytesDropped, ssize); 511
512 if (ret <= 0)
513 {
514 GNUNET_free(buf);
515 return;
516 }
517
518 msg = (struct UDPMessage *)buf;
519
520#if DEBUG_UDP
521 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
522 ("header reports message size of %d\n"), ntohs(msg->header.size));
523
524 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
525 ("header reports message type of %d\n"), ntohs(msg->header.type));
526#endif
527 /*if (ntohs(hdr->size) < sizeof(struct UDPMessage))
528 {
529 GNUNET_free(buf);
530 GNUNET_NETWORK_fdset_zero(plugin->rs);
531 GNUNET_NETWORK_fdset_set(plugin->rs, udp_sock);
532 break;
533 }*/
534 hdr = (const struct GNUNET_MessageHeader *)&msg[1];
535 sender = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
536 memcpy(sender, &msg->sender, sizeof(struct GNUNET_PeerIdentity));
537
538#if DEBUG_UDP
539 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
540 ("msg reports message size of %d\n"), ntohs(hdr->size));
541
542 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
543 ("msg reports message type of %d\n"), ntohs(hdr->type));
544#endif
545
546 if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING)
547 {
548 handle_udp_ping(plugin, sender, &addr, fromlen, hdr);
549 }
550
551 if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PONG)
552 {
553 handle_udp_pong(plugin, sender, hdr);
554 }
555
556 GNUNET_free(buf);
557
410 } 558 }
411 GNUNET_free (mp); 559 while (GNUNET_NETWORK_socket_select (plugin->rs,
412 return ok; 560 NULL,
561 NULL,
562 timeout) > 0 && GNUNET_NETWORK_fdset_isset(plugin->rs, udp_sock));
563
564 plugin->select_task = GNUNET_SCHEDULER_add_select(plugin->env->sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK,
565 GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, NULL, &udp_plugin_select, plugin);
566
413} 567}
414 568
415/** 569/**
416 * Start the server process to receive inbound traffic. 570 * Create a UDP socket. If possible, use IPv6, otherwise
417 * 571 * try IPv4.
418 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
419 */ 572 */
420static int 573static struct GNUNET_NETWORK_Handle *
421udp_transport_server_start () 574udp_transport_server_start (void *cls)
422{ 575{
576 struct Plugin *plugin = cls;
577 struct GNUNET_NETWORK_Handle *desc;
423 struct sockaddr_in serverAddrv4; 578 struct sockaddr_in serverAddrv4;
424 struct sockaddr_in6 serverAddrv6; 579 struct sockaddr_in6 serverAddrv6;
425 struct sockaddr *serverAddr; 580 struct sockaddr *serverAddr;
426 socklen_t addrlen; 581 socklen_t addrlen;
427 GNUNET_NETWORK_Handle *desc; 582
428 const int on = 1; 583 desc = NULL;
429 unsigned short port; 584 if (GNUNET_YES !=
430 585 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "GNUNETD", "DISABLE-IPV6"))
431 GNUNET_GE_ASSERT (coreAPI->ectx, selector == NULL);
432 /* initialize UDP network */
433 port = get_port ();
434 if (port != 0)
435 { 586 {
436 desc = udp_create_socket (); 587 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 17);
588 if (desc != NULL)
589 {
590 memset (&serverAddrv6, 0, sizeof (serverAddrv6));
591 #if HAVE_SOCKADDR_IN_SIN_LEN
592 serverAddrv6.sin6_len = sizeof (serverAddrv6);
593 #endif
594 serverAddrv6.sin6_family = AF_INET6;
595 serverAddrv6.sin6_addr = in6addr_any;
596 serverAddrv6.sin6_port = htons (plugin->open_port);
597 addrlen = sizeof (serverAddrv6);
598 serverAddr = (struct sockaddr *) &serverAddrv6;
599 }
600 }
601 if (NULL == desc)
602 {
603 desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 17);
437 if (NULL == desc) 604 if (NULL == desc)
438 return GNUNET_SYSERR;
439 if (GNUNET_net_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
440 { 605 {
441 GNUNET_GE_DIE_STRERROR (coreAPI->ectx, 606 GNUNET_log_from(GNUNET_ERROR_TYPE_DEBUG,
442 GNUNET_GE_FATAL | GNUNET_GE_ADMIN | 607 "udp",
443 GNUNET_GE_IMMEDIATE, "setsockopt"); 608 "socket");
444 return GNUNET_SYSERR; 609 return NULL;
445 } 610 }
446 if (available_protocols == VERSION_AVAILABLE_IPV4) 611 else
447 { 612 {
448 memset (&serverAddrv4, 0, sizeof (serverAddrv4)); 613 memset (&serverAddrv4, 0, sizeof (serverAddrv4));
449#if HAVE_SOCKADDR_IN_SIN_LEN 614 #if HAVE_SOCKADDR_IN_SIN_LEN
450 serverAddrv4.sin_len = sizeof (serverAddrv4); 615 serverAddrv4.sin_len = sizeof (serverAddrv4);
451#endif 616 #endif
452 serverAddrv4.sin_family = AF_INET; 617 serverAddrv4.sin_family = AF_INET;
453 serverAddrv4.sin_addr.s_addr = INADDR_ANY; 618 serverAddrv4.sin_addr.s_addr = INADDR_ANY;
454 serverAddrv4.sin_port = htons (port); 619 serverAddrv4.sin_port = htons (plugin->open_port);
455 addrlen = sizeof (serverAddrv4); 620 addrlen = sizeof (serverAddrv4);
456 serverAddr = (struct sockaddr *) &serverAddrv4; 621 serverAddr = (struct sockaddr *) &serverAddrv4;
457 } 622 }
458 else
459 {
460 memset (&serverAddrv6, 0, sizeof (serverAddrv6));
461#if HAVE_SOCKADDR_IN_SIN_LEN
462 serverAddrv6.sin6_len = sizeof (serverAddrv6);
463#endif
464 serverAddrv6.sin6_family = AF_INET6;
465 serverAddrv6.sin6_addr = in6addr_any;
466 serverAddrv6.sin6_port = htons (port);
467 addrlen = sizeof (serverAddrv6);
468 serverAddr = (struct sockaddr *) &serverAddrv6;
469 }
470 if (GNUNET_net_bind (desc, serverAddr, addrlen) < 0)
471 {
472 GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
473 GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
474 GNUNET_GE_IMMEDIATE, "bind");
475 GNUNET_GE_LOG (coreAPI->ectx,
476 GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
477 GNUNET_GE_IMMEDIATE,
478 _("Failed to bind to %s port %d.\n"),
479 MY_TRANSPORT_NAME, port);
480 if (0 != GNUNET_net_close (&desc))
481 GNUNET_GE_LOG_STRERROR (coreAPI->ectx,
482 GNUNET_GE_ERROR | GNUNET_GE_USER |
483 GNUNET_GE_ADMIN | GNUNET_GE_BULK,
484 "close");
485 return GNUNET_SYSERR;
486 }
487 selector = GNUNET_select_create ("udp", GNUNET_YES, coreAPI->ectx, load_monitor, desc, addrlen, 0, /* timeout */
488 &select_message_handler,
489 NULL,
490 &select_accept_handler,
491 NULL,
492 &select_close_handler,
493 NULL, 64 * 1024,
494 16 /* max sockets */ );
495 if (selector == NULL)
496 return GNUNET_SYSERR;
497 } 623 }
498 desc = udp_create_socket (); 624
499 if (NULL == desc) 625 if (desc != NULL)
500 { 626 {
501 GNUNET_GE_LOG_STRERROR (coreAPI->ectx, 627 GNUNET_assert(GNUNET_NETWORK_socket_bind(desc, serverAddr, addrlen) == GNUNET_OK);
502 GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
503 GNUNET_GE_BULK, "socket");
504 GNUNET_select_destroy (selector);
505 selector = NULL;
506 return GNUNET_SYSERR;
507 } 628 }
508 udp_sock = GNUNET_socket_create (coreAPI->ectx, load_monitor, desc); 629
509 GNUNET_GE_ASSERT (coreAPI->ectx, udp_sock != NULL); 630 plugin->rs = GNUNET_NETWORK_fdset_create ();
631
632 GNUNET_NETWORK_fdset_zero(plugin->rs);
633 GNUNET_NETWORK_fdset_set(plugin->rs, desc);
634
635 plugin->select_task = GNUNET_SCHEDULER_add_select(plugin->env->sched, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SCHEDULER_NO_TASK,
636 GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, NULL, &udp_plugin_select, plugin);
637
638 return desc;
639}
640
641/**
642 * Function that can be used by the transport service to validate that
643 * another peer is reachable at a particular address (even if we
644 * already have a connection to this peer, this function is required
645 * to establish a new one).
646 *
647 * @param cls closure
648 * @param target who should receive this message
649 * @param challenge challenge code to use
650 * @param addrlen length of the address
651 * @param addr the address
652 * @param timeout how long should we try to transmit these?
653 * @return GNUNET_OK if the transmission has been scheduled
654 */
655static int
656udp_plugin_validate (void *cls,
657 const struct GNUNET_PeerIdentity *target,
658 uint32_t challenge,
659 struct GNUNET_TIME_Relative timeout,
660 const void *addr, size_t addrlen)
661{
662 struct Plugin *plugin = cls;
663 struct Session *new_session;
664 struct UDPPongMessage *msg;
665
666 if (addrlen <= 0)
667 return GNUNET_SYSERR;
668
669 new_session = GNUNET_malloc(sizeof(struct Session));
670 new_session->connect_addr = GNUNET_malloc(addrlen);
671 memcpy(new_session->connect_addr, addr, addrlen);
672 new_session->connect_alen = addrlen;
673#if DEBUG_UDP
674 if (memcmp(target, plugin->env->my_identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
675 {
676 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
677 ("definitely adding self to session list... hmmm\n"));
678 }
679#endif
680 memcpy(&new_session->target, target, sizeof(struct GNUNET_PeerIdentity));
681 new_session->challenge = challenge;
682 new_session->validated = GNUNET_NO;
683 new_session->next = plugin->sessions;
684 plugin->sessions = new_session;
685
686 msg = GNUNET_malloc (sizeof (struct UDPPongMessage));
687 msg->header.size = htons(sizeof(struct UDPPongMessage));
688 msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_PING);
689 msg->challenge = htons(challenge);
690#if DEBUG_UDP
691 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
692 ("In validate, header size is %d, type %d, challenge %u\n"), ntohs(msg->header.size), ntohs(msg->header.type), ntohl(msg->challenge));
693#endif
694 udp_plugin_send(plugin, target, GNUNET_SCHEDULER_PRIORITY_DEFAULT, &msg->header, timeout, NULL, NULL);
695
510 return GNUNET_OK; 696 return GNUNET_OK;
511} 697}
512 698
513/** 699/**
700 * Convert the transports address to a nice, human-readable
701 * format.
702 *
703 * @param cls closure
704 * @param type name of the transport that generated the address
705 * @param addr one of the addresses of the host, NULL for the last address
706 * the specific address format depends on the transport
707 * @param addrlen length of the address
708 * @param numeric should (IP) addresses be displayed in numeric form?
709 * @param timeout after how long should we give up?
710 * @param asc function to call on each string
711 * @param asc_cls closure for asc
712 */
713static void
714udp_plugin_address_pretty_printer (void *cls,
715 const char *type,
716 const void *addr,
717 size_t addrlen,
718 int numeric,
719 struct GNUNET_TIME_Relative timeout,
720 GNUNET_TRANSPORT_AddressStringCallback asc,
721 void *asc_cls)
722{
723
724}
725
726/**
727 * Set a quota for receiving data from the given peer; this is a
728 * per-transport limit. The transport should limit its read/select
729 * calls to stay below the quota (in terms of incoming data).
730 *
731 * @param cls closure
732 * @param target the peer for whom the quota is given
733 * @param quota_in quota for receiving/sending data in bytes per ms
734 */
735static void
736udp_plugin_set_receive_quota (void *cls,
737 const struct GNUNET_PeerIdentity *target,
738 uint32_t quota_in)
739{
740
741}
742
743/**
744 * Another peer has suggested an address for this
745 * peer and transport plugin. Check that this could be a valid
746 * address. If so, consider adding it to the list
747 * of addresses.
748 *
749 * @param cls closure
750 * @param addr pointer to the address
751 * @param addrlen length of addr
752 * @return GNUNET_OK if this is a plausible address for this peer
753 * and transport
754 */
755static int
756udp_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
757{
758
759 return GNUNET_SYSERR;
760}
761
762
763/**
514 * The exported method. Makes the core api available via a global and 764 * The exported method. Makes the core api available via a global and
515 * returns the udp transport API. 765 * returns the udp transport API.
516 */ 766 */
517GNUNET_TransportAPI * 767void *
518inittransport_udp (GNUNET_CoreAPIForTransport * core) 768libgnunet_plugin_transport_udp_init (void *cls)
519{ 769{
520 unsigned long long mtu; 770 unsigned long long mtu;
521 771
522 cfg = core->cfg; 772 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
523 load_monitor = core->load_monitor; 773 struct GNUNET_TRANSPORT_PluginFunctions *api;
524 GNUNET_GE_ASSERT (coreAPI->ectx, sizeof (UDPMessage) == 68); 774 struct Plugin *plugin;
525 GNUNET_GE_ASSERT (coreAPI->ectx, sizeof (HostAddress) == 24); 775 struct GNUNET_SERVICE_Context *service;
526 coreAPI = core; 776 unsigned long long aport;
527 if (-1 == GNUNET_GC_get_configuration_value_number (cfg, 777 unsigned long long bport;
528 "UDP", 778
529 "MTU", 779 service = GNUNET_SERVICE_start ("transport-udp", env->sched, env->cfg);
530 sizeof (UDPMessage) 780 if (service == NULL)
531 +
532 GNUNET_P2P_MESSAGE_OVERHEAD
533 +
534 sizeof
535 (GNUNET_MessageHeader) +
536 32, 65500,
537 MESSAGE_SIZE, &mtu))
538 { 781 {
782 GNUNET_log_from(GNUNET_ERROR_TYPE_WARNING, "udp", _
783 ("Failed to start service for `%s' transport plugin.\n"), "udp");
539 return NULL; 784 return NULL;
540 } 785 }
786 aport = 0;
787 if ((GNUNET_OK !=
788 GNUNET_CONFIGURATION_get_value_number (env->cfg,
789 "transport-udp",
790 "PORT",
791 &bport)) ||
792 (bport > 65535) ||
793 ((GNUNET_OK ==
794 GNUNET_CONFIGURATION_get_value_number (env->cfg,
795 "transport-udp",
796 "ADVERTISED-PORT",
797 &aport)) && (aport > 65535)))
798 {
799 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
800 "udp",
801 _
802 ("Require valid port number for service `%s' in configuration!\n"),
803 "transport-udp");
804 GNUNET_SERVICE_stop (service);
805 return NULL;
806 }
807 if (aport == 0)
808 aport = bport;
809
810 mtu = 1240;
541 if (mtu < 1200) 811 if (mtu < 1200)
542 GNUNET_GE_LOG (coreAPI->ectx, 812 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO,
543 GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE, 813 "udp",
544 _("MTU %llu for `%s' is probably too low!\n"), mtu, "UDP"); 814 _("MTU %llu for `%s' is probably too low!\n"), mtu, "UDP");
545 lock = GNUNET_mutex_create (GNUNET_NO); 815
546 if (0 != 816 plugin = GNUNET_malloc (sizeof (struct Plugin));
547 GNUNET_GC_attach_change_listener (cfg, &reload_configuration, NULL)) 817 plugin->open_port = bport;
548 { 818 plugin->adv_port = aport;
549 GNUNET_mutex_destroy (lock); 819 plugin->env = env;
550 lock = NULL; 820 plugin->statistics = NULL;
551 return NULL; 821 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
552 } 822 plugin->sessions = NULL;
553 if (GNUNET_GC_get_configuration_value_yesno (cfg, "UDP", "UPNP", GNUNET_YES) 823 api->cls = plugin;
554 == GNUNET_YES) 824
555 { 825 api->validate = &udp_plugin_validate;
556 upnp = coreAPI->service_request ("upnp"); 826 api->send = &udp_plugin_send;
557 if (upnp == NULL) 827 api->disconnect = &udp_disconnect;
558 GNUNET_GE_LOG (coreAPI->ectx, 828 api->address_pretty_printer = &udp_plugin_address_pretty_printer;
559 GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE, 829 api->set_receive_quota = &udp_plugin_set_receive_quota;
560 "The UPnP service could not be loaded. To disable UPnP, set the " 830 api->address_suggested = &udp_plugin_address_suggested;
561 "configuration option \"UPNP\" in section \"%s\" to \"NO\"\n", 831 api->cost_estimate = 17; /* TODO: ATS */
562 "UDP"); 832 plugin->service = service;
563 } 833
564 stats = coreAPI->service_request ("stats"); 834 udp_sock = udp_transport_server_start(plugin);
565 if (stats != NULL) 835
566 { 836 GNUNET_assert(udp_sock != NULL);
567 stat_bytesReceived 837
568 = stats->create (gettext_noop ("# bytes received via UDP")); 838 return api;
569 stat_bytesSent = stats->create (gettext_noop ("# bytes sent via UDP"));
570 stat_bytesDropped
571 = stats->create (gettext_noop ("# bytes dropped by UDP (outgoing)"));
572 stat_udpConnected
573 = stats->create (gettext_noop ("# UDP connections (right now)"));
574 }
575 myAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_UDP;
576 myAPI.mtu = mtu - sizeof (UDPMessage);
577 myAPI.cost = 20000;
578 myAPI.hello_verify = &verify_hello;
579 myAPI.hello_create = &create_hello;
580 myAPI.connect = &udp_connect;
581 myAPI.send = &udp_send;
582 myAPI.associate = &udp_associate;
583 myAPI.disconnect = &udp_disconnect;
584 myAPI.server_start = &udp_transport_server_start;
585 myAPI.server_stop = &udp_transport_server_stop;
586 myAPI.hello_to_address = &hello_to_address;
587 myAPI.send_now_test = &udp_test_would_try;
588
589 return &myAPI;
590} 839}
591 840
592void 841void *
593donetransport_udp () 842libgnunet_plugin_transport_udp_done (void *cls)
594{ 843{
595 do_shutdown (); 844 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
845 struct Plugin *plugin = api->cls;
846
847 udp_transport_server_stop(plugin);
848 if (NULL != hostname_dns)
849 {
850 GNUNET_RESOLVER_request_cancel (hostname_dns);
851 hostname_dns = NULL;
852 }
853 GNUNET_SERVICE_stop (plugin->service);
854 GNUNET_free (plugin);
855 GNUNET_free (api);
856 return NULL;
596} 857}
597 858
598/* end of udp.c */ 859/* end of plugin_transport_udp.c */
diff --git a/src/transport/test_plugin_transport_data_udp.conf b/src/transport/test_plugin_transport_data_udp.conf
new file mode 100644
index 000000000..7583a868b
--- /dev/null
+++ b/src/transport/test_plugin_transport_data_udp.conf
@@ -0,0 +1,24 @@
1[PATHS]
2SERVICEHOME = /tmp/test-gnunetd-plugin-transport/
3
4[resolver]
5PORT = 2364
6
7[transport]
8PORT = 2365
9PLUGINS = udp
10
11[arm]
12PORT = 2366
13
14[statistics]
15PORT = 2367
16
17[transport-udp]
18PORT = 2368
19
20[peerinfo]
21PORT = 2369
22
23[testing]
24WEAKRANDOM = YES
diff --git a/src/transport/test_plugin_transport_udp.c b/src/transport/test_plugin_transport_udp.c
new file mode 100644
index 000000000..85740c256
--- /dev/null
+++ b/src/transport/test_plugin_transport_udp.c
@@ -0,0 +1,358 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file transport/test_transport_api.c
22 * @brief testcase for transport_api.c
23 * @author Sailor Siraj
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_constants.h"
29#include "gnunet_getopt_lib.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_os_lib.h"
32#include "gnunet_peerinfo_service.h"
33#include "gnunet_plugin_lib.h"
34#include "gnunet_protocols.h"
35#include "gnunet_program_lib.h"
36#include "gnunet_signatures.h"
37#include "plugin_transport.h"
38#include "transport.h"
39
40#define VERBOSE GNUNET_NO
41
42/**
43 * How long until we give up on transmitting the message?
44 */
45#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
46
47/**
48 * Our public key.
49 */
50static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
51
52/**
53 * Our identity.
54 */
55static struct GNUNET_PeerIdentity my_identity;
56
57/**
58 * Our private key.
59 */
60static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
61
62/**
63 * Our scheduler.
64 */
65struct GNUNET_SCHEDULER_Handle *sched;
66
67/**
68 * Our configuration.
69 */
70const struct GNUNET_CONFIGURATION_Handle *cfg;
71
72/**
73 * Number of neighbours we'd like to have.
74 */
75static uint32_t max_connect_per_transport;
76
77/**
78 * Environment for this plugin.
79 */
80struct GNUNET_TRANSPORT_PluginEnvironment env;
81
82/**
83 *handle for the api provided by this plugin
84 */
85struct GNUNET_TRANSPORT_PluginFunctions *api;
86
87/**
88 * Did the test pass or fail?
89 */
90static int ok;
91
92/**
93 * Initialize Environment for this plugin
94 */
95static void
96receive(void *cls,
97 struct GNUNET_TIME_Relative
98 latency,
99 const struct GNUNET_PeerIdentity
100 * peer,
101 const struct GNUNET_MessageHeader
102 * message)
103{
104 /* do nothing */
105}
106
107void notify_address(void *cls,
108 const char *name,
109 const void *addr,
110 size_t addrlen,
111 struct
112 GNUNET_TIME_Relative
113 expires)
114{
115}
116
117/**
118 * Function called when the service shuts
119 * down. Unloads our plugins.
120 *
121 * @param cls closure
122 * @param cfg configuration to use
123 */
124static void
125unload_plugins (void *cls,
126 const struct GNUNET_CONFIGURATION_Handle *cfg)
127{
128 GNUNET_assert (NULL == GNUNET_PLUGIN_unload ("libgnunet_plugin_transport_udp",api));
129 if (my_private_key != NULL)
130 GNUNET_CRYPTO_rsa_key_free (my_private_key);
131
132}
133
134
135static void
136unload_task (void *cls,
137 const struct GNUNET_SCHEDULER_TaskContext *tc)
138{
139 struct GNUNET_CONFIGURATION_Handle *cfg = cls;
140 unload_plugins (NULL, cfg);
141}
142
143
144static GNUNET_SCHEDULER_TaskIdentifier validation_timeout_task;
145
146
147static void
148validation_notification (void *cls,
149 const char *name,
150 const struct GNUNET_PeerIdentity *peer,
151 uint32_t challenge,
152 const char *sender_addr)
153{
154 if (validation_timeout_task != GNUNET_SCHEDULER_NO_TASK)
155 {
156 GNUNET_SCHEDULER_cancel (sched, validation_timeout_task);
157 validation_timeout_task = GNUNET_SCHEDULER_NO_TASK;
158 }
159
160 GNUNET_assert (challenge == 42);
161
162 ok = 0; /* if the last test succeeded, report success */
163
164 GNUNET_SCHEDULER_add_continuation (sched,
165 &unload_task,
166 (void*) cfg,
167 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
168}
169
170
171static void
172validation_failed (void *cls,
173 const struct GNUNET_SCHEDULER_TaskContext *tc)
174{
175 validation_timeout_task = GNUNET_SCHEDULER_NO_TASK;
176 GNUNET_break (0); /* output error */
177 /* the "validation_notification" was not called
178 in a timely fashion; we should set an error
179 code for main and shut down */
180 unload_plugins (NULL, cfg);
181}
182
183
184/**
185 * Simple example test that invokes
186 * the "validate" function of the plugin
187 * and tries to see if the plugin would
188 * succeed to validate its own address.
189 * (This test is not well-written since
190 * we hand-compile the address which
191 * kind-of works for TCP but would not
192 * work for other plugins; we should ask
193 * the plugin about its address instead...).
194 */
195/* FIXME: won't work on IPv6 enabled systems where IPv4 mapping
196 * isn't enabled (eg. FreeBSD > 4)
197 */
198static void
199test_validation ()
200{
201 struct sockaddr_in soaddr;
202
203 memset (&soaddr, 0, sizeof(soaddr));
204#if HAVE_SOCKADDR_IN_SIN_LEN
205 soaddr.sin_len = sizeof (soaddr);
206#endif
207 soaddr.sin_family = AF_INET;
208 soaddr.sin_port = htons(2368 /* FIXME: get from config! */);
209 soaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
210
211 /* add job to catch failure (timeout) */
212 validation_timeout_task =
213 GNUNET_SCHEDULER_add_delayed (sched,
214 TIMEOUT,
215 &validation_failed,
216 NULL);
217
218 api->validate (api->cls,
219 &my_identity,
220 42,
221 TIMEOUT,
222 &soaddr,
223 sizeof(soaddr));
224}
225
226
227static void setup_plugin_environment()
228{
229 env.cfg = cfg;
230 env.sched = sched;
231 env.my_public_key = &my_public_key;
232 env.my_private_key = my_private_key;
233 env.my_identity = &my_identity;
234 env.cls=&env;
235 env.receive=&receive;
236 env.notify_address=&notify_address;
237 env.notify_validation = &validation_notification;
238 env.max_connections = max_connect_per_transport;
239}
240static int retx;
241
242/**
243 * Runs the test.
244 *
245 * @param cls closure
246 * @param s scheduler to use
247 * @param c configuration to use
248 */
249static void
250run (void *cls,
251 struct GNUNET_SCHEDULER_Handle *s,
252 char *const *args,
253 const char *cfgfile,
254 const struct GNUNET_CONFIGURATION_Handle *c)
255{
256 unsigned long long tneigh;
257 char *keyfile;
258 char *libname;
259
260 sched = s;
261 cfg = c;
262 /* parse configuration */
263 if ((GNUNET_OK !=
264 GNUNET_CONFIGURATION_get_value_number (c,
265 "TRANSPORT",
266 "NEIGHBOUR_LIMIT",
267 &tneigh)) ||
268 (GNUNET_OK !=
269 GNUNET_CONFIGURATION_get_value_filename (c,
270 "GNUNETD",
271 "HOSTKEY", &keyfile)))
272 {
273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274 _("Transport service is lacking key configuration settings. Exiting.\n"));
275 GNUNET_SCHEDULER_shutdown (s);
276 return;
277 }
278 max_connect_per_transport = (uint32_t) tneigh;
279 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
280 GNUNET_free (keyfile);
281 if (my_private_key == NULL)
282 {
283 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
284 _("Transport service could not access hostkey. Exiting.\n"));
285 GNUNET_SCHEDULER_shutdown (s);
286 return;
287 }
288 GNUNET_CRYPTO_rsa_key_get_public (my_private_key,
289 &my_public_key);
290 GNUNET_CRYPTO_hash (&my_public_key,
291 sizeof (my_public_key),
292 &my_identity.hashPubKey);
293
294 /* load plugins... */
295 setup_plugin_environment();
296 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
297 _("Loading udp transport plugin\n"));
298 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_udp");
299
300 api = GNUNET_PLUGIN_load(libname, &env);
301 GNUNET_free (libname);
302 if (api == NULL)
303 {
304 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
305 _("Failed to load transport plugin for udp\n"));
306 /* FIXME: set some error code for main */
307 return;
308 }
309 test_validation ();
310}
311
312
313/**
314 * The main function for the transport service.
315 *
316 * @param argc number of arguments from the command line
317 * @param argv command line arguments
318 * @return 0 ok, 1 on error
319 */
320int
321main (int argc, char *const *argv)
322{
323 static struct GNUNET_GETOPT_CommandLineOption options[] = {
324 GNUNET_GETOPT_OPTION_END
325 };
326 int ret;
327 char *const argv_prog[] = {
328 "test_plugin_transport",
329 "-c",
330 "test_plugin_transport_data_udp.conf",
331 "-L",
332#if VERBOSE
333 "DEBUG",
334#else
335 "WARNING",
336#endif
337 NULL
338 };
339 GNUNET_log_setup ("test-plugin-transport",
340#if VERBOSE
341 "DEBUG",
342#else
343 "WARNING",
344#endif
345 NULL);
346 ok = 1; /* set to fail */
347 ret = (GNUNET_OK ==
348 GNUNET_PROGRAM_run (5,
349 argv_prog,
350 "test-plugin-transport",
351 "testcase",
352 options,
353 &run, NULL)) ? ok : 1;
354 GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-plugin-transport");
355 return ret;
356}
357
358/* end of test_plugin_transport_udp.c */
diff --git a/src/util/network.c b/src/util/network.c
index d889fa94b..398f2b51a 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -355,6 +355,62 @@ GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
355 355
356 356
357/** 357/**
358 * How much data is available to be read on this descriptor?
359 *
360 * Returns GNUNET_NO if no data is available, or on error!
361 * @param desc socket
362 */
363unsigned int
364GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * desc)
365{
366 int error;
367 unsigned int pending;
368
369 /* How much is there to be read? */
370 error = ioctl(desc->fd, FIONREAD, &pending);
371 GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, "udp", _
372 ("pending is %u bytes, error is %d\n"), pending, error);
373
374 if (error == 0)
375 return pending;
376 else
377 return GNUNET_NO;
378}
379
380/**
381 * Read data from a connected socket (always non-blocking).
382 * @param desc socket
383 * @param buffer buffer
384 * @param length length of buffer
385 * @param src_addr either the source to recv from, or all zeroes
386 * to be filled in by recvfrom
387 * @param addrlen length of the addr
388 */
389ssize_t
390GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc,
391 void *buffer, size_t length,
392 struct sockaddr *src_addr, socklen_t *addrlen)
393{
394 int ret;
395 int flags;
396 flags = 0;
397
398#ifdef MSG_DONTWAIT
399 flags |= MSG_DONTWAIT;
400
401#endif /* */
402 ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
403
404#ifdef MINGW
405 if (SOCKET_ERROR == ret)
406 SetErrnoFromWinsockError (WSAGetLastError ());
407
408#endif /* */
409 return ret;
410}
411
412
413/**
358 * Read data from a connected socket (always non-blocking). 414 * Read data from a connected socket (always non-blocking).
359 * @param desc socket 415 * @param desc socket
360 * @param buffer buffer 416 * @param buffer buffer
@@ -643,6 +699,12 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
643#endif 699#endif
644} 700}
645 701
702int
703GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc)
704{
705 return desc->fd;
706}
707
646/** 708/**
647 * Copy a native fd set 709 * Copy a native fd set
648 * 710 *
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index a8e5add3e..6b12c7d1a 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -365,7 +365,7 @@ check_ready (struct GNUNET_SCHEDULER_Handle *handle,
365 { 365 {
366#if DEBUG_TASKS 366#if DEBUG_TASKS
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368 "Checking readyness of task: %llu / %p\n", 368 "Checking readiness of task: %llu / %p\n",
369 pos->id, pos->callback_cls); 369 pos->id, pos->callback_cls);
370#endif 370#endif
371 next = pos->next; 371 next = pos->next;
@@ -406,7 +406,7 @@ GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched)
406 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; 406 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
407 /* we don't move the task into the ready queue yet; check_ready 407 /* we don't move the task into the ready queue yet; check_ready
408 will do that later, possibly adding additional 408 will do that later, possibly adding additional
409 readyness-factors */ 409 readiness-factors */
410 pos = pos->next; 410 pos = pos->next;
411 } 411 }
412 for (i=0;i<GNUNET_SCHEDULER_PRIORITY_COUNT;i++) 412 for (i=0;i<GNUNET_SCHEDULER_PRIORITY_COUNT;i++)
@@ -417,7 +417,7 @@ GNUNET_SCHEDULER_shutdown (struct GNUNET_SCHEDULER_Handle *sched)
417 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; 417 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
418 /* we don't move the task into the ready queue yet; check_ready 418 /* we don't move the task into the ready queue yet; check_ready
419 will do that later, possibly adding additional 419 will do that later, possibly adding additional
420 readyness-factors */ 420 readiness-factors */
421 pos = pos->next; 421 pos = pos->next;
422 } 422 }
423 } 423 }
@@ -773,7 +773,7 @@ GNUNET_SCHEDULER_add_continuation (struct GNUNET_SCHEDULER_Handle *sched,
773 * @param sched scheduler to use 773 * @param sched scheduler to use
774 * @param prerequisite_task run this task after the task with the given 774 * @param prerequisite_task run this task after the task with the given
775 * task identifier completes (and any of our other 775 * task identifier completes (and any of our other
776 * conditions, such as delay, read or write-readyness 776 * conditions, such as delay, read or write-readiness
777 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency 777 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
778 * on completion of other tasks (this will cause the task to run as 778 * on completion of other tasks (this will cause the task to run as
779 * soon as possible). 779 * soon as possible).
@@ -1044,7 +1044,7 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_SCHEDULER_Handle * sched,
1044 * @param prio how important is this task? 1044 * @param prio how important is this task?
1045 * @param prerequisite_task run this task after the task with the given 1045 * @param prerequisite_task run this task after the task with the given
1046 * task identifier completes (and any of our other 1046 * task identifier completes (and any of our other
1047 * conditions, such as delay, read or write-readyness 1047 * conditions, such as delay, read or write-readiness
1048 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency 1048 * are satisfied). Use GNUNET_SCHEDULER_NO_TASK to not have any dependency
1049 * on completion of other tasks. 1049 * on completion of other tasks.
1050 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", 1050 * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever",