1#include <dtls.h>
2#include <errno.h>
3#include <netdb.h>
4#include <stdlib.h>
5#include <assert.h>
6
7#include <sys/types.h>
8#include <sys/socket.h>
9
10#include "dat.h"
11
12static socklen_t
13str2addr(char *host, char *port, struct sockaddr *dest)
14{
15 socklen_t len;
16 struct addrinfo hint, *res, *r;
17
18 memset(&hint, '\0', sizeof(hint));
19 hint.ai_family = AF_UNSPEC;
20 hint.ai_socktype = SOCK_DGRAM;
21
22 if (getaddrinfo(host, port, &hint, &res)) {
23 errno = EAFNOSUPPORT;
24 return 0;
25 }
26
27 len = 0;
28 for (r = res; r != NULL; r = r->ai_next) {
29 switch (r->ai_family) {
30 case AF_INET6:
31 case AF_INET:
32 len = r->ai_addrlen;
33 memcpy(dest, r->ai_addr, len);
34 goto ret;
35 default:
36 errno = EADDRNOTAVAIL;
37 goto ret;
38 }
39 }
40
41 errno = EADDRNOTAVAIL;
42ret:
43 freeaddrinfo(res);
44 return len;
45}
46
47static int
48sock(char *host, char *port, struct sockaddr *addr, socklen_t *alen)
49{
50 int fd;
51
52 /* From getaddrinfo(3)
53 * The nodename and servname arguments are either null
54 * pointers or pointers to null-terminated strings. One or
55 * both of these two arguments shall be supplied by the
56 * application as a non-null pointer.
57 */
58 assert(host != NULL || port != NULL);
59 if (!(*alen = str2addr(host, port, addr)))
60 return -1;
61
62 if ((fd = socket(addr->sa_family, SOCK_DGRAM, 0)) == -1)
63 return -1;
64
65 return fd;
66}
67
68int
69usock(char *host, char *port, sockop op)
70{
71 int fd;
72 socklen_t alen;
73 struct sockaddr_storage addr;
74
75 if ((fd = sock(host, port, (struct sockaddr*)&addr, &alen)) == -1)
76 return -1;
77
78 switch (op) {
79 case SOCK_CONN:
80 if ((connect(fd, (struct sockaddr*)&addr, alen)) == -1)
81 return -1;
82 break;
83 case SOCK_BIND:
84 if ((bind(fd, (struct sockaddr*)&addr, alen)) == -1)
85 return -1;
86 break;
87 default: /* unknown operation */
88 errno = EINVAL;
89 return -1;
90 }
91
92 return fd;
93}
94
95dtls_context_t*
96dsock(char *host, char *port, unsigned char *id,
97 unsigned char *key, int ufd, sockop op)
98{
99 int fd;
100 struct dctx *dctx;
101 dtls_context_t *ctx;
102
103 if (!(dctx = malloc(sizeof(*dctx))))
104 return NULL;
105
106 memset(&dsess, '\0', sizeof(dsess));
107 if ((fd = sock(host, port, &dsess.addr.sa, &dsess.size)) == -1)
108 return NULL;
109
110 dctx->ufd = ufd;
111 dctx->dfd = fd;
112 dctx->key = key;
113 dctx->id = id;
114
115 if (!(ctx = dtls_new_context(dctx))) {
116 errno = ENOMEM;
117 return NULL;
118 }
119
120 dtls_set_handler(ctx, &dtlscb);
121 switch (op) {
122 case SOCK_CONN:
123 if (dtls_connect(ctx, &dsess) < 0) {
124 errno = ECONNREFUSED;
125 return NULL;
126 }
127 break;
128 case SOCK_BIND:
129 if (bind(dctx->dfd, (struct sockaddr*)&dsess.addr.sa, dsess.size) == -1)
130 return NULL;
131 break;
132 default: /* unknown operation */
133 errno = EINVAL;
134 return NULL;
135 }
136
137 return ctx;
138}