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 16 : struct NaClSimpleServiceConnection *self,
30 16 : struct NaClSimpleService *server,
31 16 : struct NaClDesc *conn,
32 16 : void *instance_data) {
33 16 : NaClLog(4,
34 : "NaClSimpleServiceConnectionCtor: self 0x%"NACL_PRIxPTR"\n",
35 : (uintptr_t) self);
36 16 : if (!NaClRefCountCtor((struct NaClRefCount *) self)) {
37 0 : return 0;
38 : }
39 16 : self->server = (struct NaClSimpleService *) NaClRefCountRef(
40 : (struct NaClRefCount *) server);
41 16 : self->connected_socket = (struct NaClDesc *) NaClRefCountRef(
42 : (struct NaClRefCount *) conn);
43 16 : self->instance_data = instance_data;
44 :
45 16 : self->thread = NULL;
46 :
47 16 : self->base.vtbl = (struct NaClRefCountVtbl const *)
48 : &kNaClSimpleServiceConnectionVtbl;
49 16 : return 1;
50 16 : }
51 :
52 3 : void NaClSimpleServiceConnectionDtor(struct NaClRefCount *vself) {
53 3 : struct NaClSimpleServiceConnection *self =
54 : (struct NaClSimpleServiceConnection *) vself;
55 :
56 3 : NaClRefCountUnref((struct NaClRefCount *) self->server);
57 3 : NaClRefCountUnref((struct NaClRefCount *) self->connected_socket);
58 :
59 3 : NACL_VTBL(NaClRefCount, self) = &kNaClRefCountVtbl;
60 3 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
61 3 : }
62 :
63 : int NaClSimpleServiceConnectionServerLoop(
64 16 : struct NaClSimpleServiceConnection *self) {
65 16 : int retval;
66 :
67 16 : NaClLog(4,
68 : "NaClSimpleServiceConnectionServerLoop: handling RPC requests from"
69 : " client at socket %"NACL_PRIxPTR"\n",
70 : (uintptr_t) self->connected_socket);
71 16 : retval = NaClSrpcServerLoop(self->connected_socket,
72 : self->server->handlers,
73 : self->instance_data);
74 16 : NaClLog(4,
75 : "NaClSimpleServiceConnectionServerLoop: NaClSrpcServerLoop exited,"
76 : " value %d\n", retval);
77 16 : 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 16 : struct NaClSimpleService *self,
92 16 : struct NaClSimpleServiceConnection *conn) {
93 32 : UNREFERENCED_PARAMETER(self);
94 :
95 16 : (*NACL_VTBL(NaClSimpleServiceConnection, conn)->ServerLoop)(
96 : conn);
97 16 : }
98 :
99 16 : static void *RpcHandlerBase(struct NaClThreadInterface *tif) {
100 16 : struct NaClSimpleServiceConnection *conn =
101 : (struct NaClSimpleServiceConnection *) tif->thread_data;
102 :
103 16 : NaClLog(4, "Entered RpcHandlerBase, invoking RpcHandler virtual fn\n");
104 16 : (*NACL_VTBL(NaClSimpleService, conn->server)->RpcHandler)(conn->server,
105 : conn);
106 16 : 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 16 : NaClRefCountUnref((struct NaClRefCount *) conn);
115 16 : return (void *) NULL;
116 : }
117 :
118 : static int NaClSimpleServiceCtorIntern(
119 563 : struct NaClSimpleService *self,
120 563 : struct NaClSrpcHandlerDesc const *srpc_handlers,
121 563 : NaClThreadIfFactoryFunction thread_factory_fn,
122 563 : void *thread_factory_data) {
123 563 : NaClLog(4,
124 : "NaClSimpleServiceCtorIntern, self 0x%"NACL_PRIxPTR"\n",
125 : (uintptr_t) self);
126 563 : if (!NaClRefCountCtor((struct NaClRefCount *) self)) {
127 0 : NaClLog(4, "NaClSimpleServiceCtorIntern: NaClRefCountCtor failed\n");
128 0 : return 0;
129 : }
130 563 : self->handlers = srpc_handlers;
131 563 : self->thread_factory_fn = thread_factory_fn;
132 563 : self->thread_factory_data = thread_factory_data;
133 563 : self->acceptor = (struct NaClThreadInterface *) NULL;
134 :
135 563 : self->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClSimpleServiceVtbl;
136 563 : NaClLog(4, "Leaving NaClSimpleServiceCtorIntern\n");
137 563 : return 1;
138 563 : }
139 :
140 : int NaClSimpleServiceCtor(
141 553 : struct NaClSimpleService *self,
142 553 : struct NaClSrpcHandlerDesc const *srpc_handlers,
143 553 : NaClThreadIfFactoryFunction thread_factory_fn,
144 553 : void *thread_factory_data) {
145 553 : NaClLog(4,
146 : "Entered NaClSimpleServiceCtor: self 0x%"NACL_PRIxPTR"\n",
147 : (uintptr_t) self);
148 :
149 553 : if (0 != NaClCommonDescMakeBoundSock(self->bound_and_cap)) {
150 0 : return 0;
151 : }
152 553 : 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 553 : return 1;
159 553 : }
160 :
161 : int NaClSimpleServiceWithSocketCtor(
162 10 : struct NaClSimpleService *self,
163 10 : struct NaClSrpcHandlerDesc const *srpc_handlers,
164 10 : NaClThreadIfFactoryFunction thread_factory_fn,
165 10 : void *thread_factory_data,
166 10 : struct NaClDesc *service_port,
167 10 : struct NaClDesc *sock_addr) {
168 10 : NaClLog(4,
169 : "NaClSimpleServiceWithSocketCtor: self 0x%"NACL_PRIxPTR"\n",
170 : (uintptr_t) self);
171 10 : if (!NaClSimpleServiceCtorIntern(self, srpc_handlers,
172 : thread_factory_fn, thread_factory_data)) {
173 0 : return 0;
174 : }
175 10 : self->bound_and_cap[0] = NaClDescRef(service_port);
176 10 : self->bound_and_cap[1] = NaClDescRef(sock_addr);
177 :
178 10 : return 1;
179 10 : }
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 15 : struct NaClSimpleService *self,
193 15 : struct NaClDesc *conn,
194 15 : void *instance_data,
195 15 : struct NaClSimpleServiceConnection **out) {
196 15 : struct NaClSimpleServiceConnection *server_conn;
197 15 : int status;
198 :
199 15 : NaClLog(4, "Entered NaClSimpleServiceConnectionFactory\n");
200 15 : server_conn = malloc(sizeof *server_conn);
201 15 : if (NULL == server_conn) {
202 0 : status = -NACL_ABI_ENOMEM;
203 0 : goto abort;
204 : }
205 15 : NaClLog(4,
206 : "NaClSimpleServiceConnectionFactory: self 0x%"NACL_PRIxPTR"\n",
207 : (uintptr_t) self);
208 15 : NaClLog(4,
209 : "NaClSimpleServiceConnectionFactory: conn 0x%"NACL_PRIxPTR"\n",
210 : (uintptr_t) conn);
211 15 : 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 15 : 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 15 : NaClLog(4,
227 : "NaClSimpleServiceConnectionFactory: constructed 0x%"NACL_PRIxPTR"\n",
228 : (uintptr_t) server_conn);
229 15 : *out = server_conn;
230 15 : status = 0;
231 : abort:
232 15 : NaClLog(4, "Leaving NaClSimpleServiceConnectionFactory: status %d\n", status);
233 15 : return status;
234 : }
235 :
236 : int NaClSimpleServiceConnectionFactory(
237 5 : struct NaClSimpleService *self,
238 5 : struct NaClDesc *conn,
239 5 : struct NaClSimpleServiceConnection **out) {
240 5 : return NaClSimpleServiceConnectionFactoryWithInstanceData(
241 : self, conn, (struct NaClRefCount *) self, out);
242 : }
243 :
244 : int NaClSimpleServiceAcceptConnection(
245 538 : struct NaClSimpleService *self,
246 538 : struct NaClSimpleServiceConnection **out) {
247 538 : int status = -NACL_ABI_EINVAL;
248 538 : struct NaClSimpleServiceConnection *conn = NULL;
249 538 : struct NaClDesc *connected_desc = NULL;
250 :
251 538 : NaClLog(4, "Entered NaClSimpleServiceAcceptConnection\n");
252 538 : conn = malloc(sizeof *conn);
253 538 : if (NULL == conn) {
254 0 : return -NACL_ABI_ENOMEM;
255 : }
256 : /* NB: conn is allocated but not constructed */
257 16 : status = (*NACL_VTBL(NaClDesc, self->bound_and_cap[0])->
258 : AcceptConn)(self->bound_and_cap[0], &connected_desc);
259 16 : 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 16 : NaClLog(4,
267 : "connected_desc is 0x%"NACL_PRIxPTR"\n",
268 : (uintptr_t) connected_desc);
269 :
270 16 : status = (*NACL_VTBL(NaClSimpleService, self)->ConnectionFactory)(
271 : self,
272 : connected_desc,
273 : &conn);
274 16 : if (0 != status) {
275 0 : NaClLog(4, "ConnectionFactory failed\n");
276 0 : goto cleanup;
277 : }
278 : /* all okay! */
279 :
280 16 : NaClLog(4,
281 : "NaClSimpleServiceAcceptConnection: conn is 0x%"NACL_PRIxPTR"\n",
282 : (uintptr_t) conn);
283 16 : NaClLog(4,
284 : "NaClSimpleServiceAcceptConnection: out is 0x%"NACL_PRIxPTR"\n",
285 : (uintptr_t) out);
286 16 : *out = conn;
287 16 : status = 0;
288 : cleanup:
289 16 : NaClRefCountSafeUnref((struct NaClRefCount *) connected_desc);
290 16 : NaClLog(4, "Leaving NaClSimpleServiceAcceptConnection, status %d\n", status);
291 16 : return status;
292 16 : }
293 :
294 : int NaClSimpleServiceAcceptAndSpawnHandler(
295 16 : struct NaClSimpleService *self) {
296 16 : struct NaClSimpleServiceConnection *conn = NULL;
297 16 : int status;
298 :
299 16 : NaClLog(4, "Entered NaClSimpleServiceAcceptAndSpawnHandler\n");
300 16 : NaClLog(4,
301 : ("NaClSimpleServiceAcceptAndSpawnHandler:"
302 : " &conn is 0x%"NACL_PRIxPTR"\n"),
303 : (uintptr_t) &conn);
304 16 : status = (*NACL_VTBL(NaClSimpleService, self)->AcceptConnection)(
305 : self,
306 : &conn);
307 16 : NaClLog(4, "AcceptConnection vfn returned %d\n", status);
308 16 : if (0 != status) {
309 0 : goto abort;
310 : }
311 16 : NaClLog(4,
312 : "NaClSimpleServiceAcceptAndSpawnHandler: conn is 0x%"NACL_PRIxPTR"\n",
313 : (uintptr_t) conn);
314 16 : NaClLog(4, "NaClSimpleServiceAcceptAndSpawnHandler: spawning thread\n");
315 :
316 48 : CHECK(NULL == conn->thread);
317 :
318 : /* ownership of |conn| reference is passed to the thread */
319 16 : 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 : status = -NACL_ABI_EAGAIN;
329 0 : goto abort;
330 : }
331 16 : status = 0;
332 : abort:
333 16 : NaClLog(4,
334 : "Leaving NaClSimpleServiceAcceptAndSpawnHandler, status %d\n",
335 : status);
336 16 : return status;
337 : }
338 :
339 : struct NaClSimpleServiceVtbl const kNaClSimpleServiceVtbl = {
340 : {
341 : NaClSimpleServiceDtor,
342 : },
343 : NaClSimpleServiceConnectionFactory,
344 : NaClSimpleServiceAcceptConnection,
345 : NaClSimpleServiceAcceptAndSpawnHandler,
346 : NaClSimpleServiceRpcHandler,
347 : };
348 :
349 :
350 523 : static void *AcceptThread(struct NaClThreadInterface *tif) {
351 523 : struct NaClSimpleService *server =
352 : (struct NaClSimpleService *) tif->thread_data;
353 :
354 523 : NaClLog(4, "Entered AcceptThread\n");
355 539 : while (0 == (*NACL_VTBL(NaClSimpleService, server)->
356 : AcceptAndSpawnHandler)(server)) {
357 16 : NaClLog(4, "AcceptThread: accepted, looping to next thread\n");
358 16 : continue;
359 : }
360 0 : NaClRefCountUnref(&server->base);
361 0 : return (void *) NULL;
362 : }
363 :
364 523 : int NaClSimpleServiceStartServiceThread(struct NaClSimpleService *server) {
365 523 : NaClLog(4, "NaClSimpleServiceStartServiceThread: spawning thread\n");
366 1569 : CHECK(server->acceptor == NULL);
367 :
368 1046 : if (!NaClThreadInterfaceConstructAndStartThread(
369 : server->thread_factory_fn,
370 : server->thread_factory_data,
371 : AcceptThread,
372 523 : NaClRefCountRef(&server->base),
373 : NACL_KERN_STACK_SIZE,
374 : &server->acceptor)) {
375 0 : NaClLog(4, "NaClSimpleServiceStartServiceThread: no thread\n");
376 0 : NaClRefCountUnref(&server->base); /* undo ref in Ctor call arglist */
377 0 : return 0;
378 : }
379 523 : NaClLog(4, "NaClSimpleServiceStartServiceThread: success\n");
380 523 : return 1;
381 523 : }
|