1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
8 :
9 : #include "native_client/src/include/nacl_compiler_annotations.h"
10 :
11 : #include "native_client/src/shared/platform/nacl_check.h"
12 : #include "native_client/src/shared/platform/nacl_log.h"
13 : #include "native_client/src/shared/platform/nacl_threads.h"
14 : #include "native_client/src/shared/srpc/nacl_srpc.h"
15 :
16 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
17 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
18 : #include "native_client/src/trusted/desc/nrd_xfer.h"
19 :
20 : #include "native_client/src/trusted/nacl_base/nacl_refcount.h"
21 :
22 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
23 : /* NACL_KERN_STACK_SIZE */
24 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
25 :
26 : #include "native_client/src/trusted/threading/nacl_thread_interface.h"
27 :
28 : int NaClSimpleServiceConnectionCtor(
29 : struct NaClSimpleServiceConnection *self,
30 : struct NaClSimpleService *server,
31 : struct NaClDesc *conn,
32 0 : void *instance_data) {
33 0 : NaClLog(4,
34 : "NaClSimpleServiceConnectionCtor: self 0x%"NACL_PRIxPTR"\n",
35 : (uintptr_t) self);
36 0 : if (!NaClRefCountCtor((struct NaClRefCount *) self)) {
37 0 : return 0;
38 : }
39 0 : self->server = (struct NaClSimpleService *) NaClRefCountRef(
40 : (struct NaClRefCount *) server);
41 0 : self->connected_socket = (struct NaClDesc *) NaClRefCountRef(
42 : (struct NaClRefCount *) conn);
43 0 : self->instance_data = instance_data;
44 :
45 0 : self->thread = NULL;
46 :
47 0 : self->base.vtbl = (struct NaClRefCountVtbl const *)
48 : &kNaClSimpleServiceConnectionVtbl;
49 0 : return 1;
50 : }
51 :
52 0 : void NaClSimpleServiceConnectionDtor(struct NaClRefCount *vself) {
53 : struct NaClSimpleServiceConnection *self =
54 0 : (struct NaClSimpleServiceConnection *) vself;
55 :
56 0 : NaClRefCountUnref((struct NaClRefCount *) self->server);
57 0 : NaClRefCountUnref((struct NaClRefCount *) self->connected_socket);
58 :
59 0 : NACL_VTBL(NaClRefCount, self) = &kNaClRefCountVtbl;
60 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
61 0 : }
62 :
63 : int NaClSimpleServiceConnectionServerLoop(
64 0 : struct NaClSimpleServiceConnection *self) {
65 : int retval;
66 :
67 0 : NaClLog(4,
68 : "NaClSimpleServiceConnectionServerLoop: handling RPC requests from"
69 : " client at socket %"NACL_PRIxPTR"\n",
70 : (uintptr_t) self->connected_socket);
71 0 : retval = NaClSrpcServerLoop(self->connected_socket,
72 : self->server->handlers,
73 : self->instance_data);
74 0 : NaClLog(4,
75 : "NaClSimpleServiceConnectionServerLoop: NaClSrpcServerLoop exited,"
76 : " value %d\n", retval);
77 0 : return retval;
78 : }
79 :
80 : struct NaClSimpleServiceConnectionVtbl
81 : const kNaClSimpleServiceConnectionVtbl = {
82 : {
83 : NaClSimpleServiceConnectionDtor,
84 : },
85 : NaClSimpleServiceConnectionServerLoop,
86 : };
87 :
88 :
89 : /* default rpc_handler */
90 : void NaClSimpleServiceRpcHandler(
91 : struct NaClSimpleService *self,
92 0 : struct NaClSimpleServiceConnection *conn) {
93 : UNREFERENCED_PARAMETER(self);
94 :
95 0 : (*NACL_VTBL(NaClSimpleServiceConnection, conn)->ServerLoop)(
96 : conn);
97 0 : }
98 :
99 0 : static void *RpcHandlerBase(struct NaClThreadInterface *tif) {
100 : struct NaClSimpleServiceConnection *conn =
101 0 : (struct NaClSimpleServiceConnection *) tif->thread_data;
102 :
103 0 : NaClLog(4, "Entered RpcHandlerBase, invoking RpcHandler virtual fn\n");
104 0 : (*NACL_VTBL(NaClSimpleService, conn->server)->RpcHandler)(conn->server,
105 : conn);
106 0 : NaClLog(4, "Leaving RpcHandlerBase\n");
107 : /*
108 : * The unref of conn may Dtor the currently running thread. This is
109 : * okay, since this only removes the ability to use the thread
110 : * handle (in Windows) but does not otherwise affect the thread. We
111 : * don't log afterwards, just in case the logging code (is later
112 : * modified to) use thread info.
113 : */
114 0 : NaClRefCountUnref((struct NaClRefCount *) conn);
115 0 : return (void *) NULL;
116 : }
117 :
118 : static int NaClSimpleServiceCtorIntern(
119 : struct NaClSimpleService *self,
120 : struct NaClSrpcHandlerDesc const *srpc_handlers,
121 : NaClThreadIfFactoryFunction thread_factory_fn,
122 22 : void *thread_factory_data) {
123 22 : NaClLog(4,
124 : "NaClSimpleServiceCtorIntern, self 0x%"NACL_PRIxPTR"\n",
125 : (uintptr_t) self);
126 22 : if (!NaClRefCountCtor((struct NaClRefCount *) self)) {
127 0 : NaClLog(4, "NaClSimpleServiceCtorIntern: NaClRefCountCtor failed\n");
128 0 : return 0;
129 : }
130 22 : self->handlers = srpc_handlers;
131 22 : self->thread_factory_fn = thread_factory_fn;
132 22 : self->thread_factory_data = thread_factory_data;
133 22 : self->acceptor = (struct NaClThreadInterface *) NULL;
134 :
135 22 : self->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClSimpleServiceVtbl;
136 22 : NaClLog(4, "Leaving NaClSimpleServiceCtorIntern\n");
137 22 : return 1;
138 : }
139 :
140 : int NaClSimpleServiceCtor(
141 : struct NaClSimpleService *self,
142 : struct NaClSrpcHandlerDesc const *srpc_handlers,
143 : NaClThreadIfFactoryFunction thread_factory_fn,
144 22 : void *thread_factory_data) {
145 22 : NaClLog(4,
146 : "Entered NaClSimpleServiceCtor: self 0x%"NACL_PRIxPTR"\n",
147 : (uintptr_t) self);
148 :
149 22 : if (0 != NaClCommonDescMakeBoundSock(self->bound_and_cap)) {
150 0 : return 0;
151 : }
152 22 : if (!NaClSimpleServiceCtorIntern(self, srpc_handlers,
153 : thread_factory_fn, thread_factory_data)) {
154 0 : NaClDescUnref(self->bound_and_cap[0]);
155 0 : NaClDescUnref(self->bound_and_cap[1]);
156 0 : return 0;
157 : }
158 22 : return 1;
159 : }
160 :
161 : int NaClSimpleServiceWithSocketCtor(
162 : struct NaClSimpleService *self,
163 : struct NaClSrpcHandlerDesc const *srpc_handlers,
164 : NaClThreadIfFactoryFunction thread_factory_fn,
165 : void *thread_factory_data,
166 : struct NaClDesc *service_port,
167 0 : struct NaClDesc *sock_addr) {
168 0 : NaClLog(4,
169 : "NaClSimpleServiceWithSocketCtor: self 0x%"NACL_PRIxPTR"\n",
170 : (uintptr_t) self);
171 0 : if (!NaClSimpleServiceCtorIntern(self, srpc_handlers,
172 : thread_factory_fn, thread_factory_data)) {
173 0 : return 0;
174 : }
175 0 : self->bound_and_cap[0] = NaClDescRef(service_port);
176 0 : self->bound_and_cap[1] = NaClDescRef(sock_addr);
177 :
178 0 : return 1;
179 : }
180 :
181 0 : void NaClSimpleServiceDtor(struct NaClRefCount *vself) {
182 0 : struct NaClSimpleService *self = (struct NaClSimpleService *) vself;
183 :
184 0 : NaClRefCountSafeUnref((struct NaClRefCount *) self->bound_and_cap[0]);
185 0 : NaClRefCountSafeUnref((struct NaClRefCount *) self->bound_and_cap[1]);
186 :
187 0 : NACL_VTBL(NaClRefCount, self) = &kNaClRefCountVtbl;
188 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
189 0 : }
190 :
191 : int NaClSimpleServiceConnectionFactoryWithInstanceData(
192 : struct NaClSimpleService *self,
193 : struct NaClDesc *conn,
194 : void *instance_data,
195 0 : struct NaClSimpleServiceConnection **out) {
196 : struct NaClSimpleServiceConnection *server_conn;
197 : int status;
198 :
199 0 : NaClLog(4, "Entered NaClSimpleServiceConnectionFactory\n");
200 0 : server_conn = malloc(sizeof *server_conn);
201 0 : if (NULL == server_conn) {
202 0 : status = -NACL_ABI_ENOMEM;
203 0 : goto abort;
204 : }
205 0 : NaClLog(4,
206 : "NaClSimpleServiceConnectionFactory: self 0x%"NACL_PRIxPTR"\n",
207 : (uintptr_t) self);
208 0 : NaClLog(4,
209 : "NaClSimpleServiceConnectionFactory: conn 0x%"NACL_PRIxPTR"\n",
210 : (uintptr_t) conn);
211 0 : NaClLog(4,
212 : "NaClSimpleServiceConnectionFactory: out 0x%"NACL_PRIxPTR"\n",
213 : (uintptr_t) out);
214 : /*
215 : * In the common/degenerate case, factory instance data becomes
216 : * connection instance data.
217 : */
218 0 : if (!NaClSimpleServiceConnectionCtor(server_conn,
219 : self,
220 : conn,
221 : instance_data)) {
222 0 : free(server_conn);
223 0 : status = -NACL_ABI_EIO;
224 0 : goto abort;
225 : }
226 0 : NaClLog(4,
227 : "NaClSimpleServiceConnectionFactory: constructed 0x%"NACL_PRIxPTR"\n",
228 : (uintptr_t) server_conn);
229 0 : *out = server_conn;
230 0 : status = 0;
231 0 : abort:
232 0 : NaClLog(4, "Leaving NaClSimpleServiceConnectionFactory: status %d\n", status);
233 0 : return status;
234 : }
235 :
236 : int NaClSimpleServiceConnectionFactory(
237 : struct NaClSimpleService *self,
238 : struct NaClDesc *conn,
239 0 : struct NaClSimpleServiceConnection **out) {
240 0 : return NaClSimpleServiceConnectionFactoryWithInstanceData(
241 : self, conn, (struct NaClRefCount *) self, out);
242 : }
243 :
244 : int NaClSimpleServiceAcceptConnection(
245 : struct NaClSimpleService *self,
246 6 : struct NaClSimpleServiceConnection **out) {
247 6 : int status = -NACL_ABI_EINVAL;
248 6 : struct NaClSimpleServiceConnection *conn = NULL;
249 6 : struct NaClDesc *connected_desc = NULL;
250 :
251 6 : NaClLog(4, "Entered NaClSimpleServiceAcceptConnection\n");
252 6 : conn = malloc(sizeof *conn);
253 6 : if (NULL == conn) {
254 0 : return -NACL_ABI_ENOMEM;
255 : }
256 : /* NB: conn is allocated but not constructed */
257 6 : status = (*NACL_VTBL(NaClDesc, self->bound_and_cap[0])->
258 : AcceptConn)(self->bound_and_cap[0], &connected_desc);
259 0 : if (0 != status) {
260 0 : NaClLog(4, "Accept failed\n");
261 0 : free(conn);
262 0 : conn = NULL;
263 0 : goto cleanup;
264 : }
265 :
266 0 : NaClLog(4,
267 : "connected_desc is 0x%"NACL_PRIxPTR"\n",
268 : (uintptr_t) connected_desc);
269 :
270 0 : status = (*NACL_VTBL(NaClSimpleService, self)->ConnectionFactory)(
271 : self,
272 : connected_desc,
273 : &conn);
274 0 : if (0 != status) {
275 0 : NaClLog(4, "ConnectionFactory failed\n");
276 0 : goto cleanup;
277 : }
278 : /* all okay! */
279 :
280 0 : NaClLog(4,
281 : "NaClSimpleServiceAcceptConnection: conn is 0x%"NACL_PRIxPTR"\n",
282 : (uintptr_t) conn);
283 0 : NaClLog(4,
284 : "NaClSimpleServiceAcceptConnection: out is 0x%"NACL_PRIxPTR"\n",
285 : (uintptr_t) out);
286 0 : *out = conn;
287 0 : status = 0;
288 0 : cleanup:
289 0 : NaClRefCountSafeUnref((struct NaClRefCount *) connected_desc);
290 0 : NaClLog(4, "Leaving NaClSimpleServiceAcceptConnection, status %d\n", status);
291 0 : return status;
292 : }
293 :
294 : int NaClSimpleServiceAcceptAndSpawnHandler(
295 6 : struct NaClSimpleService *self) {
296 6 : struct NaClSimpleServiceConnection *conn = NULL;
297 : int status;
298 :
299 6 : NaClLog(4, "Entered NaClSimpleServiceAcceptAndSpawnHandler\n");
300 6 : NaClLog(4,
301 : ("NaClSimpleServiceAcceptAndSpawnHandler:"
302 : " &conn is 0x%"NACL_PRIxPTR"\n"),
303 : (uintptr_t) &conn);
304 6 : status = (*NACL_VTBL(NaClSimpleService, self)->AcceptConnection)(
305 : self,
306 : &conn);
307 0 : NaClLog(4, "AcceptConnection vfn returned %d\n", status);
308 0 : if (0 != status) {
309 0 : goto abort;
310 : }
311 0 : NaClLog(4,
312 : "NaClSimpleServiceAcceptAndSpawnHandler: conn is 0x%"NACL_PRIxPTR"\n",
313 : (uintptr_t) conn);
314 0 : NaClLog(4, "NaClSimpleServiceAcceptAndSpawnHandler: spawning thread\n");
315 :
316 0 : CHECK(NULL == conn->thread);
317 :
318 : /* ownership of |conn| reference is passed to the thread */
319 0 : if (!NaClThreadInterfaceConstructAndStartThread(
320 : self->thread_factory_fn,
321 : self->thread_factory_data,
322 : RpcHandlerBase,
323 : conn,
324 : NACL_KERN_STACK_SIZE,
325 : &conn->thread)) {
326 0 : NaClLog(4, "NaClSimpleServiceAcceptAndSpawnHandler: no thread\n");
327 0 : NaClRefCountUnref((struct NaClRefCount *) conn);
328 0 : conn = NULL;
329 0 : conn->thread = NULL;
330 0 : status = -NACL_ABI_EAGAIN;
331 0 : goto abort;
332 : }
333 0 : status = 0;
334 0 : abort:
335 0 : NaClLog(4,
336 : "Leaving NaClSimpleServiceAcceptAndSpawnHandler, status %d\n",
337 : status);
338 0 : return status;
339 : }
340 :
341 : struct NaClSimpleServiceVtbl const kNaClSimpleServiceVtbl = {
342 : {
343 : NaClSimpleServiceDtor,
344 : },
345 : NaClSimpleServiceConnectionFactory,
346 : NaClSimpleServiceAcceptConnection,
347 : NaClSimpleServiceAcceptAndSpawnHandler,
348 : NaClSimpleServiceRpcHandler,
349 : };
350 :
351 :
352 6 : static void *AcceptThread(struct NaClThreadInterface *tif) {
353 : struct NaClSimpleService *server =
354 6 : (struct NaClSimpleService *) tif->thread_data;
355 :
356 6 : NaClLog(4, "Entered AcceptThread\n");
357 12 : while (0 == (*NACL_VTBL(NaClSimpleService, server)->
358 : AcceptAndSpawnHandler)(server)) {
359 0 : NaClLog(4, "AcceptThread: accepted, looping to next thread\n");
360 : continue;
361 : }
362 0 : NaClRefCountUnref(&server->base);
363 0 : return (void *) NULL;
364 : }
365 :
366 6 : int NaClSimpleServiceStartServiceThread(struct NaClSimpleService *server) {
367 6 : NaClLog(4, "NaClSimpleServiceStartServiceThread: spawning thread\n");
368 6 : CHECK(server->acceptor == NULL);
369 :
370 6 : if (!NaClThreadInterfaceConstructAndStartThread(
371 : server->thread_factory_fn,
372 : server->thread_factory_data,
373 : AcceptThread,
374 : NaClRefCountRef(&server->base),
375 : NACL_KERN_STACK_SIZE,
376 : &server->acceptor)) {
377 0 : NaClLog(4, "NaClSimpleServiceStartServiceThread: no thread\n");
378 0 : NaClRefCountUnref(&server->base); /* undo ref in Ctor call arglist */
379 0 : server->acceptor = NULL;
380 0 : return 0;
381 : }
382 6 : NaClLog(4, "NaClSimpleServiceStartServiceThread: success\n");
383 6 : return 1;
384 : }
|