BSD sockets fix-up
[akaros.git] / user / bsd / socket.c
1 /* 
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9 /* posix */
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <sys/stat.h>
18
19 /* bsd extensions */
20 #include <sys/uio.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23
24 #include "priv.h"
25
26 Rock *_sock_rock;
27
28 Rock*
29 _sock_findrock(int fd, struct stat *dp)
30 {
31         Rock *r;
32         struct stat d;
33
34         if(dp == 0)
35                 dp = &d;
36         fstat(fd, dp);
37         for(r = _sock_rock; r; r = r->next){
38                 if(r->inode == dp->st_ino
39                 && r->dev == dp->st_dev)
40                         break;
41         }
42         return r;
43 }
44
45 Rock*
46 _sock_newrock(int fd)
47 {
48         Rock *r;
49         struct stat d;
50
51         r = _sock_findrock(fd, &d);
52         if(r == 0){
53                 r = malloc(sizeof(Rock));
54                 if(r == 0)
55                         return 0;
56                 r->dev = d.st_dev;
57                 r->inode = d.st_ino;
58                 r->other = -1;
59                 /* TODO: this is not thread-safe! */
60                 r->next = _sock_rock;
61                 _sock_rock = r;
62         }
63         memset(&r->raddr, 0, sizeof(r->raddr));
64         memset(&r->addr, 0, sizeof(r->addr));
65         r->reserved = 0;
66         r->dev = d.st_dev;
67         r->inode = d.st_ino;
68         r->other = -1;
69         return r;
70 }
71
72 /* For a ctlfd and a few other settings, it opens and returns the corresponding
73  * datafd. */
74 int
75 _sock_data(int cfd, char *net, int domain, int stype, int protocol, Rock **rp)
76 {
77         int n, fd;
78         Rock *r;
79         char name[Ctlsize];
80
81         /* get the data file name */
82         n = read(cfd, name, sizeof(name)-1);
83         if(n < 0){
84                 close(cfd);
85                 errno = ENOBUFS;
86                 return -1;
87         }
88         name[n] = 0;
89         n = strtoul(name, 0, 0);
90         snprintf(name, sizeof name, "/net/%s/%d/data", net, n);
91
92         /* open data file */
93         fd = open(name, O_RDWR);
94         close(cfd);
95         if(fd < 0){
96                 close(cfd);
97                 errno = ENOBUFS;
98                 return -1;
99         }
100
101         /* hide stuff under the rock */
102         snprintf(name, sizeof name, "/net/%s/%d/ctl", net, n);
103         r = _sock_newrock(fd);
104         if(r == 0){
105                 errno = ENOBUFS;
106                 close(fd);
107                 return -1;
108         }
109         if(rp)
110                 *rp = r;
111         memset(&r->raddr, 0, sizeof(r->raddr));
112         memset(&r->addr, 0, sizeof(r->addr));
113         r->domain = domain;
114         r->stype = stype;
115         r->protocol = protocol;
116         strcpy(r->ctl, name);
117         return fd;
118 }
119
120 int
121 socket(int domain, int stype, int protocol)
122 {
123         Rock *r;
124         int cfd, fd, n;
125         int pfd[2];
126         char *net;
127
128         switch(domain){
129         case PF_INET:
130                 /* get a free network directory */
131                 switch(stype){
132                 case SOCK_DGRAM:
133                         net = "udp";
134                         cfd = open("/net/udp/clone", O_RDWR);
135                         break;
136                 case SOCK_STREAM:
137                         net = "tcp";
138                         cfd = open("/net/tcp/clone", O_RDWR);
139                         break;
140                 default:
141                         errno = EPROTONOSUPPORT;
142                         return -1;
143                 }
144                 if(cfd < 0){
145                         return -1;
146                 }
147                 return _sock_data(cfd, net, domain, stype, protocol, 0);
148         case PF_UNIX:
149                 if(pipe(pfd) < 0){
150                         return -1;
151                 }
152                 r = _sock_newrock(pfd[0]);
153                 r->domain = domain;
154                 r->stype = stype;
155                 r->protocol = protocol;
156                 r->other = pfd[1];
157                 return pfd[0];
158         default:
159                 errno = EPROTONOSUPPORT;
160                 return -1;
161         }
162 }
163
164 int
165 issocket(int fd)
166 {
167         Rock *r;
168
169         r = _sock_findrock(fd, 0);
170         return (r != 0);
171 }
172
173 /*
174  * probably should do better than this
175  */
176 int getsockopt (int __fd, int __level, int __optname,
177                        void *__restrict __optval,
178                        socklen_t *__restrict __optlen)
179 {
180         return -1;
181 }
182
183 int setsockopt (int __fd, int __level, int __optname,
184                        __const void *__optval, socklen_t __optlen)
185 {
186         return 0;
187 }
188