raw: Fix: check type for SOCK_DGRAM instead of SOCK_RAW.
[swifty.git] / src / raw / swift_raw.c
1 /*
2  * swift implementation of syscall API
3  *
4  * Simulates the classic socket syscalls (socket, bind, send, recv).
5  * Implementation uses raw sockets (AF_INET, SOCK_RAW).
6  *
7  * Subsequently, implementation is to be ported into kernel space and
8  * the interface is going to be offered by the Linux syscall API.
9  *
10  * Heavily inspired by GLIBC's <sys/socket.h>
11  * (/usr/include/sys/socket.h).
12  *
13  * 2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #include "swift_types.h"
26 #include "swift_raw.h"
27
28 enum sock_rw_state {
29         STATE_NO_SHUT,
30         STATE_SHUT_RD,
31         STATE_SHUT_WR,
32         STATE_SHUT_RDWR
33 };
34
35 enum sock_bind_state {
36         STATE_NOTBOUND,
37         STATE_BOUND
38 };
39
40 /* socket management structure */
41 struct sock_list {
42         int s;
43         struct sockaddr_sw addr;
44         enum sock_rw_state rw_state;
45         enum sock_bind_state bind_state;
46         struct sock_list *next;
47         struct sock_list *prev;
48 };
49
50 static struct sock_list sock_list_head = {
51         .next = &sock_list_head,
52         .prev = &sock_list_head
53 };
54
55 /*
56  * Add new socket to list. Called by sw_socket "syscall".
57  */
58
59 static struct sock_list *list_add_socket(int s)
60 {
61         struct sock_list *ptr = malloc(sizeof(*ptr));
62         if (ptr == NULL)
63                 return NULL;
64
65         ptr->next = &sock_list_head;
66         ptr->prev = sock_list_head.prev;
67         sock_list_head.prev->next = ptr;
68         sock_list_head.prev = ptr;
69         ptr->s = s;
70
71         return ptr;
72 }
73
74 /*
75  * Bind socket to given address. Called by sw_bind "syscall".
76  */
77
78 static struct sock_list *list_update_socket_address(int s, __CONST_SOCKADDR_ARG addr)
79 {
80         struct sock_list *ptr;
81
82         for (ptr = sock_list_head.next; ptr != &sock_list_head; ptr = ptr->next)
83                 if (ptr->s == s) {
84                         memcpy(&ptr->addr, addr, sizeof(ptr->addr));
85                         return ptr;
86                 }
87
88         return NULL;
89 }
90
91 /*
92  * Get list element containing socket s. Called by sw_send* "syscalls".
93  */
94
95 static struct sock_list *list_elem_from_socket(int s)
96 {
97         struct sock_list *ptr;
98
99         for (ptr = sock_list_head.next; ptr != &sock_list_head; ptr = ptr->next)
100                 if (ptr->s == s)
101                         return ptr;
102
103         return NULL;
104 }
105
106 /*
107  * Get list element containing address addr. Called by sw_bind "syscall".
108  */
109
110 static struct sock_list *list_elem_from_address(__CONST_SOCKADDR_ARG addr)
111 {
112         struct sock_list *ptr;
113
114         for (ptr = sock_list_head.next; ptr != &sock_list_head; ptr = ptr->next) {
115                 if (ptr->bind_state == STATE_NOTBOUND)
116                         continue;
117                 if (memcmp(&ptr->addr, addr, sizeof(addr)) == 0)
118                         return ptr;
119         }
120
121         return NULL;
122 }
123
124 static struct sock_list *list_unlink_socket(int s)
125 {
126         struct sock_list *ptr;
127
128         for (ptr = sock_list_head.next; ptr != &sock_list_head; ptr = ptr->next)
129                 if (ptr->s == s) {
130                         ptr->next->prev = ptr->prev;
131                         ptr->prev->next = ptr->next;
132                         ptr->next = ptr;
133                         ptr->prev = ptr;
134                         return ptr;
135                 }
136
137         return NULL;
138 }
139
140 /*
141  * Remove socket from list. Called by sw_close "syscall".
142  */
143
144 static int list_remove_socket(int s)
145 {
146         struct sock_list *ptr;
147
148         ptr = list_unlink_socket(s);
149         if (ptr == NULL)
150                 return -1;
151
152         free(ptr);
153         return 0;
154 }
155
156 static int list_socket_is_bound(int s)
157 {
158         struct sock_list *ptr;
159
160         for (ptr = sock_list_head.next; ptr != &sock_list_head; ptr = ptr->next)
161                 if (ptr->s == s) {
162                         if (ptr->bind_state == STATE_BOUND)
163                                 return 1;
164                         break;
165                 }
166
167         return 0;
168 }
169
170 /*
171  * Create a new socket of type TYPE in domain DOMAIN, using
172  * protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
173  * Returns a file descriptor for the new socket, or -1 for errors.
174  *
175  * swift: PROTOCOL is IPPROTO_SWIFT. Ignore TYPE.
176  */
177 int sw_socket(int __domain, int __type, int __protocol)
178 {
179         int s;
180         struct sock_list *list;
181
182         if (__domain != PF_INET || __type != SOCK_DGRAM || __protocol != IPPROTO_SWIFT) {
183                 errno = EINVAL;
184                 goto sock_err;
185         }
186
187         s = socket(PF_INET, SOCK_RAW, IPPROTO_SWIFT);
188         if (s < 0) {
189                 goto sock_err;
190         }
191
192         list = list_add_socket(s);
193         if (list == NULL) {
194                 errno = ENOMEM;
195                 goto list_add_err;
196         }
197
198         /* Socket is fully open. */
199         list->rw_state = STATE_NO_SHUT;
200
201         /* Socket is not bound. */
202         list->bind_state = STATE_NOTBOUND;
203
204         return s;
205
206 list_add_err:
207         close(s);
208 sock_err:
209         return -1;
210 }
211
212 /*
213  * Give the socket FD the local address ADDR (which is LEN bytes long).
214  *
215  * swift: ADDR is of type struct sockaddr_sw.
216  */
217 int sw_bind(int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
218 {
219         struct sock_list *list;
220         int rc;
221
222         rc = list_socket_is_bound(__fd);
223         if (rc == 1) {
224                 errno = EINVAL;
225                 goto socket_bound_err;
226         }
227
228         /* Check whether address is already in use. */
229         list = list_elem_from_address(__addr);
230         if (list != NULL) {
231                 errno = EADDRINUSE;
232                 goto list_elem_err;
233         }
234
235         /* Update __fd entry in socket management list. */
236         list = list_update_socket_address(__fd, __addr);
237         if (list == NULL) {
238                 errno = EBADF;
239                 goto list_update_err;
240         }
241
242         return 0;
243
244 socket_bound_err:
245 list_update_err:
246 list_elem_err:
247         return -1;
248 }
249
250 /* Put the local address of FD into *ADDR and its length in *LEN.  */
251 int sw_getsockname(int __fd, __SOCKADDR_ARG __addr,
252                         socklen_t *__restrict __len)
253 {
254         struct sock_list *list;
255
256         /* Find socket in management structure. */
257         list = list_elem_from_socket(__fd);
258         if (list == NULL) {
259                 errno = EBADF;
260                 goto list_elem_err;
261         }
262
263         memcpy(__addr, &list->addr, sizeof(list->addr));
264         *__len = sizeof(list->addr);
265
266         return 0;
267
268 list_elem_err:
269         return -1;
270 }
271
272 /*
273  * Send N bytes of BUF on socket FD to peer at address ADDR (which is
274  * ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.
275  *
276  * This function is a cancellation point and therefore not marked with
277  * __THROW.
278  */
279 ssize_t sw_sendto(int __fd, __const void *__buf, size_t __n,
280                        int __flags, __CONST_SOCKADDR_ARG __addr,
281                        socklen_t __addr_len)
282 {
283         ssize_t bytes_sent;
284         struct sock_list *list;
285         struct iovec __iov[1];
286         struct msghdr __msgh;
287         
288         list = list_elem_from_socket(__fd);
289         if (list == NULL) {
290                 errno = EBADF;
291                 goto sock_err;
292         }
293
294         if (list->rw_state == STATE_SHUT_WR || list->rw_state == STATE_SHUT_RDWR) {
295                 errno = ENOTCONN;
296                 goto sock_err;  
297         }
298 /*
299         if (list->state == STATE_NOBOUND) {
300                 errno = EDESTADDRREQ;
301                 goto sock_err;
302         }
303  */
304         
305         /* Specify the components of the message in an "iovec".   */
306         __iov[0].iov_base = __buf;
307         __iov[0].iov_len = __n;
308         
309         /* The message header contains parameters for sendmsg.    */
310         __msgh.msg_name = (caddr_t) __addr;
311         __msgh.msg_namelen = sizeof(__addr);
312         __msgh.msg_iov = __iov;
313         __msgh.msg_iovlen = 1;
314         __msgh.msg_control = NULL;            /* irrelevant to AF_INET */
315         __msgh.msg_controllen = 0;            /* irrelevant to AF_INET */
316
317         return sendmsg(__fd, &__msgh, 0);
318
319 sock_err:
320         return -1;
321 }
322
323 /*
324  * Read N bytes into BUF through socket FD.
325  * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with tha address of
326  * the sender, and store the actual size of the address in *ADDR_LEN.
327  * Returns the number of bytes read or -1 for errors.
328  *
329  * This function is a cancellation point and therefore not marked with
330  * __THROW.
331  */
332 ssize_t sw_recvfrom(int __fd, void *__restrict __buf, size_t __n,
333                          int __flags, __SOCKADDR_ARG __addr,
334                          socklen_t *__restrict __addr_len)
335 {
336         ssize_t bytes_recv;
337
338         /* TODO */
339
340         return bytes_recv;
341 }
342
343 /*
344  * Send a message described MESSAGE on socket FD.
345  * Returns the number of bytes sent, or -1 for errors.
346  *
347  * This function is a cancellation point and therefore not marked with
348  * __THROW.
349  */
350 ssize_t sw_sendmsg(int __fd, __const struct msghdr *__message,
351                         int __flags)
352 {
353         ssize_t bytes_sent;
354
355         return sendmsg(__fd, __message, __flags);
356 }
357
358 /*
359  * Receive a message as described by MESSAGE from socket FD.
360  * Returns the number of bytes read or -1 for errors.
361  *
362  * This function is a cancellation point and therefore not marked with
363  * __THROW.
364  */
365 ssize_t sw_recvmsg(int __fd, struct msghdr *__message, int __flags)
366 {
367         ssize_t bytes_recv;
368
369         /* TODO */
370
371         return bytes_recv;
372 }
373
374 /*
375  * Put the current value for socket FD's option OPTNAME at protocol level
376  * LEVEL into OPTVAL (which is *OPTLEN bytes long), and set *OPTLEN to the
377  * value's actual length.  Returns 0 on success, -1 for errors.
378  */
379 int sw_getsockopt(int __fd, int __level, int __optname,
380                        void *__restrict __optval,
381                        socklen_t *__restrict __optlen)
382 {
383         /* Call classical interface of getsockopt(2). */
384         return getsockopt(__fd, __level, __optname, __optval, __optlen);
385 }
386
387 /*
388  * Set socket FD's option OPTNAME at protocol level LEVEL
389  * to *OPTVAL (which is OPTLEN bytes long).
390  * Returns 0 on success, -1 for errors.
391  */
392
393 int sw_setsockopt(int __fd, int __level, int __optname,
394                        __const void *__optval, socklen_t __optlen)
395 {
396         /* Call classical interface of setsockopt(2). */
397         return setsockopt(__fd, __level, __optname, __optval, __optlen);
398 }
399
400 /*
401  * Shut down all or part of the connection open on socket FD.
402  * HOW determines what to shut down:
403  *   SHUT_RD   = No more receptions;
404  *   SHUT_WR   = No more transmissions;
405  *   SHUT_RDWR = No more receptions or transmissions.
406  * Returns 0 on success, -1 for errors.
407  */
408 int sw_shutdown(int __fd, int __how)
409 {
410         struct sock_list *list;
411         int rc;
412
413         /* Find socket in management structure. */
414         list = list_elem_from_socket(__fd);
415         if (list == NULL) {
416                 errno = EBADF;
417                 goto list_elem_err;
418         }
419
420         /* Check and update socket state. */
421         if (__how == STATE_SHUT_RDWR)
422                 list->rw_state = STATE_SHUT_RDWR;
423         else if (__how == STATE_SHUT_WR) {
424                 if (list->rw_state == STATE_SHUT_RD)
425                         list->rw_state = STATE_SHUT_RDWR;
426                 else if (list->rw_state == STATE_SHUT_WR) {
427                         errno = ENOTCONN;
428                         goto not_conn_err;
429                 }
430         }
431         else if (__how == STATE_SHUT_RD) {
432                 if (list->rw_state == STATE_SHUT_WR)
433                         list->rw_state = STATE_SHUT_RDWR;
434                 else if (list->rw_state == STATE_SHUT_RD) {
435                         errno = ENOTCONN;
436                         goto not_conn_err;
437                 }
438         }
439
440         /* Remove socket from socket management structure. */
441         if (list->rw_state == STATE_SHUT_RDWR) {
442                 rc = list_remove_socket(__fd);
443                 if (rc < 0) {
444                         errno = EBADF;
445                         goto list_unlink_err;
446                 }
447         }
448
449         /* Call classical interface of shutdown(2). */
450         return shutdown(__fd, __how);
451
452 not_conn_err:
453 list_elem_err:
454 list_unlink_err:
455         return -1;
456 }
457
458 /*
459  * Close file descriptor for socket FD.
460  * Returns 0 on success, -1 for errors.
461  */
462 int sw_close(int __fd)
463 {
464         int rc;
465
466         /* Remove socket from socket management structure. */
467         rc = list_remove_socket(__fd);
468         if (rc < 0) {
469                 errno = EBADF;
470                 goto list_unlink_err;
471         }
472
473         /* Call classical interface of close(2). */
474         return close(__fd);
475
476 list_unlink_err:
477         return -1;
478 }