rumpclient.c revision 1.1 1 /* $NetBSD: rumpclient.c,v 1.1 2010/11/04 21:01:29 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 send_syscall_req(struct spclient *spc, int sysnum,
62 const void *data, size_t dlen)
63 {
64 struct rsp_hdr rhdr;
65
66 rhdr.rsp_len = sizeof(rhdr) + dlen;
67 rhdr.rsp_reqno = nextreq++;
68 rhdr.rsp_type = RUMPSP_SYSCALL_REQ;
69 rhdr.rsp_sysnum = sysnum;
70
71 dosend(spc, &rhdr, sizeof(rhdr));
72 dosend(spc, data, dlen);
73
74 return 0;
75 }
76
77 static int
78 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen)
79 {
80 struct rsp_hdr rhdr;
81
82 rhdr.rsp_len = sizeof(rhdr) + dlen;
83 rhdr.rsp_reqno = reqno;
84 rhdr.rsp_type = RUMPSP_COPYIN_RESP;
85 rhdr.rsp_sysnum = 0;
86
87 dosend(spc, &rhdr, sizeof(rhdr));
88 dosend(spc, data, dlen);
89
90 return 0;
91 }
92
93 static int
94 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
95 {
96 struct rsp_hdr rhdr;
97
98 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
99 rhdr.rsp_reqno = reqno;
100 rhdr.rsp_type = RUMPSP_ANONMMAP_RESP;
101 rhdr.rsp_sysnum = 0;
102
103 dosend(spc, &rhdr, sizeof(rhdr));
104 dosend(spc, &addr, sizeof(addr));
105
106 return 0;
107 }
108
109 int
110 rumpclient_syscall(int sysnum, const void *data, size_t dlen,
111 register_t *retval)
112 {
113 struct rsp_sysresp *resp;
114 struct rsp_copydata *copydata;
115 struct pollfd pfd;
116 size_t maplen;
117 void *mapaddr;
118 int gotresp;
119
120 DPRINTF(("rump_sp_syscall: executing syscall %d\n", sysnum));
121
122 send_syscall_req(&clispc, sysnum, data, dlen);
123
124 DPRINTF(("rump_sp_syscall: syscall %d request sent. "
125 "waiting for response\n", sysnum));
126
127 pfd.fd = clispc.spc_fd;
128 pfd.events = POLLIN;
129
130 gotresp = 0;
131 while (!gotresp) {
132 while (readframe(&clispc) < 1)
133 poll(&pfd, 1, INFTIM);
134
135 switch (clispc.spc_hdr.rsp_type) {
136 case RUMPSP_COPYIN_REQ:
137 /*LINTED*/
138 copydata = (struct rsp_copydata *)clispc.spc_buf;
139 DPRINTF(("rump_sp_syscall: copyin request: %p/%zu\n",
140 copydata->rcp_addr, copydata->rcp_len));
141 send_copyin_resp(&clispc, clispc.spc_hdr.rsp_reqno,
142 copydata->rcp_addr, copydata->rcp_len);
143 clispc.spc_off = 0;
144 break;
145 case RUMPSP_COPYOUT_REQ:
146 /*LINTED*/
147 copydata = (struct rsp_copydata *)clispc.spc_buf;
148 DPRINTF(("rump_sp_syscall: copyout request: %p/%zu\n",
149 copydata->rcp_addr, copydata->rcp_len));
150 /*LINTED*/
151 memcpy(copydata->rcp_addr, copydata->rcp_data,
152 copydata->rcp_len);
153 clispc.spc_off = 0;
154 break;
155 case RUMPSP_ANONMMAP_REQ:
156 /*LINTED*/
157 maplen = *(size_t *)clispc.spc_buf;
158 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
159 MAP_ANON, -1, 0);
160 if (mapaddr == MAP_FAILED)
161 mapaddr = NULL;
162 send_anonmmap_resp(&clispc,
163 clispc.spc_hdr.rsp_reqno, mapaddr);
164 clispc.spc_off = 0;
165 break;
166 case RUMPSP_SYSCALL_RESP:
167 DPRINTF(("rump_sp_syscall: got response \n"));
168 gotresp = 1;
169 break;
170 }
171 }
172
173 /*LINTED*/
174 resp = (struct rsp_sysresp *)clispc.spc_buf;
175 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
176 clispc.spc_off = 0;
177
178 return resp->rsys_error;
179 }
180
181 int
182 rumpclient_init()
183 {
184 struct sockaddr *sap;
185 char *p;
186 unsigned idx;
187 int error, s;
188
189 if ((p = getenv("RUMP_SP_CLIENT")) == NULL)
190 return ENOENT;
191
192 if ((error = parseurl(p, &sap, &idx, 0)) != 0)
193 return error;
194
195 s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
196 if (s == -1)
197 return errno;
198
199 if (connect(s, sap, sap->sa_len) == -1) {
200 fprintf(stderr, "rump_sp: client connect failed\n");
201 return errno;
202 }
203 if ((error = parsetab[idx].connhook(s)) != 0) {
204 fprintf(stderr, "rump_sp: connect hook failed\n");
205 return error;
206 }
207
208 clispc.spc_fd = s;
209
210 return 0;
211 }
212