initial code for the socket
[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                 close(ctx->fd);
72                 ctx->fd = -1;
73                 return (psmb_result_t){PSMB_ERROR};
74         }
75         if (setsockopt(ctx->fd, IPPROTO_IPV6, IPV6_PKTINFO,
76                         &on, sizeof(on)) < 0) {
77                 close(ctx->fd);
78                 ctx->fd = -1;
79                 return (psmb_result_t){PSMB_ERROR};
80         }
81         if (bind(ctx->fd, (struct sockaddr *)&addr,
82                         sizeof(struct sockaddr)) == -1) {
83                 close(ctx->fd);
84                 ctx->fd = -1;
85                 return (psmb_result_t){PSMB_ERROR};
86         }
87         return (psmb_result_t){PSMB_OK};
88 }