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
listenproc(Rock * r,int fd)32 listenproc(Rock *r, int fd)
33 {
34 Rock *nr;
35 char *net;
36 int cfd, nfd, dfd;
37 int pfd[2];
38 struct stat d;
39 char *p;
40 char listen[Ctlsize];
41 char name[Ctlsize];
42
43 switch(r->stype){
44 case SOCK_DGRAM:
45 net = "udp";
46 break;
47 case SOCK_STREAM:
48 net = "tcp";
49 break;
50 default:
51 net = "gok";
52 break;
53 }
54
55 strcpy(listen, r->ctl);
56 p = strrchr(listen, '/');
57 if(p == 0)
58 return -1;
59 strcpy(p+1, "listen");
60
61 if(pipe(pfd) < 0)
62 return -1;
63
64 /* replace fd with a pipe */
65 nfd = dup(fd);
66 dup2(pfd[0], fd);
67 close(pfd[0]);
68 fstat(fd, &d);
69 r->inode = d.st_ino;
70 r->dev = d.st_dev;
71
72 /* start listening process */
73 switch(fork()){
74 case -1:
75 close(pfd[1]);
76 close(nfd);
77 return -1;
78 case 0:
79 if(_muxsid == -1) {
80 _RFORK(RFNOTEG);
81 _muxsid = getpgrp();
82 } else
83 setpgid(getpid(), _muxsid);
84 _RENDEZVOUS(2, _muxsid);
85 break;
86 default:
87 atexit(_killmuxsid);
88 _muxsid = _RENDEZVOUS(2, 0);
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
listen(int fd,int)119 listen(int fd, int)
120 {
121 Rock *r;
122 int n, cfd;
123 char msg[128];
124 struct sockaddr_in *lip;
125 struct sockaddr_un *lunix;
126
127 r = _sock_findrock(fd, 0);
128 if(r == 0){
129 errno = ENOTSOCK;
130 return -1;
131 }
132
133 switch(r->domain){
134 case PF_INET:
135 cfd = open(r->ctl, O_RDWR);
136 if(cfd < 0){
137 errno = EBADF;
138 return -1;
139 }
140 lip = (struct sockaddr_in*)&r->addr;
141 if(1 || lip->sin_port >= 0) { /* sin_port is unsigned */
142 if(write(cfd, "bind 0", 6) < 0) {
143 errno = EGREG;
144 close(cfd);
145 return -1;
146 }
147 snprintf(msg, sizeof msg, "announce %d",
148 ntohs(lip->sin_port));
149 }
150 else
151 strcpy(msg, "announce *");
152 n = write(cfd, msg, strlen(msg));
153 if(n < 0){
154 errno = EOPNOTSUPP; /* Improve error reporting!!! */
155 close(cfd);
156 return -1;
157 }
158 close(cfd);
159
160 return listenproc(r, fd);
161 case PF_UNIX:
162 if(r->other < 0){
163 errno = EGREG;
164 return -1;
165 }
166 lunix = (struct sockaddr_un*)&r->addr;
167 if(_sock_srv(lunix->sun_path, r->other) < 0){
168 _syserrno();
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 }
179