Re-add the bsd library
[akaros.git] / user / bsd / listen.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 <fcntl.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <sys/stat.h>
18 #include <signal.h>
19
20 /* socket extensions */
21 #include <sys/uio.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <sys/un.h>
25
26 #include "priv.h"
27
28 extern int      _muxsid;
29 extern void     _killmuxsid(void);
30
31 /*
32  * replace the fd with a pipe and start a process to
33  * accept calls in.  this is all to make select work.
34  */
35 static int
36 listenproc(Rock *r, int fd)
37 {
38         Rock *nr;
39         char *net;
40         int cfd, nfd, dfd;
41         int pfd[2];
42         struct stat d;
43         char *p;
44         char listen[Ctlsize];
45         char name[Ctlsize];
46
47         switch(r->stype){
48         case SOCK_DGRAM:
49                 net = "udp";
50                 break;
51         case SOCK_STREAM:
52                 net = "tcp";
53                 break;
54         }
55
56         strcpy(listen, r->ctl);
57         p = strrchr(listen, '/');
58         if(p == 0)
59                 return -1;
60         strcpy(p+1, "listen");
61
62         if(pipe(pfd) < 0)
63                 return -1;
64
65         /* replace fd with a pipe */
66         nfd = dup(fd);
67         dup2(pfd[0], fd);
68         close(pfd[0]);
69         fstat(fd, &d);
70         r->inode = d.st_ino;
71         r->dev = d.st_dev;
72
73         /* start listening process */
74         switch(fork()){
75         case -1:
76                 close(pfd[1]);
77                 close(nfd);
78                 return -1;
79         case 0:
80                 if(_muxsid == -1) {
81                         fork(); //_RFORK(RFNOTEG);
82                         _muxsid = getpgrp();
83                 } else
84                         setpgid(getpid(), _muxsid);
85                 //_RENDEZVOUS(2, _muxsid);
86                 break;
87         default:
88                 atexit(_killmuxsid);
89  #warning "no rendezvous for listen"
90                 //_muxsid = _RENDEZVOUS(2, 0);
91                 close(pfd[1]);
92                 close(nfd);
93                 return 0;
94         }
95
96 /*      for(fd = 0; fd < 30; fd++)
97                 if(fd != nfd && fd != pfd[1])
98                         close(fd);/**/
99
100         for(;;){
101                 cfd = open(listen, O_RDWR);
102                 if(cfd < 0)
103                         break;
104
105                 dfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
106                 if(dfd < 0)
107                         break;
108
109                 if(write(pfd[1], nr->ctl, strlen(nr->ctl)) < 0)
110                         break;
111                 if(read(pfd[1], name, sizeof(name)) <= 0)
112                         break;
113
114                 close(dfd);
115         }
116         exit(0);
117         return 0;
118 }
119
120 int
121 listen(fd, backlog)
122         int fd;
123         int backlog;
124 {
125         Rock *r;
126         int n, cfd;
127         char msg[128];
128         struct sockaddr_in *lip;
129         struct sockaddr_un *lunix;
130
131         r = _sock_findrock(fd, 0);
132         if(r == 0){
133                 errno = ENOTSOCK;
134                 return -1;
135         }
136
137         switch(r->domain){
138         case PF_INET:
139                 cfd = open(r->ctl, O_RDWR);
140                 if(cfd < 0){
141                         errno = EBADF;
142                         return -1;
143                 }
144                 lip = (struct sockaddr_in*)&r->addr;
145                 if(lip->sin_port >= 0) {
146                         if(write(cfd, "bind 0", 6) < 0) {
147                                 errno = EINVAL; //EGREG;
148                                 close(cfd);
149                                 return -1;
150                         }
151                         snprintf(msg, sizeof msg, "announce %d",
152                                 ntohs(lip->sin_port));
153                 }
154                 else
155                         strcpy(msg, "announce *");
156                 n = write(cfd, msg, strlen(msg));
157                 if(n < 0){
158                         errno = EOPNOTSUPP;     /* Improve error reporting!!! */
159                         close(cfd);
160                         return -1;
161                 }
162                 close(cfd);
163
164                 return listenproc(r, fd);
165         case PF_UNIX:
166                 if(r->other < 0){
167                         errno = EINVAL;//EGREG;
168                         return -1;
169                 }
170                 lunix = (struct sockaddr_un*)&r->addr;
171                 if(_sock_srv(lunix->sun_path, r->other) < 0){
172                         _syserrno();
173                         r->other = -1;
174                         return -1;
175                 }
176                 r->other = -1;
177                 return 0;
178         default:
179                 errno = EAFNOSUPPORT;
180                 return -1;
181         }
182 }