First stab at a working blocking example.
[radsecproxy.git] / lib / base.c
1 #include <sys/socket.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <string.h>
5 //#include <unistd.h>
6 #include <stdint.h>
7 #include "../tlv11.h"           /* FIXME: .. */
8 #include "libradsec-base.h"
9
10 static int
11 _do_connect(int type,
12             const struct sockaddr *addr,
13             socklen_t addrlen)
14 {
15   int s;
16
17   s = socket(AF_INET, type, 0); /* FIXME: do AF_INET6 too */
18   if (s >= 0)
19       if (connect(s, addr, addrlen)) {
20           close(s);
21           s = -1;
22       }
23   return s;
24 }
25
26 static struct list *
27 _list_new(const struct rs_config *ctx)
28 {
29     struct list *list = rs_malloc(ctx, sizeof(struct list));
30     if (list)
31         memset(list, 0, sizeof(struct list));
32     return list;
33 }
34
35 static int
36 _list_push(const struct rs_config *ctx, /* FIXME: code duplicate, list.c */
37            struct list *list,
38            void *data)
39 {
40     struct list_node *node;
41
42     node = rs_malloc(ctx, sizeof(struct list_node));
43     if (!node)
44         return 0;
45
46     node->next = NULL;
47     node->data = data;
48
49     if (list->first)
50         list->last->next = node;
51     else
52         list->first = node;
53     list->last = node;
54
55     list->count++;
56     return 1;
57 }
58
59 static void
60 _list_destroy(const struct rs_config *ctx, /* FIXME: code dup */
61               struct list *list)
62 {
63     struct list_node *node, *next;
64
65     if (list) {
66         for (node = list->first; node; node = next) {
67             rs_free(ctx, node->data);
68             next = node->next;
69             rs_free(ctx, node);
70         }
71         free(list);
72     }
73 }
74
75 /* ------------------------------------------------------- */
76 int
77 rs_connect(const struct rs_config *conf,
78            const struct sockaddr *addr,
79            socklen_t addrlen)
80 {
81     switch (conf->conn_type)
82     {
83     case RS_CONN_TYPE_UDP:
84         return _do_connect(SOCK_DGRAM, addr, addrlen);
85     case RS_CONN_TYPE_TCP:
86         return _do_connect(SOCK_STREAM, addr, addrlen);
87         /* fall thru */
88     case RS_CONN_TYPE_TLS:
89         /* fall thru */
90     case RS_CONN_TYPE_DTLS:
91         /* fall thru */
92     default:
93         errno = ENOSYS;
94         return -1;
95     }
96 }
97
98 int
99 rs_disconnect( const struct rs_config *conf, int fd)
100 {
101     switch (conf->conn_type)
102     {
103     case RS_CONN_TYPE_UDP:
104         return close(fd);
105     case RS_CONN_TYPE_TCP:
106         shutdown(fd, SHUT_RDWR);
107         return close(fd);
108     case RS_CONN_TYPE_TLS:
109         /* fall thru */
110     case RS_CONN_TYPE_DTLS:
111         /* fall thru */
112     default:
113         errno = ENOSYS;
114         return -1;
115     }
116 }
117
118 struct rs_packet *
119 rs_packet_new(const struct rs_config *ctx,
120               const uint8_t buf[RS_HEADER_LEN],
121               size_t *count)
122 {
123     struct rs_packet *p = rs_malloc(ctx, sizeof(struct rs_packet));
124     if (p) {
125         p->attrs = _list_new(ctx);
126         if (p->attrs) {
127             p->code = buf[0];
128             p->id = buf[1];
129             if (count)
130                 *count = (buf[2] << 8) + buf[3];
131         }
132         else
133             rs_packet_free(ctx, &p);
134     }
135     return p;
136 }
137
138 struct rs_packet *
139 rs_packet_parse(const struct rs_config *ctx,
140                 struct rs_packet **packet,
141                 const uint8_t *buf,
142                 size_t buflen)
143 {
144     struct rs_packet *p = *packet;
145     struct tlv *tlv;
146     size_t i;
147     uint8_t atype, alen;
148
149     if (buflen < 16) {
150         errno = EPROTO;
151         rs_packet_free(ctx, &p);
152         return NULL;
153     }
154
155     i = 16;
156     while (i + 2 < buflen) {
157         atype = buf[i++];
158         alen = buf[i++];
159         if (alen < 2) {
160 #if DEBUG
161             fprintf(stderr,
162                     "%s: DEBUG: attribute (type %d, len %d) has an invalid length\n",
163                     __func__, atype, alen);
164 #endif
165             errno = EPROTO;
166             rs_packet_free(ctx, &p);
167             return NULL;
168         }
169         alen -= 2;
170         if (alen + i >= buflen) {
171 #if DEBUG
172             fprintf(stderr,
173                     "%s: DEBUG: attribute (type %d, len %d) wouldn't fit packet\n",
174                     __func__, atype, alen);
175 #endif
176             errno = EPROTO;
177             rs_packet_free(ctx, &p);
178             return NULL;
179         }
180         tlv = maketlv(atype, alen, (void *) (buf + i));
181         if (tlv)
182             _list_push(ctx, p->attrs, tlv);
183         else {
184             errno = ENOMEM;
185             rs_packet_free(ctx, &p);
186         }
187         i += alen;
188     }
189     memcpy(p->auth, buf, 16);
190     return p;
191 }
192
193 void
194 rs_packet_free(const struct rs_config *ctx,
195                struct rs_packet **packet)
196 {
197     _list_destroy(ctx, (*packet)->attrs);
198     rs_free(ctx, *packet);
199     *packet = NULL;
200 }
201
202 ssize_t
203 rs_packet_serialize(const struct rs_packet *packet,
204                     uint8_t *buf,
205                     size_t buflen)
206 {
207     struct list_node *ln;
208     size_t pktlen;
209     ssize_t i;
210
211     for (ln = list_first(packet->attrs), pktlen = 20; ln; ln = list_next(ln))
212         pktlen += ((struct rs_attribute *)(ln->data))->length;
213     if (pktlen > buflen)
214         return -(pktlen - buflen);
215
216     buf[0] = packet->code;
217     buf[1] = packet->id;
218     buf[2] = (pktlen & 0xff00) >> 8;
219     buf[3] = pktlen & 0xff;
220
221     memcpy(buf + 4, packet->auth, 16);
222
223     for (ln = list_first(packet->attrs), i = 20; ln; ln = list_next(ln)) {
224         struct rs_attribute *a = (struct rs_attribute *)(ln->data);
225         buf[i++] = a->type;
226         buf[i++] = a->length;
227         memcpy(buf + i, a->value, a->length - 2);
228         i += a->length - 2;
229     }
230
231     return i;
232 }
233
234 /* Local Variables: */
235 /* c-file-style: "stroustrup" */
236 /* End: */