de449f37408ea22406aa437af1472741054bd0ec
[akaros.git] / user / parlib / net.c
1 /* Copyright (c) 2014 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Networking helpers for dealing with the plan 9 interface. */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <parlib/assert.h>
12 #include <parlib/net.h>
13
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17
18 /* my cheap dial, assumes either /net/ or a protocol first, with !s btw the
19  * proto, host, and port.  it also will modify addr temporarily.  */
20 int cheap_dial(char *addr, char *local, char *dir, int *cfdp)
21 {
22         int ret, ctlfd, datafd, conv_id;
23         char *prefix;
24         char *hostname;                                         /* including !port */
25         size_t buf_len = strlen(addr) + 30;     /* 30 should be enough extra */
26         char *buf = malloc(buf_len);
27         if (!buf) {
28                 perror("Unable to malloc buf!");
29                 return -1;
30         }
31         if (local || dir) {
32                 perror("Cheap dial doesn't support local or dir");
33                 ret = -1;
34                 goto out_buf;
35         }
36         hostname = strchr(addr, '!');
37         if (!hostname) {
38                 perror("No first bang");
39                 ret = -1;
40                 goto out_buf;
41         }
42         *hostname++ = '\0';
43         prefix = (addr[0] == '/' ? "" : "/net/");
44         ret = snprintf(buf, buf_len, "%s%s/clone", prefix, addr);
45         if (snprintf_overflow(ret, buf, buf_len)) {
46                 perror("Clone chan path too long");
47                 ret = -1;
48                 goto out_readdr;
49         }
50         ctlfd = open(buf, O_RDWR);
51         if (ctlfd < 0) {
52                 perror("Can't clone a conversation");
53                 ret = -1;
54                 goto out_readdr;
55         }
56         ret = read(ctlfd, buf, buf_len - 1);
57         if (ret <= 0) {
58                 if (!ret)
59                         printf("Got early EOF from ctl\n");
60                 else
61                         perror("Can't read ctl");
62                 ret = -1;
63                 goto out_ctlfd;
64         }
65         buf[ret] = 0;
66         conv_id = atoi(buf);
67         ret = snprintf(buf, buf_len, "connect %s", hostname);
68         if (snprintf_overflow(ret, buf, buf_len)) {
69                 perror("Connect string too long");
70                 ret = -1;
71                 goto out_ctlfd;
72         }
73         if ((write(ctlfd, buf, strlen(buf)) <= 0)) {
74                 perror("Failed to connect");
75                 ret = -1;
76                 goto out_ctlfd;
77         }
78         ret = snprintf(buf, buf_len, "%s%s/%d/data", prefix, addr, conv_id);
79         if (snprintf_overflow(ret, buf, buf_len)) {
80                 perror("Data chan path too long");
81                 ret = -1;
82                 goto out_ctlfd;
83         }
84         datafd = open(buf, O_RDWR);
85         if (datafd < 0) {
86                 perror("Failed to open data chan");
87                 ret = -1;
88                 goto out_ctlfd;
89         }
90         if (cfdp)
91                 *cfdp = ctlfd;
92         else
93                 close(ctlfd);
94         ret = datafd;
95         /* skip over the ctlfd close */
96         goto out_readdr;
97
98 out_ctlfd:
99         close(ctlfd);
100 out_readdr:
101         /* restore the change we made to addr */
102         *--hostname = '!';
103 out_buf:
104         free(buf);
105         return ret;
106 }