net: rock: Use a helper for conversation filenames (XCC)
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / accept4.c
1 /* This file is part of the UCB release of Plan 9. It is subject to the license
2  * terms in the LICENSE file found in the top-level directory of this
3  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
4  * part of the UCB release of Plan 9, including this file, may be copied,
5  * modified, propagated, or distributed except according to the terms contained
6  * in the LICENSE file. */
7
8 /* posix */
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <string.h>
16
17 /* bsd extensions */
18 #include <sys/uio.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <sys/un.h>
22
23 #include <sys/plan9_helpers.h>
24
25 int __libc_accept4(int fd, __SOCKADDR_ARG addr, socklen_t *alen, int a4_flags)
26 {
27         int nfd, lcfd;
28         socklen_t n;
29         Rock *r, *nr;
30         struct sockaddr_in *ip;
31         char name[Ctlsize];
32         char file[8 + Ctlsize + 1];
33         const char *net = 0;
34         char listen[Ctlsize];
35         int open_flags;
36
37         r = _sock_findrock(fd, 0);
38         if (r == 0) {
39                 errno = ENOTSOCK;
40                 return -1;
41         }
42
43         switch (r->domain) {
44                 case PF_INET:
45                         switch (r->stype) {
46                                 case SOCK_DGRAM:
47                                         net = "udp";
48                                         break;
49                                 case SOCK_STREAM:
50                                         net = "tcp";
51                                         break;
52                         }
53                         /* at this point, our FD is for the data file.  we need to open the
54                          * listen file. */
55                         _sock_get_conv_filename(r, "listen", listen);
56                         open_flags = O_RDWR;
57                         /* This is for the listen - maybe don't block on open */
58                         open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0);
59                         /* This is for the ctl we get back - maybe CLOEXEC, based on what
60                          * accept4 wants for the child */
61                         open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0);
62                         lcfd = open(listen, open_flags);
63                         if (lcfd < 0)
64                                 return -1;
65                         /* at this point, we have a new conversation, and lcfd is its ctl
66                          * fd.  nfd will be the FD for that conv's data file.  sock_data
67                          * will store our lcfd in the rock and return the data file fd.
68                          *
69                          * Note, we pass the listen socket's stype, but not it's sopts.  The
70                          * sopts (e.g. SOCK_NONBLOCK) apply to the original socket, not to
71                          * the new one.  Instead, we pass the accept4 flags, which are the
72                          * sopts for the new socket.  Note that this is just the sopts.
73                          * Both the listen socket and the new socket have the same stype. */
74                         nfd = _sock_data(lcfd, net, r->domain, a4_flags | r->stype,
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                                 open_flags = O_RDWR;
106                                 /* This is for the listen - maybe don't block on open */
107                                 open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0);
108                                 /* This is for the ctl we get back - maybe CLOEXEC, based on
109                                  * what accept4 wants for the child */
110                                 open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0);
111                                 nfd = open(file, open_flags);
112                                 if (nfd < 0)
113                                         continue;
114
115                                 /* confirm opening on new connection */
116                                 if (write(nfd, name, strlen(name)) > 0)
117                                         break;
118
119                                 close(nfd);
120                         }
121
122                         nr = _sock_newrock(nfd);
123                         if (nr == 0) {
124                                 close(nfd);
125                                 return -1;
126                         }
127                         nr->domain = r->domain;
128                         nr->stype = r->stype;
129                         nr->sopts = a4_flags;
130                         nr->protocol = r->protocol;
131
132                         return nfd;
133                 default:
134                         errno = EOPNOTSUPP;
135                         return -1;
136         }
137 }
138 weak_alias(__libc_accept4, accept4)