aboutsummaryrefslogtreecommitdiff
path: root/src/util/network_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/network_socket.c')
-rw-r--r--src/util/network_socket.c678
1 files changed, 678 insertions, 0 deletions
diff --git a/src/util/network_socket.c b/src/util/network_socket.c
new file mode 100644
index 000000000..59afb7246
--- /dev/null
+++ b/src/util/network_socket.c
@@ -0,0 +1,678 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file util/sock.c
23 * @brief basic, low-level networking interface
24 * @author Nils Durner
25 */
26
27#include "platform.h"
28#include "gnunet_disk_lib.h"
29#include "disk.h"
30#include "gnunet_container_lib.h"
31
32#define DEBUG_SOCK GNUNET_NO
33
34struct GNUNET_NETWORK_Descriptor
35{
36 int fd;
37};
38
39struct GNUNET_NETWORK_FDSet
40{
41 /* socket descriptors */
42 int nsds;
43 fd_set sds;
44#ifdef WINDOWS
45 /* handles */
46 struct GNUNET_CONTAINER_Vector *handles;
47#endif
48};
49
50#ifndef FD_COPY
51#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
52#endif
53
54struct GNUNET_NETWORK_Descriptor *
55GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Descriptor *desc,
56 struct sockaddr *address,
57 socklen_t * address_len)
58{
59 struct GNUNET_NETWORK_Descriptor *ret;
60
61 ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));
62 ret->fd = accept (desc->fd, address, address_len);
63#ifdef MINGW
64 if (INVALID_SOCKET == ret->fd)
65 SetErrnoFromWinsockError (WSAGetLastError ());
66#endif
67 return ret;
68}
69
70int
71GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc,
72 const struct sockaddr *address,
73 socklen_t address_len)
74{
75 int ret;
76
77 ret = bind (desc->fd, address, address_len);
78#ifdef MINGW
79 if (SOCKET_ERROR == ret)
80 SetErrnoFromWinsockError (WSAGetLastError ());
81#endif
82 return ret;
83}
84
85/**
86 * Set if a socket should use blocking or non-blocking IO.
87 *
88 * @return GNUNET_OK on success, GNUNET_SYSERR on error
89 */
90int
91GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Descriptor *fd,
92 int doBlock)
93{
94#if MINGW
95 u_long mode;
96 mode = !doBlock;
97 if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)
98 {
99 SetErrnoFromWinsockError (WSAGetLastError ());
100 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");
101 return GNUNET_SYSERR;
102 }
103 return GNUNET_OK;
104
105#else
106 /* not MINGW */
107 int flags = fcntl (fd->fd, F_GETFL);
108 if (flags == -1)
109 {
110 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");
111 return GNUNET_SYSERR;
112 }
113 if (doBlock)
114 flags &= ~O_NONBLOCK;
115 else
116 flags |= O_NONBLOCK;
117 if (0 != fcntl (fd->fd, F_SETFL, flags))
118 {
119 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");
120 return GNUNET_SYSERR;
121 }
122 return GNUNET_OK;
123#endif
124}
125
126int
127GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Descriptor *desc)
128{
129 int ret;
130#ifdef MINGW
131 ret = closesocket (desc->fd);
132 if (SOCKET_ERROR != ret)
133 GNUNET_free (desc);
134 else
135 SetErrnoFromWinsockError (WSAGetLastError ());
136#else
137 ret = close (desc->fd);
138 if (-1 == ret)
139 {
140 GNUNET_free (desc);
141 }
142#endif
143
144 return ret;
145}
146
147int
148GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Descriptor *desc,
149 const struct sockaddr *address,
150 socklen_t address_len)
151{
152 int ret;
153
154 ret = connect (desc->fd, address, address_len);
155#ifdef MINGW
156 if (SOCKET_ERROR == ret)
157 SetErrnoFromWinsockError (WSAGetLastError ());
158#endif
159 return ret;
160}
161
162int
163GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Descriptor *desc,
164 int level, int optname, void *optval,
165 socklen_t * optlen)
166{
167 int ret;
168
169 ret = getsockopt (desc->fd, level, optname, optval, optlen);
170#ifdef MINGW
171 if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)
172 *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));
173 else if (SOCKET_ERROR == ret)
174 SetErrnoFromWinsockError (WSAGetLastError ());
175#endif
176 return ret;
177}
178
179int
180GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Descriptor *desc,
181 int backlog)
182{
183 int ret;
184
185 ret = listen (desc->fd, backlog);
186#ifdef MINGW
187 if (SOCKET_ERROR == ret)
188 SetErrnoFromWinsockError (WSAGetLastError ());
189#endif
190
191 return ret;
192}
193
194ssize_t
195GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Descriptor * desc,
196 void *buffer, size_t length, int flags)
197{
198 int ret;
199
200 ret = recv (desc->fd, buffer, length, flags);
201#ifdef MINGW
202 if (SOCKET_ERROR == ret)
203 SetErrnoFromWinsockError (WSAGetLastError ());
204#endif
205
206 return ret;
207}
208
209ssize_t
210GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Descriptor * desc,
211 const void *buffer, size_t length, int flags)
212{
213 int ret;
214
215 ret = send (desc->fd, buffer, length, flags);
216#ifdef MINGW
217 if (SOCKET_ERROR == ret)
218 SetErrnoFromWinsockError (WSAGetLastError ());
219#endif
220
221 return ret;
222}
223
224ssize_t
225GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Descriptor * desc,
226 const void *message, size_t length, int flags,
227 const struct sockaddr * dest_addr,
228 socklen_t dest_len)
229{
230 int ret;
231
232 ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);
233#ifdef MINGW
234 if (SOCKET_ERROR == ret)
235 SetErrnoFromWinsockError (WSAGetLastError ());
236#endif
237
238 return ret;
239}
240
241int
242GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Descriptor *fd,
243 int level, int option_name,
244 const void *option_value,
245 socklen_t option_len)
246{
247 int ret;
248
249 ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
250#ifdef MINGW
251 if (SOCKET_ERROR == ret)
252 SetErrnoFromWinsockError (WSAGetLastError ());
253#endif
254
255 return ret;
256}
257
258struct GNUNET_NETWORK_Descriptor *
259GNUNET_NETWORK_socket_socket (int domain, int type, int protocol)
260{
261 struct GNUNET_NETWORK_Descriptor *ret;
262
263 ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));
264 ret->fd = socket (domain, type, protocol);
265#ifdef MINGW
266 if (INVALID_SOCKET == ret->fd)
267 SetErrnoFromWinsockError (WSAGetLastError ());
268#endif
269
270 if (ret->fd < 0)
271 {
272 GNUNET_free (ret);
273 ret = NULL;
274 }
275
276 return ret;
277}
278
279int
280GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Descriptor *desc,
281 int how)
282{
283 int ret;
284
285 ret = shutdown (desc->fd, how);
286#ifdef MINGW
287 if (ret != 0)
288 SetErrnoFromWinsockError (WSAGetLastError ());
289#endif
290
291 return ret;
292}
293
294int
295GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Descriptor
296 *desc)
297{
298#ifdef MINGW
299 errno = ENOSYS;
300 return GNUNET_SYSERR;
301#else
302 return fcntl (desc->fd, F_SETFD,
303 fcntl (desc->fd,
304 F_GETFD) | FD_CLOEXEC) ==
305 0 ? GNUNET_OK : GNUNET_SYSERR;
306#endif
307}
308
309void
310GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
311{
312 FD_ZERO (&fds->sds);
313 fds->nsds = 0;
314#ifdef MINGW
315 if (fds->handles)
316 GNUNET_CONTAINER_vector_destroy (fds->handles);
317 fds->handles = GNUNET_CONTAINER_vector_create (2);
318#endif
319}
320
321void
322GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
323 const struct GNUNET_NETWORK_Descriptor *desc)
324{
325 FD_SET (desc->fd, &fds->sds);
326
327 if (desc->fd + 1 > fds->nsds)
328 fds->nsds = desc->fd + 1;
329}
330
331int
332GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
333 const struct GNUNET_NETWORK_Descriptor *desc)
334{
335 return FD_ISSET (desc->fd, &fds->sds);
336}
337
338void
339GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
340 const struct GNUNET_NETWORK_FDSet *src)
341{
342 int nfds;
343
344 for (nfds = src->nsds; nfds > 0; nfds--)
345 if (FD_ISSET (nfds, &src->sds))
346 {
347 FD_SET (nfds, &dst->sds);
348 if (nfds + 1 > dst->nsds)
349 dst->nsds = nfds + 1;
350 }
351}
352
353void
354GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
355 const struct GNUNET_NETWORK_FDSet *from)
356{
357 FD_COPY (&from->sds, &to->sds);
358 to->nsds = from->nsds;
359#ifdef MINGW
360 void *obj;
361
362 if (to->handles)
363 GNUNET_CONTAINER_vector_destroy (to->handles);
364 to->handles = GNUNET_CONTAINER_vector_create (2);
365 for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL;
366 obj = GNUNET_CONTAINER_vector_get_next (from->handles))
367 {
368 GNUNET_CONTAINER_vector_insert_last (to->handles, obj);
369 }
370#endif
371}
372
373void
374GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
375 const fd_set * from, int nfds)
376{
377 FD_COPY (from, &to->sds);
378 to->nsds = nfds;
379}
380
381void
382GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
383 const struct GNUNET_DISK_FileHandle *h)
384{
385#ifdef MINGW
386 HANDLE hw;
387
388 GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE));
389 GNUNET_CONTAINER_vector_insert_last (fds->handles, h);
390#else
391 int fd;
392
393 GNUNET_internal_disk_file_handle (h, &fd, sizeof (int));
394 FD_SET (fd, &fds->sds);
395 if (fd + 1 > fds->nsds)
396 fds->nsds = fd + 1;
397#endif
398}
399
400int
401GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
402 const struct GNUNET_DISK_FileHandle *h)
403{
404#ifdef MINGW
405 return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) !=
406 (unsigned int) -1;
407#else
408 return FD_ISSET (h->fd, &fds->sds);
409#endif
410}
411
412int
413GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
414 const struct GNUNET_NETWORK_FDSet *fds2)
415{
416 int nfds;
417
418 nfds = fds1->nsds;
419 if (nfds < fds2->nsds)
420 nfds = fds2->nsds;
421
422 for (; nfds >= 0; nfds--)
423 if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
424 return GNUNET_YES;
425
426 return GNUNET_NO;
427}
428
429struct GNUNET_NETWORK_FDSet *
430GNUNET_NETWORK_fdset_create ()
431{
432 struct GNUNET_NETWORK_FDSet *fds;
433
434 fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));
435#ifdef MINGW
436 fds->handles = NULL;
437#endif
438 GNUNET_NETWORK_fdset_zero (fds);
439
440 return fds;
441}
442
443void
444GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
445{
446#ifdef MINGW
447 GNUNET_CONTAINER_vector_destroy (fds->handles);
448#endif
449 GNUNET_free (fds);
450}
451
452int
453GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
454 struct GNUNET_NETWORK_FDSet *wfds,
455 struct GNUNET_NETWORK_FDSet *efds,
456 const struct GNUNET_TIME_Relative timeout)
457{
458 int nfds;
459
460 nfds = 0;
461
462 if (rfds)
463 nfds = rfds->nsds;
464 if (wfds && wfds->nsds > nfds)
465 nfds = wfds->nsds;
466 if (efds && efds->nsds > nfds)
467 nfds = efds->nsds;
468
469#ifndef MINGW
470 struct timeval tv;
471
472 tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;
473 tv.tv_usec = (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value))
474 / GNUNET_TIME_UNIT_MILLISECONDS.value;
475
476 return select (nfds + 1, rfds ? &rfds->sds : NULL, wfds ? &wfds->sds : NULL,
477 efds ? &efds->sds : NULL, timeout.value
478 == GNUNET_TIME_UNIT_FOREVER_REL.value ? NULL : &tv);
479#else
480 DWORD limit;
481 fd_set sock_read, sock_write, sock_except;
482 fd_set aread, awrite, aexcept;
483 int i;
484 struct timeval tvslice;
485 int retcode;
486 DWORD ms_total;
487
488#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set))
489
490 /* calculate how long we need to wait in milliseconds */
491 if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
492 ms_total = INFINITE;
493 else
494 ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;
495
496 /* select() may be used as a portable way to sleep */
497 if (!(rfds || wfds || efds))
498 {
499 Sleep (ms_total);
500
501 return 0;
502 }
503
504 if (rfds)
505 sock_read = rfds->sds;
506 else
507 FD_ZERO(&sock_read);
508
509 if (wfds)
510 sock_write = wfds->sds;
511 else
512 FD_ZERO(&sock_write);
513
514 if (efds)
515 sock_except = efds->sds;
516 else
517 FD_ZERO(&sock_except);
518
519 /*
520 if (rfds)
521 FD_COPY (&rfds->sds, &sock_read);
522 else
523 FD_ZERO(&sock_read);
524
525 if (wfds)
526 FD_COPY (&wfds->sds, &sock_write);
527 else
528 FD_ZERO(&sock_write);
529
530 if (efds)
531 FD_COPY (&efds->sds, &sock_except);
532 else
533 FD_ZERO(&sock_except);
534*/
535
536 /* multiplex between winsock select() and waiting on the handles */
537
538 FD_ZERO (&aread);
539 FD_ZERO (&awrite);
540 FD_ZERO (&aexcept);
541
542 limit = GetTickCount () + ms_total;
543 do
544 {
545 retcode = 0;
546
547 if (nfds > 0)
548 {
549 /* overwrite the zero'd sets here; the select call
550 * will clear those that are not active */
551
552 FD_COPY (&sock_read, &aread);
553 FD_COPY (&sock_write, &awrite);
554 FD_COPY (&sock_except, &aexcept);
555
556 tvslice.tv_sec = 0;
557 tvslice.tv_usec = 100000;
558
559 if ((retcode =
560 select (nfds + 1, &aread, &awrite, &aexcept,
561 &tvslice)) == SOCKET_ERROR)
562 {
563 SetErrnoFromWinsockError (WSAGetLastError ());
564 if (errno == ENOTSOCK)
565 errno = EBADF;
566
567#if DEBUG_SOCK
568 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
569#endif
570
571 goto select_loop_end;
572 }
573 }
574
575 /* Poll read pipes */
576 if (rfds)
577 for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--)
578 {
579 DWORD dwBytes;
580
581 if (!PeekNamedPipe
582 (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,
583 NULL, &dwBytes, NULL))
584 {
585 GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);
586
587 retcode = -1;
588 SetErrnoFromWinError (GetLastError ());
589#if DEBUG_SOCK
590 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");
591#endif
592 goto select_loop_end;
593 }
594 else if (dwBytes)
595 {
596 retcode++;
597 }
598 else
599 GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);
600 }
601
602 /* Poll for faulty pipes */
603 if (efds)
604 for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--)
605 {
606 DWORD dwBytes;
607
608 if (PeekNamedPipe
609 (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,
610 NULL, &dwBytes, NULL))
611 {
612 GNUNET_CONTAINER_vector_remove_at (efds->handles, i);
613
614 retcode++;
615 }
616 }
617
618 /* FIXME */
619 if (wfds)
620 GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0);
621
622 /* Check for closed sockets */
623 for (i = 0; i < nfds; i++)
624 {
625 if (SAFE_FD_ISSET (i, &sock_read))
626 {
627 struct sockaddr addr;
628 int len;
629
630 if (getpeername (i, &addr, &len) == SOCKET_ERROR)
631 {
632 int err, len;
633
634 len = sizeof (err);
635 if (getsockopt
636 (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0
637 && err == WSAENOTCONN)
638 {
639 if (!SAFE_FD_ISSET (i, &aread))
640 {
641 FD_SET (i, &aread);
642 retcode++;
643 }
644 }
645 }
646 }
647 }
648
649 select_loop_end:;
650 }
651 while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
652
653 if (retcode != -1)
654 {
655 if (rfds)
656 {
657 GNUNET_NETWORK_fdset_zero (rfds);
658 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
659 }
660
661 if (wfds)
662 {
663 GNUNET_NETWORK_fdset_zero (wfds);
664 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
665 }
666
667 if (efds)
668 {
669 GNUNET_NETWORK_fdset_zero (efds);
670 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
671 }
672 }
673
674 return retcode;
675#endif
676}
677
678/* end of sock.c */