PCI: adds device-specific data pointer
[akaros.git] / user / bsd / 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 "priv.h"
25
26 /* they've made the delcarations hurl-inducing. */
27 int
28 accept(int fd, __SOCKADDR_ARG __addr,
29        socklen_t *__restrict alen)
30 {
31         void *a = (void*)__addr;
32         int n, nfd, lcfd;
33         Rock *r, *nr;
34         struct sockaddr_in *ip;
35         char name[Ctlsize];
36         char file[8+Ctlsize+1];
37         char *p, *net;
38         char listen[Ctlsize];
39
40         r = _sock_findrock(fd, 0);
41         if(r == 0){
42                 errno = ENOTSOCK;
43                 return -1;
44         }
45
46         switch(r->domain){
47         case PF_INET:
48                 switch(r->stype){
49                 case SOCK_DGRAM:
50                         net = "udp";
51                         break;
52                 case SOCK_STREAM:
53                         net = "tcp";
54                         break;
55                 }
56                 /* at this point, our FD is for the data file.  we need to open the
57                  * listen file.  The line is stored in r->ctl (e.g. /net/tcp/666/ctl) */
58                 strcpy(listen, r->ctl);
59                 p = strrchr(listen, '/');
60                 if (p == 0)
61                         return -1;
62                 strcpy(p + 1, "listen");
63
64                 lcfd = open(listen, O_RDWR);
65                 if (lcfd < 0)
66                         return -1;
67                 /* at this point, we have a new conversation, and lcfd is its ctl fd.
68                  * nfd will be the FD for that conv's data file.  sock_data will trade
69                  * our lcfd for the data file fd.  even if it fails, sock_data will
70                  * close our lcfd for us.  when it succeeds, it'll open the data file
71                  * before closing lcfd, which will keep the converstation alive. */
72                 nfd = _sock_data(lcfd, net, r->domain, r->stype, r->protocol, &nr);
73                 if (nfd < 0)
74                         return -1;
75
76                 /* get remote address */
77                 ip = (struct sockaddr_in*)&nr->raddr;
78                 _sock_ingetaddr(nr, ip, &n, "remote");
79                 if(a){
80                         memmove(a, ip, sizeof(struct sockaddr_in));
81                         *alen = sizeof(struct sockaddr_in);
82                 }
83
84                 return nfd;
85         case PF_UNIX:
86                 if(r->other >= 0){
87                         errno = EINVAL; // was EGREG
88                         return -1;
89                 }
90
91                 for(;;){
92                         /* read path to new connection */
93                         n = read(fd, name, sizeof(name) - 1);
94                         if(n < 0)
95                                 return -1;
96                         if(n == 0)
97                                 continue;
98                         name[n] = 0;
99
100                         /* open new connection */
101                         _sock_srvname(file, name);
102                         nfd = open(file, O_RDWR);
103                         if(nfd < 0)
104                                 continue;
105
106                         /* confirm opening on new connection */
107                         if(write(nfd, name, strlen(name)) > 0)
108                                 break;
109
110                         close(nfd);
111                 }
112
113                 nr = _sock_newrock(nfd);
114                 if(nr == 0){
115                         close(nfd);
116                         return -1;
117                 }
118                 nr->domain = r->domain;
119                 nr->stype = r->stype;
120                 nr->protocol = r->protocol;
121
122                 return nfd;
123         default:
124                 errno = EOPNOTSUPP;
125                 return -1;
126         }
127 }