rumpclient.c revision 1.6 1 /* $NetBSD: rumpclient.c,v 1.6 2010/11/29 16:08:03 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/param.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 do {
74 putwait(spc, &rw, &rhdr);
75 rv = dosend(spc, &rhdr, sizeof(rhdr));
76 rv = dosend(spc, data, dlen);
77 if (rv) {
78 unputwait(spc, &rw);
79 return rv;
80 }
81
82 rv = waitresp(spc, &rw);
83 } while (rv == EAGAIN);
84
85 *resp = rw.rw_data;
86 return rv;
87 }
88
89 static int
90 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
91 int wantstr)
92 {
93 struct rsp_hdr rhdr;
94 int rv;
95
96 if (wantstr)
97 dlen = MIN(dlen, strlen(data)+1);
98
99 rhdr.rsp_len = sizeof(rhdr) + dlen;
100 rhdr.rsp_reqno = reqno;
101 rhdr.rsp_class = RUMPSP_RESP;
102 rhdr.rsp_type = RUMPSP_COPYIN;
103 rhdr.rsp_sysnum = 0;
104
105 sendlock(spc);
106 rv = dosend(spc, &rhdr, sizeof(rhdr));
107 rv = dosend(spc, data, dlen);
108 sendunlock(spc);
109
110 return rv;
111 }
112
113 static int
114 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
115 {
116 struct rsp_hdr rhdr;
117 int rv;
118
119 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
120 rhdr.rsp_reqno = reqno;
121 rhdr.rsp_class = RUMPSP_RESP;
122 rhdr.rsp_type = RUMPSP_ANONMMAP;
123 rhdr.rsp_sysnum = 0;
124
125 sendlock(spc);
126 rv = dosend(spc, &rhdr, sizeof(rhdr));
127 rv = dosend(spc, &addr, sizeof(addr));
128 sendunlock(spc);
129
130 return rv;
131 }
132
133 int
134 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
135 register_t *retval)
136 {
137 struct rsp_sysresp *resp;
138 void *rdata;
139 int rv;
140
141 DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
142 sysnum, data, dlen));
143
144 rv = syscall_req(&clispc, sysnum, data, dlen, &rdata);
145 if (rv)
146 return rv;
147
148 resp = rdata;
149 DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
150 sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
151
152 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
153 rv = resp->rsys_error;
154 free(rdata);
155
156 return rv;
157 }
158
159 static void
160 handlereq(struct spclient *spc)
161 {
162 struct rsp_copydata *copydata;
163 void *mapaddr;
164 size_t maplen;
165 int reqtype = spc->spc_hdr.rsp_type;
166
167 switch (reqtype) {
168 case RUMPSP_COPYIN:
169 case RUMPSP_COPYINSTR:
170 /*LINTED*/
171 copydata = (struct rsp_copydata *)spc->spc_buf;
172 DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
173 copydata->rcp_addr, copydata->rcp_len));
174 send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
175 copydata->rcp_addr, copydata->rcp_len,
176 reqtype == RUMPSP_COPYINSTR);
177 break;
178 case RUMPSP_COPYOUT:
179 case RUMPSP_COPYOUTSTR:
180 /*LINTED*/
181 copydata = (struct rsp_copydata *)spc->spc_buf;
182 DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
183 copydata->rcp_addr, copydata->rcp_len));
184 /*LINTED*/
185 memcpy(copydata->rcp_addr, copydata->rcp_data,
186 copydata->rcp_len);
187 break;
188 case RUMPSP_ANONMMAP:
189 /*LINTED*/
190 maplen = *(size_t *)spc->spc_buf;
191 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
192 MAP_ANON, -1, 0);
193 if (mapaddr == MAP_FAILED)
194 mapaddr = NULL;
195 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
196 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
197 break;
198 default:
199 printf("PANIC: INVALID TYPE\n");
200 abort();
201 break;
202 }
203
204 spcfreebuf(spc);
205 }
206
207 int
208 rumpclient_init()
209 {
210 struct sockaddr *sap;
211 char *p;
212 unsigned idx;
213 int error, s;
214
215 if ((p = getenv("RUMP_SP_CLIENT")) == NULL) {
216 errno = ENOENT;
217 return -1;
218 }
219
220 if ((error = parseurl(p, &sap, &idx, 0)) != 0) {
221 errno = error;
222 return -1;
223 }
224
225 s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
226 if (s == -1)
227 return -1;
228
229 if (connect(s, sap, sap->sa_len) == -1) {
230 error = errno;
231 fprintf(stderr, "rump_sp: client connect failed\n");
232 errno = error;
233 return -1;
234 }
235
236 if ((error = parsetab[idx].connhook(s)) != 0) {
237 error = errno;
238 fprintf(stderr, "rump_sp: connect hook failed\n");
239 errno = error;
240 return -1;
241 }
242 clispc.spc_fd = s;
243 TAILQ_INIT(&clispc.spc_respwait);
244 pthread_mutex_init(&clispc.spc_mtx, NULL);
245 pthread_cond_init(&clispc.spc_cv, NULL);
246
247 return 0;
248 }
249