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