raw: Extract sock_list in a file
[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 #include "swift_list.h"
28
29 /*
30  * Create a new socket of type TYPE in domain DOMAIN, using
31  * protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
32  * Returns a file descriptor for the new socket, or -1 for errors.
33  *
34  * swift: PROTOCOL is IPPROTO_SWIFT. Ignore TYPE.
35  */
36 int sw_socket(int __domain, int __type, int __protocol)
37 {
38         int s;
39         struct sock_list *list;
40
41         if (__domain != PF_INET || __type != SOCK_DGRAM || __protocol != IPPROTO_SWIFT) {
42                 errno = EINVAL;
43                 goto sock_err;
44         }
45
46         s = socket(PF_INET, SOCK_RAW, IPPROTO_SWIFT);
47         if (s < 0) {
48                 goto sock_err;
49         }
50
51         list = list_add_socket(s);
52         if (list == NULL) {
53                 errno = ENOMEM;
54                 goto list_add_err;
55         }
56
57         /* Socket is fully open. */
58         list->rw_state = STATE_NO_SHUT;
59
60         /* Socket is not bound. */
61         list->bind_state = STATE_NOTBOUND;
62
63         return s;
64
65 list_add_err:
66         close(s);
67 sock_err:
68         return -1;
69 }
70
71 /*
72  * Give the socket FD the local address ADDR (which is LEN bytes long).
73  *
74  * swift: ADDR is of type struct sockaddr_sw.
75  */
76 int sw_bind(int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
77 {
78         struct sock_list *list;
79         int rc;
80
81         rc = list_socket_is_bound(__fd);
82         if (rc == 1) {
83                 errno = EINVAL;
84                 goto socket_bound_err;
85         }
86
87         /* Check whether address is already in use. */
88         list = list_elem_from_address(__addr);
89         if (list != NULL) {
90                 errno = EADDRINUSE;
91                 goto list_elem_err;
92         }
93
94         /* Update __fd entry in socket management list. */
95         list = list_update_socket_address(__fd, __addr);
96         if (list == NULL) {
97                 errno = EBADF;
98                 goto list_update_err;
99         }
100
101         return 0;
102
103 socket_bound_err:
104 list_update_err:
105 list_elem_err:
106         return -1;
107 }
108
109 /* Put the local address of FD into *ADDR and its length in *LEN.  */
110 int sw_getsockname(int __fd, __SOCKADDR_ARG __addr,
111                         socklen_t *__restrict __len)
112 {
113         struct sock_list *list;
114
115         /* Find socket in management structure. */
116         list = list_elem_from_socket(__fd);
117         if (list == NULL) {
118                 errno = EBADF;
119                 goto list_elem_err;
120         }
121
122         memcpy(__addr, &list->addr, sizeof(list->addr));
123         *__len = sizeof(list->addr);
124
125         return 0;
126
127 list_elem_err:
128         return -1;
129 }
130
131 /*
132  * Send N bytes of BUF on socket FD to peer at address ADDR (which is
133  * ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.
134  *
135  * This function is a cancellation point and therefore not marked with
136  * __THROW.
137  */
138 ssize_t sw_sendto(int __fd, __const void *__buf, size_t __n,
139                        int __flags, __CONST_SOCKADDR_ARG __addr,
140                        socklen_t __addr_len)
141 {
142         ssize_t bytes_sent;
143         struct sock_list *list;
144         struct iovec __iov[1];
145         struct msghdr __msgh;
146         
147         list = list_elem_from_socket(__fd);
148         if (list == NULL) {
149                 errno = EBADF;
150                 goto sock_err;
151         }
152
153         if (list->rw_state == STATE_SHUT_WR || list->rw_state == STATE_SHUT_RDWR) {
154                 errno = ENOTCONN;
155                 goto sock_err;  
156         }
157 /*
158         if (list->state == STATE_NOBOUND) {
159                 errno = EDESTADDRREQ;
160                 goto sock_err;
161         }
162  */
163         
164         /* Specify the components of the message in an "iovec".   */
165         __iov[0].iov_base = __buf;
166         __iov[0].iov_len = __n;
167         
168         /* The message header contains parameters for sendmsg.    */
169         __msgh.msg_name = (caddr_t) __addr;
170         __msgh.msg_namelen = sizeof(__addr);
171         __msgh.msg_iov = __iov;
172         __msgh.msg_iovlen = 1;
173         __msgh.msg_control = NULL;            /* irrelevant to AF_INET */
174         __msgh.msg_controllen = 0;            /* irrelevant to AF_INET */
175
176         return sendmsg(__fd, &__msgh, 0);
177
178 sock_err:
179         return -1;
180 }
181
182 /*
183  * Read N bytes into BUF through socket FD.
184  * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with tha address of
185  * the sender, and store the actual size of the address in *ADDR_LEN.
186  * Returns the number of bytes read or -1 for errors.
187  *
188  * This function is a cancellation point and therefore not marked with
189  * __THROW.
190  */
191 ssize_t sw_recvfrom(int __fd, void *__restrict __buf, size_t __n,
192                          int __flags, __SOCKADDR_ARG __addr,
193                          socklen_t *__restrict __addr_len)
194 {
195         ssize_t bytes_recv;
196
197         /* TODO */
198
199         return bytes_recv;
200 }
201
202 /*
203  * Send a message described MESSAGE on socket FD.
204  * Returns the number of bytes sent, or -1 for errors.
205  *
206  * This function is a cancellation point and therefore not marked with
207  * __THROW.
208  */
209 ssize_t sw_sendmsg(int __fd, __const struct msghdr *__message,
210                         int __flags)
211 {
212         ssize_t bytes_sent;
213
214         return sendmsg(__fd, __message, __flags);
215 }
216
217 /*
218  * Receive a message as described by MESSAGE from socket FD.
219  * Returns the number of bytes read or -1 for errors.
220  *
221  * This function is a cancellation point and therefore not marked with
222  * __THROW.
223  */
224 ssize_t sw_recvmsg(int __fd, struct msghdr *__message, int __flags)
225 {
226         ssize_t bytes_recv;
227
228         /* TODO */
229
230         return bytes_recv;
231 }
232
233 /*
234  * Put the current value for socket FD's option OPTNAME at protocol level
235  * LEVEL into OPTVAL (which is *OPTLEN bytes long), and set *OPTLEN to the
236  * value's actual length.  Returns 0 on success, -1 for errors.
237  */
238 int sw_getsockopt(int __fd, int __level, int __optname,
239                        void *__restrict __optval,
240                        socklen_t *__restrict __optlen)
241 {
242         /* Call classical interface of getsockopt(2). */
243         return getsockopt(__fd, __level, __optname, __optval, __optlen);
244 }
245
246 /*
247  * Set socket FD's option OPTNAME at protocol level LEVEL
248  * to *OPTVAL (which is OPTLEN bytes long).
249  * Returns 0 on success, -1 for errors.
250  */
251
252 int sw_setsockopt(int __fd, int __level, int __optname,
253                        __const void *__optval, socklen_t __optlen)
254 {
255         /* Call classical interface of setsockopt(2). */
256         return setsockopt(__fd, __level, __optname, __optval, __optlen);
257 }
258
259 /*
260  * Shut down all or part of the connection open on socket FD.
261  * HOW determines what to shut down:
262  *   SHUT_RD   = No more receptions;
263  *   SHUT_WR   = No more transmissions;
264  *   SHUT_RDWR = No more receptions or transmissions.
265  * Returns 0 on success, -1 for errors.
266  */
267 int sw_shutdown(int __fd, int __how)
268 {
269         struct sock_list *list;
270         int rc;
271
272         /* Find socket in management structure. */
273         list = list_elem_from_socket(__fd);
274         if (list == NULL) {
275                 errno = EBADF;
276                 goto list_elem_err;
277         }
278
279         /* Check and update socket state. */
280         if (__how == STATE_SHUT_RDWR)
281                 list->rw_state = STATE_SHUT_RDWR;
282         else if (__how == STATE_SHUT_WR) {
283                 if (list->rw_state == STATE_SHUT_RD)
284                         list->rw_state = STATE_SHUT_RDWR;
285                 else if (list->rw_state == STATE_SHUT_WR) {
286                         errno = ENOTCONN;
287                         goto not_conn_err;
288                 }
289         }
290         else if (__how == STATE_SHUT_RD) {
291                 if (list->rw_state == STATE_SHUT_WR)
292                         list->rw_state = STATE_SHUT_RDWR;
293                 else if (list->rw_state == STATE_SHUT_RD) {
294                         errno = ENOTCONN;
295                         goto not_conn_err;
296                 }
297         }
298
299         /* Remove socket from socket management structure. */
300         if (list->rw_state == STATE_SHUT_RDWR) {
301                 rc = list_remove_socket(__fd);
302                 if (rc < 0) {
303                         errno = EBADF;
304                         goto list_unlink_err;
305                 }
306         }
307
308         /* Call classical interface of shutdown(2). */
309         return shutdown(__fd, __how);
310
311 not_conn_err:
312 list_elem_err:
313 list_unlink_err:
314         return -1;
315 }
316
317 /*
318  * Close file descriptor for socket FD.
319  * Returns 0 on success, -1 for errors.
320  */
321 int sw_close(int __fd)
322 {
323         int rc;
324
325         /* Remove socket from socket management structure. */
326         rc = list_remove_socket(__fd);
327         if (rc < 0) {
328                 errno = EBADF;
329                 goto list_unlink_err;
330         }
331
332         /* Call classical interface of close(2). */
333         return close(__fd);
334
335 list_unlink_err:
336         return -1;
337 }