aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/Makefile.am4
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c30
-rw-r--r--src/transport/plugin_transport_http_client.c21
-rw-r--r--src/transport/plugin_transport_http_server.c23
-rw-r--r--src/transport/plugin_transport_tcp.c528
-rw-r--r--src/transport/plugin_transport_udp.c39
-rw-r--r--src/transport/plugin_transport_udp.h12
-rw-r--r--src/transport/plugin_transport_udp_broadcasting.c30
-rw-r--r--src/transport/plugin_transport_wlan.c29
-rw-r--r--src/transport/tcp_connection_legacy.c1647
-rw-r--r--src/transport/tcp_server_legacy.c1748
-rw-r--r--src/transport/tcp_server_mst_legacy.c311
-rw-r--r--src/transport/tcp_service_legacy.c1687
-rw-r--r--src/transport/test_plugin_transport.c2
14 files changed, 5979 insertions, 132 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index acc2557c6..7687f2348 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -191,6 +191,8 @@ libexec_PROGRAMS = \
191 $(BT_BIN) \ 191 $(BT_BIN) \
192 gnunet-service-transport 192 gnunet-service-transport
193 193
194
195
194bin_PROGRAMS = \ 196bin_PROGRAMS = \
195 gnunet-transport \ 197 gnunet-transport \
196 gnunet-transport-certificate-creation 198 gnunet-transport-certificate-creation
@@ -561,7 +563,7 @@ TESTS = \
561 $(HTTP_API_TIMEOUT_TEST) \ 563 $(HTTP_API_TIMEOUT_TEST) \
562 $(HTTPS_API_TIMEOUT_TEST) \ 564 $(HTTPS_API_TIMEOUT_TEST) \
563 $(WLAN_TIMEOUT_TEST) \ 565 $(WLAN_TIMEOUT_TEST) \
564 $(BT_TIMEOUT_TEST) 566 $(BT_TIMEOUT_TEST)
565if HAVE_GETOPT_BINARY 567if HAVE_GETOPT_BINARY
566TESTS += \ 568TESTS += \
567test_transport_api_slow_ats 569test_transport_api_slow_ats
diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c
index 684546314..63ed9c4b7 100644
--- a/src/transport/gnunet-helper-transport-wlan-dummy.c
+++ b/src/transport/gnunet-helper-transport-wlan-dummy.c
@@ -120,11 +120,11 @@ send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
120 * type to the output forward and copy it to the buffer for stdout. 120 * type to the output forward and copy it to the buffer for stdout.
121 * 121 *
122 * @param cls the 'struct SendBuffer' to copy the converted message to 122 * @param cls the 'struct SendBuffer' to copy the converted message to
123 * @param client unused
124 * @param hdr inbound message from the FIFO 123 * @param hdr inbound message from the FIFO
125 */ 124 */
126static int 125static int
127stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) 126stdin_send (void *cls,
127 const struct GNUNET_MessageHeader *hdr)
128{ 128{
129 struct SendBuffer *write_pout = cls; 129 struct SendBuffer *write_pout = cls;
130 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in; 130 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
@@ -166,11 +166,11 @@ stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
166 * We read a full message from stdin. Copy it to our send buffer. 166 * We read a full message from stdin. Copy it to our send buffer.
167 * 167 *
168 * @param cls the 'struct SendBuffer' to copy to 168 * @param cls the 'struct SendBuffer' to copy to
169 * @param client unused
170 * @param hdr the message we received to copy to the buffer 169 * @param hdr the message we received to copy to the buffer
171 */ 170 */
172static int 171static int
173file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) 172file_in_send (void *cls,
173 const struct GNUNET_MessageHeader *hdr)
174{ 174{
175 struct SendBuffer *write_std = cls; 175 struct SendBuffer *write_std = cls;
176 uint16_t sendsize; 176 uint16_t sendsize;
@@ -213,8 +213,8 @@ main (int argc, char *argv[])
213 fd_set wfds; 213 fd_set wfds;
214 struct timeval tv; 214 struct timeval tv;
215 int retval; 215 int retval;
216 struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst = NULL; 216 struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
217 struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst = NULL; 217 struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
218 struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr; 218 struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
219 int first; 219 int first;
220 220
@@ -340,8 +340,8 @@ main (int argc, char *argv[])
340 write_std.pos = 0; 340 write_std.pos = 0;
341 write_pout.size = 0; 341 write_pout.size = 0;
342 write_pout.pos = 0; 342 write_pout.pos = 0;
343 stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout); 343 stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
344 file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std); 344 file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
345 345
346 /* Send 'random' mac address */ 346 /* Send 'random' mac address */
347 macaddr.mac[0] = 0x13; 347 macaddr.mac[0] = 0x13;
@@ -453,8 +453,9 @@ main (int argc, char *argv[])
453 } 453 }
454 else if (0 < readsize) 454 else if (0 < readsize)
455 { 455 {
456 GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize, 456 GNUNET_MST_from_buffer (stdin_mst,
457 GNUNET_NO, GNUNET_NO); 457 readbuf, readsize,
458 GNUNET_NO, GNUNET_NO);
458 459
459 } 460 }
460 else 461 else
@@ -475,8 +476,9 @@ main (int argc, char *argv[])
475 } 476 }
476 else if (0 < readsize) 477 else if (0 < readsize)
477 { 478 {
478 GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize, 479 GNUNET_MST_from_buffer (file_in_mst,
479 GNUNET_NO, GNUNET_NO); 480 readbuf, readsize,
481 GNUNET_NO, GNUNET_NO);
480 } 482 }
481 else 483 else
482 { 484 {
@@ -489,9 +491,9 @@ main (int argc, char *argv[])
489end: 491end:
490 /* clean up */ 492 /* clean up */
491 if (NULL != stdin_mst) 493 if (NULL != stdin_mst)
492 GNUNET_SERVER_mst_destroy (stdin_mst); 494 GNUNET_MST_destroy (stdin_mst);
493 if (NULL != file_in_mst) 495 if (NULL != file_in_mst)
494 GNUNET_SERVER_mst_destroy (file_in_mst); 496 GNUNET_MST_destroy (file_in_mst);
495 497
496 if (NULL != fpout) 498 if (NULL != fpout)
497 fclose (fpout); 499 fclose (fpout);
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
index ceed94af8..e91149289 100644
--- a/src/transport/plugin_transport_http_client.c
+++ b/src/transport/plugin_transport_http_client.c
@@ -221,7 +221,7 @@ struct GNUNET_ATS_Session
221 /** 221 /**
222 * Message stream tokenizer for incoming data 222 * Message stream tokenizer for incoming data
223 */ 223 */
224 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; 224 struct GNUNET_MessageStreamTokenizer *msg_tk;
225 225
226 /** 226 /**
227 * Session timeout task 227 * Session timeout task
@@ -528,7 +528,7 @@ client_delete_session (struct GNUNET_ATS_Session *s)
528 GNUNET_TRANSPORT_SS_DONE); 528 GNUNET_TRANSPORT_SS_DONE);
529 if (NULL != s->msg_tk) 529 if (NULL != s->msg_tk)
530 { 530 {
531 GNUNET_SERVER_mst_destroy (s->msg_tk); 531 GNUNET_MST_destroy (s->msg_tk);
532 s->msg_tk = NULL; 532 s->msg_tk = NULL;
533 } 533 }
534 GNUNET_HELLO_address_free (s->address); 534 GNUNET_HELLO_address_free (s->address);
@@ -1158,13 +1158,11 @@ client_wake_up (void *cls)
1158 * Callback for message stream tokenizer 1158 * Callback for message stream tokenizer
1159 * 1159 *
1160 * @param cls the session 1160 * @param cls the session
1161 * @param client not used
1162 * @param message the message received 1161 * @param message the message received
1163 * @return always #GNUNET_OK 1162 * @return always #GNUNET_OK
1164 */ 1163 */
1165static int 1164static int
1166client_receive_mst_cb (void *cls, 1165client_receive_mst_cb (void *cls,
1167 void *client,
1168 const struct GNUNET_MessageHeader *message) 1166 const struct GNUNET_MessageHeader *message)
1169{ 1167{
1170 struct GNUNET_ATS_Session *s = cls; 1168 struct GNUNET_ATS_Session *s = cls;
@@ -1274,14 +1272,13 @@ client_receive (void *stream,
1274 return CURL_WRITEFUNC_PAUSE; 1272 return CURL_WRITEFUNC_PAUSE;
1275 } 1273 }
1276 if (NULL == s->msg_tk) 1274 if (NULL == s->msg_tk)
1277 s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, 1275 s->msg_tk = GNUNET_MST_create (&client_receive_mst_cb,
1278 s); 1276 s);
1279 GNUNET_SERVER_mst_receive (s->msg_tk, 1277 GNUNET_MST_from_buffer (s->msg_tk,
1280 s, 1278 stream,
1281 stream, 1279 len,
1282 len, 1280 GNUNET_NO,
1283 GNUNET_NO, 1281 GNUNET_NO);
1284 GNUNET_NO);
1285 return len; 1282 return len;
1286} 1283}
1287 1284
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
index 63c67b81c..2d6f40d58 100644
--- a/src/transport/plugin_transport_http_server.c
+++ b/src/transport/plugin_transport_http_server.c
@@ -201,7 +201,7 @@ struct GNUNET_ATS_Session
201 /** 201 /**
202 * Message stream tokenizer for incoming data 202 * Message stream tokenizer for incoming data
203 */ 203 */
204 struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; 204 struct GNUNET_MessageStreamTokenizer *msg_tk;
205 205
206 /** 206 /**
207 * Client recv handle 207 * Client recv handle
@@ -608,7 +608,7 @@ server_delete_session (struct GNUNET_ATS_Session *s)
608 } 608 }
609 if (NULL != s->msg_tk) 609 if (NULL != s->msg_tk)
610 { 610 {
611 GNUNET_SERVER_mst_destroy (s->msg_tk); 611 GNUNET_MST_destroy (s->msg_tk);
612 s->msg_tk = NULL; 612 s->msg_tk = NULL;
613 } 613 }
614 GNUNET_HELLO_address_free (s->address); 614 GNUNET_HELLO_address_free (s->address);
@@ -1621,13 +1621,11 @@ server_send_callback (void *cls,
1621 * Callback called by MessageStreamTokenizer when a message has arrived 1621 * Callback called by MessageStreamTokenizer when a message has arrived
1622 * 1622 *
1623 * @param cls current session as closure 1623 * @param cls current session as closure
1624 * @param client client
1625 * @param message the message to be forwarded to transport service 1624 * @param message the message to be forwarded to transport service
1626 * @return #GNUNET_OK 1625 * @return #GNUNET_OK
1627 */ 1626 */
1628static int 1627static int
1629server_receive_mst_cb (void *cls, 1628server_receive_mst_cb (void *cls,
1630 void *client,
1631 const struct GNUNET_MessageHeader *message) 1629 const struct GNUNET_MessageHeader *message)
1632{ 1630{
1633 struct GNUNET_ATS_Session *s = cls; 1631 struct GNUNET_ATS_Session *s = cls;
@@ -1847,13 +1845,16 @@ server_access_cb (void *cls,
1847 *upload_data_size); 1845 *upload_data_size);
1848 if (s->msg_tk == NULL) 1846 if (s->msg_tk == NULL)
1849 { 1847 {
1850 s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); 1848 s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb,
1849 s);
1851 } 1850 }
1852 GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, *upload_data_size, 1851 GNUNET_MST_from_buffer (s->msg_tk,
1853 GNUNET_NO, GNUNET_NO); 1852 upload_data,
1853 *upload_data_size,
1854 GNUNET_NO, GNUNET_NO);
1854 server_mhd_connection_timeout (plugin, s, 1855 server_mhd_connection_timeout (plugin, s,
1855 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL 1856 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
1856 / 1000LL); 1857 / 1000LL);
1857 (*upload_data_size) = 0; 1858 (*upload_data_size) = 0;
1858 } 1859 }
1859 else 1860 else
@@ -1935,7 +1936,7 @@ server_disconnect_cb (void *cls,
1935 sc->session->server_recv = NULL; 1936 sc->session->server_recv = NULL;
1936 if (NULL != sc->session->msg_tk) 1937 if (NULL != sc->session->msg_tk)
1937 { 1938 {
1938 GNUNET_SERVER_mst_destroy (sc->session->msg_tk); 1939 GNUNET_MST_destroy (sc->session->msg_tk);
1939 sc->session->msg_tk = NULL; 1940 sc->session->msg_tk = NULL;
1940 } 1941 }
1941 } 1942 }
@@ -2757,7 +2758,7 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2757 return; 2758 return;
2758 } 2759 }
2759 2760
2760 plugin->nat 2761 plugin->nat
2761 = GNUNET_NAT_register (plugin->env->cfg, 2762 = GNUNET_NAT_register (plugin->env->cfg,
2762 "transport-http_server", 2763 "transport-http_server",
2763 IPPROTO_TCP, 2764 IPPROTO_TCP,
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 34bbd00e0..10ea01cec 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -45,10 +45,495 @@
45 */ 45 */
46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) 46#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
47 47
48GNUNET_NETWORK_STRUCT_BEGIN 48/**
49 * Opaque handle that can be used to cancel
50 * a transmit-ready notification.
51 */
52struct GNUNET_CONNECTION_TransmitHandle;
53
54/**
55 * @brief handle for a server
56 */
57struct GNUNET_SERVER_Handle;
58
59/**
60 * @brief opaque handle for a client of the server
61 */
62struct GNUNET_SERVER_Client;
63
64/**
65 * @brief opaque handle server returns for aborting transmission to a client.
66 */
67struct GNUNET_SERVER_TransmitHandle;
68
69/**
70 * @brief handle for a network connection
71 */
72struct GNUNET_CONNECTION_Handle;
73
74
75/**
76 * Function called to notify a client about the connection begin ready
77 * to queue more data. @a buf will be NULL and @a size zero if the
78 * connection was closed for writing in the meantime.
79 *
80 * @param cls closure
81 * @param size number of bytes available in @a buf
82 * @param buf where the callee should write the message
83 * @return number of bytes written to @a buf
84 */
85typedef size_t
86(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
87 size_t size,
88 void *buf);
89
90/**
91 * Credentials for UNIX domain sockets.
92 */
93struct GNUNET_CONNECTION_Credentials
94{
95 /**
96 * UID of the other end of the connection.
97 */
98 uid_t uid;
99
100 /**
101 * GID of the other end of the connection.
102 */
103 gid_t gid;
104};
105
106
107/**
108 * Functions with this signature are called whenever a client
109 * is disconnected on the network level.
110 *
111 * @param cls closure
112 * @param client identification of the client; NULL
113 * for the last call when the server is destroyed
114 */
115typedef void
116(*GNUNET_SERVER_DisconnectCallback) (void *cls,
117 struct GNUNET_SERVER_Client *client);
118
119
120/**
121 * Functions with this signature are called whenever a client
122 * is connected on the network level.
123 *
124 * @param cls closure
125 * @param client identification of the client
126 */
127typedef void
128(*GNUNET_SERVER_ConnectCallback) (void *cls,
129 struct GNUNET_SERVER_Client *client);
130
131
49 132
50 133
51/** 134/**
135 * Function to call for access control checks.
136 *
137 * @param cls closure
138 * @param ucred credentials, if available, otherwise NULL
139 * @param addr address
140 * @param addrlen length of address
141 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
142 * for unknown address family (will be denied).
143 */
144typedef int
145(*GNUNET_CONNECTION_AccessCheck) (void *cls,
146 const struct
147 GNUNET_CONNECTION_Credentials *
148 ucred,
149 const struct sockaddr * addr,
150 socklen_t addrlen);
151
152/**
153 * Callback function for data received from the network. Note that
154 * both "available" and "err" would be 0 if the read simply timed out.
155 *
156 * @param cls closure
157 * @param buf pointer to received data
158 * @param available number of bytes availabe in "buf",
159 * possibly 0 (on errors)
160 * @param addr address of the sender
161 * @param addrlen size of addr
162 * @param errCode value of errno (on errors receiving)
163 */
164typedef void
165(*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
166 size_t available,
167 const struct sockaddr * addr,
168 socklen_t addrlen, int errCode);
169
170
171
172/**
173 * Close the connection and free associated resources. There must
174 * not be any pending requests for reading or writing to the
175 * connection at this time.
176 *
177 * @param connection connection to destroy
178 */
179void
180GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
181
182
183/**
184 * Signature of a function to create a custom tokenizer.
185 *
186 * @param cls closure from #GNUNET_SERVER_set_callbacks
187 * @param client handle to client the tokenzier will be used for
188 * @return handle to custom tokenizer ('mst')
189 */
190typedef void*
191(*GNUNET_SERVER_MstCreateCallback) (void *cls,
192 struct GNUNET_SERVER_Client *client);
193
194
195/**
196 * Signature of a function to destroy a custom tokenizer.
197 *
198 * @param cls closure from #GNUNET_SERVER_set_callbacks
199 * @param mst custom tokenizer handle
200 */
201typedef void
202(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
203 void *mst);
204
205/**
206 * Signature of a function to receive data for a custom tokenizer.
207 *
208 * @param cls closure from #GNUNET_SERVER_set_callbacks
209 * @param mst custom tokenizer handle
210 * @param client_identity ID of client for which this is a buffer,
211 * can be NULL (will be passed back to 'cb')
212 * @param buf input data to add
213 * @param size number of bytes in @a buf
214 * @param purge should any excess bytes in the buffer be discarded
215 * (i.e. for packet-based services like UDP)
216 * @param one_shot only call callback once, keep rest of message in buffer
217 * @return #GNUNET_OK if we are done processing (need more data)
218 * #GNUNET_NO if one_shot was set and we have another message ready
219 * #GNUNET_SYSERR if the data stream is corrupt
220 */
221typedef int
222(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
223 struct GNUNET_SERVER_Client *client,
224 const char *buf,
225 size_t size,
226 int purge,
227 int one_shot);
228/**
229 * Functions with this signature are called whenever a message is
230 * received.
231 *
232 * @param cls closure
233 * @param client identification of the client
234 * @param message the actual message
235 */
236typedef void
237(*GNUNET_SERVER_MessageCallback) (void *cls,
238 struct GNUNET_SERVER_Client *client,
239 const struct GNUNET_MessageHeader *message);
240
241/**
242 * Message handler. Each struct specifies how to handle on particular
243 * type of message received.
244 */
245struct GNUNET_SERVER_MessageHandler
246{
247 /**
248 * Function to call for messages of "type".
249 */
250 GNUNET_SERVER_MessageCallback callback;
251
252 /**
253 * Closure argument for @e callback.
254 */
255 void *callback_cls;
256
257 /**
258 * Type of the message this handler covers.
259 */
260 uint16_t type;
261
262 /**
263 * Expected size of messages of this type. Use 0 for
264 * variable-size. If non-zero, messages of the given
265 * type will be discarded (and the connection closed)
266 * if they do not have the right size.
267 */
268 uint16_t expected_size;
269
270};
271
272/**
273 * Ask the server to disconnect from the given client. This is the
274 * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
275 * except that it allows dropping of a client even when not handling a
276 * message from that client.
277 *
278 * @param client the client to disconnect from
279 */
280void
281GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
282
283/**
284 * Return user context associated with the given client.
285 * Note: you should probably use the macro (call without the underscore).
286 *
287 * @param client client to query
288 * @param size number of bytes in user context struct (for verification only)
289 * @return pointer to user context
290 */
291void *
292GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
293 size_t size);
294
295
296/**
297 * Functions with this signature are called whenever a
298 * complete message is received by the tokenizer.
299 *
300 * Do not call #GNUNET_SERVER_mst_destroy from within
301 * the scope of this callback.
302 *
303 * @param cls closure
304 * @param client identification of the client
305 * @param message the actual message
306 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
307 */
308typedef int
309(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
310 void *client,
311 const struct GNUNET_MessageHeader *message);
312
313
314/**
315 * Create a message stream tokenizer.
316 *
317 * @param cb function to call on completed messages
318 * @param cb_cls closure for @a cb
319 * @return handle to tokenizer
320 */
321struct GNUNET_SERVER_MessageStreamTokenizer *
322GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
323 void *cb_cls);
324
325/**
326 * Add incoming data to the receive buffer and call the
327 * callback for all complete messages.
328 *
329 * @param mst tokenizer to use
330 * @param client_identity ID of client for which this is a buffer,
331 * can be NULL (will be passed back to 'cb')
332 * @param buf input data to add
333 * @param size number of bytes in @a buf
334 * @param purge should any excess bytes in the buffer be discarded
335 * (i.e. for packet-based services like UDP)
336 * @param one_shot only call callback once, keep rest of message in buffer
337 * @return #GNUNET_OK if we are done processing (need more data)
338 * #GNUNET_NO if one_shot was set and we have another message ready
339 * #GNUNET_SYSERR if the data stream is corrupt
340 */
341int
342GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
343 void *client_identity,
344 const char *buf, size_t size,
345 int purge, int one_shot);
346
347
348
349/**
350 * Destroys a tokenizer.
351 *
352 * @param mst tokenizer to destroy
353 */
354void
355GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
356
357
358/**
359 * Set user context to be associated with the given client.
360 * Note: you should probably use the macro (call without the underscore).
361 *
362 * @param client client to query
363 * @param ptr pointer to user context
364 * @param size number of bytes in user context struct (for verification only)
365 */
366void
367GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
368 void *ptr,
369 size_t size);
370/**
371 * Return user context associated with the given client.
372 *
373 * @param client client to query
374 * @param type expected return type (i.e. 'struct Foo')
375 * @return pointer to user context of type 'type *'.
376 */
377#define GNUNET_SERVER_client_get_user_context(client,type) \
378 (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
379
380/**
381 * Set user context to be associated with the given client.
382 *
383 * @param client client to query
384 * @param value pointer to user context
385 */
386#define GNUNET_SERVER_client_set_user_context(client,value) \
387 GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
388
389
390
391/**
392 * Notify us when the server has enough space to transmit
393 * a message of the given size to the given client.
394 *
395 * @param client client to transmit message to
396 * @param size requested amount of buffer space
397 * @param timeout after how long should we give up (and call
398 * notify with buf NULL and size 0)?
399 * @param callback function to call when space is available
400 * @param callback_cls closure for @a callback
401 * @return non-NULL if the notify callback was queued; can be used
402 * to cancel the request using
403 * #GNUNET_SERVER_notify_transmit_ready_cancel.
404 * NULL if we are already going to notify someone else (busy)
405 */
406struct GNUNET_SERVER_TransmitHandle *
407GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
408 size_t size,
409 struct GNUNET_TIME_Relative timeout,
410 GNUNET_CONNECTION_TransmitReadyNotify callback,
411 void *callback_cls);
412
413/**
414 * Abort transmission request.
415 *
416 * @param th request to abort
417 */
418void
419GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
420
421
422
423
424/**
425 * Notify the server that the given client handle should
426 * be kept (keeps the connection up if possible, increments
427 * the internal reference counter).
428 *
429 * @param client the client to keep
430 */
431void
432GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
433
434
435/**
436 * Notify the server that the given client handle is no
437 * longer required. Decrements the reference counter. If
438 * that counter reaches zero an inactive connection maybe
439 * closed.
440 *
441 * @param client the client to drop
442 */
443void
444GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
445
446
447/**
448 * Function called by the service's run
449 * method to run service-specific setup code.
450 *
451 * @param cls closure
452 * @param server the initialized server
453 * @param cfg configuration to use
454 */
455typedef void
456(*GNUNET_SERVICE_Main) (void *cls,
457 struct GNUNET_SERVER_Handle *server,
458 const struct GNUNET_CONFIGURATION_Handle *cfg);
459
460
461
462/**
463 * Suspend accepting connections from the listen socket temporarily.
464 * Resume activity using #GNUNET_SERVER_resume.
465 *
466 * @param server server to stop accepting connections.
467 */
468void
469GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
470
471/**
472 * Notify us when the server has enough space to transmit
473 * a message of the given size to the given client.
474 *
475 * @param client client to transmit message to
476 * @param size requested amount of buffer space
477 * @param timeout after how long should we give up (and call
478 * notify with buf NULL and size 0)?
479 * @param callback function to call when space is available
480 * @param callback_cls closure for @a callback
481 * @return non-NULL if the notify callback was queued; can be used
482 * to cancel the request using
483 * #GNUNET_SERVER_notify_transmit_ready_cancel.
484 * NULL if we are already going to notify someone else (busy)
485 */
486struct GNUNET_SERVER_TransmitHandle *
487GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
488 size_t size,
489 struct GNUNET_TIME_Relative timeout,
490 GNUNET_CONNECTION_TransmitReadyNotify callback,
491 void *callback_cls);
492
493
494/**
495 * Add a TCP socket-based connection to the set of handles managed by
496 * this server. Use this function for outgoing (P2P) connections that
497 * we initiated (and where this server should process incoming
498 * messages).
499 *
500 * @param server the server to use
501 * @param connection the connection to manage (client must
502 * stop using this connection from now on)
503 * @return the client handle
504 */
505struct GNUNET_SERVER_Client *
506GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
507 struct GNUNET_CONNECTION_Handle *connection);
508
509
510/**
511 * Resume accepting connections from the listen socket.
512 *
513 * @param server server to resume accepting connections.
514 */
515void
516GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
517
518/**
519 * Free resources held by this server.
520 *
521 * @param server server to destroy
522 */
523void
524GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
525
526
527
528
529#include "tcp_connection_legacy.c"
530#include "tcp_server_mst_legacy.c"
531#include "tcp_server_legacy.c"
532#include "tcp_service_legacy.c"
533
534GNUNET_NETWORK_STRUCT_BEGIN
535
536/**
52 * Initial handshake message for a session. 537 * Initial handshake message for a session.
53 */ 538 */
54struct WelcomeMessage 539struct WelcomeMessage
@@ -521,47 +1006,6 @@ struct Plugin
521}; 1006};
522 1007
523 1008
524/* begin of ancient copy-and-pasted code that should be
525 specialized for TCP ...*/
526/**
527 * Add the given UNIX domain path as an address to the
528 * list (as the first entry).
529 *
530 * @param saddrs array to update
531 * @param saddrlens where to store the address length
532 * @param unixpath path to add
533 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
534 * parameter is ignore on systems other than LINUX
535 */
536static void
537add_unixpath (struct sockaddr **saddrs,
538 socklen_t *saddrlens,
539 const char *unixpath,
540 int abstract)
541{
542#ifdef AF_UNIX
543 struct sockaddr_un *un;
544
545 un = GNUNET_new (struct sockaddr_un);
546 un->sun_family = AF_UNIX;
547 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
548#ifdef LINUX
549 if (GNUNET_YES == abstract)
550 un->sun_path[0] = '\0';
551#endif
552#if HAVE_SOCKADDR_UN_SUN_LEN
553 un->sun_len = (u_char) sizeof (struct sockaddr_un);
554#endif
555 *saddrs = (struct sockaddr *) un;
556 *saddrlens = sizeof (struct sockaddr_un);
557#else
558 /* this function should never be called
559 * unless AF_UNIX is defined! */
560 GNUNET_assert (0);
561#endif
562}
563
564
565/** 1009/**
566 * Get the list of addresses that a server for the given service 1010 * Get the list of addresses that a server for the given service
567 * should bind to. 1011 * should bind to.
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
index eb48341b7..3a9013a5a 100644
--- a/src/transport/plugin_transport_udp.c
+++ b/src/transport/plugin_transport_udp.c
@@ -159,6 +159,11 @@ struct GNUNET_ATS_Session
159 struct GNUNET_PeerIdentity target; 159 struct GNUNET_PeerIdentity target;
160 160
161 /** 161 /**
162 * Tokenizer for inbound messages.
163 */
164 struct GNUNET_MessageStreamTokenizer *mst;
165
166 /**
162 * Plugin this session belongs to. 167 * Plugin this session belongs to.
163 */ 168 */
164 struct Plugin *plugin; 169 struct Plugin *plugin;
@@ -626,6 +631,11 @@ free_session (struct GNUNET_ATS_Session *s)
626 GNUNET_free (s->frag_ctx); 631 GNUNET_free (s->frag_ctx);
627 s->frag_ctx = NULL; 632 s->frag_ctx = NULL;
628 } 633 }
634 if (NULL != s->mst)
635 {
636 GNUNET_MST_destroy (s->mst);
637 s->mst = NULL;
638 }
629 GNUNET_free (s); 639 GNUNET_free (s);
630} 640}
631 641
@@ -2499,18 +2509,16 @@ read_process_ack (struct Plugin *plugin,
2499 * Message tokenizer has broken up an incomming message. Pass it on 2509 * Message tokenizer has broken up an incomming message. Pass it on
2500 * to the service. 2510 * to the service.
2501 * 2511 *
2502 * @param cls the `struct Plugin *` 2512 * @param cls the `struct GNUNET_ATS_Session *`
2503 * @param client the `struct GNUNET_ATS_Session *`
2504 * @param hdr the actual message 2513 * @param hdr the actual message
2505 * @return #GNUNET_OK (always) 2514 * @return #GNUNET_OK (always)
2506 */ 2515 */
2507static int 2516static int
2508process_inbound_tokenized_messages (void *cls, 2517process_inbound_tokenized_messages (void *cls,
2509 void *client,
2510 const struct GNUNET_MessageHeader *hdr) 2518 const struct GNUNET_MessageHeader *hdr)
2511{ 2519{
2512 struct Plugin *plugin = cls; 2520 struct GNUNET_ATS_Session *session = cls;
2513 struct GNUNET_ATS_Session *session = client; 2521 struct Plugin *plugin = session->plugin;
2514 2522
2515 if (GNUNET_YES == session->in_destroy) 2523 if (GNUNET_YES == session->in_destroy)
2516 return GNUNET_OK; 2524 return GNUNET_OK;
@@ -2626,6 +2634,8 @@ udp_plugin_create_session (void *cls,
2626 struct GNUNET_ATS_Session *s; 2634 struct GNUNET_ATS_Session *s;
2627 2635
2628 s = GNUNET_new (struct GNUNET_ATS_Session); 2636 s = GNUNET_new (struct GNUNET_ATS_Session);
2637 s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
2638 s);
2629 s->plugin = plugin; 2639 s->plugin = plugin;
2630 s->address = GNUNET_HELLO_address_copy (address); 2640 s->address = GNUNET_HELLO_address_copy (address);
2631 s->target = address->peer; 2641 s->target = address->peer;
@@ -2792,12 +2802,11 @@ process_udp_message (struct Plugin *plugin,
2792 GNUNET_free (address); 2802 GNUNET_free (address);
2793 2803
2794 s->rc++; 2804 s->rc++;
2795 GNUNET_SERVER_mst_receive (plugin->mst, 2805 GNUNET_MST_from_buffer (s->mst,
2796 s, 2806 (const char *) &msg[1],
2797 (const char *) &msg[1], 2807 ntohs (msg->header.size) - sizeof(struct UDPMessage),
2798 ntohs (msg->header.size) - sizeof(struct UDPMessage), 2808 GNUNET_YES,
2799 GNUNET_YES, 2809 GNUNET_NO);
2800 GNUNET_NO);
2801 s->rc--; 2810 s->rc--;
2802 if ( (0 == s->rc) && 2811 if ( (0 == s->rc) &&
2803 (GNUNET_YES == s->in_destroy) ) 2812 (GNUNET_YES == s->in_destroy) )
@@ -3990,8 +3999,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
3990 p->sessions = GNUNET_CONTAINER_multipeermap_create (16, 3999 p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
3991 GNUNET_NO); 4000 GNUNET_NO);
3992 p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); 4001 p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3993 p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages,
3994 p);
3995 GNUNET_BANDWIDTH_tracker_init (&p->tracker, 4002 GNUNET_BANDWIDTH_tracker_init (&p->tracker,
3996 NULL, 4003 NULL,
3997 NULL, 4004 NULL,
@@ -4008,7 +4015,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
4008 _("Failed to create UDP network sockets\n")); 4015 _("Failed to create UDP network sockets\n"));
4009 GNUNET_CONTAINER_multipeermap_destroy (p->sessions); 4016 GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
4010 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs); 4017 GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
4011 GNUNET_SERVER_mst_destroy (p->mst);
4012 if (NULL != p->nat) 4018 if (NULL != p->nat)
4013 GNUNET_NAT_unregister (p->nat); 4019 GNUNET_NAT_unregister (p->nat);
4014 GNUNET_free (p); 4020 GNUNET_free (p);
@@ -4120,11 +4126,6 @@ libgnunet_plugin_transport_udp_done (void *cls)
4120 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs); 4126 GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs);
4121 plugin->defrag_ctxs = NULL; 4127 plugin->defrag_ctxs = NULL;
4122 } 4128 }
4123 if (NULL != plugin->mst)
4124 {
4125 GNUNET_SERVER_mst_destroy (plugin->mst);
4126 plugin->mst = NULL;
4127 }
4128 while (NULL != (udpw = plugin->ipv4_queue_head)) 4129 while (NULL != (udpw = plugin->ipv4_queue_head))
4129 { 4130 {
4130 dequeue (plugin, 4131 dequeue (plugin,
diff --git a/src/transport/plugin_transport_udp.h b/src/transport/plugin_transport_udp.h
index 152b16099..48c7365c7 100644
--- a/src/transport/plugin_transport_udp.h
+++ b/src/transport/plugin_transport_udp.h
@@ -164,11 +164,6 @@ struct Plugin
164 struct GNUNET_SCHEDULER_Task *select_task_v6; 164 struct GNUNET_SCHEDULER_Task *select_task_v6;
165 165
166 /** 166 /**
167 * Tokenizer for inbound messages.
168 */
169 struct GNUNET_SERVER_MessageStreamTokenizer *mst;
170
171 /**
172 * Bandwidth tracker to limit global UDP traffic. 167 * Bandwidth tracker to limit global UDP traffic.
173 */ 168 */
174 struct GNUNET_BANDWIDTH_Tracker tracker; 169 struct GNUNET_BANDWIDTH_Tracker tracker;
@@ -192,7 +187,7 @@ struct Plugin
192 * Handle to NAT traversal support. 187 * Handle to NAT traversal support.
193 */ 188 */
194 struct GNUNET_NAT_STUN_Handle *stun; 189 struct GNUNET_NAT_STUN_Handle *stun;
195 190
196 /** 191 /**
197 * The read socket for IPv4 192 * The read socket for IPv4
198 */ 193 */
@@ -204,11 +199,6 @@ struct Plugin
204 struct GNUNET_NETWORK_Handle *sockv6; 199 struct GNUNET_NETWORK_Handle *sockv6;
205 200
206 /** 201 /**
207 * Tokenizer for inbound messages.
208 */
209 struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_mst;
210
211 /**
212 * Head of DLL of broadcast addresses 202 * Head of DLL of broadcast addresses
213 */ 203 */
214 struct BroadcastAddress *broadcast_tail; 204 struct BroadcastAddress *broadcast_tail;
diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c
index a440830fd..c6ddbce9b 100644
--- a/src/transport/plugin_transport_udp_broadcasting.c
+++ b/src/transport/plugin_transport_udp_broadcasting.c
@@ -133,11 +133,10 @@ struct MstContext
133 */ 133 */
134static int 134static int
135broadcast_mst_cb (void *cls, 135broadcast_mst_cb (void *cls,
136 void *client,
137 const struct GNUNET_MessageHeader *message) 136 const struct GNUNET_MessageHeader *message)
138{ 137{
139 struct Plugin *plugin = cls; 138 struct MstContext *mc = cls;
140 struct MstContext *mc = client; 139 struct Plugin *plugin = mc->plugin;
141 struct GNUNET_HELLO_Address *address; 140 struct GNUNET_HELLO_Address *address;
142 const struct GNUNET_MessageHeader *hello; 141 const struct GNUNET_MessageHeader *hello;
143 const struct UDP_Beacon_Message *msg; 142 const struct UDP_Beacon_Message *msg;
@@ -191,16 +190,20 @@ udp_broadcast_receive (struct Plugin *plugin,
191 size_t udp_addr_len, 190 size_t udp_addr_len,
192 enum GNUNET_ATS_Network_Type network_type) 191 enum GNUNET_ATS_Network_Type network_type)
193{ 192{
193 struct GNUNET_MessageStreamTokenizer *broadcast_mst;
194 struct MstContext mc; 194 struct MstContext mc;
195 195
196 broadcast_mst = GNUNET_MST_create (&broadcast_mst_cb,
197 &mc);
198 mc.plugin = plugin;
196 mc.udp_addr = udp_addr; 199 mc.udp_addr = udp_addr;
197 mc.udp_addr_len = udp_addr_len; 200 mc.udp_addr_len = udp_addr_len;
198 mc.ats_address_network_type = network_type; 201 mc.ats_address_network_type = network_type;
199 GNUNET_SERVER_mst_receive (plugin->broadcast_mst, 202 GNUNET_MST_from_buffer (broadcast_mst,
200 &mc, 203 buf, size,
201 buf, size, 204 GNUNET_NO,
202 GNUNET_NO, 205 GNUNET_NO);
203 GNUNET_NO); 206 GNUNET_MST_destroy (broadcast_mst);
204} 207}
205 208
206 209
@@ -546,10 +549,6 @@ setup_broadcast (struct Plugin *plugin,
546 return; 549 return;
547 } 550 }
548 551
549 /* always create tokenizers */
550 plugin->broadcast_mst =
551 GNUNET_SERVER_mst_create (&broadcast_mst_cb, plugin);
552
553 if (GNUNET_YES != plugin->enable_broadcasting) 552 if (GNUNET_YES != plugin->enable_broadcasting)
554 return; /* We do not send, just receive */ 553 return; /* We do not send, just receive */
555 554
@@ -636,13 +635,6 @@ stop_broadcast (struct Plugin *plugin)
636 GNUNET_free (p); 635 GNUNET_free (p);
637 } 636 }
638 } 637 }
639
640 /* Destroy MSTs */
641 if (NULL != plugin->broadcast_mst)
642 {
643 GNUNET_SERVER_mst_destroy (plugin->broadcast_mst);
644 plugin->broadcast_mst = NULL;
645 }
646} 638}
647 639
648/* end of plugin_transport_udp_broadcasting.c */ 640/* end of plugin_transport_udp_broadcasting.c */
diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c
index 376065d24..3f5ada10b 100644
--- a/src/transport/plugin_transport_wlan.c
+++ b/src/transport/plugin_transport_wlan.c
@@ -38,6 +38,7 @@
38#include "gnunet_fragmentation_lib.h" 38#include "gnunet_fragmentation_lib.h"
39#include "gnunet_constants.h" 39#include "gnunet_constants.h"
40 40
41
41#if BUILD_WLAN 42#if BUILD_WLAN
42/* begin case wlan */ 43/* begin case wlan */
43#define PLUGIN_NAME "wlan" 44#define PLUGIN_NAME "wlan"
@@ -48,6 +49,7 @@
48#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done 49#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done
49#define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__) 50#define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__)
50 51
52
51/** 53/**
52 * time out of a mac endpoint 54 * time out of a mac endpoint
53 */ 55 */
@@ -92,6 +94,30 @@
92#error need to build wlan or bluetooth 94#error need to build wlan or bluetooth
93#endif 95#endif
94 96
97
98
99/**
100 * Functions with this signature are called whenever a
101 * complete message is received by the tokenizer.
102 *
103 * Do not call #GNUNET_SERVER_mst_destroy from within
104 * the scope of this callback.
105 *
106 * @param cls closure
107 * @param client identification of the client
108 * @param message the actual message
109 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
110 */
111typedef int
112(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
113 void *client,
114 const struct GNUNET_MessageHeader *message);
115
116
117/* Include legacy message stream tokenizer that was removed from util (for now) */
118#include "tcp_server_mst_legacy.c"
119
120
95/** 121/**
96 * Max size of packet (that we give to the WLAN driver for transmission) 122 * Max size of packet (that we give to the WLAN driver for transmission)
97 */ 123 */
@@ -1728,11 +1754,10 @@ send_hello_beacon (void *cls)
1728 * Function used for to process the data from the suid process 1754 * Function used for to process the data from the suid process
1729 * 1755 *
1730 * @param cls the plugin handle 1756 * @param cls the plugin handle
1731 * @param client client that send the data (not used)
1732 * @param hdr header of the GNUNET_MessageHeader 1757 * @param hdr header of the GNUNET_MessageHeader
1733 */ 1758 */
1734static int 1759static int
1735handle_helper_message (void *cls, void *client, 1760handle_helper_message (void *cls,
1736 const struct GNUNET_MessageHeader *hdr) 1761 const struct GNUNET_MessageHeader *hdr)
1737{ 1762{
1738 struct Plugin *plugin = cls; 1763 struct Plugin *plugin = cls;
diff --git a/src/transport/tcp_connection_legacy.c b/src/transport/tcp_connection_legacy.c
new file mode 100644
index 000000000..f5253445d
--- /dev/null
+++ b/src/transport/tcp_connection_legacy.c
@@ -0,0 +1,1647 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
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 3, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/connection.c
23 * @brief TCP connection management
24 * @author Christian Grothoff
25 *
26 * This code is rather complex. Only modify it if you
27 * 1) Have a NEW testcase showing that the new code
28 * is needed and correct
29 * 2) All EXISTING testcases pass with the new code
30 * These rules should apply in general, but for this
31 * module they are VERY, VERY important.
32 */
33#include "platform.h"
34#include "gnunet_util_lib.h"
35#include "gnunet_resolver_service.h"
36
37
38
39#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
40
41
42/**
43 * Transmission handle. There can only be one for each connection.
44 */
45struct GNUNET_CONNECTION_TransmitHandle
46{
47
48 /**
49 * Function to call if the send buffer has notify_size
50 * bytes available.
51 */
52 GNUNET_CONNECTION_TransmitReadyNotify notify_ready;
53
54 /**
55 * Closure for notify_ready.
56 */
57 void *notify_ready_cls;
58
59 /**
60 * Our connection handle.
61 */
62 struct GNUNET_CONNECTION_Handle *connection;
63
64 /**
65 * Timeout for receiving (in absolute time).
66 */
67 struct GNUNET_TIME_Absolute transmit_timeout;
68
69 /**
70 * Task called on timeout.
71 */
72 struct GNUNET_SCHEDULER_Task * timeout_task;
73
74 /**
75 * At what number of bytes available in the
76 * write buffer should the notify method be called?
77 */
78 size_t notify_size;
79
80};
81
82
83/**
84 * During connect, we try multiple possible IP addresses
85 * to find out which one might work.
86 */
87struct AddressProbe
88{
89
90 /**
91 * This is a linked list.
92 */
93 struct AddressProbe *next;
94
95 /**
96 * This is a doubly-linked list.
97 */
98 struct AddressProbe *prev;
99
100 /**
101 * The address; do not free (allocated at the end of this struct).
102 */
103 const struct sockaddr *addr;
104
105 /**
106 * Underlying OS's socket.
107 */
108 struct GNUNET_NETWORK_Handle *sock;
109
110 /**
111 * Connection for which we are probing.
112 */
113 struct GNUNET_CONNECTION_Handle *connection;
114
115 /**
116 * Lenth of addr.
117 */
118 socklen_t addrlen;
119
120 /**
121 * Task waiting for the connection to finish connecting.
122 */
123 struct GNUNET_SCHEDULER_Task * task;
124};
125
126
127/**
128 * @brief handle for a network connection
129 */
130struct GNUNET_CONNECTION_Handle
131{
132
133 /**
134 * Configuration to use.
135 */
136 const struct GNUNET_CONFIGURATION_Handle *cfg;
137
138 /**
139 * Linked list of sockets we are currently trying out
140 * (during connect).
141 */
142 struct AddressProbe *ap_head;
143
144 /**
145 * Linked list of sockets we are currently trying out
146 * (during connect).
147 */
148 struct AddressProbe *ap_tail;
149
150 /**
151 * Network address of the other end-point, may be NULL.
152 */
153 struct sockaddr *addr;
154
155 /**
156 * Pointer to the hostname if connection was
157 * created using DNS lookup, otherwise NULL.
158 */
159 char *hostname;
160
161 /**
162 * Underlying OS's socket, set to NULL after fatal errors.
163 */
164 struct GNUNET_NETWORK_Handle *sock;
165
166 /**
167 * Function to call on data received, NULL if no receive is pending.
168 */
169 GNUNET_CONNECTION_Receiver receiver;
170
171 /**
172 * Closure for @e receiver.
173 */
174 void *receiver_cls;
175
176 /**
177 * Pointer to our write buffer.
178 */
179 char *write_buffer;
180
181 /**
182 * Current size of our @e write_buffer.
183 */
184 size_t write_buffer_size;
185
186 /**
187 * Current write-offset in @e write_buffer (where
188 * would we write next).
189 */
190 size_t write_buffer_off;
191
192 /**
193 * Current read-offset in @e write_buffer (how many
194 * bytes have already been sent).
195 */
196 size_t write_buffer_pos;
197
198 /**
199 * Length of @e addr.
200 */
201 socklen_t addrlen;
202
203 /**
204 * Read task that we may need to wait for.
205 */
206 struct GNUNET_SCHEDULER_Task *read_task;
207
208 /**
209 * Write task that we may need to wait for.
210 */
211 struct GNUNET_SCHEDULER_Task *write_task;
212
213 /**
214 * Handle to a pending DNS lookup request.
215 */
216 struct GNUNET_RESOLVER_RequestHandle *dns_active;
217
218 /**
219 * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready().
220 */
221 struct GNUNET_CONNECTION_TransmitHandle nth;
222
223 /**
224 * Timeout for receiving (in absolute time).
225 */
226 struct GNUNET_TIME_Absolute receive_timeout;
227
228 /**
229 * Maximum number of bytes to read (for receiving).
230 */
231 size_t max;
232
233 /**
234 * Port to connect to.
235 */
236 uint16_t port;
237
238 /**
239 * When shutdown, do not ever actually close the socket, but
240 * free resources. Only should ever be set if using program
241 * termination as a signal (because only then will the leaked
242 * socket be freed!)
243 */
244 int8_t persist;
245
246 /**
247 * Usually 0. Set to 1 if this handle is in use, and should
248 * #GNUNET_CONNECTION_destroy() be called right now, the action needs
249 * to be deferred by setting it to -1.
250 */
251 int8_t destroy_later;
252
253 /**
254 * Handle to subsequent connection after proxy handshake completes,
255 */
256 struct GNUNET_CONNECTION_Handle *proxy_handshake;
257
258};
259
260
261/**
262 * Set the persist option on this connection handle. Indicates
263 * that the underlying socket or fd should never really be closed.
264 * Used for indicating process death.
265 *
266 * @param connection the connection to set persistent
267 */
268void
269GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
270{
271 connection->persist = GNUNET_YES;
272}
273
274
275/**
276 * Disable the "CORK" feature for communication with the given connection,
277 * forcing the OS to immediately flush the buffer on transmission
278 * instead of potentially buffering multiple messages. Essentially
279 * reduces the OS send buffers to zero.
280 * Used to make sure that the last messages sent through the connection
281 * reach the other side before the process is terminated.
282 *
283 * @param connection the connection to make flushing and blocking
284 * @return #GNUNET_OK on success
285 */
286int
287GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
288{
289 return GNUNET_NETWORK_socket_disable_corking (connection->sock);
290}
291
292
293/**
294 * Create a connection handle by boxing an existing OS socket. The OS
295 * socket should henceforth be no longer used directly.
296 * #GNUNET_connection_destroy() will close it.
297 *
298 * @param osSocket existing socket to box
299 * @return the boxed connection handle
300 */
301struct GNUNET_CONNECTION_Handle *
302GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
303{
304 struct GNUNET_CONNECTION_Handle *connection;
305
306 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
307 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
308 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
309 connection->sock = osSocket;
310 return connection;
311}
312
313
314/**
315 * Create a connection handle by accepting on a listen socket. This
316 * function may block if the listen socket has no connection ready.
317 *
318 * @param access_cb function to use to check if access is allowed
319 * @param access_cb_cls closure for @a access_cb
320 * @param lsock listen socket
321 * @return the connection handle, NULL on error
322 */
323struct GNUNET_CONNECTION_Handle *
324GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
325 void *access_cb_cls,
326 struct GNUNET_NETWORK_Handle *lsock)
327{
328 struct GNUNET_CONNECTION_Handle *connection;
329 char addr[128];
330 socklen_t addrlen;
331 struct GNUNET_NETWORK_Handle *sock;
332 int aret;
333 struct sockaddr_in *v4;
334 struct sockaddr_in6 *v6;
335 struct sockaddr *sa;
336 void *uaddr;
337#ifdef SO_PEERCRED
338 struct ucred uc;
339 socklen_t olen;
340#endif
341 struct GNUNET_CONNECTION_Credentials *gcp;
342#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
343 struct GNUNET_CONNECTION_Credentials gc;
344
345 gc.uid = 0;
346 gc.gid = 0;
347#endif
348
349 addrlen = sizeof (addr);
350 sock =
351 GNUNET_NETWORK_socket_accept (lsock,
352 (struct sockaddr *) &addr,
353 &addrlen);
354 if (NULL == sock)
355 {
356 if (EAGAIN != errno)
357 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
358 return NULL;
359 }
360 if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
361 {
362 GNUNET_break (0);
363 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
364 return NULL;
365 }
366
367 sa = (struct sockaddr *) addr;
368 v6 = (struct sockaddr_in6 *) addr;
369 if ( (AF_INET6 == sa->sa_family) &&
370 (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) )
371 {
372 /* convert to V4 address */
373 v4 = GNUNET_new (struct sockaddr_in);
374 memset (v4, 0, sizeof (struct sockaddr_in));
375 v4->sin_family = AF_INET;
376#if HAVE_SOCKADDR_IN_SIN_LEN
377 v4->sin_len = (u_char) sizeof (struct sockaddr_in);
378#endif
379 GNUNET_memcpy (&v4->sin_addr,
380 &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
381 sizeof (struct in_addr)],
382 sizeof (struct in_addr));
383 v4->sin_port = v6->sin6_port;
384 uaddr = v4;
385 addrlen = sizeof (struct sockaddr_in);
386 }
387 else
388 {
389 uaddr = GNUNET_malloc (addrlen);
390 GNUNET_memcpy (uaddr, addr, addrlen);
391 }
392 gcp = NULL;
393 if (AF_UNIX == sa->sa_family)
394 {
395#if HAVE_GETPEEREID
396 /* most BSDs */
397 if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock),
398 &gc.uid,
399 &gc.gid))
400 gcp = &gc;
401#else
402#ifdef SO_PEERCRED
403 /* largely traditional GNU/Linux */
404 olen = sizeof (uc);
405 if ( (0 ==
406 getsockopt (GNUNET_NETWORK_get_fd (sock),
407 SOL_SOCKET,
408 SO_PEERCRED,
409 &uc,
410 &olen)) &&
411 (olen == sizeof (uc)) )
412 {
413 gc.uid = uc.uid;
414 gc.gid = uc.gid;
415 gcp = &gc;
416 }
417#else
418#if HAVE_GETPEERUCRED
419 /* this is for Solaris 10 */
420 ucred_t *uc;
421
422 uc = NULL;
423 if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
424 {
425 gc.uid = ucred_geteuid (uc);
426 gc.gid = ucred_getegid (uc);
427 gcp = &gc;
428 }
429 ucred_free (uc);
430#endif
431#endif
432#endif
433 }
434
435 if ( (NULL != access_cb) &&
436 (GNUNET_YES != (aret = access_cb (access_cb_cls,
437 gcp,
438 uaddr,
439 addrlen))) )
440 {
441 if (GNUNET_NO == aret)
442 LOG (GNUNET_ERROR_TYPE_INFO,
443 _("Access denied to `%s'\n"),
444 GNUNET_a2s (uaddr,
445 addrlen));
446 GNUNET_break (GNUNET_OK ==
447 GNUNET_NETWORK_socket_shutdown (sock,
448 SHUT_RDWR));
449 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
450 GNUNET_free (uaddr);
451 return NULL;
452 }
453 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
454 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
455 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
456 connection->addr = uaddr;
457 connection->addrlen = addrlen;
458 connection->sock = sock;
459 LOG (GNUNET_ERROR_TYPE_INFO,
460 _("Accepting connection from `%s': %p\n"),
461 GNUNET_a2s (uaddr,
462 addrlen),
463 connection);
464 return connection;
465}
466
467
468/**
469 * Obtain the network address of the other party.
470 *
471 * @param connection the client to get the address for
472 * @param addr where to store the address
473 * @param addrlen where to store the length of the @a addr
474 * @return #GNUNET_OK on success
475 */
476int
477GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
478 void **addr,
479 size_t *addrlen)
480{
481 if ((NULL == connection->addr) || (0 == connection->addrlen))
482 return GNUNET_NO;
483 *addr = GNUNET_malloc (connection->addrlen);
484 GNUNET_memcpy (*addr, connection->addr, connection->addrlen);
485 *addrlen = connection->addrlen;
486 return GNUNET_OK;
487}
488
489
490/**
491 * Tell the receiver callback that we had an IO error.
492 *
493 * @param connection connection to signal error
494 * @param errcode error code to send
495 */
496static void
497signal_receive_error (struct GNUNET_CONNECTION_Handle *connection,
498 int errcode)
499{
500 GNUNET_CONNECTION_Receiver receiver;
501
502 LOG (GNUNET_ERROR_TYPE_DEBUG,
503 "Receive encounters error (%s), connection closed (%p)\n",
504 STRERROR (errcode),
505 connection);
506 GNUNET_assert (NULL != (receiver = connection->receiver));
507 connection->receiver = NULL;
508 receiver (connection->receiver_cls,
509 NULL,
510 0,
511 connection->addr,
512 connection->addrlen,
513 errcode);
514}
515
516
517/**
518 * Tell the receiver callback that a timeout was reached.
519 *
520 * @param connection connection to signal for
521 */
522static void
523signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
524{
525 GNUNET_CONNECTION_Receiver receiver;
526
527 LOG (GNUNET_ERROR_TYPE_DEBUG,
528 "Connection signals timeout to receiver (%p)!\n",
529 connection);
530 GNUNET_assert (NULL != (receiver = connection->receiver));
531 connection->receiver = NULL;
532 receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
533}
534
535
536/**
537 * We failed to transmit data to the service, signal the error.
538 *
539 * @param connection handle that had trouble
540 * @param ecode error code (errno)
541 */
542static void
543signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection,
544 int ecode)
545{
546 GNUNET_CONNECTION_TransmitReadyNotify notify;
547
548 LOG (GNUNET_ERROR_TYPE_DEBUG,
549 "Transmission encounterd error (%s), connection closed (%p)\n",
550 STRERROR (ecode),
551 connection);
552 if (NULL != connection->sock)
553 {
554 (void) GNUNET_NETWORK_socket_shutdown (connection->sock,
555 SHUT_RDWR);
556 GNUNET_break (GNUNET_OK ==
557 GNUNET_NETWORK_socket_close (connection->sock));
558 connection->sock = NULL;
559 GNUNET_assert (NULL == connection->write_task);
560 }
561 if (NULL != connection->read_task)
562 {
563 /* send errors trigger read errors... */
564 GNUNET_SCHEDULER_cancel (connection->read_task);
565 connection->read_task = NULL;
566 signal_receive_timeout (connection);
567 return;
568 }
569 if (NULL == connection->nth.notify_ready)
570 return; /* nobody to tell about it */
571 notify = connection->nth.notify_ready;
572 connection->nth.notify_ready = NULL;
573 notify (connection->nth.notify_ready_cls,
574 0,
575 NULL);
576}
577
578
579/**
580 * We've failed for good to establish a connection (timeout or
581 * no more addresses to try).
582 *
583 * @param connection the connection we tried to establish
584 */
585static void
586connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
587{
588 LOG (GNUNET_ERROR_TYPE_INFO,
589 "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
590 connection->hostname,
591 connection->port);
592 GNUNET_break (NULL == connection->ap_head);
593 GNUNET_break (NULL == connection->ap_tail);
594 GNUNET_break (GNUNET_NO == connection->dns_active);
595 GNUNET_break (NULL == connection->sock);
596 GNUNET_assert (NULL == connection->write_task);
597 GNUNET_assert (NULL == connection->proxy_handshake);
598
599 /* signal errors for jobs that used to wait on the connection */
600 connection->destroy_later = 1;
601 if (NULL != connection->receiver)
602 signal_receive_error (connection,
603 ECONNREFUSED);
604 if (NULL != connection->nth.notify_ready)
605 {
606 GNUNET_assert (NULL != connection->nth.timeout_task);
607 GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
608 connection->nth.timeout_task = NULL;
609 signal_transmit_error (connection,
610 ECONNREFUSED);
611 }
612 if (-1 == connection->destroy_later)
613 {
614 /* do it now */
615 connection->destroy_later = 0;
616 GNUNET_CONNECTION_destroy (connection);
617 return;
618 }
619 connection->destroy_later = 0;
620}
621
622
623/**
624 * We are ready to transmit (or got a timeout).
625 *
626 * @param cls our connection handle
627 */
628static void
629transmit_ready (void *cls);
630
631
632/**
633 * This function is called once we either timeout or have data ready
634 * to read.
635 *
636 * @param cls connection to read from
637 */
638static void
639receive_ready (void *cls);
640
641
642/**
643 * We've succeeded in establishing a connection.
644 *
645 * @param connection the connection we tried to establish
646 */
647static void
648connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
649{
650 LOG (GNUNET_ERROR_TYPE_DEBUG,
651 "Connection to `%s' succeeded! (%p)\n",
652 GNUNET_a2s (connection->addr,
653 connection->addrlen),
654 connection);
655 /* trigger jobs that waited for the connection */
656 if (NULL != connection->receiver)
657 {
658 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 "Connection succeeded, starting with receiving data (%p)\n",
660 connection);
661 GNUNET_assert (NULL == connection->read_task);
662 connection->read_task =
663 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
664 (connection->receive_timeout),
665 connection->sock,
666 &receive_ready, connection);
667 }
668 if (NULL != connection->nth.notify_ready)
669 {
670 LOG (GNUNET_ERROR_TYPE_DEBUG,
671 "Connection succeeded, starting with sending data (%p)\n",
672 connection);
673 GNUNET_assert (connection->nth.timeout_task != NULL);
674 GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
675 connection->nth.timeout_task = NULL;
676 GNUNET_assert (connection->write_task == NULL);
677 connection->write_task =
678 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
679 (connection->nth.transmit_timeout), connection->sock,
680 &transmit_ready, connection);
681 }
682}
683
684
685/**
686 * Scheduler let us know that we're either ready to write on the
687 * socket OR connect timed out. Do the right thing.
688 *
689 * @param cls the `struct AddressProbe *` with the address that we are probing
690 */
691static void
692connect_probe_continuation (void *cls)
693{
694 struct AddressProbe *ap = cls;
695 struct GNUNET_CONNECTION_Handle *connection = ap->connection;
696 const struct GNUNET_SCHEDULER_TaskContext *tc;
697 struct AddressProbe *pos;
698 int error;
699 socklen_t len;
700
701 GNUNET_assert (NULL != ap->sock);
702 GNUNET_CONTAINER_DLL_remove (connection->ap_head,
703 connection->ap_tail,
704 ap);
705 len = sizeof (error);
706 errno = 0;
707 error = 0;
708 tc = GNUNET_SCHEDULER_get_task_context ();
709 if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
710 (GNUNET_OK !=
711 GNUNET_NETWORK_socket_getsockopt (ap->sock,
712 SOL_SOCKET,
713 SO_ERROR,
714 &error,
715 &len)) ||
716 (0 != error) )
717 {
718 GNUNET_break (GNUNET_OK ==
719 GNUNET_NETWORK_socket_close (ap->sock));
720 GNUNET_free (ap);
721 if ( (NULL == connection->ap_head) &&
722 (GNUNET_NO == connection->dns_active) &&
723 (NULL == connection->proxy_handshake) )
724 connect_fail_continuation (connection);
725 return;
726 }
727 GNUNET_assert (NULL == connection->sock);
728 connection->sock = ap->sock;
729 GNUNET_assert (NULL == connection->addr);
730 connection->addr = GNUNET_malloc (ap->addrlen);
731 GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen);
732 connection->addrlen = ap->addrlen;
733 GNUNET_free (ap);
734 /* cancel all other attempts */
735 while (NULL != (pos = connection->ap_head))
736 {
737 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
738 GNUNET_SCHEDULER_cancel (pos->task);
739 GNUNET_CONTAINER_DLL_remove (connection->ap_head,
740 connection->ap_tail,
741 pos);
742 GNUNET_free (pos);
743 }
744 connect_success_continuation (connection);
745}
746
747
748/**
749 * Try to establish a connection given the specified address.
750 * This function is called by the resolver once we have a DNS reply.
751 *
752 * @param cls our `struct GNUNET_CONNECTION_Handle *`
753 * @param addr address to try, NULL for "last call"
754 * @param addrlen length of @a addr
755 */
756static void
757try_connect_using_address (void *cls,
758 const struct sockaddr *addr,
759 socklen_t addrlen)
760{
761 struct GNUNET_CONNECTION_Handle *connection = cls;
762 struct AddressProbe *ap;
763 struct GNUNET_TIME_Relative delay;
764
765 if (NULL == addr)
766 {
767 connection->dns_active = NULL;
768 if ((NULL == connection->ap_head) &&
769 (NULL == connection->sock) &&
770 (NULL == connection->proxy_handshake))
771 connect_fail_continuation (connection);
772 return;
773 }
774 if (NULL != connection->sock)
775 return; /* already connected */
776 GNUNET_assert (NULL == connection->addr);
777 /* try to connect */
778 LOG (GNUNET_ERROR_TYPE_DEBUG,
779 "Trying to connect using address `%s:%u/%s:%u'\n",
780 connection->hostname,
781 connection->port,
782 GNUNET_a2s (addr, addrlen),
783 connection->port);
784 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
785 ap->addr = (const struct sockaddr *) &ap[1];
786 GNUNET_memcpy (&ap[1], addr, addrlen);
787 ap->addrlen = addrlen;
788 ap->connection = connection;
789
790 switch (ap->addr->sa_family)
791 {
792 case AF_INET:
793 ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
794 break;
795 case AF_INET6:
796 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
797 break;
798 default:
799 GNUNET_break (0);
800 GNUNET_free (ap);
801 return; /* not supported by us */
802 }
803 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
804 SOCK_STREAM, 0);
805 if (NULL == ap->sock)
806 {
807 GNUNET_free (ap);
808 return; /* not supported by OS */
809 }
810 LOG (GNUNET_ERROR_TYPE_INFO,
811 "Trying to connect to `%s' (%p)\n",
812 GNUNET_a2s (ap->addr, ap->addrlen),
813 connection);
814 if ((GNUNET_OK !=
815 GNUNET_NETWORK_socket_connect (ap->sock,
816 ap->addr,
817 ap->addrlen)) &&
818 (EINPROGRESS != errno))
819 {
820 /* maybe refused / unsupported address, try next */
821 LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
822 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
823 GNUNET_free (ap);
824 return;
825 }
826 GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
827 delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
828 if (NULL != connection->nth.notify_ready)
829 delay = GNUNET_TIME_relative_min (delay,
830 GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
831 if (NULL != connection->receiver)
832 delay = GNUNET_TIME_relative_min (delay,
833 GNUNET_TIME_absolute_get_remaining (connection->receive_timeout));
834 ap->task = GNUNET_SCHEDULER_add_write_net (delay,
835 ap->sock,
836 &connect_probe_continuation,
837 ap);
838}
839
840
841/**
842 * Create a connection handle by (asynchronously) connecting to a host.
843 * This function returns immediately, even if the connection has not
844 * yet been established. This function only creates TCP connections.
845 *
846 * @param cfg configuration to use
847 * @param hostname name of the host to connect to
848 * @param port port to connect to
849 * @return the connection handle
850 */
851struct GNUNET_CONNECTION_Handle *
852GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
853 const char *hostname,
854 uint16_t port)
855{
856 struct GNUNET_CONNECTION_Handle *connection;
857
858 GNUNET_assert (0 < strlen (hostname)); /* sanity check */
859 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
860 connection->cfg = cfg;
861 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
862 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
863 connection->port = port;
864 connection->hostname = GNUNET_strdup (hostname);
865 connection->dns_active =
866 GNUNET_RESOLVER_ip_get (connection->hostname,
867 AF_UNSPEC,
868 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
869 &try_connect_using_address,
870 connection);
871 return connection;
872}
873
874
875/**
876 * Create a connection handle by connecting to a UNIX domain service.
877 * This function returns immediately, even if the connection has not
878 * yet been established. This function only creates UNIX connections.
879 *
880 * @param cfg configuration to use
881 * @param unixpath path to connect to
882 * @return the connection handle, NULL on systems without UNIX support
883 */
884struct GNUNET_CONNECTION_Handle *
885GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg,
886 const char *unixpath)
887{
888#ifdef AF_UNIX
889 struct GNUNET_CONNECTION_Handle *connection;
890 struct sockaddr_un *un;
891
892 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
893 un = GNUNET_new (struct sockaddr_un);
894 un->sun_family = AF_UNIX;
895 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
896#ifdef LINUX
897 {
898 int abstract;
899
900 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
901 "TESTING",
902 "USE_ABSTRACT_SOCKETS");
903 if (GNUNET_YES == abstract)
904 un->sun_path[0] = '\0';
905 }
906#endif
907#if HAVE_SOCKADDR_UN_SUN_LEN
908 un->sun_len = (u_char) sizeof (struct sockaddr_un);
909#endif
910 connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
911 connection->cfg = cfg;
912 connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
913 connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
914 connection->port = 0;
915 connection->hostname = NULL;
916 connection->addr = (struct sockaddr *) un;
917 connection->addrlen = sizeof (struct sockaddr_un);
918 connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX,
919 SOCK_STREAM,
920 0);
921 if (NULL == connection->sock)
922 {
923 GNUNET_free (connection->addr);
924 GNUNET_free (connection->write_buffer);
925 GNUNET_free (connection);
926 return NULL;
927 }
928 if ( (GNUNET_OK !=
929 GNUNET_NETWORK_socket_connect (connection->sock,
930 connection->addr,
931 connection->addrlen)) &&
932 (EINPROGRESS != errno) )
933 {
934 /* Just return; we expect everything to work eventually so don't fail HARD */
935 GNUNET_break (GNUNET_OK ==
936 GNUNET_NETWORK_socket_close (connection->sock));
937 connection->sock = NULL;
938 return connection;
939 }
940 connect_success_continuation (connection);
941 return connection;
942#else
943 return NULL;
944#endif
945}
946
947
948/**
949 * Create a connection handle by (asynchronously) connecting to a host.
950 * This function returns immediately, even if the connection has not
951 * yet been established. This function only creates TCP connections.
952 *
953 * @param s socket to connect
954 * @param serv_addr server address
955 * @param addrlen length of @a serv_addr
956 * @return the connection handle
957 */
958struct GNUNET_CONNECTION_Handle *
959GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
960 const struct sockaddr *serv_addr,
961 socklen_t addrlen)
962{
963 struct GNUNET_CONNECTION_Handle *connection;
964
965 if ( (GNUNET_OK !=
966 GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
967 (EINPROGRESS != errno) )
968 {
969 /* maybe refused / unsupported address, try next */
970 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
971 "connect");
972 LOG (GNUNET_ERROR_TYPE_DEBUG,
973 "Attempt to connect to `%s' failed\n",
974 GNUNET_a2s (serv_addr,
975 addrlen));
976 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
977 return NULL;
978 }
979 connection = GNUNET_CONNECTION_create_from_existing (s);
980 connection->addr = GNUNET_malloc (addrlen);
981 GNUNET_memcpy (connection->addr, serv_addr, addrlen);
982 connection->addrlen = addrlen;
983 LOG (GNUNET_ERROR_TYPE_INFO,
984 "Trying to connect to `%s' (%p)\n",
985 GNUNET_a2s (serv_addr, addrlen),
986 connection);
987 return connection;
988}
989
990
991/**
992 * Create a connection handle by creating a socket and
993 * (asynchronously) connecting to a host. This function returns
994 * immediately, even if the connection has not yet been established.
995 * This function only creates TCP connections.
996 *
997 * @param af_family address family to use
998 * @param serv_addr server address
999 * @param addrlen length of @a serv_addr
1000 * @return the connection handle
1001 */
1002struct GNUNET_CONNECTION_Handle *
1003GNUNET_CONNECTION_create_from_sockaddr (int af_family,
1004 const struct sockaddr *serv_addr,
1005 socklen_t addrlen)
1006{
1007 struct GNUNET_NETWORK_Handle *s;
1008
1009 s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
1010 if (NULL == s)
1011 {
1012 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1013 "socket");
1014 return NULL;
1015 }
1016 return GNUNET_CONNECTION_connect_socket (s,
1017 serv_addr,
1018 addrlen);
1019}
1020
1021
1022/**
1023 * Check if connection is valid (no fatal errors have happened so far).
1024 * Note that a connection that is still trying to connect is considered
1025 * valid.
1026 *
1027 * @param connection connection to check
1028 * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
1029 */
1030int
1031GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
1032{
1033 if ((NULL != connection->ap_head) ||
1034 (NULL != connection->dns_active) ||
1035 (NULL != connection->proxy_handshake))
1036 return GNUNET_YES; /* still trying to connect */
1037 if ( (0 != connection->destroy_later) ||
1038 (NULL == connection->sock) )
1039 return GNUNET_NO;
1040 return GNUNET_YES;
1041}
1042
1043
1044/**
1045 * Close the connection and free associated resources. There must
1046 * not be any pending requests for reading or writing to the
1047 * connection at this time.
1048 *
1049 * @param connection connection to destroy
1050 */
1051void
1052GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
1053{
1054 struct AddressProbe *pos;
1055
1056 if (0 != connection->destroy_later)
1057 {
1058 connection->destroy_later = -1;
1059 return;
1060 }
1061 LOG (GNUNET_ERROR_TYPE_DEBUG,
1062 "Shutting down connection (%p)\n",
1063 connection);
1064 GNUNET_assert (NULL == connection->nth.notify_ready);
1065 GNUNET_assert (NULL == connection->receiver);
1066 if (NULL != connection->write_task)
1067 {
1068 GNUNET_SCHEDULER_cancel (connection->write_task);
1069 connection->write_task = NULL;
1070 connection->write_buffer_off = 0;
1071 }
1072 if (NULL != connection->read_task)
1073 {
1074 GNUNET_SCHEDULER_cancel (connection->read_task);
1075 connection->read_task = NULL;
1076 }
1077 if (NULL != connection->nth.timeout_task)
1078 {
1079 GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
1080 connection->nth.timeout_task = NULL;
1081 }
1082 connection->nth.notify_ready = NULL;
1083 if (NULL != connection->dns_active)
1084 {
1085 GNUNET_RESOLVER_request_cancel (connection->dns_active);
1086 connection->dns_active = NULL;
1087 }
1088 if (NULL != connection->proxy_handshake)
1089 {
1090 /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
1091 connection->proxy_handshake->destroy_later = -1;
1092 connection->proxy_handshake = NULL; /* Not leaked ??? */
1093 }
1094 while (NULL != (pos = connection->ap_head))
1095 {
1096 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
1097 GNUNET_SCHEDULER_cancel (pos->task);
1098 GNUNET_CONTAINER_DLL_remove (connection->ap_head,
1099 connection->ap_tail,
1100 pos);
1101 GNUNET_free (pos);
1102 }
1103 if ( (NULL != connection->sock) &&
1104 (GNUNET_YES != connection->persist) )
1105 {
1106 if ((GNUNET_OK !=
1107 GNUNET_NETWORK_socket_shutdown (connection->sock,
1108 SHUT_RDWR)) &&
1109 (ENOTCONN != errno) &&
1110 (ECONNRESET != errno) )
1111 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
1112 "shutdown");
1113 }
1114 if (NULL != connection->sock)
1115 {
1116 if (GNUNET_YES != connection->persist)
1117 {
1118 GNUNET_break (GNUNET_OK ==
1119 GNUNET_NETWORK_socket_close (connection->sock));
1120 }
1121 else
1122 {
1123 GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
1124 * leak the socket in this special case) ... */
1125 }
1126 }
1127 GNUNET_free_non_null (connection->addr);
1128 GNUNET_free_non_null (connection->hostname);
1129 GNUNET_free (connection->write_buffer);
1130 GNUNET_free (connection);
1131}
1132
1133
1134/**
1135 * This function is called once we either timeout
1136 * or have data ready to read.
1137 *
1138 * @param cls connection to read from
1139 */
1140static void
1141receive_ready (void *cls)
1142{
1143 struct GNUNET_CONNECTION_Handle *connection = cls;
1144 const struct GNUNET_SCHEDULER_TaskContext *tc;
1145 char buffer[connection->max];
1146 ssize_t ret;
1147 GNUNET_CONNECTION_Receiver receiver;
1148
1149 connection->read_task = NULL;
1150 tc = GNUNET_SCHEDULER_get_task_context ();
1151 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
1152 {
1153 LOG (GNUNET_ERROR_TYPE_DEBUG,
1154 "Receive from `%s' encounters error: timeout (%s, %p)\n",
1155 GNUNET_a2s (connection->addr,
1156 connection->addrlen),
1157 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout),
1158 GNUNET_YES),
1159 connection);
1160 signal_receive_timeout (connection);
1161 return;
1162 }
1163 if (NULL == connection->sock)
1164 {
1165 /* connect failed for good */
1166 signal_receive_error (connection, ECONNREFUSED);
1167 return;
1168 }
1169 GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready,
1170 connection->sock));
1171RETRY:
1172 ret = GNUNET_NETWORK_socket_recv (connection->sock,
1173 buffer,
1174 connection->max);
1175 if (-1 == ret)
1176 {
1177 if (EINTR == errno)
1178 goto RETRY;
1179 signal_receive_error (connection, errno);
1180 return;
1181 }
1182 LOG (GNUNET_ERROR_TYPE_DEBUG,
1183 "receive_ready read %u/%u bytes from `%s' (%p)!\n",
1184 (unsigned int) ret,
1185 connection->max,
1186 GNUNET_a2s (connection->addr,
1187 connection->addrlen),
1188 connection);
1189 GNUNET_assert (NULL != (receiver = connection->receiver));
1190 connection->receiver = NULL;
1191 receiver (connection->receiver_cls,
1192 buffer,
1193 ret,
1194 connection->addr,
1195 connection->addrlen,
1196 0);
1197}
1198
1199
1200/**
1201 * Receive data from the given connection. Note that this function
1202 * will call @a receiver asynchronously using the scheduler. It will
1203 * "immediately" return. Note that there MUST only be one active
1204 * receive call per connection at any given point in time (so do not
1205 * call receive again until the receiver callback has been invoked).
1206 *
1207 * @param connection connection handle
1208 * @param max maximum number of bytes to read
1209 * @param timeout maximum amount of time to wait
1210 * @param receiver function to call with received data
1211 * @param receiver_cls closure for @a receiver
1212 */
1213void
1214GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
1215 size_t max,
1216 struct GNUNET_TIME_Relative timeout,
1217 GNUNET_CONNECTION_Receiver receiver,
1218 void *receiver_cls)
1219{
1220 GNUNET_assert ((NULL == connection->read_task) &&
1221 (NULL == connection->receiver));
1222 GNUNET_assert (NULL != receiver);
1223 connection->receiver = receiver;
1224 connection->receiver_cls = receiver_cls;
1225 connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1226 connection->max = max;
1227 if (NULL != connection->sock)
1228 {
1229 connection->read_task =
1230 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
1231 (connection->receive_timeout),
1232 connection->sock,
1233 &receive_ready,
1234 connection);
1235 return;
1236 }
1237 if ((NULL == connection->dns_active) &&
1238 (NULL == connection->ap_head) &&
1239 (NULL == connection->proxy_handshake))
1240 {
1241 connection->receiver = NULL;
1242 receiver (receiver_cls,
1243 NULL, 0,
1244 NULL, 0,
1245 ETIMEDOUT);
1246 return;
1247 }
1248}
1249
1250
1251/**
1252 * Cancel receive job on the given connection. Note that the
1253 * receiver callback must not have been called yet in order
1254 * for the cancellation to be valid.
1255 *
1256 * @param connection connection handle
1257 * @return closure of the original receiver callback closure
1258 */
1259void *
1260GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
1261{
1262 if (NULL != connection->read_task)
1263 {
1264 GNUNET_assert (connection ==
1265 GNUNET_SCHEDULER_cancel (connection->read_task));
1266 connection->read_task = NULL;
1267 }
1268 connection->receiver = NULL;
1269 return connection->receiver_cls;
1270}
1271
1272
1273/**
1274 * Try to call the transmit notify method (check if we do
1275 * have enough space available first)!
1276 *
1277 * @param connection connection for which we should do this processing
1278 * @return #GNUNET_YES if we were able to call notify
1279 */
1280static int
1281process_notify (struct GNUNET_CONNECTION_Handle *connection)
1282{
1283 size_t used;
1284 size_t avail;
1285 size_t size;
1286 GNUNET_CONNECTION_TransmitReadyNotify notify;
1287
1288 LOG (GNUNET_ERROR_TYPE_DEBUG,
1289 "process_notify is running\n");
1290 GNUNET_assert (NULL == connection->write_task);
1291 if (NULL == (notify = connection->nth.notify_ready))
1292 {
1293 LOG (GNUNET_ERROR_TYPE_DEBUG,
1294 "No one to notify\n");
1295 return GNUNET_NO;
1296 }
1297 used = connection->write_buffer_off - connection->write_buffer_pos;
1298 avail = connection->write_buffer_size - used;
1299 size = connection->nth.notify_size;
1300 if (size > avail)
1301 {
1302 LOG (GNUNET_ERROR_TYPE_DEBUG,
1303 "Not enough buffer\n");
1304 return GNUNET_NO;
1305 }
1306 connection->nth.notify_ready = NULL;
1307 if (connection->write_buffer_size - connection->write_buffer_off < size)
1308 {
1309 /* need to compact */
1310 memmove (connection->write_buffer,
1311 &connection->write_buffer[connection->write_buffer_pos],
1312 used);
1313 connection->write_buffer_off -= connection->write_buffer_pos;
1314 connection->write_buffer_pos = 0;
1315 }
1316 avail = connection->write_buffer_size - connection->write_buffer_off;
1317 GNUNET_assert (avail >= size);
1318 size =
1319 notify (connection->nth.notify_ready_cls, avail,
1320 &connection->write_buffer[connection->write_buffer_off]);
1321 GNUNET_assert (size <= avail);
1322 if (0 != size)
1323 connection->write_buffer_off += size;
1324 return GNUNET_YES;
1325}
1326
1327
1328/**
1329 * Task invoked by the scheduler when a call to transmit
1330 * is timing out (we never got enough buffer space to call
1331 * the callback function before the specified timeout
1332 * expired).
1333 *
1334 * This task notifies the client about the timeout.
1335 *
1336 * @param cls the `struct GNUNET_CONNECTION_Handle`
1337 */
1338static void
1339transmit_timeout (void *cls)
1340{
1341 struct GNUNET_CONNECTION_Handle *connection = cls;
1342 GNUNET_CONNECTION_TransmitReadyNotify notify;
1343
1344 connection->nth.timeout_task = NULL;
1345 LOG (GNUNET_ERROR_TYPE_DEBUG,
1346 "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
1347 connection->hostname,
1348 connection->port,
1349 GNUNET_a2s (connection->addr,
1350 connection->addrlen),
1351 connection);
1352 notify = connection->nth.notify_ready;
1353 GNUNET_assert (NULL != notify);
1354 connection->nth.notify_ready = NULL;
1355 notify (connection->nth.notify_ready_cls,
1356 0,
1357 NULL);
1358}
1359
1360
1361/**
1362 * Task invoked by the scheduler when we failed to connect
1363 * at the time of being asked to transmit.
1364 *
1365 * This task notifies the client about the error.
1366 *
1367 * @param cls the `struct GNUNET_CONNECTION_Handle`
1368 */
1369static void
1370connect_error (void *cls)
1371{
1372 struct GNUNET_CONNECTION_Handle *connection = cls;
1373 GNUNET_CONNECTION_TransmitReadyNotify notify;
1374
1375 LOG (GNUNET_ERROR_TYPE_DEBUG,
1376 "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
1377 connection->nth.notify_size,
1378 connection->hostname,
1379 connection->port,
1380 connection);
1381 connection->write_task = NULL;
1382 notify = connection->nth.notify_ready;
1383 connection->nth.notify_ready = NULL;
1384 notify (connection->nth.notify_ready_cls,
1385 0,
1386 NULL);
1387}
1388
1389
1390/**
1391 * We are ready to transmit (or got a timeout).
1392 *
1393 * @param cls our connection handle
1394 */
1395static void
1396transmit_ready (void *cls)
1397{
1398 struct GNUNET_CONNECTION_Handle *connection = cls;
1399 GNUNET_CONNECTION_TransmitReadyNotify notify;
1400 const struct GNUNET_SCHEDULER_TaskContext *tc;
1401 ssize_t ret;
1402 size_t have;
1403
1404 LOG (GNUNET_ERROR_TYPE_DEBUG,
1405 "transmit_ready running (%p).\n",
1406 connection);
1407 GNUNET_assert (NULL != connection->write_task);
1408 connection->write_task = NULL;
1409 GNUNET_assert (NULL == connection->nth.timeout_task);
1410 tc = GNUNET_SCHEDULER_get_task_context ();
1411 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
1412 {
1413 LOG (GNUNET_ERROR_TYPE_DEBUG,
1414 "Transmit to `%s' fails, time out reached (%p).\n",
1415 GNUNET_a2s (connection->addr,
1416 connection->addrlen),
1417 connection);
1418 notify = connection->nth.notify_ready;
1419 GNUNET_assert (NULL != notify);
1420 connection->nth.notify_ready = NULL;
1421 notify (connection->nth.notify_ready_cls, 0, NULL);
1422 return;
1423 }
1424 GNUNET_assert (NULL != connection->sock);
1425 if (NULL == tc->write_ready)
1426 {
1427 /* special circumstances (in particular, PREREQ_DONE after
1428 * connect): not yet ready to write, but no "fatal" error either.
1429 * Hence retry. */
1430 goto SCHEDULE_WRITE;
1431 }
1432 if (! GNUNET_NETWORK_fdset_isset (tc->write_ready,
1433 connection->sock))
1434 {
1435 GNUNET_assert (NULL == connection->write_task);
1436 /* special circumstances (in particular, shutdown): not yet ready
1437 * to write, but no "fatal" error either. Hence retry. */
1438 goto SCHEDULE_WRITE;
1439 }
1440 GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
1441 if ((NULL != connection->nth.notify_ready) &&
1442 (connection->write_buffer_size < connection->nth.notify_size))
1443 {
1444 connection->write_buffer =
1445 GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
1446 connection->write_buffer_size = connection->nth.notify_size;
1447 }
1448 process_notify (connection);
1449 have = connection->write_buffer_off - connection->write_buffer_pos;
1450 if (0 == have)
1451 {
1452 /* no data ready for writing, terminate write loop */
1453 return;
1454 }
1455 GNUNET_assert (have <= connection->write_buffer_size);
1456 GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size);
1457 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
1458RETRY:
1459 ret =
1460 GNUNET_NETWORK_socket_send (connection->sock,
1461 &connection->write_buffer[connection->write_buffer_pos],
1462 have);
1463 if (-1 == ret)
1464 {
1465 if (EINTR == errno)
1466 goto RETRY;
1467 if (NULL != connection->write_task)
1468 {
1469 GNUNET_SCHEDULER_cancel (connection->write_task);
1470 connection->write_task = NULL;
1471 }
1472 signal_transmit_error (connection, errno);
1473 return;
1474 }
1475 LOG (GNUNET_ERROR_TYPE_DEBUG,
1476 "Connection transmitted %u/%u bytes to `%s' (%p)\n",
1477 (unsigned int) ret,
1478 have,
1479 GNUNET_a2s (connection->addr,
1480 connection->addrlen),
1481 connection);
1482 connection->write_buffer_pos += ret;
1483 if (connection->write_buffer_pos == connection->write_buffer_off)
1484 {
1485 /* transmitted all pending data */
1486 connection->write_buffer_pos = 0;
1487 connection->write_buffer_off = 0;
1488 }
1489 if ( (0 == connection->write_buffer_off) &&
1490 (NULL == connection->nth.notify_ready) )
1491 return; /* all data sent! */
1492 /* not done writing, schedule more */
1493SCHEDULE_WRITE:
1494 LOG (GNUNET_ERROR_TYPE_DEBUG,
1495 "Re-scheduling transmit_ready (more to do) (%p).\n",
1496 connection);
1497 have = connection->write_buffer_off - connection->write_buffer_pos;
1498 GNUNET_assert ( (NULL != connection->nth.notify_ready) ||
1499 (have > 0) );
1500 if (NULL == connection->write_task)
1501 connection->write_task =
1502 GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
1503 NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
1504 GNUNET_TIME_absolute_get_remaining
1505 (connection->nth.transmit_timeout),
1506 connection->sock,
1507 &transmit_ready, connection);
1508}
1509
1510
1511/**
1512 * Ask the connection to call us once the specified number of bytes
1513 * are free in the transmission buffer. Will never call the @a notify
1514 * callback in this task, but always first go into the scheduler.
1515 *
1516 * @param connection connection
1517 * @param size number of bytes to send
1518 * @param timeout after how long should we give up (and call
1519 * @a notify with buf NULL and size 0)?
1520 * @param notify function to call
1521 * @param notify_cls closure for @a notify
1522 * @return non-NULL if the notify callback was queued,
1523 * NULL if we are already going to notify someone else (busy)
1524 */
1525struct GNUNET_CONNECTION_TransmitHandle *
1526GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
1527 size_t size,
1528 struct GNUNET_TIME_Relative timeout,
1529 GNUNET_CONNECTION_TransmitReadyNotify notify,
1530 void *notify_cls)
1531{
1532 if (NULL != connection->nth.notify_ready)
1533 {
1534 GNUNET_assert (0);
1535 return NULL;
1536 }
1537 GNUNET_assert (NULL != notify);
1538 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1539 GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
1540 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
1541 GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
1542 connection->nth.notify_ready = notify;
1543 connection->nth.notify_ready_cls = notify_cls;
1544 connection->nth.connection = connection;
1545 connection->nth.notify_size = size;
1546 connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
1547 GNUNET_assert (NULL == connection->nth.timeout_task);
1548 if ((NULL == connection->sock) &&
1549 (NULL == connection->ap_head) &&
1550 (NULL == connection->dns_active) &&
1551 (NULL == connection->proxy_handshake))
1552 {
1553 if (NULL != connection->write_task)
1554 GNUNET_SCHEDULER_cancel (connection->write_task);
1555 connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
1556 connection);
1557 return &connection->nth;
1558 }
1559 if (NULL != connection->write_task)
1560 return &connection->nth; /* previous transmission still in progress */
1561 if (NULL != connection->sock)
1562 {
1563 /* connected, try to transmit now */
1564 LOG (GNUNET_ERROR_TYPE_DEBUG,
1565 "Scheduling transmission (%p).\n",
1566 connection);
1567 connection->write_task =
1568 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
1569 (connection->nth.transmit_timeout),
1570 connection->sock,
1571 &transmit_ready, connection);
1572 return &connection->nth;
1573 }
1574 /* not yet connected, wait for connection */
1575 LOG (GNUNET_ERROR_TYPE_DEBUG,
1576 "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
1577 connection);
1578 connection->nth.timeout_task =
1579 GNUNET_SCHEDULER_add_delayed (timeout,
1580 &transmit_timeout,
1581 connection);
1582 return &connection->nth;
1583}
1584
1585
1586/**
1587 * Cancel the specified transmission-ready notification.
1588 *
1589 * @param th notification to cancel
1590 */
1591void
1592GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
1593{
1594 GNUNET_assert (NULL != th->notify_ready);
1595 th->notify_ready = NULL;
1596 if (NULL != th->timeout_task)
1597 {
1598 GNUNET_SCHEDULER_cancel (th->timeout_task);
1599 th->timeout_task = NULL;
1600 }
1601 if (NULL != th->connection->write_task)
1602 {
1603 GNUNET_SCHEDULER_cancel (th->connection->write_task);
1604 th->connection->write_task = NULL;
1605 }
1606}
1607
1608
1609/**
1610 * Create a connection to be proxied using a given connection.
1611 *
1612 * @param cph connection to proxy server
1613 * @return connection to be proxied
1614 */
1615struct GNUNET_CONNECTION_Handle *
1616GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph)
1617{
1618 struct GNUNET_CONNECTION_Handle *proxied = GNUNET_CONNECTION_create_from_existing (NULL);
1619
1620 proxied->proxy_handshake = cph;
1621 return proxied;
1622}
1623
1624
1625/**
1626 * Activate proxied connection and destroy initial proxy handshake connection.
1627 * There must not be any pending requests for reading or writing to the
1628 * proxy hadshake connection at this time.
1629 *
1630 * @param proxied connection connection to proxy server
1631 */
1632void
1633GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
1634{
1635 struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
1636
1637 GNUNET_assert (NULL != cph);
1638 GNUNET_assert (NULL == proxied->sock);
1639 GNUNET_assert (NULL != cph->sock);
1640 proxied->sock = cph->sock;
1641 cph->sock = NULL;
1642 GNUNET_CONNECTION_destroy (cph);
1643 connect_success_continuation (proxied);
1644}
1645
1646
1647/* end of connection.c */
diff --git a/src/transport/tcp_server_legacy.c b/src/transport/tcp_server_legacy.c
new file mode 100644
index 000000000..c055285b1
--- /dev/null
+++ b/src/transport/tcp_server_legacy.c
@@ -0,0 +1,1748 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
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 3, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/server.c
23 * @brief library for building GNUnet network servers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30
31#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
32
33
34/**
35 * List of arrays of message handlers.
36 */
37struct HandlerList
38{
39 /**
40 * This is a linked list.
41 */
42 struct HandlerList *next;
43
44 /**
45 * NULL-terminated array of handlers.
46 */
47 const struct GNUNET_SERVER_MessageHandler *handlers;
48};
49
50
51/**
52 * List of arrays of message handlers.
53 */
54struct NotifyList
55{
56 /**
57 * This is a doubly linked list.
58 */
59 struct NotifyList *next;
60
61 /**
62 * This is a doubly linked list.
63 */
64 struct NotifyList *prev;
65
66 /**
67 * Function to call.
68 */
69 GNUNET_SERVER_DisconnectCallback callback;
70
71 /**
72 * Closure for callback.
73 */
74 void *callback_cls;
75};
76
77
78/**
79 * @brief handle for a server
80 */
81struct GNUNET_SERVER_Handle
82{
83 /**
84 * List of handlers for incoming messages.
85 */
86 struct HandlerList *handlers;
87
88 /**
89 * Head of list of our current clients.
90 */
91 struct GNUNET_SERVER_Client *clients_head;
92
93 /**
94 * Head of list of our current clients.
95 */
96 struct GNUNET_SERVER_Client *clients_tail;
97
98 /**
99 * Head of linked list of functions to call on disconnects by clients.
100 */
101 struct NotifyList *disconnect_notify_list_head;
102
103 /**
104 * Tail of linked list of functions to call on disconnects by clients.
105 */
106 struct NotifyList *disconnect_notify_list_tail;
107
108 /**
109 * Head of linked list of functions to call on connects by clients.
110 */
111 struct NotifyList *connect_notify_list_head;
112
113 /**
114 * Tail of linked list of functions to call on connects by clients.
115 */
116 struct NotifyList *connect_notify_list_tail;
117
118 /**
119 * Function to call for access control.
120 */
121 GNUNET_CONNECTION_AccessCheck access_cb;
122
123 /**
124 * Closure for @e access_cb.
125 */
126 void *access_cb_cls;
127
128 /**
129 * NULL-terminated array of sockets used to listen for new
130 * connections.
131 */
132 struct GNUNET_NETWORK_Handle **listen_sockets;
133
134 /**
135 * After how long should an idle connection time
136 * out (on write).
137 */
138 struct GNUNET_TIME_Relative idle_timeout;
139
140 /**
141 * Task scheduled to do the listening.
142 */
143 struct GNUNET_SCHEDULER_Task * listen_task;
144
145 /**
146 * Alternative function to create a MST instance.
147 */
148 GNUNET_SERVER_MstCreateCallback mst_create;
149
150 /**
151 * Alternative function to destroy a MST instance.
152 */
153 GNUNET_SERVER_MstDestroyCallback mst_destroy;
154
155 /**
156 * Alternative function to give data to a MST instance.
157 */
158 GNUNET_SERVER_MstReceiveCallback mst_receive;
159
160 /**
161 * Closure for 'mst_'-callbacks.
162 */
163 void *mst_cls;
164
165 /**
166 * Do we ignore messages of types that we do not understand or do we
167 * require that a handler is found (and if not kill the connection)?
168 */
169 int require_found;
170
171 /**
172 * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
173 * all non-monitor clients to disconnect before we call
174 * #GNUNET_SERVER_destroy. See test_monitor_clients(). Set to
175 * #GNUNET_SYSERR once the final destroy task has been scheduled
176 * (we cannot run it in the same task).
177 */
178 int in_soft_shutdown;
179};
180
181
182/**
183 * Handle server returns for aborting transmission to a client.
184 */
185struct GNUNET_SERVER_TransmitHandle
186{
187 /**
188 * Function to call to get the message.
189 */
190 GNUNET_CONNECTION_TransmitReadyNotify callback;
191
192 /**
193 * Closure for @e callback
194 */
195 void *callback_cls;
196
197 /**
198 * Active connection transmission handle.
199 */
200 struct GNUNET_CONNECTION_TransmitHandle *cth;
201
202};
203
204
205/**
206 * @brief handle for a client of the server
207 */
208struct GNUNET_SERVER_Client
209{
210
211 /**
212 * This is a doubly linked list.
213 */
214 struct GNUNET_SERVER_Client *next;
215
216 /**
217 * This is a doubly linked list.
218 */
219 struct GNUNET_SERVER_Client *prev;
220
221 /**
222 * Processing of incoming data.
223 */
224 void *mst;
225
226 /**
227 * Server that this client belongs to.
228 */
229 struct GNUNET_SERVER_Handle *server;
230
231 /**
232 * Client closure for callbacks.
233 */
234 struct GNUNET_CONNECTION_Handle *connection;
235
236 /**
237 * User context value, manipulated using
238 * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
239 */
240 void *user_context;
241
242 /**
243 * ID of task used to restart processing.
244 */
245 struct GNUNET_SCHEDULER_Task * restart_task;
246
247 /**
248 * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
249 */
250 struct GNUNET_SCHEDULER_Task * warn_task;
251
252 /**
253 * Time when the warn task was started.
254 */
255 struct GNUNET_TIME_Absolute warn_start;
256
257 /**
258 * Last activity on this socket (used to time it out
259 * if reference_count == 0).
260 */
261 struct GNUNET_TIME_Absolute last_activity;
262
263 /**
264 * Transmission handle we return for this client from
265 * #GNUNET_SERVER_notify_transmit_ready.
266 */
267 struct GNUNET_SERVER_TransmitHandle th;
268
269 /**
270 * After how long should an idle connection time
271 * out (on write).
272 */
273 struct GNUNET_TIME_Relative idle_timeout;
274
275 /**
276 * Number of external entities with a reference to
277 * this client object.
278 */
279 unsigned int reference_count;
280
281 /**
282 * Was processing if incoming messages suspended while
283 * we were still processing data already received?
284 * This is a counter saying how often processing was
285 * suspended (once per handler invoked).
286 */
287 unsigned int suspended;
288
289 /**
290 * Last size given when user context was initialized; used for
291 * sanity check.
292 */
293 size_t user_context_size;
294
295 /**
296 * Are we currently in the "process_client_buffer" function (and
297 * will hence restart the receive job on exit if suspended == 0 once
298 * we are done?). If this is set, then "receive_done" will
299 * essentially only decrement suspended; if this is not set, then
300 * "receive_done" may need to restart the receive process (either
301 * from the side-buffer or via select/recv).
302 */
303 int in_process_client_buffer;
304
305 /**
306 * We're about to close down this client.
307 */
308 int shutdown_now;
309
310 /**
311 * Are we currently trying to receive? (#GNUNET_YES if we are,
312 * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
313 * available in MST).
314 */
315 int receive_pending;
316
317 /**
318 * Persist the file handle for this client no matter what happens,
319 * force the OS to close once the process actually dies. Should only
320 * be used in special cases!
321 */
322 int persist;
323
324 /**
325 * Is this client a 'monitor' client that should not be counted
326 * when deciding on destroying the server during soft shutdown?
327 * (see also #GNUNET_SERVICE_start)
328 */
329 int is_monitor;
330
331 /**
332 * Type of last message processed (for warn_no_receive_done).
333 */
334 uint16_t warn_type;
335};
336
337
338
339/**
340 * Return user context associated with the given client.
341 * Note: you should probably use the macro (call without the underscore).
342 *
343 * @param client client to query
344 * @param size number of bytes in user context struct (for verification only)
345 * @return pointer to user context
346 */
347void *
348GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
349 size_t size)
350{
351 if ((0 == client->user_context_size) &&
352 (NULL == client->user_context))
353 return NULL; /* never set */
354 GNUNET_assert (size == client->user_context_size);
355 return client->user_context;
356}
357
358
359/**
360 * Set user context to be associated with the given client.
361 * Note: you should probably use the macro (call without the underscore).
362 *
363 * @param client client to query
364 * @param ptr pointer to user context
365 * @param size number of bytes in user context struct (for verification only)
366 */
367void
368GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
369 void *ptr,
370 size_t size)
371{
372 if (NULL == ptr)
373 {
374 client->user_context_size = 0;
375 client->user_context = ptr;
376 return;
377 }
378 client->user_context_size = size;
379 client->user_context = ptr;
380}
381
382
383/**
384 * Scheduler says our listen socket is ready. Process it!
385 *
386 * @param cls handle to our server for which we are processing the listen
387 * socket
388 */
389static void
390process_listen_socket (void *cls)
391{
392 struct GNUNET_SERVER_Handle *server = cls;
393 const struct GNUNET_SCHEDULER_TaskContext *tc;
394 struct GNUNET_CONNECTION_Handle *sock;
395 unsigned int i;
396
397 server->listen_task = NULL;
398 tc = GNUNET_SCHEDULER_get_task_context ();
399 for (i = 0; NULL != server->listen_sockets[i]; i++)
400 {
401 if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
402 server->listen_sockets[i]))
403 {
404 sock =
405 GNUNET_CONNECTION_create_from_accept (server->access_cb,
406 server->access_cb_cls,
407 server->listen_sockets[i]);
408 if (NULL != sock)
409 {
410 LOG (GNUNET_ERROR_TYPE_DEBUG,
411 "Server accepted incoming connection.\n");
412 (void) GNUNET_SERVER_connect_socket (server,
413 sock);
414 }
415 }
416 }
417 /* listen for more! */
418 GNUNET_SERVER_resume (server);
419}
420
421
422/**
423 * Create and initialize a listen socket for the server.
424 *
425 * @param server_addr address to listen on
426 * @param socklen length of @a server_addr
427 * @return NULL on error, otherwise the listen socket
428 */
429static struct GNUNET_NETWORK_Handle *
430open_listen_socket (const struct sockaddr *server_addr,
431 socklen_t socklen)
432{
433 struct GNUNET_NETWORK_Handle *sock;
434 uint16_t port;
435 int eno;
436
437 switch (server_addr->sa_family)
438 {
439 case AF_INET:
440 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
441 break;
442 case AF_INET6:
443 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
444 break;
445 case AF_UNIX:
446 port = 0;
447 break;
448 default:
449 GNUNET_break (0);
450 port = 0;
451 break;
452 }
453 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
454 if (NULL == sock)
455 {
456 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
457 errno = 0;
458 return NULL;
459 }
460 /* bind the socket */
461 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
462 {
463 eno = errno;
464 if (EADDRINUSE != errno)
465 {
466 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
467 * fail if we already took the port on IPv6; if both IPv4 and
468 * IPv6 binds fail, then our caller will log using the
469 * errno preserved in 'eno' */
470 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
471 "bind");
472 if (0 != port)
473 LOG (GNUNET_ERROR_TYPE_ERROR,
474 _("`%s' failed for port %d (%s).\n"),
475 "bind",
476 port,
477 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
478 eno = 0;
479 }
480 else
481 {
482 if (0 != port)
483 LOG (GNUNET_ERROR_TYPE_WARNING,
484 _("`%s' failed for port %d (%s): address already in use\n"),
485 "bind", port,
486 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
487 else if (AF_UNIX == server_addr->sa_family)
488 {
489 LOG (GNUNET_ERROR_TYPE_WARNING,
490 _("`%s' failed for `%s': address already in use\n"),
491 "bind",
492 GNUNET_a2s (server_addr, socklen));
493 }
494 }
495 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
496 errno = eno;
497 return NULL;
498 }
499 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
500 {
501 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
502 "listen");
503 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
504 errno = 0;
505 return NULL;
506 }
507 if (0 != port)
508 LOG (GNUNET_ERROR_TYPE_DEBUG,
509 "Server starts to listen on port %u.\n",
510 port);
511 return sock;
512}
513
514
515/**
516 * Create a new server.
517 *
518 * @param access_cb function for access control
519 * @param access_cb_cls closure for @a access_cb
520 * @param lsocks NULL-terminated array of listen sockets
521 * @param idle_timeout after how long should we timeout idle connections?
522 * @param require_found if #GNUNET_YES, connections sending messages of unknown type
523 * will be closed
524 * @return handle for the new server, NULL on error
525 * (typically, "port" already in use)
526 */
527struct GNUNET_SERVER_Handle *
528GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
529 void *access_cb_cls,
530 struct GNUNET_NETWORK_Handle **lsocks,
531 struct GNUNET_TIME_Relative idle_timeout,
532 int require_found)
533{
534 struct GNUNET_SERVER_Handle *server;
535
536 server = GNUNET_new (struct GNUNET_SERVER_Handle);
537 server->idle_timeout = idle_timeout;
538 server->listen_sockets = lsocks;
539 server->access_cb = access_cb;
540 server->access_cb_cls = access_cb_cls;
541 server->require_found = require_found;
542 if (NULL != lsocks)
543 GNUNET_SERVER_resume (server);
544 return server;
545}
546
547
548/**
549 * Create a new server.
550 *
551 * @param access_cb function for access control
552 * @param access_cb_cls closure for @a access_cb
553 * @param server_addr address to listen on (including port), NULL terminated array
554 * @param socklen length of server_addr
555 * @param idle_timeout after how long should we timeout idle connections?
556 * @param require_found if YES, connections sending messages of unknown type
557 * will be closed
558 * @return handle for the new server, NULL on error
559 * (typically, "port" already in use)
560 */
561struct GNUNET_SERVER_Handle *
562GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
563 void *access_cb_cls,
564 struct sockaddr *const *server_addr,
565 const socklen_t * socklen,
566 struct GNUNET_TIME_Relative idle_timeout,
567 int require_found)
568{
569 struct GNUNET_NETWORK_Handle **lsocks;
570 unsigned int i;
571 unsigned int j;
572 unsigned int k;
573 int seen;
574
575 i = 0;
576 while (NULL != server_addr[i])
577 i++;
578 if (i > 0)
579 {
580 lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
581 i = 0;
582 j = 0;
583 while (NULL != server_addr[i])
584 {
585 seen = 0;
586 for (k=0;k<i;k++)
587 if ( (socklen[k] == socklen[i]) &&
588 (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) )
589 {
590 seen = 1;
591 break;
592 }
593 if (0 != seen)
594 {
595 /* duplicate address, skip */
596 i++;
597 continue;
598 }
599 lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
600 if (NULL != lsocks[j])
601 j++;
602 i++;
603 }
604 if (0 == j)
605 {
606 if (0 != errno)
607 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
608 GNUNET_free (lsocks);
609 lsocks = NULL;
610 }
611 }
612 else
613 {
614 lsocks = NULL;
615 }
616 return GNUNET_SERVER_create_with_sockets (access_cb,
617 access_cb_cls,
618 lsocks,
619 idle_timeout,
620 require_found);
621}
622
623
624/**
625 * Set the 'monitor' flag on this client. Clients which have been
626 * marked as 'monitors' won't prevent the server from shutting down
627 * once '#GNUNET_SERVER_stop_listening()' has been invoked. The idea is
628 * that for "normal" clients we likely want to allow them to process
629 * their requests; however, monitor-clients are likely to 'never'
630 * disconnect during shutdown and thus will not be considered when
631 * determining if the server should continue to exist after
632 * #GNUNET_SERVER_destroy() has been called.
633 *
634 * @param client the client to set the 'monitor' flag on
635 */
636void
637GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
638{
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640 "Marking client as monitor!\n");
641 client->is_monitor = GNUNET_YES;
642}
643
644
645/**
646 * Helper function for #test_monitor_clients() to trigger
647 * #GNUNET_SERVER_destroy() after the stack has unwound.
648 *
649 * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
650 */
651static void
652do_destroy (void *cls)
653{
654 struct GNUNET_SERVER_Handle *server = cls;
655
656 GNUNET_SERVER_destroy (server);
657}
658
659
660/**
661 * Check if only 'monitor' clients are left. If so, destroy the
662 * server completely.
663 *
664 * @param server server to test for full shutdown
665 */
666static void
667test_monitor_clients (struct GNUNET_SERVER_Handle *server)
668{
669 struct GNUNET_SERVER_Client *client;
670
671 if (GNUNET_YES != server->in_soft_shutdown)
672 return;
673 for (client = server->clients_head; NULL != client; client = client->next)
674 if (GNUNET_NO == client->is_monitor)
675 return; /* not done yet */
676 server->in_soft_shutdown = GNUNET_SYSERR;
677 (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
678}
679
680
681/**
682 * Suspend accepting connections from the listen socket temporarily.
683 *
684 * @param server server to stop accepting connections.
685 */
686void
687GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
688{
689 if (NULL != server->listen_task)
690 {
691 GNUNET_SCHEDULER_cancel (server->listen_task);
692 server->listen_task = NULL;
693 }
694}
695
696
697/**
698 * Resume accepting connections from the listen socket.
699 *
700 * @param server server to stop accepting connections.
701 */
702void
703GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
704{
705 struct GNUNET_NETWORK_FDSet *r;
706 unsigned int i;
707
708 if (NULL == server->listen_sockets)
709 return;
710 if (NULL == server->listen_sockets[0])
711 return; /* nothing to do, no listen sockets! */
712 if (NULL == server->listen_sockets[1])
713 {
714 /* simplified method: no fd set needed; this is then much simpler
715 and much more efficient */
716 server->listen_task =
717 GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
718 GNUNET_SCHEDULER_PRIORITY_HIGH,
719 server->listen_sockets[0],
720 &process_listen_socket, server);
721 return;
722 }
723 r = GNUNET_NETWORK_fdset_create ();
724 i = 0;
725 while (NULL != server->listen_sockets[i])
726 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
727 server->listen_task =
728 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
729 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
730 &process_listen_socket, server);
731 GNUNET_NETWORK_fdset_destroy (r);
732}
733
734
735/**
736 * Stop the listen socket and get ready to shutdown the server
737 * once only 'monitor' clients are left.
738 *
739 * @param server server to stop listening on
740 */
741void
742GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
743{
744 unsigned int i;
745
746 LOG (GNUNET_ERROR_TYPE_DEBUG,
747 "Server in soft shutdown\n");
748 if (NULL != server->listen_task)
749 {
750 GNUNET_SCHEDULER_cancel (server->listen_task);
751 server->listen_task = NULL;
752 }
753 if (NULL != server->listen_sockets)
754 {
755 i = 0;
756 while (NULL != server->listen_sockets[i])
757 GNUNET_break (GNUNET_OK ==
758 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
759 GNUNET_free (server->listen_sockets);
760 server->listen_sockets = NULL;
761 }
762 if (GNUNET_NO == server->in_soft_shutdown)
763 server->in_soft_shutdown = GNUNET_YES;
764 test_monitor_clients (server);
765}
766
767
768/**
769 * Free resources held by this server.
770 *
771 * @param server server to destroy
772 */
773void
774GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
775{
776 struct HandlerList *hpos;
777 struct NotifyList *npos;
778 unsigned int i;
779
780 LOG (GNUNET_ERROR_TYPE_DEBUG,
781 "Server shutting down.\n");
782 if (NULL != server->listen_task)
783 {
784 GNUNET_SCHEDULER_cancel (server->listen_task);
785 server->listen_task = NULL;
786 }
787 if (NULL != server->listen_sockets)
788 {
789 i = 0;
790 while (NULL != server->listen_sockets[i])
791 GNUNET_break (GNUNET_OK ==
792 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
793 GNUNET_free (server->listen_sockets);
794 server->listen_sockets = NULL;
795 }
796 while (NULL != server->clients_head)
797 GNUNET_SERVER_client_disconnect (server->clients_head);
798 while (NULL != (hpos = server->handlers))
799 {
800 server->handlers = hpos->next;
801 GNUNET_free (hpos);
802 }
803 while (NULL != (npos = server->disconnect_notify_list_head))
804 {
805 npos->callback (npos->callback_cls,
806 NULL);
807 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
808 server->disconnect_notify_list_tail,
809 npos);
810 GNUNET_free (npos);
811 }
812 while (NULL != (npos = server->connect_notify_list_head))
813 {
814 npos->callback (npos->callback_cls,
815 NULL);
816 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
817 server->connect_notify_list_tail,
818 npos);
819 GNUNET_free (npos);
820 }
821 GNUNET_free (server);
822}
823
824
825/**
826 * Add additional handlers to an existing server.
827 *
828 * @param server the server to add handlers to
829 * @param handlers array of message handlers for
830 * incoming messages; the last entry must
831 * have "NULL" for the "callback"; multiple
832 * entries for the same type are allowed,
833 * they will be called in order of occurence.
834 * These handlers can be removed later;
835 * the handlers array must exist until removed
836 * (or server is destroyed).
837 */
838void
839GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
840 const struct GNUNET_SERVER_MessageHandler *handlers)
841{
842 struct HandlerList *p;
843
844 p = GNUNET_new (struct HandlerList);
845 p->handlers = handlers;
846 p->next = server->handlers;
847 server->handlers = p;
848}
849
850
851/**
852 * Change functions used by the server to tokenize the message stream.
853 * (very rarely used).
854 *
855 * @param server server to modify
856 * @param create new tokenizer initialization function
857 * @param destroy new tokenizer destruction function
858 * @param receive new tokenizer receive function
859 * @param cls closure for @a create, @a receive, @a destroy
860 */
861void
862GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
863 GNUNET_SERVER_MstCreateCallback create,
864 GNUNET_SERVER_MstDestroyCallback destroy,
865 GNUNET_SERVER_MstReceiveCallback receive,
866 void *cls)
867{
868 server->mst_create = create;
869 server->mst_destroy = destroy;
870 server->mst_receive = receive;
871 server->mst_cls = cls;
872}
873
874
875/**
876 * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
877 *
878 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
879 */
880static void
881warn_no_receive_done (void *cls)
882{
883 struct GNUNET_SERVER_Client *client = cls;
884
885 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
886 client->warn_task =
887 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
888 &warn_no_receive_done, client);
889 LOG (GNUNET_ERROR_TYPE_WARNING,
890 _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
891 (unsigned int) client->warn_type,
892 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
893 GNUNET_YES));
894}
895
896
897/**
898 * Disable the warning the server issues if a message is not acknowledged
899 * in a timely fashion. Use this call if a client is intentionally delayed
900 * for a while. Only applies to the current message.
901 *
902 * @param client client for which to disable the warning
903 */
904void
905GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
906{
907 if (NULL != client->warn_task)
908 {
909 GNUNET_SCHEDULER_cancel (client->warn_task);
910 client->warn_task = NULL;
911 }
912}
913
914
915/**
916 * Inject a message into the server, pretend it came
917 * from the specified client. Delivery of the message
918 * will happen instantly (if a handler is installed;
919 * otherwise the call does nothing).
920 *
921 * @param server the server receiving the message
922 * @param sender the "pretended" sender of the message
923 * can be NULL!
924 * @param message message to transmit
925 * @return #GNUNET_OK if the message was OK and the
926 * connection can stay open
927 * #GNUNET_SYSERR if the connection to the
928 * client should be shut down
929 */
930int
931GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
932 struct GNUNET_SERVER_Client *sender,
933 const struct GNUNET_MessageHeader *message)
934{
935 struct HandlerList *pos;
936 const struct GNUNET_SERVER_MessageHandler *mh;
937 unsigned int i;
938 uint16_t type;
939 uint16_t size;
940 int found;
941
942 type = ntohs (message->type);
943 size = ntohs (message->size);
944 LOG (GNUNET_ERROR_TYPE_INFO,
945 "Received message of type %u and size %u from client\n",
946 type, size);
947 found = GNUNET_NO;
948 for (pos = server->handlers; NULL != pos; pos = pos->next)
949 {
950 i = 0;
951 while (pos->handlers[i].callback != NULL)
952 {
953 mh = &pos->handlers[i];
954 if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
955 {
956 if ((0 != mh->expected_size) && (mh->expected_size != size))
957 {
958#if GNUNET8_NETWORK_IS_DEAD
959 LOG (GNUNET_ERROR_TYPE_WARNING,
960 "Expected %u bytes for message of type %u, got %u\n",
961 mh->expected_size, mh->type, size);
962 GNUNET_break_op (0);
963#else
964 LOG (GNUNET_ERROR_TYPE_DEBUG,
965 "Expected %u bytes for message of type %u, got %u\n",
966 mh->expected_size, mh->type, size);
967#endif
968 return GNUNET_SYSERR;
969 }
970 if (NULL != sender)
971 {
972 if ( (0 == sender->suspended) &&
973 (NULL == sender->warn_task) )
974 {
975 GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
976 sender->warn_start = GNUNET_TIME_absolute_get ();
977 sender->warn_task =
978 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
979 &warn_no_receive_done,
980 sender);
981 sender->warn_type = type;
982 }
983 sender->suspended++;
984 }
985 mh->callback (mh->callback_cls, sender, message);
986 found = GNUNET_YES;
987 }
988 i++;
989 }
990 }
991 if (GNUNET_NO == found)
992 {
993 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
994 "Received message of unknown type %d\n", type);
995 if (GNUNET_YES == server->require_found)
996 return GNUNET_SYSERR;
997 }
998 return GNUNET_OK;
999}
1000
1001
1002/**
1003 * We are receiving an incoming message. Process it.
1004 *
1005 * @param cls our closure (handle for the client)
1006 * @param buf buffer with data received from network
1007 * @param available number of bytes available in buf
1008 * @param addr address of the sender
1009 * @param addrlen length of @a addr
1010 * @param errCode code indicating errors receiving, 0 for success
1011 */
1012static void
1013process_incoming (void *cls,
1014 const void *buf,
1015 size_t available,
1016 const struct sockaddr *addr,
1017 socklen_t addrlen,
1018 int errCode);
1019
1020
1021/**
1022 * Process messages from the client's message tokenizer until either
1023 * the tokenizer is empty (and then schedule receiving more), or
1024 * until some handler is not immediately done (then wait for restart_processing)
1025 * or shutdown.
1026 *
1027 * @param client the client to process, RC must have already been increased
1028 * using #GNUNET_SERVER_client_keep and will be decreased by one in this
1029 * function
1030 * @param ret #GNUNET_NO to start processing from the buffer,
1031 * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
1032 * #GNUNET_SYSERR if we should instantly abort due to error in a previous step
1033 */
1034static void
1035process_mst (struct GNUNET_SERVER_Client *client,
1036 int ret)
1037{
1038 while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
1039 (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
1040 {
1041 if (GNUNET_OK == ret)
1042 {
1043 LOG (GNUNET_ERROR_TYPE_DEBUG,
1044 "Server re-enters receive loop, timeout: %s.\n",
1045 GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
1046 client->receive_pending = GNUNET_YES;
1047 GNUNET_CONNECTION_receive (client->connection,
1048 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1049 client->idle_timeout,
1050 &process_incoming,
1051 client);
1052 break;
1053 }
1054 LOG (GNUNET_ERROR_TYPE_DEBUG,
1055 "Server processes additional messages instantly.\n");
1056 if (NULL != client->server->mst_receive)
1057 ret =
1058 client->server->mst_receive (client->server->mst_cls, client->mst,
1059 client, NULL, 0, GNUNET_NO, GNUNET_YES);
1060 else
1061 ret =
1062 GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
1063 GNUNET_YES);
1064 }
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
1067 ret, client->server,
1068 client->shutdown_now,
1069 client->suspended);
1070 if (GNUNET_NO == ret)
1071 {
1072 LOG (GNUNET_ERROR_TYPE_DEBUG,
1073 "Server has more data pending but is suspended.\n");
1074 client->receive_pending = GNUNET_SYSERR; /* data pending */
1075 }
1076 if ( (GNUNET_SYSERR == ret) ||
1077 (GNUNET_YES == client->shutdown_now) )
1078 GNUNET_SERVER_client_disconnect (client);
1079}
1080
1081
1082/**
1083 * We are receiving an incoming message. Process it.
1084 *
1085 * @param cls our closure (handle for the client)
1086 * @param buf buffer with data received from network
1087 * @param available number of bytes available in buf
1088 * @param addr address of the sender
1089 * @param addrlen length of @a addr
1090 * @param errCode code indicating errors receiving, 0 for success
1091 */
1092static void
1093process_incoming (void *cls,
1094 const void *buf,
1095 size_t available,
1096 const struct sockaddr *addr,
1097 socklen_t addrlen,
1098 int errCode)
1099{
1100 struct GNUNET_SERVER_Client *client = cls;
1101 struct GNUNET_SERVER_Handle *server = client->server;
1102 struct GNUNET_TIME_Absolute end;
1103 struct GNUNET_TIME_Absolute now;
1104 int ret;
1105
1106 GNUNET_assert (GNUNET_YES == client->receive_pending);
1107 client->receive_pending = GNUNET_NO;
1108 now = GNUNET_TIME_absolute_get ();
1109 end = GNUNET_TIME_absolute_add (client->last_activity,
1110 client->idle_timeout);
1111
1112 if ( (NULL == buf) &&
1113 (0 == available) &&
1114 (NULL == addr) &&
1115 (0 == errCode) &&
1116 (GNUNET_YES != client->shutdown_now) &&
1117 (NULL != server) &&
1118 (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
1119 (end.abs_value_us > now.abs_value_us) )
1120 {
1121 /* wait longer, timeout changed (i.e. due to us sending) */
1122 LOG (GNUNET_ERROR_TYPE_DEBUG,
1123 "Receive time out, but no disconnect due to sending (%p)\n",
1124 client);
1125 client->receive_pending = GNUNET_YES;
1126 GNUNET_CONNECTION_receive (client->connection,
1127 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1128 GNUNET_TIME_absolute_get_remaining (end),
1129 &process_incoming,
1130 client);
1131 return;
1132 }
1133 if ( (NULL == buf) ||
1134 (0 == available) ||
1135 (0 != errCode) ||
1136 (NULL == server) ||
1137 (GNUNET_YES == client->shutdown_now) ||
1138 (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) )
1139 {
1140 /* other side closed connection, error connecting, etc. */
1141 LOG (GNUNET_ERROR_TYPE_DEBUG,
1142 "Failed to connect or other side closed connection (%p)\n",
1143 client);
1144 GNUNET_SERVER_client_disconnect (client);
1145 return;
1146 }
1147 LOG (GNUNET_ERROR_TYPE_DEBUG,
1148 "Server receives %u bytes from `%s'.\n",
1149 (unsigned int) available,
1150 GNUNET_a2s (addr, addrlen));
1151 GNUNET_SERVER_client_keep (client);
1152 client->last_activity = now;
1153
1154 if (NULL != server->mst_receive)
1155 {
1156 ret = client->server->mst_receive (client->server->mst_cls,
1157 client->mst,
1158 client,
1159 buf,
1160 available,
1161 GNUNET_NO,
1162 GNUNET_YES);
1163 }
1164 else if (NULL != client->mst)
1165 {
1166 ret =
1167 GNUNET_SERVER_mst_receive (client->mst,
1168 client,
1169 buf,
1170 available,
1171 GNUNET_NO,
1172 GNUNET_YES);
1173 }
1174 else
1175 {
1176 GNUNET_break (0);
1177 return;
1178 }
1179 process_mst (client,
1180 ret);
1181 GNUNET_SERVER_client_drop (client);
1182}
1183
1184
1185/**
1186 * Task run to start again receiving from the network
1187 * and process requests.
1188 *
1189 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
1190 */
1191static void
1192restart_processing (void *cls)
1193{
1194 struct GNUNET_SERVER_Client *client = cls;
1195
1196 GNUNET_assert (GNUNET_YES != client->shutdown_now);
1197 client->restart_task = NULL;
1198 if (GNUNET_NO == client->receive_pending)
1199 {
1200 LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
1201 client->receive_pending = GNUNET_YES;
1202 GNUNET_CONNECTION_receive (client->connection,
1203 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1204 client->idle_timeout,
1205 &process_incoming,
1206 client);
1207 return;
1208 }
1209 LOG (GNUNET_ERROR_TYPE_DEBUG,
1210 "Server continues processing messages still in the buffer.\n");
1211 GNUNET_SERVER_client_keep (client);
1212 client->receive_pending = GNUNET_NO;
1213 process_mst (client,
1214 GNUNET_NO);
1215 GNUNET_SERVER_client_drop (client);
1216}
1217
1218
1219/**
1220 * This function is called whenever our inbound message tokenizer has
1221 * received a complete message.
1222 *
1223 * @param cls closure (struct GNUNET_SERVER_Handle)
1224 * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
1225 * @param message the actual message
1226 *
1227 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
1228 */
1229static int
1230client_message_tokenizer_callback (void *cls,
1231 void *client,
1232 const struct GNUNET_MessageHeader *message)
1233{
1234 struct GNUNET_SERVER_Handle *server = cls;
1235 struct GNUNET_SERVER_Client *sender = client;
1236 int ret;
1237
1238 LOG (GNUNET_ERROR_TYPE_DEBUG,
1239 "Tokenizer gives server message of type %u and size %u from client\n",
1240 ntohs (message->type), ntohs (message->size));
1241 sender->in_process_client_buffer = GNUNET_YES;
1242 ret = GNUNET_SERVER_inject (server, sender, message);
1243 sender->in_process_client_buffer = GNUNET_NO;
1244 if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) )
1245 {
1246 GNUNET_SERVER_client_disconnect (sender);
1247 return GNUNET_SYSERR;
1248 }
1249 return GNUNET_OK;
1250}
1251
1252
1253/**
1254 * Add a TCP socket-based connection to the set of handles managed by
1255 * this server. Use this function for outgoing (P2P) connections that
1256 * we initiated (and where this server should process incoming
1257 * messages).
1258 *
1259 * @param server the server to use
1260 * @param connection the connection to manage (client must
1261 * stop using this connection from now on)
1262 * @return the client handle
1263 */
1264struct GNUNET_SERVER_Client *
1265GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
1266 struct GNUNET_CONNECTION_Handle *connection)
1267{
1268 struct GNUNET_SERVER_Client *client;
1269 struct NotifyList *n;
1270
1271 client = GNUNET_new (struct GNUNET_SERVER_Client);
1272 client->connection = connection;
1273 client->server = server;
1274 client->last_activity = GNUNET_TIME_absolute_get ();
1275 client->idle_timeout = server->idle_timeout;
1276 GNUNET_CONTAINER_DLL_insert (server->clients_head,
1277 server->clients_tail,
1278 client);
1279 if (NULL != server->mst_create)
1280 client->mst =
1281 server->mst_create (server->mst_cls, client);
1282 else
1283 client->mst =
1284 GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
1285 server);
1286 GNUNET_assert (NULL != client->mst);
1287 for (n = server->connect_notify_list_head; NULL != n; n = n->next)
1288 n->callback (n->callback_cls, client);
1289 client->receive_pending = GNUNET_YES;
1290 GNUNET_CONNECTION_receive (client->connection,
1291 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1292 client->idle_timeout,
1293 &process_incoming,
1294 client);
1295 return client;
1296}
1297
1298
1299/**
1300 * Change the timeout for a particular client. Decreasing the timeout
1301 * may not go into effect immediately (only after the previous timeout
1302 * times out or activity happens on the socket).
1303 *
1304 * @param client the client to update
1305 * @param timeout new timeout for activities on the socket
1306 */
1307void
1308GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
1309 struct GNUNET_TIME_Relative timeout)
1310{
1311 client->idle_timeout = timeout;
1312}
1313
1314
1315/**
1316 * Notify the server that the given client handle should
1317 * be kept (keeps the connection up if possible, increments
1318 * the internal reference counter).
1319 *
1320 * @param client the client to keep
1321 */
1322void
1323GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1324{
1325 client->reference_count++;
1326}
1327
1328
1329/**
1330 * Notify the server that the given client handle is no
1331 * longer required. Decrements the reference counter. If
1332 * that counter reaches zero an inactive connection maybe
1333 * closed.
1334 *
1335 * @param client the client to drop
1336 */
1337void
1338GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1339{
1340 GNUNET_assert (client->reference_count > 0);
1341 client->reference_count--;
1342 if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
1343 GNUNET_SERVER_client_disconnect (client);
1344}
1345
1346
1347/**
1348 * Obtain the network address of the other party.
1349 *
1350 * @param client the client to get the address for
1351 * @param addr where to store the address
1352 * @param addrlen where to store the length of the @a addr
1353 * @return #GNUNET_OK on success
1354 */
1355int
1356GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1357 void **addr, size_t * addrlen)
1358{
1359 return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
1360}
1361
1362
1363/**
1364 * Ask the server to notify us whenever a client disconnects.
1365 * This function is called whenever the actual network connection
1366 * is closed; the reference count may be zero or larger than zero
1367 * at this point.
1368 *
1369 * @param server the server manageing the clients
1370 * @param callback function to call on disconnect
1371 * @param callback_cls closure for @a callback
1372 */
1373void
1374GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1375 GNUNET_SERVER_DisconnectCallback callback,
1376 void *callback_cls)
1377{
1378 struct NotifyList *n;
1379
1380 n = GNUNET_new (struct NotifyList);
1381 n->callback = callback;
1382 n->callback_cls = callback_cls;
1383 GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
1384 server->disconnect_notify_list_tail,
1385 n);
1386}
1387
1388
1389/**
1390 * Ask the server to notify us whenever a client connects.
1391 * This function is called whenever the actual network connection
1392 * is opened. If the server is destroyed before this
1393 * notification is explicitly cancelled, the 'callback' will
1394 * once be called with a 'client' argument of NULL to indicate
1395 * that the server itself is now gone (and that the callback
1396 * won't be called anymore and also can no longer be cancelled).
1397 *
1398 * @param server the server manageing the clients
1399 * @param callback function to call on sconnect
1400 * @param callback_cls closure for @a callback
1401 */
1402void
1403GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
1404 GNUNET_SERVER_ConnectCallback callback,
1405 void *callback_cls)
1406{
1407 struct NotifyList *n;
1408 struct GNUNET_SERVER_Client *client;
1409
1410 n = GNUNET_new (struct NotifyList);
1411 n->callback = callback;
1412 n->callback_cls = callback_cls;
1413 GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
1414 server->connect_notify_list_tail,
1415 n);
1416 for (client = server->clients_head; NULL != client; client = client->next)
1417 callback (callback_cls, client);
1418}
1419
1420
1421/**
1422 * Ask the server to stop notifying us whenever a client connects.
1423 *
1424 * @param server the server manageing the clients
1425 * @param callback function to call on connect
1426 * @param callback_cls closure for @a callback
1427 */
1428void
1429GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1430 GNUNET_SERVER_DisconnectCallback callback,
1431 void *callback_cls)
1432{
1433 struct NotifyList *pos;
1434
1435 for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
1436 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1437 break;
1438 if (NULL == pos)
1439 {
1440 GNUNET_break (0);
1441 return;
1442 }
1443 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
1444 server->disconnect_notify_list_tail,
1445 pos);
1446 GNUNET_free (pos);
1447}
1448
1449
1450/**
1451 * Ask the server to stop notifying us whenever a client disconnects.
1452 *
1453 * @param server the server manageing the clients
1454 * @param callback function to call on disconnect
1455 * @param callback_cls closure for @a callback
1456 */
1457void
1458GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1459 GNUNET_SERVER_ConnectCallback callback,
1460 void *callback_cls)
1461{
1462 struct NotifyList *pos;
1463
1464 for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
1465 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1466 break;
1467 if (NULL == pos)
1468 {
1469 GNUNET_break (0);
1470 return;
1471 }
1472 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
1473 server->connect_notify_list_tail,
1474 pos);
1475 GNUNET_free (pos);
1476}
1477
1478
1479/**
1480 * Destroy the connection that is passed in via @a cls. Used
1481 * as calling #GNUNET_CONNECTION_destroy from within a function
1482 * that was itself called from within process_notify() of
1483 * 'connection.c' is not allowed (see #2329).
1484 *
1485 * @param cls connection to destroy
1486 */
1487static void
1488destroy_connection (void *cls)
1489{
1490 struct GNUNET_CONNECTION_Handle *connection = cls;
1491
1492 GNUNET_CONNECTION_destroy (connection);
1493}
1494
1495
1496/**
1497 * Ask the server to disconnect from the given client.
1498 * This is the same as returning #GNUNET_SYSERR from a message
1499 * handler, except that it allows dropping of a client even
1500 * when not handling a message from that client.
1501 *
1502 * @param client the client to disconnect from
1503 */
1504void
1505GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1506{
1507 struct GNUNET_SERVER_Handle *server = client->server;
1508 struct NotifyList *n;
1509
1510 LOG (GNUNET_ERROR_TYPE_DEBUG,
1511 "Client is being disconnected from the server.\n");
1512 if (NULL != client->restart_task)
1513 {
1514 GNUNET_SCHEDULER_cancel (client->restart_task);
1515 client->restart_task = NULL;
1516 }
1517 if (NULL != client->warn_task)
1518 {
1519 GNUNET_SCHEDULER_cancel (client->warn_task);
1520 client->warn_task = NULL;
1521 }
1522 if (GNUNET_YES == client->receive_pending)
1523 {
1524 GNUNET_CONNECTION_receive_cancel (client->connection);
1525 client->receive_pending = GNUNET_NO;
1526 }
1527 client->shutdown_now = GNUNET_YES;
1528 client->reference_count++; /* make sure nobody else clean up client... */
1529 if ( (NULL != client->mst) &&
1530 (NULL != server) )
1531 {
1532 GNUNET_CONTAINER_DLL_remove (server->clients_head,
1533 server->clients_tail,
1534 client);
1535 if (NULL != server->mst_destroy)
1536 server->mst_destroy (server->mst_cls,
1537 client->mst);
1538 else
1539 GNUNET_SERVER_mst_destroy (client->mst);
1540 client->mst = NULL;
1541 for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
1542 n->callback (n->callback_cls,
1543 client);
1544 }
1545 client->reference_count--;
1546 if (client->reference_count > 0)
1547 {
1548 LOG (GNUNET_ERROR_TYPE_DEBUG,
1549 "RC of %p still positive, not destroying everything.\n",
1550 client);
1551 client->server = NULL;
1552 return;
1553 }
1554 if (GNUNET_YES == client->in_process_client_buffer)
1555 {
1556 LOG (GNUNET_ERROR_TYPE_DEBUG,
1557 "Still processing inputs of %p, not destroying everything.\n",
1558 client);
1559 return;
1560 }
1561 LOG (GNUNET_ERROR_TYPE_DEBUG,
1562 "RC of %p now zero, destroying everything.\n",
1563 client);
1564 if (GNUNET_YES == client->persist)
1565 GNUNET_CONNECTION_persist_ (client->connection);
1566 if (NULL != client->th.cth)
1567 GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
1568 (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
1569 client->connection);
1570 /* need to cancel again, as it might have been re-added
1571 in the meantime (i.e. during callbacks) */
1572 if (NULL != client->warn_task)
1573 {
1574 GNUNET_SCHEDULER_cancel (client->warn_task);
1575 client->warn_task = NULL;
1576 }
1577 if (GNUNET_YES == client->receive_pending)
1578 {
1579 GNUNET_CONNECTION_receive_cancel (client->connection);
1580 client->receive_pending = GNUNET_NO;
1581 }
1582 GNUNET_free (client);
1583 /* we might be in soft-shutdown, test if we're done */
1584 if (NULL != server)
1585 test_monitor_clients (server);
1586}
1587
1588
1589/**
1590 * Disable the "CORK" feature for communication with the given client,
1591 * forcing the OS to immediately flush the buffer on transmission
1592 * instead of potentially buffering multiple messages.
1593 *
1594 * @param client handle to the client
1595 * @return #GNUNET_OK on success
1596 */
1597int
1598GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
1599{
1600 return GNUNET_CONNECTION_disable_corking (client->connection);
1601}
1602
1603
1604/**
1605 * Wrapper for transmission notification that calls the original
1606 * callback and update the last activity time for our connection.
1607 *
1608 * @param cls the `struct GNUNET_SERVER_Client *`
1609 * @param size number of bytes we can transmit
1610 * @param buf where to copy the message
1611 * @return number of bytes actually transmitted
1612 */
1613static size_t
1614transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
1615{
1616 struct GNUNET_SERVER_Client *client = cls;
1617 GNUNET_CONNECTION_TransmitReadyNotify callback;
1618
1619 client->th.cth = NULL;
1620 callback = client->th.callback;
1621 client->th.callback = NULL;
1622 client->last_activity = GNUNET_TIME_absolute_get ();
1623 return callback (client->th.callback_cls, size, buf);
1624}
1625
1626
1627/**
1628 * Notify us when the server has enough space to transmit
1629 * a message of the given size to the given client.
1630 *
1631 * @param client client to transmit message to
1632 * @param size requested amount of buffer space
1633 * @param timeout after how long should we give up (and call
1634 * notify with buf NULL and size 0)?
1635 * @param callback function to call when space is available
1636 * @param callback_cls closure for @a callback
1637 * @return non-NULL if the notify callback was queued; can be used
1638 * to cancel the request using
1639 * #GNUNET_SERVER_notify_transmit_ready_cancel().
1640 * NULL if we are already going to notify someone else (busy)
1641 */
1642struct GNUNET_SERVER_TransmitHandle *
1643GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1644 size_t size,
1645 struct GNUNET_TIME_Relative timeout,
1646 GNUNET_CONNECTION_TransmitReadyNotify callback,
1647 void *callback_cls)
1648{
1649 if (NULL != client->th.callback)
1650 return NULL;
1651 client->th.callback_cls = callback_cls;
1652 client->th.callback = callback;
1653 client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
1654 timeout,
1655 &transmit_ready_callback_wrapper,
1656 client);
1657 return &client->th;
1658}
1659
1660
1661/**
1662 * Abort transmission request.
1663 *
1664 * @param th request to abort
1665 */
1666void
1667GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
1668{
1669 GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
1670 th->cth = NULL;
1671 th->callback = NULL;
1672}
1673
1674
1675/**
1676 * Set the persistent flag on this client, used to setup client connection
1677 * to only be killed when the service it's connected to is actually dead.
1678 *
1679 * @param client the client to set the persistent flag on
1680 */
1681void
1682GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1683{
1684 client->persist = GNUNET_YES;
1685}
1686
1687
1688/**
1689 * Resume receiving from this client, we are done processing the
1690 * current request. This function must be called from within each
1691 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1692 *
1693 * @param client client we were processing a message of
1694 * @param success #GNUNET_OK to keep the connection open and
1695 * continue to receive
1696 * #GNUNET_NO to close the connection (normal behavior)
1697 * #GNUNET_SYSERR to close the connection (signal
1698 * serious error)
1699 */
1700void
1701GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
1702 int success)
1703{
1704 if (NULL == client)
1705 return;
1706 GNUNET_assert (client->suspended > 0);
1707 client->suspended--;
1708 if (GNUNET_OK != success)
1709 {
1710 LOG (GNUNET_ERROR_TYPE_DEBUG,
1711 "GNUNET_SERVER_receive_done called with failure indication\n");
1712 if ( (client->reference_count > 0) || (client->suspended > 0) )
1713 client->shutdown_now = GNUNET_YES;
1714 else
1715 GNUNET_SERVER_client_disconnect (client);
1716 return;
1717 }
1718 if (client->suspended > 0)
1719 {
1720 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 "GNUNET_SERVER_receive_done called, but more clients pending\n");
1722 return;
1723 }
1724 if (NULL != client->warn_task)
1725 {
1726 GNUNET_SCHEDULER_cancel (client->warn_task);
1727 client->warn_task = NULL;
1728 }
1729 if (GNUNET_YES == client->in_process_client_buffer)
1730 {
1731 LOG (GNUNET_ERROR_TYPE_DEBUG,
1732 "GNUNET_SERVER_receive_done called while still in processing loop\n");
1733 return;
1734 }
1735 if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
1736 {
1737 GNUNET_SERVER_client_disconnect (client);
1738 return;
1739 }
1740 LOG (GNUNET_ERROR_TYPE_DEBUG,
1741 "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
1742 GNUNET_assert (NULL == client->restart_task);
1743 client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
1744 client);
1745}
1746
1747
1748/* end of server.c */
diff --git a/src/transport/tcp_server_mst_legacy.c b/src/transport/tcp_server_mst_legacy.c
new file mode 100644
index 000000000..ba42b1837
--- /dev/null
+++ b/src/transport/tcp_server_mst_legacy.c
@@ -0,0 +1,311 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010 GNUnet e.V.
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 3, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/server_mst.c
23 * @brief convenience functions for handling inbound message buffers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30
31#if HAVE_UNALIGNED_64_ACCESS
32#define ALIGN_FACTOR 4
33#else
34#define ALIGN_FACTOR 8
35#endif
36
37
38/**
39 * Handle to a message stream tokenizer.
40 */
41struct GNUNET_SERVER_MessageStreamTokenizer
42{
43
44 /**
45 * Function to call on completed messages.
46 */
47 GNUNET_SERVER_MessageTokenizerCallback cb;
48
49 /**
50 * Closure for @e cb.
51 */
52 void *cb_cls;
53
54 /**
55 * Size of the buffer (starting at @e hdr).
56 */
57 size_t curr_buf;
58
59 /**
60 * How many bytes in buffer have we already processed?
61 */
62 size_t off;
63
64 /**
65 * How many bytes in buffer are valid right now?
66 */
67 size_t pos;
68
69 /**
70 * Beginning of the buffer. Typed like this to force alignment.
71 */
72 struct GNUNET_MessageHeader *hdr;
73
74};
75
76
77
78/**
79 * Create a message stream tokenizer.
80 *
81 * @param cb function to call on completed messages
82 * @param cb_cls closure for @a cb
83 * @return handle to tokenizer
84 */
85struct GNUNET_SERVER_MessageStreamTokenizer *
86GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
87 void *cb_cls)
88{
89 struct GNUNET_SERVER_MessageStreamTokenizer *ret;
90
91 ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
92 ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE);
93 ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE;
94 ret->cb = cb;
95 ret->cb_cls = cb_cls;
96 return ret;
97}
98
99
100/**
101 * Add incoming data to the receive buffer and call the
102 * callback for all complete messages.
103 *
104 * @param mst tokenizer to use
105 * @param client_identity ID of client for which this is a buffer
106 * @param buf input data to add
107 * @param size number of bytes in @a buf
108 * @param purge should any excess bytes in the buffer be discarded
109 * (i.e. for packet-based services like UDP)
110 * @param one_shot only call callback once, keep rest of message in buffer
111 * @return #GNUNET_OK if we are done processing (need more data)
112 * #GNUNET_NO if @a one_shot was set and we have another message ready
113 * #GNUNET_SYSERR if the data stream is corrupt
114 */
115int
116GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
117 void *client_identity,
118 const char *buf, size_t size,
119 int purge, int one_shot)
120{
121 const struct GNUNET_MessageHeader *hdr;
122 size_t delta;
123 uint16_t want;
124 char *ibuf;
125 int need_align;
126 unsigned long offset;
127 int ret;
128
129 GNUNET_assert (mst->off <= mst->pos);
130 GNUNET_assert (mst->pos <= mst->curr_buf);
131 LOG (GNUNET_ERROR_TYPE_DEBUG,
132 "Server-mst receives %u bytes with %u bytes already in private buffer\n",
133 (unsigned int) size, (unsigned int) (mst->pos - mst->off));
134 ret = GNUNET_OK;
135 ibuf = (char *) mst->hdr;
136 while (mst->pos > 0)
137 {
138do_align:
139 GNUNET_assert (mst->pos >= mst->off);
140 if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
141 (0 != (mst->off % ALIGN_FACTOR)))
142 {
143 /* need to align or need more space */
144 mst->pos -= mst->off;
145 memmove (ibuf, &ibuf[mst->off], mst->pos);
146 mst->off = 0;
147 }
148 if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
149 {
150 delta =
151 GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
152 (mst->pos - mst->off), size);
153 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
154 mst->pos += delta;
155 buf += delta;
156 size -= delta;
157 }
158 if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
159 {
160 if (purge)
161 {
162 mst->off = 0;
163 mst->pos = 0;
164 }
165 return GNUNET_OK;
166 }
167 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
168 want = ntohs (hdr->size);
169 if (want < sizeof (struct GNUNET_MessageHeader))
170 {
171 GNUNET_break_op (0);
172 return GNUNET_SYSERR;
173 }
174 if ( (mst->curr_buf - mst->off < want) &&
175 (mst->off > 0) )
176 {
177 /* can get more space by moving */
178 mst->pos -= mst->off;
179 memmove (ibuf, &ibuf[mst->off], mst->pos);
180 mst->off = 0;
181 }
182 if (mst->curr_buf < want)
183 {
184 /* need to get more space by growing buffer */
185 GNUNET_assert (0 == mst->off);
186 mst->hdr = GNUNET_realloc (mst->hdr, want);
187 ibuf = (char *) mst->hdr;
188 mst->curr_buf = want;
189 }
190 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
191 if (mst->pos - mst->off < want)
192 {
193 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
194 GNUNET_assert (mst->pos + delta <= mst->curr_buf);
195 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
196 mst->pos += delta;
197 buf += delta;
198 size -= delta;
199 }
200 if (mst->pos - mst->off < want)
201 {
202 if (purge)
203 {
204 mst->off = 0;
205 mst->pos = 0;
206 }
207 return GNUNET_OK;
208 }
209 if (one_shot == GNUNET_SYSERR)
210 {
211 /* cannot call callback again, but return value saying that
212 * we have another full message in the buffer */
213 ret = GNUNET_NO;
214 goto copy;
215 }
216 if (one_shot == GNUNET_YES)
217 one_shot = GNUNET_SYSERR;
218 mst->off += want;
219 if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
220 return GNUNET_SYSERR;
221 if (mst->off == mst->pos)
222 {
223 /* reset to beginning of buffer, it's free right now! */
224 mst->off = 0;
225 mst->pos = 0;
226 }
227 }
228 GNUNET_assert (0 == mst->pos);
229 while (size > 0)
230 {
231 LOG (GNUNET_ERROR_TYPE_DEBUG,
232 "Server-mst has %u bytes left in inbound buffer\n",
233 (unsigned int) size);
234 if (size < sizeof (struct GNUNET_MessageHeader))
235 break;
236 offset = (unsigned long) buf;
237 need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
238 if (GNUNET_NO == need_align)
239 {
240 /* can try to do zero-copy and process directly from original buffer */
241 hdr = (const struct GNUNET_MessageHeader *) buf;
242 want = ntohs (hdr->size);
243 if (want < sizeof (struct GNUNET_MessageHeader))
244 {
245 GNUNET_break_op (0);
246 mst->off = 0;
247 return GNUNET_SYSERR;
248 }
249 if (size < want)
250 break; /* or not: buffer incomplete, so copy to private buffer... */
251 if (one_shot == GNUNET_SYSERR)
252 {
253 /* cannot call callback again, but return value saying that
254 * we have another full message in the buffer */
255 ret = GNUNET_NO;
256 goto copy;
257 }
258 if (one_shot == GNUNET_YES)
259 one_shot = GNUNET_SYSERR;
260 if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
261 return GNUNET_SYSERR;
262 buf += want;
263 size -= want;
264 }
265 else
266 {
267 /* need to copy to private buffer to align;
268 * yes, we go a bit more spagetti than usual here */
269 goto do_align;
270 }
271 }
272copy:
273 if ((size > 0) && (!purge))
274 {
275 if (size + mst->pos > mst->curr_buf)
276 {
277 mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
278 ibuf = (char *) mst->hdr;
279 mst->curr_buf = size + mst->pos;
280 }
281 GNUNET_assert (size + mst->pos <= mst->curr_buf);
282 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
283 mst->pos += size;
284 }
285 if (purge)
286 {
287 mst->off = 0;
288 mst->pos = 0;
289 }
290 LOG (GNUNET_ERROR_TYPE_DEBUG,
291 "Server-mst leaves %u bytes in private buffer\n",
292 (unsigned int) (mst->pos - mst->off));
293 return ret;
294}
295
296
297/**
298 * Destroys a tokenizer.
299 *
300 * @param mst tokenizer to destroy
301 */
302void
303GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
304{
305 GNUNET_free (mst->hdr);
306 GNUNET_free (mst);
307}
308
309
310
311/* end of server_mst.c */
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c
new file mode 100644
index 000000000..c55d586f3
--- /dev/null
+++ b/src/transport/tcp_service_legacy.c
@@ -0,0 +1,1687 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 GNUnet e.V.
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 3, 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/service.c
23 * @brief functions related to starting services
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_constants.h"
30#include "gnunet_resolver_service.h"
31
32#if HAVE_MALLINFO
33#include <malloc.h>
34#include "gauger.h"
35#endif
36
37
38/* ******************* access control ******************** */
39
40/**
41 * Check if the given IP address is in the list of IP addresses.
42 *
43 * @param list a list of networks
44 * @param add the IP to check (in network byte order)
45 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
46 */
47static int
48check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
49 const struct in_addr *add)
50{
51 unsigned int i;
52
53 if (NULL == list)
54 return GNUNET_NO;
55 i = 0;
56 while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
57 {
58 if ((add->s_addr & list[i].netmask.s_addr) ==
59 (list[i].network.s_addr & list[i].netmask.s_addr))
60 return GNUNET_YES;
61 i++;
62 }
63 return GNUNET_NO;
64}
65
66
67/**
68 * Check if the given IP address is in the list of IP addresses.
69 *
70 * @param list a list of networks
71 * @param ip the IP to check (in network byte order)
72 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
73 */
74static int
75check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
76 const struct in6_addr *ip)
77{
78 unsigned int i;
79 unsigned int j;
80 struct in6_addr zero;
81
82 if (NULL == list)
83 return GNUNET_NO;
84 memset (&zero, 0, sizeof (struct in6_addr));
85 i = 0;
86NEXT:
87 while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
88 {
89 for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
90 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
91 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
92 {
93 i++;
94 goto NEXT;
95 }
96 return GNUNET_YES;
97 }
98 return GNUNET_NO;
99}
100
101
102/* ****************** service struct ****************** */
103
104
105/**
106 * Context for "service_task".
107 */
108struct GNUNET_SERVICE_Context
109{
110 /**
111 * Our configuration.
112 */
113 const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115 /**
116 * Handle for the server.
117 */
118 struct GNUNET_SERVER_Handle *server;
119
120 /**
121 * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
122 * listen sockets.
123 */
124 struct sockaddr **addrs;
125
126 /**
127 * Name of our service.
128 */
129 const char *service_name;
130
131 /**
132 * Main service-specific task to run.
133 */
134 GNUNET_SERVICE_Main task;
135
136 /**
137 * Closure for @e task.
138 */
139 void *task_cls;
140
141 /**
142 * IPv4 addresses that are not allowed to connect.
143 */
144 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
145
146 /**
147 * IPv6 addresses that are not allowed to connect.
148 */
149 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
150
151 /**
152 * IPv4 addresses that are allowed to connect (if not
153 * set, all are allowed).
154 */
155 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
156
157 /**
158 * IPv6 addresses that are allowed to connect (if not
159 * set, all are allowed).
160 */
161 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
162
163 /**
164 * My (default) message handlers. Adjusted copy
165 * of "defhandlers".
166 */
167 struct GNUNET_SERVER_MessageHandler *my_handlers;
168
169 /**
170 * Array of the lengths of the entries in addrs.
171 */
172 socklen_t *addrlens;
173
174 /**
175 * NULL-terminated array of listen sockets we should take over.
176 */
177 struct GNUNET_NETWORK_Handle **lsocks;
178
179 /**
180 * Task ID of the shutdown task.
181 */
182 struct GNUNET_SCHEDULER_Task *shutdown_task;
183
184 /**
185 * Idle timeout for server.
186 */
187 struct GNUNET_TIME_Relative timeout;
188
189 /**
190 * Overall success/failure of the service start.
191 */
192 int ret;
193
194 /**
195 * If we are daemonizing, this FD is set to the
196 * pipe to the parent. Send '.' if we started
197 * ok, '!' if not. -1 if we are not daemonizing.
198 */
199 int ready_confirm_fd;
200
201 /**
202 * Do we close connections if we receive messages
203 * for which we have no handler?
204 */
205 int require_found;
206
207 /**
208 * Do we require a matching UID for UNIX domain socket connections?
209 * #GNUNET_NO means that the UID does not have to match (however,
210 * @e match_gid may still impose other access control checks).
211 */
212 int match_uid;
213
214 /**
215 * Do we require a matching GID for UNIX domain socket connections?
216 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
217 * checking that the client's UID is in our group OR that the
218 * client's GID is our GID. If both "match_gid" and @e match_uid are
219 * #GNUNET_NO, all users on the local system have access.
220 */
221 int match_gid;
222
223 /**
224 * Our options.
225 */
226 enum GNUNET_SERVICE_Options options;
227
228};
229
230
231/* ****************** message handlers ****************** */
232
233/**
234 * Send a 'TEST' message back to the client.
235 *
236 * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
237 * @param size number of bytes available in 'buf'
238 * @param buf where to copy the message
239 * @return number of bytes written to 'buf'
240 */
241static size_t
242write_test (void *cls, size_t size, void *buf)
243{
244 struct GNUNET_SERVER_Client *client = cls;
245 struct GNUNET_MessageHeader *msg;
246
247 if (size < sizeof (struct GNUNET_MessageHeader))
248 {
249 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
250 return 0; /* client disconnected */
251 }
252 msg = (struct GNUNET_MessageHeader *) buf;
253 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
254 msg->size = htons (sizeof (struct GNUNET_MessageHeader));
255 GNUNET_SERVER_receive_done (client, GNUNET_OK);
256 return sizeof (struct GNUNET_MessageHeader);
257}
258
259
260/**
261 * Handler for TEST message.
262 *
263 * @param cls closure (refers to service)
264 * @param client identification of the client
265 * @param message the actual message
266 */
267static void
268handle_test (void *cls, struct GNUNET_SERVER_Client *client,
269 const struct GNUNET_MessageHeader *message)
270{
271 /* simply bounce message back to acknowledge */
272 if (NULL ==
273 GNUNET_SERVER_notify_transmit_ready (client,
274 sizeof (struct GNUNET_MessageHeader),
275 GNUNET_TIME_UNIT_FOREVER_REL,
276 &write_test, client))
277 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
278}
279
280
281/**
282 * Default handlers for all services. Will be copied and the
283 * "callback_cls" fields will be replaced with the specific service
284 * struct.
285 */
286static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
287 {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
288 sizeof (struct GNUNET_MessageHeader)},
289 {NULL, NULL, 0, 0}
290};
291
292
293/* ****************** service core routines ************** */
294
295
296/**
297 * Check if access to the service is allowed from the given address.
298 *
299 * @param cls closure
300 * @param uc credentials, if available, otherwise NULL
301 * @param addr address
302 * @param addrlen length of address
303 * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
304 * for unknown address family (will be denied).
305 */
306static int
307check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
308 const struct sockaddr *addr, socklen_t addrlen)
309{
310 struct GNUNET_SERVICE_Context *sctx = cls;
311 const struct sockaddr_in *i4;
312 const struct sockaddr_in6 *i6;
313 int ret;
314
315 switch (addr->sa_family)
316 {
317 case AF_INET:
318 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
319 i4 = (const struct sockaddr_in *) addr;
320 ret = ((NULL == sctx->v4_allowed) ||
321 (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
322 ((NULL == sctx->v4_denied) ||
323 (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
324 break;
325 case AF_INET6:
326 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
327 i6 = (const struct sockaddr_in6 *) addr;
328 ret = ((NULL == sctx->v6_allowed) ||
329 (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
330 ((NULL == sctx->v6_denied) ||
331 (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
332 break;
333#ifndef WINDOWS
334 case AF_UNIX:
335 ret = GNUNET_OK; /* controlled using file-system ACL now */
336 break;
337#endif
338 default:
339 LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
340 addr->sa_family);
341 return GNUNET_SYSERR;
342 }
343 if (GNUNET_OK != ret)
344 {
345 LOG (GNUNET_ERROR_TYPE_WARNING,
346 _("Access from `%s' denied to service `%s'\n"),
347 GNUNET_a2s (addr, addrlen),
348 sctx->service_name);
349 }
350 return ret;
351}
352
353
354/**
355 * Get the name of the file where we will
356 * write the PID of the service.
357 *
358 * @param sctx service context
359 * @return name of the file for the process ID
360 */
361static char *
362get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
363{
364 char *pif;
365
366 if (GNUNET_OK !=
367 GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
368 "PIDFILE", &pif))
369 return NULL;
370 return pif;
371}
372
373
374/**
375 * Parse an IPv4 access control list.
376 *
377 * @param ret location where to write the ACL (set)
378 * @param sctx service context to use to get the configuration
379 * @param option name of the ACL option to parse
380 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
381 * no ACL configured)
382 */
383static int
384process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
385 struct GNUNET_SERVICE_Context *sctx,
386 const char *option)
387{
388 char *opt;
389
390 if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
391 {
392 *ret = NULL;
393 return GNUNET_OK;
394 }
395 GNUNET_break (GNUNET_OK ==
396 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
397 sctx->service_name,
398 option, &opt));
399 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
400 {
401 LOG (GNUNET_ERROR_TYPE_WARNING,
402 _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
403 opt, sctx->service_name, option);
404 GNUNET_free (opt);
405 return GNUNET_SYSERR;
406 }
407 GNUNET_free (opt);
408 return GNUNET_OK;
409}
410
411
412/**
413 * Parse an IPv6 access control list.
414 *
415 * @param ret location where to write the ACL (set)
416 * @param sctx service context to use to get the configuration
417 * @param option name of the ACL option to parse
418 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
419 * no ACL configured)
420 */
421static int
422process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
423 struct GNUNET_SERVICE_Context *sctx,
424 const char *option)
425{
426 char *opt;
427
428 if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
429 {
430 *ret = NULL;
431 return GNUNET_OK;
432 }
433 GNUNET_break (GNUNET_OK ==
434 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
435 sctx->service_name,
436 option, &opt));
437 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
438 {
439 LOG (GNUNET_ERROR_TYPE_WARNING,
440 _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
441 opt, sctx->service_name, option);
442 GNUNET_free (opt);
443 return GNUNET_SYSERR;
444 }
445 GNUNET_free (opt);
446 return GNUNET_OK;
447}
448
449
450/**
451 * Add the given UNIX domain path as an address to the
452 * list (as the first entry).
453 *
454 * @param saddrs array to update
455 * @param saddrlens where to store the address length
456 * @param unixpath path to add
457 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
458 * parameter is ignore on systems other than LINUX
459 */
460static void
461add_unixpath (struct sockaddr **saddrs,
462 socklen_t *saddrlens,
463 const char *unixpath,
464 int abstract)
465{
466#ifdef AF_UNIX
467 struct sockaddr_un *un;
468
469 un = GNUNET_new (struct sockaddr_un);
470 un->sun_family = AF_UNIX;
471 strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
472#ifdef LINUX
473 if (GNUNET_YES == abstract)
474 un->sun_path[0] = '\0';
475#endif
476#if HAVE_SOCKADDR_UN_SUN_LEN
477 un->sun_len = (u_char) sizeof (struct sockaddr_un);
478#endif
479 *saddrs = (struct sockaddr *) un;
480 *saddrlens = sizeof (struct sockaddr_un);
481#else
482 /* this function should never be called
483 * unless AF_UNIX is defined! */
484 GNUNET_assert (0);
485#endif
486}
487
488
489/**
490 * Get the list of addresses that a server for the given service
491 * should bind to.
492 *
493 * @param service_name name of the service
494 * @param cfg configuration (which specifies the addresses)
495 * @param addrs set (call by reference) to an array of pointers to the
496 * addresses the server should bind to and listen on; the
497 * array will be NULL-terminated (on success)
498 * @param addr_lens set (call by reference) to an array of the lengths
499 * of the respective `struct sockaddr` struct in the @a addrs
500 * array (on success)
501 * @return number of addresses found on success,
502 * #GNUNET_SYSERR if the configuration
503 * did not specify reasonable finding information or
504 * if it specified a hostname that could not be resolved;
505 * #GNUNET_NO if the number of addresses configured is
506 * zero (in this case, `*addrs` and `*addr_lens` will be
507 * set to NULL).
508 */
509int
510GNUNET_SERVICE_get_server_addresses (const char *service_name,
511 const struct GNUNET_CONFIGURATION_Handle *cfg,
512 struct sockaddr ***addrs,
513 socklen_t ** addr_lens)
514{
515 int disablev6;
516 struct GNUNET_NETWORK_Handle *desc;
517 unsigned long long port;
518 char *unixpath;
519 struct addrinfo hints;
520 struct addrinfo *res;
521 struct addrinfo *pos;
522 struct addrinfo *next;
523 unsigned int i;
524 int resi;
525 int ret;
526 int abstract;
527 struct sockaddr **saddrs;
528 socklen_t *saddrlens;
529 char *hostname;
530
531 *addrs = NULL;
532 *addr_lens = NULL;
533 desc = NULL;
534 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
535 {
536 if (GNUNET_SYSERR ==
537 (disablev6 =
538 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
539 return GNUNET_SYSERR;
540 }
541 else
542 disablev6 = GNUNET_NO;
543
544 if (! disablev6)
545 {
546 /* probe IPv6 support */
547 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
548 if (NULL == desc)
549 {
550 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
551 (EACCES == errno))
552 {
553 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
554 return GNUNET_SYSERR;
555 }
556 LOG (GNUNET_ERROR_TYPE_INFO,
557 _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
558 service_name, STRERROR (errno));
559 disablev6 = GNUNET_YES;
560 }
561 else
562 {
563 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
564 desc = NULL;
565 }
566 }
567
568 port = 0;
569 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
570 {
571 if (GNUNET_OK !=
572 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
573 "PORT", &port))
574 {
575 LOG (GNUNET_ERROR_TYPE_ERROR,
576 _("Require valid port number for service `%s' in configuration!\n"),
577 service_name);
578 }
579 if (port > 65535)
580 {
581 LOG (GNUNET_ERROR_TYPE_ERROR,
582 _("Require valid port number for service `%s' in configuration!\n"),
583 service_name);
584 return GNUNET_SYSERR;
585 }
586 }
587
588 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
589 {
590 GNUNET_break (GNUNET_OK ==
591 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
592 "BINDTO", &hostname));
593 }
594 else
595 hostname = NULL;
596
597 unixpath = NULL;
598 abstract = GNUNET_NO;
599#ifdef AF_UNIX
600 if ((GNUNET_YES ==
601 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
602 (GNUNET_OK ==
603 GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
604 &unixpath)) &&
605 (0 < strlen (unixpath)))
606 {
607 /* probe UNIX support */
608 struct sockaddr_un s_un;
609
610 if (strlen (unixpath) >= sizeof (s_un.sun_path))
611 {
612 LOG (GNUNET_ERROR_TYPE_WARNING,
613 _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
614 (unsigned long long) sizeof (s_un.sun_path));
615 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
616 LOG (GNUNET_ERROR_TYPE_INFO,
617 _("Using `%s' instead\n"),
618 unixpath);
619 }
620#ifdef LINUX
621 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
622 "TESTING",
623 "USE_ABSTRACT_SOCKETS");
624 if (GNUNET_SYSERR == abstract)
625 abstract = GNUNET_NO;
626#endif
627 if ((GNUNET_YES != abstract)
628 && (GNUNET_OK !=
629 GNUNET_DISK_directory_create_for_file (unixpath)))
630 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
631 "mkdir",
632 unixpath);
633 }
634 if (NULL != unixpath)
635 {
636 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
637 if (NULL == desc)
638 {
639 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
640 (EACCES == errno))
641 {
642 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
643 GNUNET_free_non_null (hostname);
644 GNUNET_free (unixpath);
645 return GNUNET_SYSERR;
646 }
647 LOG (GNUNET_ERROR_TYPE_INFO,
648 _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
649 service_name,
650 STRERROR (errno));
651 GNUNET_free (unixpath);
652 unixpath = NULL;
653 }
654 else
655 {
656 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
657 desc = NULL;
658 }
659 }
660#endif
661
662 if ((0 == port) && (NULL == unixpath))
663 {
664 LOG (GNUNET_ERROR_TYPE_ERROR,
665 _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
666 service_name);
667 GNUNET_free_non_null (hostname);
668 return GNUNET_SYSERR;
669 }
670 if (0 == port)
671 {
672 saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
673 saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
674 add_unixpath (saddrs, saddrlens, unixpath, abstract);
675 GNUNET_free_non_null (unixpath);
676 GNUNET_free_non_null (hostname);
677 *addrs = saddrs;
678 *addr_lens = saddrlens;
679 return 1;
680 }
681
682 if (NULL != hostname)
683 {
684 LOG (GNUNET_ERROR_TYPE_DEBUG,
685 "Resolving `%s' since that is where `%s' will bind to.\n",
686 hostname,
687 service_name);
688 memset (&hints, 0, sizeof (struct addrinfo));
689 if (disablev6)
690 hints.ai_family = AF_INET;
691 hints.ai_protocol = IPPROTO_TCP;
692 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
693 (NULL == res))
694 {
695 LOG (GNUNET_ERROR_TYPE_ERROR,
696 _("Failed to resolve `%s': %s\n"),
697 hostname,
698 gai_strerror (ret));
699 GNUNET_free (hostname);
700 GNUNET_free_non_null (unixpath);
701 return GNUNET_SYSERR;
702 }
703 next = res;
704 i = 0;
705 while (NULL != (pos = next))
706 {
707 next = pos->ai_next;
708 if ((disablev6) && (pos->ai_family == AF_INET6))
709 continue;
710 i++;
711 }
712 if (0 == i)
713 {
714 LOG (GNUNET_ERROR_TYPE_ERROR,
715 _("Failed to find %saddress for `%s'.\n"),
716 disablev6 ? "IPv4 " : "",
717 hostname);
718 freeaddrinfo (res);
719 GNUNET_free (hostname);
720 GNUNET_free_non_null (unixpath);
721 return GNUNET_SYSERR;
722 }
723 resi = i;
724 if (NULL != unixpath)
725 resi++;
726 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
727 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
728 i = 0;
729 if (NULL != unixpath)
730 {
731 add_unixpath (saddrs, saddrlens, unixpath, abstract);
732 i++;
733 }
734 next = res;
735 while (NULL != (pos = next))
736 {
737 next = pos->ai_next;
738 if ((disablev6) && (AF_INET6 == pos->ai_family))
739 continue;
740 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
741 continue; /* not TCP */
742 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
743 continue; /* huh? */
744 LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
745 service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
746 if (AF_INET == pos->ai_family)
747 {
748 GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
749 saddrlens[i] = pos->ai_addrlen;
750 saddrs[i] = GNUNET_malloc (saddrlens[i]);
751 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
752 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
753 }
754 else
755 {
756 GNUNET_assert (AF_INET6 == pos->ai_family);
757 GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
758 saddrlens[i] = pos->ai_addrlen;
759 saddrs[i] = GNUNET_malloc (saddrlens[i]);
760 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
761 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
762 }
763 i++;
764 }
765 GNUNET_free (hostname);
766 freeaddrinfo (res);
767 resi = i;
768 }
769 else
770 {
771 /* will bind against everything, just set port */
772 if (disablev6)
773 {
774 /* V4-only */
775 resi = 1;
776 if (NULL != unixpath)
777 resi++;
778 i = 0;
779 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
780 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
781 if (NULL != unixpath)
782 {
783 add_unixpath (saddrs, saddrlens, unixpath, abstract);
784 i++;
785 }
786 saddrlens[i] = sizeof (struct sockaddr_in);
787 saddrs[i] = GNUNET_malloc (saddrlens[i]);
788#if HAVE_SOCKADDR_IN_SIN_LEN
789 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
790#endif
791 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
792 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
793 }
794 else
795 {
796 /* dual stack */
797 resi = 2;
798 if (NULL != unixpath)
799 resi++;
800 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
801 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
802 i = 0;
803 if (NULL != unixpath)
804 {
805 add_unixpath (saddrs, saddrlens, unixpath, abstract);
806 i++;
807 }
808 saddrlens[i] = sizeof (struct sockaddr_in6);
809 saddrs[i] = GNUNET_malloc (saddrlens[i]);
810#if HAVE_SOCKADDR_IN_SIN_LEN
811 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
812#endif
813 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
814 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
815 i++;
816 saddrlens[i] = sizeof (struct sockaddr_in);
817 saddrs[i] = GNUNET_malloc (saddrlens[i]);
818#if HAVE_SOCKADDR_IN_SIN_LEN
819 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
820#endif
821 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
822 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
823 }
824 }
825 GNUNET_free_non_null (unixpath);
826 *addrs = saddrs;
827 *addr_lens = saddrlens;
828 return resi;
829}
830
831
832#ifdef MINGW
833/**
834 * Read listen sockets from the parent process (ARM).
835 *
836 * @param sctx service context to initialize
837 * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
838 * and #GNUNET_SYSERR on error.
839 */
840static int
841receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
842{
843 const char *env_buf;
844 int fail;
845 uint64_t count;
846 uint64_t i;
847 HANDLE lsocks_pipe;
848
849 env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
850 if ((NULL == env_buf) || (strlen (env_buf) <= 0))
851 return GNUNET_NO;
852 /* Using W32 API directly here, because this pipe will
853 * never be used outside of this function, and it's just too much of a bother
854 * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
855 */
856 lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
857 if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
858 return GNUNET_NO;
859 fail = 1;
860 do
861 {
862 int ret;
863 int fail2;
864 DWORD rd;
865
866 ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
867 if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
868 break;
869 sctx->lsocks =
870 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
871
872 fail2 = 1;
873 for (i = 0; i < count; i++)
874 {
875 WSAPROTOCOL_INFOA pi;
876 uint64_t size;
877 SOCKET s;
878
879 ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
880 if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
881 break;
882 ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
883 if ( (0 == ret) || (sizeof (pi) != rd))
884 break;
885 s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
886 sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
887 if (NULL == sctx->lsocks[i])
888 break;
889 else if (i == count - 1)
890 fail2 = 0;
891 }
892 if (fail2)
893 break;
894 sctx->lsocks[count] = NULL;
895 fail = 0;
896 }
897 while (fail);
898
899 CloseHandle (lsocks_pipe);
900
901 if (fail)
902 {
903 LOG (GNUNET_ERROR_TYPE_ERROR,
904 _("Could not access a pre-bound socket, will try to bind myself\n"));
905 for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
906 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
907 GNUNET_free_non_null (sctx->lsocks);
908 sctx->lsocks = NULL;
909 return GNUNET_NO;
910 }
911 return GNUNET_YES;
912}
913#endif
914
915
916/**
917 * Setup addr, addrlen, idle_timeout
918 * based on configuration!
919 *
920 * Configuration may specify:
921 * - PORT (where to bind to for TCP)
922 * - UNIXPATH (where to bind to for UNIX domain sockets)
923 * - TIMEOUT (after how many ms does an inactive service timeout);
924 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
925 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
926 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
927 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
928 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
929 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
930 *
931 * @param sctx service context to initialize
932 * @return #GNUNET_OK if configuration succeeded
933 */
934static int
935setup_service (struct GNUNET_SERVICE_Context *sctx)
936{
937 struct GNUNET_TIME_Relative idleout;
938 int tolerant;
939
940#ifndef MINGW
941 const char *nfds;
942 unsigned int cnt;
943 int flags;
944#endif
945
946 if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
947 {
948 if (GNUNET_OK !=
949 GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
950 "TIMEOUT", &idleout))
951 {
952 LOG (GNUNET_ERROR_TYPE_ERROR,
953 _("Specified value for `%s' of service `%s' is invalid\n"),
954 "TIMEOUT", sctx->service_name);
955 return GNUNET_SYSERR;
956 }
957 sctx->timeout = idleout;
958 }
959 else
960 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
961
962 if (GNUNET_CONFIGURATION_have_value
963 (sctx->cfg, sctx->service_name, "TOLERANT"))
964 {
965 if (GNUNET_SYSERR ==
966 (tolerant =
967 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
968 "TOLERANT")))
969 {
970 LOG (GNUNET_ERROR_TYPE_ERROR,
971 _("Specified value for `%s' of service `%s' is invalid\n"),
972 "TOLERANT", sctx->service_name);
973 return GNUNET_SYSERR;
974 }
975 }
976 else
977 tolerant = GNUNET_NO;
978
979#ifndef MINGW
980 errno = 0;
981 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
982 (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
983 (cnt + 4 < FD_SETSIZE))
984 {
985 sctx->lsocks =
986 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
987 while (0 < cnt--)
988 {
989 flags = fcntl (3 + cnt, F_GETFD);
990 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
991 (NULL ==
992 (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
993 {
994 LOG (GNUNET_ERROR_TYPE_ERROR,
995 _
996 ("Could not access pre-bound socket %u, will try to bind myself\n"),
997 (unsigned int) 3 + cnt);
998 cnt++;
999 while (sctx->lsocks[cnt] != NULL)
1000 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
1001 GNUNET_free (sctx->lsocks);
1002 sctx->lsocks = NULL;
1003 break;
1004 }
1005 }
1006 unsetenv ("LISTEN_FDS");
1007 }
1008#else
1009 if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
1010 {
1011 receive_sockets_from_parent (sctx);
1012 putenv ("GNUNET_OS_READ_LSOCKS=");
1013 }
1014#endif
1015
1016 if ((NULL == sctx->lsocks) &&
1017 (GNUNET_SYSERR ==
1018 GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
1019 &sctx->addrs, &sctx->addrlens)))
1020 return GNUNET_SYSERR;
1021 sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1022 sctx->match_uid =
1023 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1024 "UNIX_MATCH_UID");
1025 sctx->match_gid =
1026 GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1027 "UNIX_MATCH_GID");
1028 process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
1029 process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
1030 process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
1031 process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
1032
1033 return GNUNET_OK;
1034}
1035
1036
1037/**
1038 * Get the name of the user that'll be used
1039 * to provide the service.
1040 *
1041 * @param sctx service context
1042 * @return value of the 'USERNAME' option
1043 */
1044static char *
1045get_user_name (struct GNUNET_SERVICE_Context *sctx)
1046{
1047 char *un;
1048
1049 if (GNUNET_OK !=
1050 GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
1051 "USERNAME", &un))
1052 return NULL;
1053 return un;
1054}
1055
1056
1057/**
1058 * Write PID file.
1059 *
1060 * @param sctx service context
1061 * @param pid PID to write (should be equal to 'getpid()'
1062 * @return #GNUNET_OK on success (including no work to be done)
1063 */
1064static int
1065write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
1066{
1067 FILE *pidfd;
1068 char *pif;
1069 char *user;
1070 char *rdir;
1071 int len;
1072
1073 if (NULL == (pif = get_pid_file_name (sctx)))
1074 return GNUNET_OK; /* no file desired */
1075 user = get_user_name (sctx);
1076 rdir = GNUNET_strdup (pif);
1077 len = strlen (rdir);
1078 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1079 len--;
1080 rdir[len] = '\0';
1081 if (0 != ACCESS (rdir, F_OK))
1082 {
1083 /* we get to create a directory -- and claim it
1084 * as ours! */
1085 (void) GNUNET_DISK_directory_create (rdir);
1086 if ((NULL != user) && (0 < strlen (user)))
1087 GNUNET_DISK_file_change_owner (rdir, user);
1088 }
1089 if (0 != ACCESS (rdir, W_OK | X_OK))
1090 {
1091 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1092 GNUNET_free (rdir);
1093 GNUNET_free_non_null (user);
1094 GNUNET_free (pif);
1095 return GNUNET_SYSERR;
1096 }
1097 GNUNET_free (rdir);
1098 pidfd = FOPEN (pif, "w");
1099 if (NULL == pidfd)
1100 {
1101 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1102 GNUNET_free (pif);
1103 GNUNET_free_non_null (user);
1104 return GNUNET_SYSERR;
1105 }
1106 if (0 > FPRINTF (pidfd, "%u", pid))
1107 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1108 GNUNET_break (0 == FCLOSE (pidfd));
1109 if ((NULL != user) && (0 < strlen (user)))
1110 GNUNET_DISK_file_change_owner (pif, user);
1111 GNUNET_free_non_null (user);
1112 GNUNET_free (pif);
1113 return GNUNET_OK;
1114}
1115
1116
1117/**
1118 * Task run during shutdown. Stops the server/service.
1119 *
1120 * @param cls the `struct GNUNET_SERVICE_Context`
1121 */
1122static void
1123shutdown_task (void *cls)
1124{
1125 struct GNUNET_SERVICE_Context *service = cls;
1126 struct GNUNET_SERVER_Handle *server = service->server;
1127
1128 service->shutdown_task = NULL;
1129 if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
1130 GNUNET_SERVER_stop_listening (server);
1131 else
1132 GNUNET_SERVER_destroy (server);
1133}
1134
1135
1136/**
1137 * Initial task for the service.
1138 *
1139 * @param cls service context
1140 */
1141static void
1142service_task (void *cls)
1143{
1144 struct GNUNET_SERVICE_Context *sctx = cls;
1145 unsigned int i;
1146
1147 GNUNET_RESOLVER_connect (sctx->cfg);
1148 if (NULL != sctx->lsocks)
1149 sctx->server
1150 = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
1151 sctx->timeout, sctx->require_found);
1152 else
1153 sctx->server
1154 = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1155 sctx->timeout, sctx->require_found);
1156 if (NULL == sctx->server)
1157 {
1158 if (NULL != sctx->addrs)
1159 for (i = 0; NULL != sctx->addrs[i]; i++)
1160 LOG (GNUNET_ERROR_TYPE_INFO,
1161 _("Failed to start `%s' at `%s'\n"),
1162 sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1163 sctx->ret = GNUNET_SYSERR;
1164 return;
1165 }
1166#ifndef WINDOWS
1167 if (NULL != sctx->addrs)
1168 for (i = 0; NULL != sctx->addrs[i]; i++)
1169 if ((AF_UNIX == sctx->addrs[i]->sa_family)
1170 && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
1171 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
1172 sctx->match_uid,
1173 sctx->match_gid);
1174#endif
1175
1176
1177 if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
1178 {
1179 /* install a task that will kill the server
1180 * process if the scheduler ever gets a shutdown signal */
1181 sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1182 sctx);
1183 }
1184 sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1185 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1186 i = 0;
1187 while (NULL != sctx->my_handlers[i].callback)
1188 sctx->my_handlers[i++].callback_cls = sctx;
1189 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1190 if (-1 != sctx->ready_confirm_fd)
1191 {
1192 GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
1193 GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
1194 sctx->ready_confirm_fd = -1;
1195 write_pid_file (sctx, getpid ());
1196 }
1197 if (NULL != sctx->addrs)
1198 {
1199 i = 0;
1200 while (NULL != sctx->addrs[i])
1201 {
1202 LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
1203 sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1204 i++;
1205 }
1206 }
1207 sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1208}
1209
1210
1211/**
1212 * Detach from terminal.
1213 *
1214 * @param sctx service context
1215 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1216 */
1217static int
1218detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1219{
1220#ifndef MINGW
1221 pid_t pid;
1222 int nullfd;
1223 int filedes[2];
1224
1225 if (0 != PIPE (filedes))
1226 {
1227 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1228 return GNUNET_SYSERR;
1229 }
1230 pid = fork ();
1231 if (pid < 0)
1232 {
1233 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1234 return GNUNET_SYSERR;
1235 }
1236 if (0 != pid)
1237 {
1238 /* Parent */
1239 char c;
1240
1241 GNUNET_break (0 == CLOSE (filedes[1]));
1242 c = 'X';
1243 if (1 != READ (filedes[0], &c, sizeof (char)))
1244 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1245 fflush (stdout);
1246 switch (c)
1247 {
1248 case '.':
1249 exit (0);
1250 case 'I':
1251 LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
1252 break;
1253 case 'S':
1254 LOG (GNUNET_ERROR_TYPE_INFO,
1255 _("Service process could not initialize server function\n"));
1256 break;
1257 case 'X':
1258 LOG (GNUNET_ERROR_TYPE_INFO,
1259 _("Service process failed to report status\n"));
1260 break;
1261 }
1262 exit (1); /* child reported error */
1263 }
1264 GNUNET_break (0 == CLOSE (0));
1265 GNUNET_break (0 == CLOSE (1));
1266 GNUNET_break (0 == CLOSE (filedes[0]));
1267 nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
1268 if (nullfd < 0)
1269 return GNUNET_SYSERR;
1270 /* set stdin/stdout to /dev/null */
1271 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1272 {
1273 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1274 (void) CLOSE (nullfd);
1275 return GNUNET_SYSERR;
1276 }
1277 (void) CLOSE (nullfd);
1278 /* Detach from controlling terminal */
1279 pid = setsid ();
1280 if (-1 == pid)
1281 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1282 sctx->ready_confirm_fd = filedes[1];
1283#else
1284 /* FIXME: we probably need to do something else
1285 * elsewhere in order to fork the process itself... */
1286 FreeConsole ();
1287#endif
1288 return GNUNET_OK;
1289}
1290
1291
1292/**
1293 * Set user ID.
1294 *
1295 * @param sctx service context
1296 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1297 */
1298static int
1299set_user_id (struct GNUNET_SERVICE_Context *sctx)
1300{
1301 char *user;
1302
1303 if (NULL == (user = get_user_name (sctx)))
1304 return GNUNET_OK; /* keep */
1305#ifndef MINGW
1306 struct passwd *pws;
1307
1308 errno = 0;
1309 pws = getpwnam (user);
1310 if (NULL == pws)
1311 {
1312 LOG (GNUNET_ERROR_TYPE_ERROR,
1313 _("Cannot obtain information about user `%s': %s\n"), user,
1314 errno == 0 ? _("No such user") : STRERROR (errno));
1315 GNUNET_free (user);
1316 return GNUNET_SYSERR;
1317 }
1318 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1319#if HAVE_INITGROUPS
1320 (0 != initgroups (user, pws->pw_gid)) ||
1321#endif
1322 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1323 {
1324 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1325 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1326 {
1327 LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
1328 user, STRERROR (errno));
1329 GNUNET_free (user);
1330 return GNUNET_SYSERR;
1331 }
1332 }
1333#endif
1334 GNUNET_free (user);
1335 return GNUNET_OK;
1336}
1337
1338
1339/**
1340 * Delete the PID file that was created by our parent.
1341 *
1342 * @param sctx service context
1343 */
1344static void
1345pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
1346{
1347 char *pif = get_pid_file_name (sctx);
1348
1349 if (NULL == pif)
1350 return; /* no PID file */
1351 if (0 != UNLINK (pif))
1352 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1353 GNUNET_free (pif);
1354}
1355
1356
1357/**
1358 * Run a standard GNUnet service startup sequence (initialize loggers
1359 * and configuration, parse options).
1360 *
1361 * @param argc number of command line arguments
1362 * @param argv command line arguments
1363 * @param service_name our service name
1364 * @param options service options
1365 * @param task main task of the service
1366 * @param task_cls closure for @a task
1367 * @return #GNUNET_SYSERR on error, #GNUNET_OK
1368 * if we shutdown nicely
1369 */
1370int
1371GNUNET_SERVICE_run (int argc, char *const *argv,
1372 const char *service_name,
1373 enum GNUNET_SERVICE_Options options,
1374 GNUNET_SERVICE_Main task,
1375 void *task_cls)
1376{
1377#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
1378
1379 int err;
1380 int ret;
1381 char *cfg_fn;
1382 char *opt_cfg_fn;
1383 char *loglev;
1384 char *logfile;
1385 int do_daemonize;
1386 unsigned int i;
1387 unsigned long long skew_offset;
1388 unsigned long long skew_variance;
1389 long long clock_offset;
1390 struct GNUNET_SERVICE_Context sctx;
1391 struct GNUNET_CONFIGURATION_Handle *cfg;
1392 const char *xdg;
1393
1394 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1395 GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
1396 {'d', "daemonize", NULL,
1397 gettext_noop ("do daemonize (detach from terminal)"), 0,
1398 GNUNET_GETOPT_set_one, &do_daemonize},
1399 GNUNET_GETOPT_OPTION_HELP (NULL),
1400 GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1401 GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1402 GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1403 GNUNET_GETOPT_OPTION_END
1404 };
1405 err = 1;
1406 do_daemonize = 0;
1407 logfile = NULL;
1408 loglev = NULL;
1409 opt_cfg_fn = NULL;
1410 xdg = getenv ("XDG_CONFIG_HOME");
1411 if (NULL != xdg)
1412 GNUNET_asprintf (&cfg_fn,
1413 "%s%s%s",
1414 xdg,
1415 DIR_SEPARATOR_STR,
1416 GNUNET_OS_project_data_get ()->config_file);
1417 else
1418 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1419 memset (&sctx, 0, sizeof (sctx));
1420 sctx.options = options;
1421 sctx.ready_confirm_fd = -1;
1422 sctx.ret = GNUNET_OK;
1423 sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1424 sctx.task = task;
1425 sctx.task_cls = task_cls;
1426 sctx.service_name = service_name;
1427 sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1428
1429 /* setup subsystems */
1430 ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1431 if (GNUNET_SYSERR == ret)
1432 goto shutdown;
1433 if (GNUNET_NO == ret)
1434 {
1435 err = 0;
1436 goto shutdown;
1437 }
1438 if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1439 HANDLE_ERROR;
1440 if (NULL == opt_cfg_fn)
1441 opt_cfg_fn = GNUNET_strdup (cfg_fn);
1442 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
1443 {
1444 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
1445 {
1446 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1447 _("Malformed configuration file `%s', exit ...\n"),
1448 opt_cfg_fn);
1449 goto shutdown;
1450 }
1451 }
1452 else
1453 {
1454 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1455 {
1456 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1457 _("Malformed configuration, exit ...\n"));
1458 goto shutdown;
1459 }
1460 if (0 != strcmp (opt_cfg_fn, cfg_fn))
1461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1462 _("Could not access configuration file `%s'\n"),
1463 opt_cfg_fn);
1464 }
1465 if (GNUNET_OK != setup_service (&sctx))
1466 goto shutdown;
1467 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1468 HANDLE_ERROR;
1469 if (GNUNET_OK != set_user_id (&sctx))
1470 goto shutdown;
1471 LOG (GNUNET_ERROR_TYPE_DEBUG,
1472 "Service `%s' runs with configuration from `%s'\n",
1473 service_name,
1474 opt_cfg_fn);
1475 if ((GNUNET_OK ==
1476 GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
1477 "SKEW_OFFSET", &skew_offset)) &&
1478 (GNUNET_OK ==
1479 GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
1480 "SKEW_VARIANCE", &skew_variance)))
1481 {
1482 clock_offset = skew_offset - skew_variance;
1483 GNUNET_TIME_set_offset (clock_offset);
1484 LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
1485 }
1486 /* actually run service */
1487 err = 0;
1488 GNUNET_SCHEDULER_run (&service_task, &sctx);
1489 /* shutdown */
1490 if ((1 == do_daemonize) && (NULL != sctx.server))
1491 pid_file_delete (&sctx);
1492 GNUNET_free_non_null (sctx.my_handlers);
1493
1494shutdown:
1495 if (-1 != sctx.ready_confirm_fd)
1496 {
1497 if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1498 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1499 GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
1500 }
1501#if HAVE_MALLINFO
1502 {
1503 char *counter;
1504
1505 if ( (GNUNET_YES ==
1506 GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
1507 "GAUGER_HEAP")) &&
1508 (GNUNET_OK ==
1509 GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
1510 "GAUGER_HEAP",
1511 &counter)) )
1512 {
1513 struct mallinfo mi;
1514
1515 mi = mallinfo ();
1516 GAUGER (service_name, counter, mi.usmblks, "blocks");
1517 GNUNET_free (counter);
1518 }
1519 }
1520#endif
1521 GNUNET_CONFIGURATION_destroy (cfg);
1522 i = 0;
1523 if (NULL != sctx.addrs)
1524 while (NULL != sctx.addrs[i])
1525 GNUNET_free (sctx.addrs[i++]);
1526 GNUNET_free_non_null (sctx.addrs);
1527 GNUNET_free_non_null (sctx.addrlens);
1528 GNUNET_free_non_null (logfile);
1529 GNUNET_free_non_null (loglev);
1530 GNUNET_free (cfg_fn);
1531 GNUNET_free_non_null (opt_cfg_fn);
1532 GNUNET_free_non_null (sctx.v4_denied);
1533 GNUNET_free_non_null (sctx.v6_denied);
1534 GNUNET_free_non_null (sctx.v4_allowed);
1535 GNUNET_free_non_null (sctx.v6_allowed);
1536
1537 return err ? GNUNET_SYSERR : sctx.ret;
1538}
1539
1540
1541/**
1542 * Run a service startup sequence within an existing
1543 * initialized system.
1544 *
1545 * @param service_name our service name
1546 * @param cfg configuration to use
1547 * @param options service options
1548 * @return NULL on error, service handle
1549 */
1550struct GNUNET_SERVICE_Context *
1551GNUNET_SERVICE_start (const char *service_name,
1552 const struct GNUNET_CONFIGURATION_Handle *cfg,
1553 enum GNUNET_SERVICE_Options options)
1554{
1555 int i;
1556 struct GNUNET_SERVICE_Context *sctx;
1557
1558 sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
1559 sctx->ready_confirm_fd = -1; /* no daemonizing */
1560 sctx->ret = GNUNET_OK;
1561 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1562 sctx->service_name = service_name;
1563 sctx->cfg = cfg;
1564 sctx->options = options;
1565
1566 /* setup subsystems */
1567 if (GNUNET_OK != setup_service (sctx))
1568 {
1569 GNUNET_SERVICE_stop (sctx);
1570 return NULL;
1571 }
1572 if (NULL != sctx->lsocks)
1573 sctx->server =
1574 GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
1575 sctx->timeout, sctx->require_found);
1576 else
1577 sctx->server =
1578 GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1579 sctx->timeout, sctx->require_found);
1580
1581 if (NULL == sctx->server)
1582 {
1583 GNUNET_SERVICE_stop (sctx);
1584 return NULL;
1585 }
1586#ifndef WINDOWS
1587 if (NULL != sctx->addrs)
1588 for (i = 0; NULL != sctx->addrs[i]; i++)
1589 if ((AF_UNIX == sctx->addrs[i]->sa_family)
1590 && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
1591 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
1592 sctx->match_uid,
1593 sctx->match_gid);
1594#endif
1595 sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1596 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1597 i = 0;
1598 while ((sctx->my_handlers[i].callback != NULL))
1599 sctx->my_handlers[i++].callback_cls = sctx;
1600 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1601 return sctx;
1602}
1603
1604
1605/**
1606 * Obtain the server used by a service. Note that the server must NOT
1607 * be destroyed by the caller.
1608 *
1609 * @param ctx the service context returned from the start function
1610 * @return handle to the server for this service, NULL if there is none
1611 */
1612struct GNUNET_SERVER_Handle *
1613GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
1614{
1615 return ctx->server;
1616}
1617
1618
1619/**
1620 * Get the NULL-terminated array of listen sockets for this service.
1621 *
1622 * @param ctx service context to query
1623 * @return NULL if there are no listen sockets, otherwise NULL-terminated
1624 * array of listen sockets.
1625 */
1626struct GNUNET_NETWORK_Handle *const*
1627GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
1628{
1629 return ctx->lsocks;
1630}
1631
1632
1633/**
1634 * Stop a service that was started with "GNUNET_SERVICE_start".
1635 *
1636 * @param sctx the service context returned from the start function
1637 */
1638void
1639GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
1640{
1641 unsigned int i;
1642
1643#if HAVE_MALLINFO
1644 {
1645 char *counter;
1646
1647 if ( (GNUNET_YES ==
1648 GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
1649 "GAUGER_HEAP")) &&
1650 (GNUNET_OK ==
1651 GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
1652 "GAUGER_HEAP",
1653 &counter)) )
1654 {
1655 struct mallinfo mi;
1656
1657 mi = mallinfo ();
1658 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1659 GNUNET_free (counter);
1660 }
1661 }
1662#endif
1663 if (NULL != sctx->shutdown_task)
1664 {
1665 GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1666 sctx->shutdown_task = NULL;
1667 }
1668 if (NULL != sctx->server)
1669 GNUNET_SERVER_destroy (sctx->server);
1670 GNUNET_free_non_null (sctx->my_handlers);
1671 if (NULL != sctx->addrs)
1672 {
1673 i = 0;
1674 while (NULL != sctx->addrs[i])
1675 GNUNET_free (sctx->addrs[i++]);
1676 GNUNET_free (sctx->addrs);
1677 }
1678 GNUNET_free_non_null (sctx->addrlens);
1679 GNUNET_free_non_null (sctx->v4_denied);
1680 GNUNET_free_non_null (sctx->v6_denied);
1681 GNUNET_free_non_null (sctx->v4_allowed);
1682 GNUNET_free_non_null (sctx->v6_allowed);
1683 GNUNET_free (sctx);
1684}
1685
1686
1687/* end of service.c */
diff --git a/src/transport/test_plugin_transport.c b/src/transport/test_plugin_transport.c
index be79d5499..1d92588ea 100644
--- a/src/transport/test_plugin_transport.c
+++ b/src/transport/test_plugin_transport.c
@@ -552,7 +552,7 @@ setup_plugin_environment ()
552 552
553 553
554static int 554static int
555handle_helper_message (void *cls, void *client, 555handle_helper_message (void *cls,
556 const struct GNUNET_MessageHeader *hdr) 556 const struct GNUNET_MessageHeader *hdr)
557{ 557{
558 return GNUNET_OK; 558 return GNUNET_OK;