xref: /plan9-contrib/sys/src/ape/lib/bsd/accept.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
1219b2ee8SDavid du Colombier /* posix */
2219b2ee8SDavid du Colombier #include <sys/types.h>
3219b2ee8SDavid du Colombier #include <unistd.h>
4219b2ee8SDavid du Colombier #include <stdlib.h>
5219b2ee8SDavid du Colombier #include <stdio.h>
6219b2ee8SDavid du Colombier #include <fcntl.h>
7219b2ee8SDavid du Colombier #include <errno.h>
8219b2ee8SDavid du Colombier #include <string.h>
9219b2ee8SDavid du Colombier 
10219b2ee8SDavid du Colombier /* bsd extensions */
11219b2ee8SDavid du Colombier #include <sys/uio.h>
12219b2ee8SDavid du Colombier #include <sys/socket.h>
13219b2ee8SDavid du Colombier #include <netinet/in.h>
14219b2ee8SDavid du Colombier #include <sys/un.h>
15219b2ee8SDavid du Colombier 
16219b2ee8SDavid du Colombier #include "priv.h"
17219b2ee8SDavid du Colombier 
18219b2ee8SDavid du Colombier int
19219b2ee8SDavid du Colombier accept(int fd, void *a, int *alen)
20219b2ee8SDavid du Colombier {
21219b2ee8SDavid du Colombier 	int n, nfd, cfd;
22219b2ee8SDavid du Colombier 	Rock *r, *nr;
23219b2ee8SDavid du Colombier 	struct sockaddr_in *ip;
24219b2ee8SDavid du Colombier 	char name[Ctlsize];
257e125112SDavid du Colombier 	char file[8+Ctlsize+1];
26*781103c4SDavid du Colombier 	char *net;
27219b2ee8SDavid du Colombier 
28219b2ee8SDavid du Colombier 	r = _sock_findrock(fd, 0);
29219b2ee8SDavid du Colombier 	if(r == 0){
30219b2ee8SDavid du Colombier 		errno = ENOTSOCK;
31219b2ee8SDavid du Colombier 		return -1;
32219b2ee8SDavid du Colombier 	}
33219b2ee8SDavid du Colombier 
34219b2ee8SDavid du Colombier 	switch(r->domain){
35219b2ee8SDavid du Colombier 	case PF_INET:
36219b2ee8SDavid du Colombier 		switch(r->stype){
37219b2ee8SDavid du Colombier 		case SOCK_DGRAM:
38219b2ee8SDavid du Colombier 			net = "udp";
39219b2ee8SDavid du Colombier 			break;
40219b2ee8SDavid du Colombier 		case SOCK_STREAM:
41219b2ee8SDavid du Colombier 			net = "tcp";
42219b2ee8SDavid du Colombier 			break;
43*781103c4SDavid du Colombier 		default:
44*781103c4SDavid du Colombier 			net = "gok";
45*781103c4SDavid du Colombier 			break;
46219b2ee8SDavid du Colombier 		}
47219b2ee8SDavid du Colombier 
48219b2ee8SDavid du Colombier 		/* get control file name from listener process */
49219b2ee8SDavid du Colombier 		n = read(fd, name, sizeof(name)-1);
50219b2ee8SDavid du Colombier 		if(n <= 0){
51219b2ee8SDavid du Colombier 			_syserrno();
52219b2ee8SDavid du Colombier 			return -1;
53219b2ee8SDavid du Colombier 		}
54219b2ee8SDavid du Colombier 		name[n] = 0;
55219b2ee8SDavid du Colombier 		cfd = open(name, O_RDWR);
56219b2ee8SDavid du Colombier 		if(cfd < 0){
57219b2ee8SDavid du Colombier 			_syserrno();
58219b2ee8SDavid du Colombier 			return -1;
59219b2ee8SDavid du Colombier 		}
60219b2ee8SDavid du Colombier 
61219b2ee8SDavid du Colombier 		nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
62219b2ee8SDavid du Colombier 		if(nfd < 0){
63219b2ee8SDavid du Colombier 			_syserrno();
64219b2ee8SDavid du Colombier 			return -1;
65219b2ee8SDavid du Colombier 		}
66219b2ee8SDavid du Colombier 
67219b2ee8SDavid du Colombier 		if(write(fd, "OK", 2) < 0){
68219b2ee8SDavid du Colombier 			close(nfd);
69219b2ee8SDavid du Colombier 			_syserrno();
70219b2ee8SDavid du Colombier 			return -1;
71219b2ee8SDavid du Colombier 		}
72219b2ee8SDavid du Colombier 
73219b2ee8SDavid du Colombier 		/* get remote address */
749a747e4fSDavid du Colombier 		ip = (struct sockaddr_in*)&nr->raddr;
75219b2ee8SDavid du Colombier 		_sock_ingetaddr(nr, ip, &n, "remote");
76219b2ee8SDavid du Colombier 		if(a){
77219b2ee8SDavid du Colombier 			memmove(a, ip, sizeof(struct sockaddr_in));
78219b2ee8SDavid du Colombier 			*alen = sizeof(struct sockaddr_in);
79219b2ee8SDavid du Colombier 		}
80219b2ee8SDavid du Colombier 
81219b2ee8SDavid du Colombier 		return nfd;
82219b2ee8SDavid du Colombier 	case PF_UNIX:
83219b2ee8SDavid du Colombier 		if(r->other >= 0){
84219b2ee8SDavid du Colombier 			errno = EGREG;
85219b2ee8SDavid du Colombier 			return -1;
86219b2ee8SDavid du Colombier 		}
87219b2ee8SDavid du Colombier 
88219b2ee8SDavid du Colombier 		for(;;){
89219b2ee8SDavid du Colombier 			/* read path to new connection */
90219b2ee8SDavid du Colombier 			n = read(fd, name, sizeof(name) - 1);
91219b2ee8SDavid du Colombier 			if(n < 0)
92219b2ee8SDavid du Colombier 				return -1;
93219b2ee8SDavid du Colombier 			if(n == 0)
94219b2ee8SDavid du Colombier 				continue;
95219b2ee8SDavid du Colombier 			name[n] = 0;
96219b2ee8SDavid du Colombier 
97219b2ee8SDavid du Colombier 			/* open new connection */
98219b2ee8SDavid du Colombier 			_sock_srvname(file, name);
99219b2ee8SDavid du Colombier 			nfd = open(file, O_RDWR);
100219b2ee8SDavid du Colombier 			if(nfd < 0)
101219b2ee8SDavid du Colombier 				continue;
102219b2ee8SDavid du Colombier 
103219b2ee8SDavid du Colombier 			/* confirm opening on new connection */
104219b2ee8SDavid du Colombier 			if(write(nfd, name, strlen(name)) > 0)
105219b2ee8SDavid du Colombier 				break;
106219b2ee8SDavid du Colombier 
107219b2ee8SDavid du Colombier 			close(nfd);
108219b2ee8SDavid du Colombier 		}
109219b2ee8SDavid du Colombier 
110219b2ee8SDavid du Colombier 		nr = _sock_newrock(nfd);
111219b2ee8SDavid du Colombier 		if(nr == 0){
112219b2ee8SDavid du Colombier 			close(nfd);
113219b2ee8SDavid du Colombier 			return -1;
114219b2ee8SDavid du Colombier 		}
115219b2ee8SDavid du Colombier 		nr->domain = r->domain;
116219b2ee8SDavid du Colombier 		nr->stype = r->stype;
117219b2ee8SDavid du Colombier 		nr->protocol = r->protocol;
118219b2ee8SDavid du Colombier 
119219b2ee8SDavid du Colombier 		return nfd;
120219b2ee8SDavid du Colombier 	default:
121219b2ee8SDavid du Colombier 		errno = EOPNOTSUPP;
122219b2ee8SDavid du Colombier 		return -1;
123219b2ee8SDavid du Colombier 	}
124219b2ee8SDavid du Colombier }
125