comparison nsock.c @ 168:a89ff602b30f

Initial import of nsock.c nsock.h
author David Demelier <markand@malikania.fr>
date Thu, 22 Aug 2013 17:40:54 +0200
parents
children 29531c2f8213
comparison
equal deleted inserted replaced
167:1167cd06b475 168:a89ff602b30f
1 /*
2 * nsock.c -- portable BSD sockets wrapper
3 *
4 * Copyright (c) 2013 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 # include <stdio.h>
20 # include <stdlib.h>
21
22 #if !defined(_WIN32)
23 # include <errno.h>
24 # include <string.h>
25 #endif
26
27 #include "nsock.h"
28
29 #define TAILQ_HEAD(name, type) \
30 struct name { \
31 struct type *tqh_first; /* first element */ \
32 struct type **tqh_last; /* addr of last next element */ \
33 size_t noclients; \
34 }
35
36 #define TAILQ_ENTRY(type) \
37 struct { \
38 struct type *tqe_next; /* next element */ \
39 struct type **tqe_prev; /* address of previous next element */ \
40 }
41
42 #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
43
44 #define TAILQ_FIRST(head) ((head)->tqh_first)
45
46 #define TAILQ_FOREACH(var, head, field) \
47 for ((var) = TAILQ_FIRST((head)); \
48 (var); \
49 (var) = TAILQ_NEXT((var), field))
50
51 #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
52 for ((var) = TAILQ_FIRST((head)); \
53 (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
54 (var) = (tvar))
55
56 #define TAILQ_INIT(head) do { \
57 TAILQ_FIRST((head)) = NULL; \
58 (head)->tqh_last = &TAILQ_FIRST((head)); \
59 } while (0)
60
61 #define TAILQ_INSERT_HEAD(head, elm, field) do { \
62 if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
63 TAILQ_FIRST((head))->field.tqe_prev = \
64 &TAILQ_NEXT((elm), field); \
65 else \
66 (head)->tqh_last = &TAILQ_NEXT((elm), field); \
67 TAILQ_FIRST((head)) = (elm); \
68 (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
69 (head)->noclients ++; \
70 } while (0)
71
72 #define TAILQ_INSERT_TAIL(head, elm, field) do { \
73 TAILQ_NEXT((elm), field) = NULL; \
74 (elm)->field.tqe_prev = (head)->tqh_last; \
75 *(head)->tqh_last = (elm); \
76 (head)->tqh_last = &TAILQ_NEXT((elm), field); \
77 (head)->noclients ++; \
78 } while (0)
79
80 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
81
82 #define TAILQ_REMOVE(head, elm, field) do { \
83 if ((TAILQ_NEXT((elm), field)) != NULL) \
84 TAILQ_NEXT((elm), field)->field.tqe_prev = \
85 (elm)->field.tqe_prev; \
86 else { \
87 (head)->tqh_last = (elm)->field.tqe_prev; \
88 } \
89 *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
90 (head)->noclients --; \
91 } while (0)
92
93 struct nsock {
94 nsock_socket_t fd;
95 char error[128];
96 };
97
98 struct nsock_ep {
99 struct sockaddr_storage addr;
100 socklen_t addrlen;
101 char error[128];
102 };
103
104 struct nsock_listener {
105 const struct nsock *sock;
106 char error[128];
107 TAILQ_HEAD(, nsock_clt) head;
108 };
109
110 struct nsock_clt {
111 const struct nsock *sock;
112 TAILQ_ENTRY(nsock_clt) link;
113 };
114
115 /* --------------------------------------------------------
116 * Private helpers
117 * -------------------------------------------------------- */
118
119 static void
120 nsock_set_error(char *buffer, size_t bufsize)
121 {
122 memset(buffer, 0, bufsize);
123
124 #if defined(_WIN32)
125 LPSTR str;
126
127 FormatMessageA(
128 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
129 NULL,
130 WSAGetLastError(),
131 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
132 (LPSTR)&str, 0, NULL);
133
134 if (str) {
135 strncpy(buffer, str, bufsize);
136 LocalFree(str);
137 }
138 #else
139 strncpy(buffer, strerror(errno), bufsize);
140 #endif
141 }
142
143 static void
144 nsock_set_errno(char *buffer, size_t bufsize, int no)
145 {
146 memset(buffer, 0, bufsize);
147 strncpy(buffer, strerror(no), bufsize - 1);
148 }
149
150 static struct nsock_clt *
151 nsock_clt_new(const struct nsock *ns)
152 {
153 struct nsock_clt *clt;
154
155 if ((clt = malloc(sizeof (struct nsock_clt))) == NULL)
156 return NULL;
157
158 clt->sock = ns;
159
160 return clt;
161 }
162
163 /* --------------------------------------------------------
164 * Sockets functions
165 * -------------------------------------------------------- */
166
167 void
168 nsock_init(void)
169 {
170 #if defined(_WIN32)
171 WSADATA wsa;
172 WSAStartup(MAKEWORD(2, 2), &wsa);
173 #endif
174 }
175
176 struct nsock *
177 nsock_create(int domain, int type, int protocol)
178 {
179 struct nsock *ns;
180
181 if ((ns = malloc(sizeof (struct nsock))) == NULL)
182 return NULL;
183
184 ns->fd = socket(domain, type, protocol);
185
186 if (ns->fd == INVALID_SOCKET)
187 nsock_set_error(ns->error, sizeof (ns->error));
188
189 return ns;
190 }
191
192 const char *
193 nsock_error(struct nsock *ns)
194 {
195 if (ns == NULL)
196 return strerror(ENOMEM);
197
198 return ns->error;
199 }
200
201 int
202 nsock_bind(struct nsock *ns, const struct nsock_ep *ep)
203 {
204 int ret;
205
206 ret = bind(ns->fd, (const struct sockaddr *)&ep->addr, ep->addrlen);
207
208 if (ret == SOCKET_ERROR)
209 nsock_set_error(ns->error, sizeof (ns->error));
210
211 return ret == SOCKET_ERROR ? -1 : 0;
212 }
213
214 int
215 nsock_listen(struct nsock *ns, int max)
216 {
217 int ret;
218
219 ret = listen(ns->fd, max);
220
221 if (ret == SOCKET_ERROR)
222 nsock_set_error(ns->error, sizeof (ns->error));
223
224 return ret == SOCKET_ERROR ? -1 : 0;
225 }
226
227 int
228 nsock_accept(struct nsock *ns, struct nsock **client, struct nsock_ep **clientinfo)
229 {
230 struct sockaddr_storage *st = NULL;
231 socklen_t *len = NULL;
232 int ret;
233
234 if ((*client = malloc(sizeof (struct nsock))) == NULL) {
235 nsock_set_errno(ns->error, sizeof (ns->error), ENOMEM);
236 return -1;
237 }
238
239 if (clientinfo != NULL) {
240 if ((*clientinfo = malloc(sizeof (struct nsock_ep))) == NULL) {
241 free(client);
242 nsock_set_errno(ns->error, sizeof (ns->error), ENOMEM);
243 return -1;
244 }
245
246 st = &(*clientinfo)->addr;
247 len = &(*clientinfo)->addrlen;
248
249 /* Set the addrlen to sockaddr_storage first */
250 *len = sizeof (struct sockaddr_storage);
251 }
252
253 /* Prepare client */
254 memset((*client)->error, 0, sizeof ((*client)->error));
255 (*client)->fd = accept(ns->fd, (struct sockaddr *)st, len);
256
257 if ((*client)->fd == INVALID_SOCKET) {
258 nsock_set_error(ns->error, sizeof (ns->error));
259
260 /* free clients and set to NULL so user will not use it */
261 free(*client);
262 *client = NULL;
263
264 if (clientinfo != NULL) {
265 free(*clientinfo);
266 *clientinfo = NULL;
267 }
268
269 ret = -1;
270 } else
271 ret = 0;
272
273 return ret;
274 }
275
276 int
277 nsock_connect(struct nsock *ns, const struct nsock_ep *ep)
278 {
279 int ret;
280
281 ret = connect(ns->fd, (const struct sockaddr *)&ep->addr, ep->addrlen);
282
283 if (ret == SOCKET_ERROR)
284 nsock_set_error(ns->error, sizeof (ns->error));
285
286 return ret == SOCKET_ERROR ? -1 : 0;
287 }
288
289 int
290 nsock_set(struct nsock *ns, int level, int name, const void *arg, unsigned arglen)
291 {
292 int ret;
293
294 ret = setsockopt(ns->fd, level, name, (nsock_carg_t)arg, arglen);
295
296 if (ret == SOCKET_ERROR)
297 nsock_set_error(ns->error, sizeof (ns->error));
298
299 return ret == SOCKET_ERROR ? -1 : 0;
300 }
301
302 long
303 nsock_recv(struct nsock *ns, void *data, size_t datasz, int flags)
304 {
305 long nbread;
306
307 nbread = recv(ns->fd, data, datasz, flags);
308
309 if (nbread == -1)
310 nsock_set_error(ns->error, sizeof (ns->error));
311
312 return nbread;
313 }
314
315 long
316 nsock_recvfrom(struct nsock *ns, struct nsock_ep *ep, void *data, size_t datasz, int flags)
317 {
318 struct sockaddr_storage *st = NULL;
319 socklen_t *len = NULL;
320 long nbread;
321
322 if (ep != NULL) {
323 st = &ep->addr;
324 len = &ep->addrlen;
325
326 /* Set the addrlen to sockaddr_storage first */
327 *len = sizeof (struct sockaddr_storage);
328 }
329
330 nbread = recvfrom(ns->fd, data, datasz, flags,
331 (struct sockaddr *)st, len);
332
333 if (nbread == SOCKET_ERROR)
334 nsock_set_error(ns->error, sizeof (ns->error));
335
336 return nbread;
337 }
338
339 long
340 nsock_send(struct nsock *ns, const void *data, size_t datasz, int flags)
341 {
342 long nbsent;
343
344 nbsent = send(ns->fd, data, datasz, flags);
345
346 if (nbsent == -1)
347 nsock_set_error(ns->error, sizeof (ns->error));
348
349 return nbsent;
350 }
351
352 long
353 nsock_sendto(struct nsock *ns, const struct nsock_ep *ep, const void *data, size_t datasz, int flags)
354 {
355 long nbsent;
356
357 nbsent = sendto(ns->fd, data, datasz, flags,
358 (const struct sockaddr *)&ep->addr, ep->addrlen);
359
360 if (nbsent == SOCKET_ERROR)
361 nsock_set_error(ns->error, sizeof (ns->error));
362
363 return nbsent;
364 }
365
366 void
367 nsock_close(struct nsock *ns)
368 {
369 closesocket(ns->fd);
370 }
371
372 void
373 nsock_free(struct nsock *ns)
374 {
375 free(ns);
376 }
377
378 void
379 nsock_finish(void)
380 {
381 #if defined(_WIN32)
382 WSACleanup();
383 #endif
384 }
385
386 /* --------------------------------------------------------
387 * End point functions
388 * -------------------------------------------------------- */
389
390 struct nsock_ep *
391 nsock_ep_create(void)
392 {
393 struct nsock_ep *ep;
394
395 if ((ep = calloc(1, sizeof (struct nsock_ep))) == NULL)
396 return NULL;
397
398 return ep;
399 }
400
401 const char *
402 nsock_ep_error(struct nsock_ep *ep)
403 {
404 if (ep == NULL)
405 return strerror(ENOMEM);
406
407 return ep->error;
408 }
409
410 int
411 nsock_ep_bind_ip(struct nsock_ep *ep, const char *iface, unsigned port, int family)
412 {
413 if (family == AF_INET6) {
414 struct sockaddr_in6 *ptr = (struct sockaddr_in6 *)&ep->addr;
415
416 memset(ptr, 0, sizeof (struct sockaddr_in6));
417 ptr->sin6_family = AF_INET6;
418 ptr->sin6_port = htons(port);
419
420 if (iface == NULL || strcmp(iface, "*") == 0)
421 ptr->sin6_addr = in6addr_any;
422 else if (inet_pton(AF_INET6, iface, &ptr->sin6_addr) <= 0) {
423 nsock_set_error(ep->error, sizeof (ep->error));
424 return -1;
425 }
426
427 ep->addrlen = sizeof (struct sockaddr_in6);
428 } else {
429 struct sockaddr_in *ptr = (struct sockaddr_in *)&ep->addr;
430
431 memset(ptr, 0, sizeof (struct sockaddr_in));
432 ptr->sin_family = AF_INET;
433 ptr->sin_port = htons(port);
434
435 if (iface == NULL || strcmp(iface, "*") == 0)
436 ptr->sin_addr.s_addr = INADDR_ANY;
437 else if (inet_pton(AF_INET, iface, &ptr->sin_addr) <= 0) {
438 nsock_set_error(ep->error, sizeof (ep->error));
439 return -1;
440 }
441
442 ep->addrlen = sizeof (struct sockaddr_in);
443 }
444
445 return 0;
446 }
447
448 int
449 nsock_ep_connect_ip(struct nsock_ep *ep, const char *host, unsigned port, int family)
450 {
451 struct addrinfo hints, *res;
452 char portstr[32];
453 int error;
454
455 memset(&hints, 0, sizeof (hints));
456 hints.ai_family = family;
457 hints.ai_socktype = SOCK_STREAM;
458
459 memset(portstr, 0, sizeof (portstr));
460 sprintf(portstr, "%u", port);
461
462 error = getaddrinfo(host, portstr, &hints, &res);
463 if (error) {
464 memset(ep->error, 0, sizeof (ep->error));
465 strncpy(ep->error, gai_strerrorA(error), sizeof (ep->error) - 1);
466 return -1;
467 }
468
469 memcpy(&ep->addr, res->ai_addr, res->ai_addrlen);
470 ep->addrlen = res->ai_addrlen;
471
472 freeaddrinfo(res);
473
474 return 0;
475 }
476
477 #if !defined(_WIN32)
478
479 void
480 nsock_ep_unix(struct nsock_ep *ep, const char *path)
481 {
482 struct sockaddr_un *ptr= (struct sockaddr_un *)&ep->addr;
483
484 /* Path */
485 memset(ptr, 0, sizeof (struct sockaddr_un));
486 strncpy(ptr->sun_path, path, sizeof (ptr->sun_path) - 1);
487 ptr->sun_family = AF_UNIX;
488
489 /* Len is computed with SUN_LEN */
490 ep->addrlen = SUN_LEN(ptr);
491 }
492
493 #endif
494
495 struct sockaddr *
496 nsock_ep_getaddr(struct nsock_ep *ep)
497 {
498 return (struct sockaddr *)&ep->addr;
499 }
500
501 socklen_t
502 nsock_ep_getaddrlen(const struct nsock_ep *ep)
503 {
504 return ep->addrlen;
505 }
506
507 void
508 nsock_ep_free(struct nsock_ep *ep)
509 {
510 free(ep);
511 }
512
513 /* --------------------------------------------------------
514 * listener functions
515 * -------------------------------------------------------- */
516
517 struct nsock_listener *
518 nsock_lst_create(const struct nsock *ns)
519 {
520 struct nsock_listener *ls;
521
522 if ((ls = malloc(sizeof (struct nsock_listener))) == NULL)
523 return NULL;
524
525 ls->sock = ns;
526 TAILQ_INIT(&ls->head);
527
528 return ls;
529 }
530
531 const char *
532 nsock_lst_error(struct nsock_listener *ls)
533 {
534 if (ls == NULL)
535 return strerror(ENOMEM);
536
537 return ls->error;
538 }
539
540 int
541 nsock_lst_push(struct nsock_listener *ls, struct nsock *ns)
542 {
543 struct nsock_clt *clt;
544
545 if ((clt = nsock_clt_new(ns)) == NULL)
546 return -1;
547
548 TAILQ_INSERT_HEAD(&ls->head, clt, link);
549
550 return 0;
551 }
552
553 int
554 nsock_lst_append(struct nsock_listener *ls, struct nsock *ns)
555 {
556 struct nsock_clt *clt;
557
558 if ((clt = nsock_clt_new(ns)) == NULL)
559 return -1;
560
561 TAILQ_INSERT_TAIL(&ls->head, clt, link);
562
563 return 0;
564 }
565
566 size_t
567 nsock_lst_count(const struct nsock_listener *ls)
568 {
569 return ls->head.noclients;
570 }
571
572 void
573 nsock_lst_remove(struct nsock_listener *ls, const struct nsock *ns)
574 {
575 struct nsock_clt *clt, *tmp;
576
577 TAILQ_FOREACH_SAFE(clt, &ls->head, link, tmp) {
578 if (clt->sock == ns) {
579 TAILQ_REMOVE(&ls->head, clt, link);
580 free(clt);
581 break;
582 }
583 }
584 }
585
586 struct nsock *
587 nsock_lst_select(struct nsock_listener *ls, long sec, long usec)
588 {
589 fd_set fds;
590 struct timeval maxwait, *towait;
591 int error;
592 int fdmax;
593 struct nsock_clt *clt;
594
595 fdmax = TAILQ_FIRST(&ls->head)->sock->fd;
596
597 FD_ZERO(&fds);
598 TAILQ_FOREACH(clt, &ls->head, link) {
599 FD_SET(clt->sock->fd, &fds);
600 if ((int)clt->sock->fd > fdmax)
601 fdmax = clt->sock->fd;
602 }
603
604 maxwait.tv_sec = sec;
605 maxwait.tv_usec = usec;
606
607 // Set to NULL for infinite timeout.
608 towait = (sec == 0 && usec == 0) ? NULL : &maxwait;
609 error = select(fdmax + 1, &fds, NULL, NULL, towait);
610
611 TAILQ_FOREACH(clt, &ls->head, link)
612 if (FD_ISSET(clt->sock->fd, &fds))
613 return (struct nsock *)clt->sock;
614
615 return NULL;
616 }
617
618 void
619 nsock_lst_free(struct nsock_listener *ls)
620 {
621 struct nsock_clt *clt, *tmp;
622
623 TAILQ_FOREACH_SAFE(clt, &ls->head, link, tmp)
624 free(clt);
625
626 free(ls);
627 }