Use weak __thread declarations in parlib-compat (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         char *p;
34         const char *net = 0;
35         char listen[Ctlsize];
36         int open_flags;
37
38         r = _sock_findrock(fd, 0);
39         if (r == 0) {
40                 errno = ENOTSOCK;
41                 return -1;
42         }
43
44         switch (r->domain) {
45                 case PF_INET:
46                         switch (r->stype) {
47                                 case SOCK_DGRAM:
48                                         net = "udp";
49                                         break;
50                                 case SOCK_STREAM:
51                                         net = "tcp";
52                                         break;
53                         }
54                         /* at this point, our FD is for the data file.  we need to open the
55                          * listen file.  The line is stored in r->ctl (e.g.
56                          * /net/tcp/666/ctl) */
57                         strcpy(listen, r->ctl);
58                         p = strrchr(listen, '/');
59                         if (p == 0)
60                                 return -1;
61                         strcpy(p + 1, "listen");
62                         open_flags = O_RDWR;
63                         /* This is for the listen - maybe don't block on open */
64                         open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0);
65                         /* This is for the ctl we get back - maybe CLOEXEC, based on what
66                          * accept4 wants for the child */
67                         open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0);
68                         lcfd = open(listen, open_flags);
69                         if (lcfd < 0)
70                                 return -1;
71                         /* at this point, we have a new conversation, and lcfd is its ctl
72                          * fd.  nfd will be the FD for that conv's data file.  sock_data
73                          * will trade our lcfd for the data file fd.  even if it fails,
74                          * sock_data will close our lcfd for us.  when it succeeds, it'll
75                          * open the data file before closing lcfd, which will keep the
76                          * converstation alive.
77                          *
78                          * Note, we pass the listen socket's stype, but not it's sopts.  The
79                          * sopts (e.g. SOCK_NONBLOCK) apply to the original socket, not to
80                          * the new one.  Instead, we pass the accept4 flags, which are the
81                          * sopts for the new socket.  Note that this is just the sopts.
82                          * Both the listen socket and the new socket have the same stype. */
83                         nfd = _sock_data(lcfd, net, r->domain, a4_flags | r->stype,
84                                          r->protocol, &nr);
85                         if (nfd < 0)
86                                 return -1;
87
88                         /* get remote address */
89                         ip = (struct sockaddr_in *)&nr->raddr;
90                         _sock_ingetaddr(nr, ip, &n, "remote");
91                         if (addr.__sockaddr__) {
92                                 memmove(addr.__sockaddr_in__, ip, sizeof(struct sockaddr_in));
93                                 *alen = sizeof(struct sockaddr_in);
94                         }
95
96                         return nfd;
97                 case PF_UNIX:
98                         if (r->other >= 0) {
99                                 errno = EINVAL; // was EGREG
100                                 return -1;
101                         }
102
103                         for (;;) {
104                                 /* read path to new connection */
105                                 n = read(fd, name, sizeof(name) - 1);
106                                 if (n < 0)
107                                         return -1;
108                                 if (n == 0)
109                                         continue;
110                                 name[n] = 0;
111
112                                 /* open new connection */
113                                 _sock_srvname(file, name);
114                                 open_flags = O_RDWR;
115                                 /* This is for the listen - maybe don't block on open */
116                                 open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0);
117                                 /* This is for the ctl we get back - maybe CLOEXEC, based on
118                                  * what accept4 wants for the child */
119                                 open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0);
120                                 nfd = open(file, open_flags);
121                                 if (nfd < 0)
122                                         continue;
123
124                                 /* confirm opening on new connection */
125                                 if (write(nfd, name, strlen(name)) > 0)
126                                         break;
127
128                                 close(nfd);
129                         }
130
131                         nr = _sock_newrock(nfd);
132                         if (nr == 0) {
133                                 close(nfd);
134                                 return -1;
135                         }
136                         nr->domain = r->domain;
137                         nr->stype = r->stype;
138                         nr->sopts = a4_flags;
139                         nr->protocol = r->protocol;
140
141                         return nfd;
142                 default:
143                         errno = EOPNOTSUPP;
144                         return -1;
145         }
146 }
147 weak_alias(__libc_accept4, accept4)