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