Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
	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
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
}