xref: /plan9/sys/src/ape/lib/bsd/accept.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
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 <errno.h>
8 #include <string.h>
9 
10 /* bsd extensions */
11 #include <sys/uio.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <sys/un.h>
15 
16 #include "priv.h"
17 
18 int
19 accept(int fd, void *a, int *alen)
20 {
21 	int n, nfd, cfd;
22 	Rock *r, *nr;
23 	struct sockaddr_in *ip;
24 	char name[Ctlsize];
25 	char file[8+Ctlsize+1];
26 	char *net;
27 
28 	r = _sock_findrock(fd, 0);
29 	if(r == 0){
30 		errno = ENOTSOCK;
31 		return -1;
32 	}
33 
34 	switch(r->domain){
35 	case PF_INET:
36 		switch(r->stype){
37 		case SOCK_DGRAM:
38 			net = "udp";
39 			break;
40 		case SOCK_STREAM:
41 			net = "tcp";
42 			break;
43 		default:
44 			net = "gok";
45 			break;
46 		}
47 
48 		/* get control file name from listener process */
49 		n = read(fd, name, sizeof(name)-1);
50 		if(n <= 0){
51 			_syserrno();
52 			return -1;
53 		}
54 		name[n] = 0;
55 		cfd = open(name, O_RDWR);
56 		if(cfd < 0){
57 			_syserrno();
58 			return -1;
59 		}
60 
61 		nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
62 		if(nfd < 0){
63 			_syserrno();
64 			return -1;
65 		}
66 
67 		if(write(fd, "OK", 2) < 0){
68 			close(nfd);
69 			_syserrno();
70 			return -1;
71 		}
72 
73 		/* get remote address */
74 		ip = (struct sockaddr_in*)&nr->raddr;
75 		_sock_ingetaddr(nr, ip, &n, "remote");
76 		if(a){
77 			memmove(a, ip, sizeof(struct sockaddr_in));
78 			*alen = sizeof(struct sockaddr_in);
79 		}
80 
81 		return nfd;
82 	case PF_UNIX:
83 		if(r->other >= 0){
84 			errno = EGREG;
85 			return -1;
86 		}
87 
88 		for(;;){
89 			/* read path to new connection */
90 			n = read(fd, name, sizeof(name) - 1);
91 			if(n < 0)
92 				return -1;
93 			if(n == 0)
94 				continue;
95 			name[n] = 0;
96 
97 			/* open new connection */
98 			_sock_srvname(file, name);
99 			nfd = open(file, O_RDWR);
100 			if(nfd < 0)
101 				continue;
102 
103 			/* confirm opening on new connection */
104 			if(write(nfd, name, strlen(name)) > 0)
105 				break;
106 
107 			close(nfd);
108 		}
109 
110 		nr = _sock_newrock(nfd);
111 		if(nr == 0){
112 			close(nfd);
113 			return -1;
114 		}
115 		nr->domain = r->domain;
116 		nr->stype = r->stype;
117 		nr->protocol = r->protocol;
118 
119 		return nfd;
120 	default:
121 		errno = EOPNOTSUPP;
122 		return -1;
123 	}
124 }
125