Split socket()'s type into two Rock fields (XCC)
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / accept.c
1 /* 
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9 /* posix */
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <string.h>
17
18 /* bsd extensions */
19 #include <sys/uio.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <sys/un.h>
23
24 #include "plan9_sockets.h"
25
26 /* Await a connection on socket FD.
27    When a connection arrives, open a new socket to communicate with it,
28    set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
29    peer and *ADDR_LEN to the address's actual length, and return the
30    new socket's descriptor, or -1 for errors.  */
31 int accept(int fd, __SOCKADDR_ARG addr, socklen_t * __restrict alen)
32 {
33         int n, nfd, lcfd;
34         Rock *r, *nr;
35         struct sockaddr_in *ip;
36         char name[Ctlsize];
37         char file[8 + Ctlsize + 1];
38         char *p;
39         const char *net = 0;
40         char listen[Ctlsize];
41
42         r = _sock_findrock(fd, 0);
43         if (r == 0) {
44                 errno = ENOTSOCK;
45                 return -1;
46         }
47
48         switch (r->domain) {
49                 case PF_INET:
50                         switch (r->stype) {
51                                 case SOCK_DGRAM:
52                                         net = "udp";
53                                         break;
54                                 case SOCK_STREAM:
55                                         net = "tcp";
56                                         break;
57                         }
58                         /* at this point, our FD is for the data file.  we need to open the
59                          * listen file.  The line is stored in r->ctl (e.g. /net/tcp/666/ctl) */
60                         strcpy(listen, r->ctl);
61                         p = strrchr(listen, '/');
62                         if (p == 0)
63                                 return -1;
64                         strcpy(p + 1, "listen");
65
66                         lcfd = open(listen, O_RDWR);
67                         if (lcfd < 0)
68                                 return -1;
69                         /* at this point, we have a new conversation, and lcfd is its ctl fd.
70                          * nfd will be the FD for that conv's data file.  sock_data will trade
71                          * our lcfd for the data file fd.  even if it fails, sock_data will
72                          * close our lcfd for us.  when it succeeds, it'll open the data file
73                          * before closing lcfd, which will keep the converstation alive. */
74                         nfd = _sock_data(lcfd, net, r->domain, r->stype | r->sopts,
75                                          r->protocol, &nr);
76                         if (nfd < 0)
77                                 return -1;
78
79                         /* get remote address */
80                         ip = (struct sockaddr_in *)&nr->raddr;
81                         _sock_ingetaddr(nr, ip, &n, "remote");
82                         if (addr.__sockaddr__) {
83                                 memmove(addr.__sockaddr_in__, ip, sizeof(struct sockaddr_in));
84                                 *alen = sizeof(struct sockaddr_in);
85                         }
86
87                         return nfd;
88                 case PF_UNIX:
89                         if (r->other >= 0) {
90                                 errno = EINVAL; // was EGREG
91                                 return -1;
92                         }
93
94                         for (;;) {
95                                 /* read path to new connection */
96                                 n = read(fd, name, sizeof(name) - 1);
97                                 if (n < 0)
98                                         return -1;
99                                 if (n == 0)
100                                         continue;
101                                 name[n] = 0;
102
103                                 /* open new connection */
104                                 _sock_srvname(file, name);
105                                 nfd = open(file, O_RDWR);
106                                 if (nfd < 0)
107                                         continue;
108
109                                 /* confirm opening on new connection */
110                                 if (write(nfd, name, strlen(name)) > 0)
111                                         break;
112
113                                 close(nfd);
114                         }
115
116                         nr = _sock_newrock(nfd);
117                         if (nr == 0) {
118                                 close(nfd);
119                                 return -1;
120                         }
121                         nr->domain = r->domain;
122                         nr->stype = r->stype;
123                         nr->protocol = r->protocol;
124
125                         return nfd;
126                 default:
127                         errno = EOPNOTSUPP;
128                         return -1;
129         }
130 }
131
132 libc_hidden_def(accept)