]> www.average.org Git - psmb.git/blob - src/psmb_socket.c
660a563c375ac8ab5ffcc439ab2b631b09088b6d
[psmb.git] / src / psmb_socket.c
1 #include <stdlib.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <arpa/inet.h>
5 #include <netinet/in.h>
6 #include <sys/socket.h>
7
8 #include <psmb.h>
9 #include "psmb_priv.h"
10
11 psmb_ctx_t *psmb_new(void)
12 {
13         return psmb_new_mm(malloc, free, realloc);
14 }
15
16 psmb_ctx_t *psmb_new_mm(void *(*malloc)(size_t size),
17                         void (*free)(void *ptr),
18                         void *(*realloc)(void *ptr, size_t size))
19 {
20         psmb_ctx_t *ctx = (*malloc)(sizeof(psmb_ctx_t));
21         if (!ctx)
22                 return NULL;
23         *ctx = (psmb_ctx_t){
24                 .fd = -1,
25                 .malloc = malloc, .free = free, .realloc = realloc,
26                 .pmtu = PSMB_DEFAULT_PMTU, .port = PSMB_DEFAULT_PORT};
27         return ctx;
28 }
29
30 psmb_result_t psmb_set_pmtu(psmb_ctx_t *ctx, unsigned int pmtu)
31 {
32         if (ctx->fd == -1) {
33                 ctx->pmtu = pmtu;
34                 return (psmb_result_t){PSMB_OK};
35         } else {
36                 errno = EBUSY;
37                 return (psmb_result_t){PSMB_ERROR};
38         }
39 }
40
41 psmb_result_t psmb_set_port(psmb_ctx_t *ctx, unsigned short port)
42 {
43         if (ctx->fd == -1) {
44                 ctx->port = port;
45                 return (psmb_result_t){PSMB_OK};
46         } else {
47                 errno = EBUSY;
48                 return (psmb_result_t){PSMB_ERROR};
49         }
50 }
51
52 psmb_result_t psmb_open(psmb_ctx_t *ctx)
53 {
54         unsigned long on = 1;
55         struct sockaddr_in6 addr = (struct sockaddr_in6){
56                 .sin6_family = AF_INET6,
57                 .sin6_addr = in6addr_any,
58                 .sin6_port = htons(ctx->port)
59         };
60
61         if (ctx->fd != -1) {
62                 errno = EBUSY;
63                 return (psmb_result_t){PSMB_ERROR};
64         }
65         ctx->fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
66         if (ctx->fd == -1) {
67                 return (psmb_result_t){PSMB_ERROR};
68         }
69         if (setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR,
70                         &on, sizeof(on)) < 0) {
71                 int sverr = errno;
72                 close(ctx->fd);
73                 ctx->fd = -1;
74                 errno = sverr;
75                 return (psmb_result_t){PSMB_ERROR};
76         }
77         if (setsockopt(ctx->fd, IPPROTO_IPV6, IPV6_PKTINFO,
78                         &on, sizeof(on)) < 0) {
79                 int sverr = errno;
80                 close(ctx->fd);
81                 ctx->fd = -1;
82                 errno = sverr;
83                 return (psmb_result_t){PSMB_ERROR};
84         }
85         if (bind(ctx->fd, (struct sockaddr *)&addr,
86                         sizeof(struct sockaddr)) == -1) {
87                 int sverr = errno;
88                 close(ctx->fd);
89                 ctx->fd = -1;
90                 errno = sverr;
91                 return (psmb_result_t){PSMB_ERROR};
92         }
93         return (psmb_result_t){PSMB_OK};
94 }