Stop using snprintf in write_hex_to_fd (XCC)
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / plan9_sockets.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 #include <assert.h>
18
19 /* bsd extensions */
20 #include <sys/uio.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <sys/un.h>
24 #include <arpa/inet.h>
25
26 #include <sys/plan9_helpers.h>
27
28 void
29 _sock_ingetaddr(Rock * r, struct sockaddr_in *ip, socklen_t * alen,
30                                 const char *a)
31 {
32         int n, fd;
33         char *p;
34         char name[Ctlsize];
35
36         /* get remote address */
37         strcpy(name, r->ctl);
38         p = strrchr(name, '/');
39         strcpy(p + 1, a);
40         fd = open(name, O_RDONLY);
41         if (fd >= 0) {
42                 n = read(fd, name, sizeof(name) - 1);
43                 if (n > 0) {
44                         name[n] = 0;
45                         p = strchr(name, '!');
46                         if (p) {
47                                 *p++ = 0;
48                                 ip->sin_family = AF_INET;
49                                 ip->sin_port = htons(atoi(p));
50                                 ip->sin_addr.s_addr = inet_addr(name);
51                                 if (alen)
52                                         *alen = sizeof(struct sockaddr_in);
53                         }
54                 }
55                 close(fd);
56         }
57
58 }
59
60 /*
61  *  return ndb attribute type of an ip name
62  */
63 int _sock_ipattr(const char *name)
64 {
65         const char *p;
66         int dot = 0;
67         int alpha = 0;
68
69         for (p = name; *p; p++) {
70                 if (isdigit(*p)) ;
71                 else if (isalpha(*p) || *p == '-')
72                         alpha = 1;
73                 else if (*p == '.')
74                         dot = 1;
75                 else
76                         return Tsys;
77         }
78
79         if (alpha) {
80                 if (dot)
81                         return Tdom;
82                 else
83                         return Tsys;
84         }
85
86         if (dot)
87                 return Tip;
88         else
89                 return Tsys;
90 }
91
92 /* we can't avoid overrunning npath because we don't know how big it is. */
93 void _sock_srvname(char *npath, char *path)
94 {
95         char *p;
96
97         strcpy(npath, "/srv/UD.");
98         p = strrchr(path, '/');
99         if (p == 0)
100                 p = path;
101         else
102                 p++;
103         strcat(npath, p);
104 }
105
106 int _sock_srv(char *path, int fd)
107 {
108         int sfd;
109         char msg[8 + 256 + 1];
110
111         /* change the path to something in srv */
112         _sock_srvname(msg, path);
113
114         /* remove any previous instance */
115         unlink(msg);
116
117         /* put the fd in /srv and then close it */
118         sfd = creat(msg, 0666);
119         if (sfd < 0) {
120                 close(fd);
121                 return -1;
122         }
123         snprintf(msg, sizeof msg, "%d", fd);
124         if (write(sfd, msg, strlen(msg)) < 0) {
125                 close(sfd);
126                 close(fd);
127                 return -1;
128         }
129         close(sfd);
130         close(fd);
131         return 0;
132 }
133
134 #warning "Not threadsafe!"
135 Rock *_sock_rock;
136
137 Rock *_sock_findrock(int fd, struct stat * dp)
138 {
139         Rock *r;
140         struct stat d;
141
142         /* Skip the fstat if there are no socket rocks */
143         if (!_sock_rock)
144                 return 0;
145         /* If they pass us a struct stat, then they already did an fstat */
146         if (dp == 0) {
147                 dp = &d;
148                 fstat(fd, dp);
149         }
150         for (r = _sock_rock; r; r = r->next) {
151                 if (r->inode == dp->st_ino && r->dev == dp->st_dev)
152                         break;
153         }
154         return r;
155 }
156
157 Rock *_sock_newrock(int fd)
158 {
159         Rock *r;
160         struct stat d;
161
162         fstat(fd, &d);
163         r = _sock_findrock(fd, &d);
164         if (r == 0) {
165                 r = malloc(sizeof(Rock));
166                 if (r == 0)
167                         return 0;
168                 r->dev = d.st_dev;
169                 r->inode = d.st_ino;
170                 /* TODO: this is not thread-safe! */
171                 r->next = _sock_rock;
172                 _sock_rock = r;
173         }
174         assert(r->dev == d.st_dev);
175         assert(r->inode == d.st_ino);
176         r->domain = 0;
177         r->stype = 0;
178         r->sopts = 0;
179         r->protocol = 0;
180         memset(&r->addr, 0, sizeof(r->addr_stor));
181         r->reserved = 0;
182         memset(&r->raddr, 0, sizeof(r->raddr_stor));
183         r->ctl[0] = '\0';
184         r->other = -1;
185         r->is_listener = FALSE;
186         r->listen_fd = -1;
187         return r;
188 }
189
190 void _sock_fd_closed(int fd)
191 {
192         Rock *r = _sock_findrock(fd, 0);
193
194         if (!r)
195                 return;
196         if (r->is_listener)
197                 close(r->listen_fd);
198 }
199
200 /* For a ctlfd and a few other settings, it opens and returns the corresponding
201  * datafd.  This will close cfd for you. */
202 int _sock_data(int cfd, const char *net, int domain, int type, int protocol,
203                Rock **rp)
204 {
205         int n, fd;
206         Rock *r;
207         char name[Ctlsize];
208         int open_flags = O_RDWR;
209
210         /* get the data file name */
211         n = read(cfd, name, sizeof(name) - 1);
212         if (n < 0) {
213                 close(cfd);
214                 errno = ENOBUFS;
215                 return -1;
216         }
217         name[n] = 0;
218         n = strtoul(name, 0, 0);
219         snprintf(name, sizeof name, "/net/%s/%d/data", net, n);
220
221         /* open data file */
222         open_flags |= (type & SOCK_NONBLOCK ? O_NONBLOCK : 0);
223         fd = open(name, open_flags);
224         close(cfd);     /* close this no matter what */
225         if (fd < 0) {
226                 errno = ENOBUFS;
227                 return -1;
228         }
229
230         /* hide stuff under the rock */
231         snprintf(name, sizeof name, "/net/%s/%d/ctl", net, n);
232         r = _sock_newrock(fd);
233         if (r == 0) {
234                 errno = ENOBUFS;
235                 close(fd);
236                 return -1;
237         }
238         if (rp)
239                 *rp = r;
240         memset(&r->raddr, 0, sizeof(r->raddr_stor));
241         memset(&r->addr, 0, sizeof(r->addr_stor));
242         r->domain = domain;
243         r->stype = _sock_strip_opts(type);
244         r->sopts = _sock_get_opts(type);
245         r->protocol = protocol;
246         strcpy(r->ctl, name);
247         return fd;
248 }
249
250 /* Takes network-byte ordered IPv4 addr and writes it into buf, in the plan 9 IP
251  * addr format */
252 void naddr_to_plan9addr(uint32_t sin_addr, uint8_t * buf)
253 {
254         uint8_t *sin_bytes = (uint8_t *) & sin_addr;
255         memset(buf, 0, 10);
256         buf += 10;
257         buf[0] = 0xff;
258         buf[1] = 0xff;
259         buf += 2;
260         buf[0] = sin_bytes[0];  /* e.g. 192 */
261         buf[1] = sin_bytes[1];  /* e.g. 168 */
262         buf[2] = sin_bytes[2];  /* e.g.   0 */
263         buf[3] = sin_bytes[3];  /* e.g.   1 */
264 }
265
266 /* does v4 only */
267 uint32_t plan9addr_to_naddr(uint8_t * buf)
268 {
269         buf += 12;
270         return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
271 }
272
273 /* Returns a rock* if the socket exists and is UDP */
274 Rock *udp_sock_get_rock(int fd)
275 {
276         Rock *r = _sock_findrock(fd, 0);
277         if (!r) {
278                 errno = ENOTSOCK;
279                 return 0;
280         }
281         if ((r->domain == PF_INET) && (r->stype == SOCK_DGRAM))
282                 return r;
283         else
284                 return 0;
285 }
286
287 /* In Linux, socket options are multiplexed in the socket type. */
288 int _sock_strip_opts(int type)
289 {
290         return type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
291 }
292
293 int _sock_get_opts(int type)
294 {
295         return type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
296 }
297
298 /* Opens the FD for "listen", and attaches it to the Rock.  When the dfd (and
299  * thus the Rock) closes, we'll close the listen file too.  Returns the FD on
300  * success, -1 on error. */
301 int _rock_open_listen_fd(Rock *r)
302 {
303         char listen_file[Ctlsize + 3];
304         char *x, *last_ctl;
305         int ret;
306
307         if (!r->is_listener)
308                 return -1;
309         strncpy(listen_file, r->ctl, sizeof(listen_file));
310         /* We want the conversation directory.  We can find the last "ctl"
311          * in the CTL name (they could have mounted at /ctlfoo/net/) */
312         x = listen_file;
313         do {
314                 last_ctl = x;
315                 x++;    /* move forward enough to not find the same "ctl" */
316                 x = strstr(x, "ctl");
317         } while (x);
318         /* last_ctl is either listen_file (if we never found ctl, which should never
319          * happen) or it points at the 'c' in the last "ctl". */
320         assert(last_ctl != listen_file);
321         strcpy(last_ctl, "listen");
322         ret = open(listen_file, O_PATH);
323         /* Probably a bug in the rock code (or the kernel!) if we couldn't walk to
324          * our listen. */
325         assert(ret >= 0);
326         r->listen_fd = ret;
327         return ret;
328 }
329
330 /* Used by user/iplib (e.g. epoll).  Looks up the FD listen file for this
331  * conversation.  Returns -1 if the FD is not a listener. */
332 int _sock_lookup_listen_fd(int sock_fd)
333 {
334         Rock *r = _sock_findrock(sock_fd, 0);
335
336         if (!r)
337                 return -1;
338         if (!r->is_listener)
339                 return -1;
340         return r->listen_fd;
341 }
342
343 /* Given an FD, opens the FD with the name 'sibling' in the same directory.
344  * e.g., you have a data, you open a ctl.  Don't use this with cloned FDs (i.e.
345  * open clone, get a ctl back) until we fix 9p and fd2path. */
346 int get_sibling_fd(int fd, const char *sibling)
347 {
348         char path[MAX_PATH_LEN];
349         char *graft;
350
351         if (syscall(SYS_fd2path, fd, path, sizeof(path)) < 0)
352                 return -1;
353         graft = strrchr(path, '/');
354         if (!graft)
355                 return -1;
356         graft++;
357         *graft = 0;
358         snprintf(graft, sizeof(path) - strlen(path), sibling);
359         return open(path, O_RDWR);
360 }
361
362 /* Writes num to FD in ASCII in hex format. */
363 int write_hex_to_fd(int fd, uint64_t num)
364 {
365         int ret;
366         char cmd[50];
367         char *ptr;
368
369         ptr = u64_to_str(num, cmd, sizeof(cmd));
370         if (!ptr)
371                 return -1;
372         ret = write(fd, ptr, sizeof(cmd) - (ptr - cmd));
373         if (ret <= 0)
374                 return -1;
375         return 0;
376 }
377
378 /* Returns a char representing the lowest 4 bits of x */
379 static char num_to_nibble(unsigned int x)
380 {
381         return "0123456789abcdef"[x & 0xf];
382 }
383
384 /* Converts num to a string, in hex, using buf as storage.  Returns a pointer to
385  * the string from within your buf, or 0 on failure. */
386 char *u64_to_str(uint64_t num, char *buf, size_t len)
387 {
388         char *ptr;
389         size_t nr_nibbles = sizeof(num) * 8 / 4;
390
391         /* 3: 0, x, and \0 */
392         if (len < nr_nibbles + 3)
393                 return 0;
394         ptr = &buf[len - 1];
395         /* Build the string backwards */
396         *ptr = '\0';
397         for (int i = 0; i < nr_nibbles; i++) {
398                 ptr--;
399                 *ptr = num_to_nibble(num);
400                 num >>= 4;
401         }
402         ptr--;
403         *ptr = 'x';
404         ptr--;
405         *ptr = '0';
406         return ptr;
407 }