rumpclient.c revision 1.3 1 /* $NetBSD: rumpclient.c,v 1.3 2010/11/19 15:25:49 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * Client side routines for rump syscall proxy.
30 */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD");
34
35 #include <sys/types.h>
36 #include <sys/mman.h>
37 #include <sys/socket.h>
38
39 #include <arpa/inet.h>
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42
43 #include <assert.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <poll.h>
47 #include <pthread.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53
54 #include <rump/rumpclient.h>
55
56 #include "sp_common.c"
57
58 static struct spclient clispc;
59
60 static int
61 syscall_req(struct spclient *spc, int sysnum,
62 const void *data, size_t dlen, void **resp)
63 {
64 struct rsp_hdr rhdr;
65 struct respwait rw;
66 int rv;
67
68 rhdr.rsp_len = sizeof(rhdr) + dlen;
69 rhdr.rsp_class = RUMPSP_REQ;
70 rhdr.rsp_type = RUMPSP_SYSCALL;
71 rhdr.rsp_sysnum = sysnum;
72
73 putwait(spc, &rw, &rhdr);
74
75 sendlock(spc);
76 rv = dosend(spc, &rhdr, sizeof(rhdr));
77 rv = dosend(spc, data, dlen);
78 sendunlock(spc);
79 if (rv)
80 return rv; /* XXX: unputwait */
81
82 rv = waitresp(spc, &rw);
83 *resp = rw.rw_data;
84 return rv;
85 }
86
87 static int
88 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen)
89 {
90 struct rsp_hdr rhdr;
91 int rv;
92
93 rhdr.rsp_len = sizeof(rhdr) + dlen;
94 rhdr.rsp_reqno = reqno;
95 rhdr.rsp_class = RUMPSP_RESP;
96 rhdr.rsp_type = RUMPSP_COPYIN;
97 rhdr.rsp_sysnum = 0;
98
99 sendlock(spc);
100 rv = dosend(spc, &rhdr, sizeof(rhdr));
101 rv = dosend(spc, data, dlen);
102 sendunlock(spc);
103
104 return rv;
105 }
106
107 static int
108 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
109 {
110 struct rsp_hdr rhdr;
111 int rv;
112
113 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
114 rhdr.rsp_reqno = reqno;
115 rhdr.rsp_class = RUMPSP_RESP;
116 rhdr.rsp_type = RUMPSP_ANONMMAP;
117 rhdr.rsp_sysnum = 0;
118
119 sendlock(spc);
120 rv = dosend(spc, &rhdr, sizeof(rhdr));
121 rv = dosend(spc, &addr, sizeof(addr));
122 sendunlock(spc);
123
124 return rv;
125 }
126
127 int
128 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
129 register_t *retval)
130 {
131 struct rsp_sysresp *resp;
132 void *rdata;
133 int rv;
134
135 DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
136 sysnum, data, dlen));
137
138 rv = syscall_req(&clispc, sysnum, data, dlen, &rdata);
139 if (rv)
140 return rv;
141
142 resp = rdata;
143 DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
144 sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
145
146 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
147 rv = resp->rsys_error;
148 free(rdata);
149
150 return rv;
151 }
152
153 static void
154 handlereq(struct spclient *spc)
155 {
156 struct rsp_copydata *copydata;
157 void *mapaddr;
158 size_t maplen;
159
160 switch (spc->spc_hdr.rsp_type) {
161 case RUMPSP_COPYIN:
162 /*LINTED*/
163 copydata = (struct rsp_copydata *)spc->spc_buf;
164 DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
165 copydata->rcp_addr, copydata->rcp_len));
166 send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
167 copydata->rcp_addr, copydata->rcp_len);
168 break;
169 case RUMPSP_COPYOUT:
170 /*LINTED*/
171 copydata = (struct rsp_copydata *)spc->spc_buf;
172 DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
173 copydata->rcp_addr, copydata->rcp_len));
174 /*LINTED*/
175 memcpy(copydata->rcp_addr, copydata->rcp_data,
176 copydata->rcp_len);
177 break;
178 case RUMPSP_ANONMMAP:
179 /*LINTED*/
180 maplen = *(size_t *)spc->spc_buf;
181 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
182 MAP_ANON, -1, 0);
183 if (mapaddr == MAP_FAILED)
184 mapaddr = NULL;
185 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
186 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
187 break;
188 default:
189 printf("PANIC: INVALID TYPE\n");
190 abort();
191 break;
192 }
193
194 free(spc->spc_buf);
195 spc->spc_off = 0;
196 spc->spc_buf = NULL;
197 }
198
199 int
200 rumpclient_init()
201 {
202 struct sockaddr *sap;
203 char *p;
204 unsigned idx;
205 int error, s;
206
207 if ((p = getenv("RUMP_SP_CLIENT")) == NULL) {
208 errno = ENOENT;
209 return -1;
210 }
211
212 if ((error = parseurl(p, &sap, &idx, 0)) != 0) {
213 errno = error;
214 return -1;
215 }
216
217 s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
218 if (s == -1)
219 return -1;
220
221 if (connect(s, sap, sap->sa_len) == -1) {
222 error = errno;
223 fprintf(stderr, "rump_sp: client connect failed\n");
224 errno = error;
225 return -1;
226 }
227 if ((error = parsetab[idx].connhook(s)) != 0) {
228 error = errno;
229 fprintf(stderr, "rump_sp: connect hook failed\n");
230 errno = error;
231 return -1;
232 }
233 clispc.spc_fd = s;
234 TAILQ_INIT(&clispc.spc_respwait);
235 pthread_mutex_init(&clispc.spc_mtx, NULL);
236 pthread_cond_init(&clispc.spc_cv, NULL);
237
238 return 0;
239 }
240