Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / nacl_secure_service.c
1 /*
2  * Copyright (c) 2012 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/service_runtime/nacl_secure_service.h"
8
9 #include <string.h>
10
11 #include "native_client/src/public/secure_service.h"
12
13 #include "native_client/src/shared/platform/nacl_exit.h"
14 #include "native_client/src/shared/platform/nacl_log.h"
15 #include "native_client/src/shared/platform/nacl_sync.h"
16 #include "native_client/src/shared/platform/nacl_sync_checked.h"
17 #include "native_client/src/shared/srpc/nacl_srpc.h"
18
19 #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
20 #include "native_client/src/trusted/fault_injection/fault_injection.h"
21 #include "native_client/src/trusted/manifest_name_service_proxy/manifest_proxy.h"
22 #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
23 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
24 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
25 #include "native_client/src/trusted/service_runtime/nacl_app.h"
26 #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
27 #include "native_client/src/trusted/service_runtime/nacl_reverse_host_interface.h"
28 #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
29 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
30 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
31
32 struct NaClSrpcHandlerDesc const kNaClSecureServiceHandlers[];
33
34 int NaClSecureServiceCtor(struct NaClSecureService  *self,
35                           struct NaClApp            *nap,
36                           struct NaClDesc           *service_port,
37                           struct NaClDesc           *sock_addr) {
38   NaClLog(4,
39           "Entered NaClSecureServiceCtor: self 0x%"NACL_PRIxPTR"\n",
40           (uintptr_t) self);
41   if (NACL_FI_ERROR_COND(
42           "NaClSecureServiceCtor__NaClSimpleServiceWithSocketCtor",
43           !NaClSimpleServiceWithSocketCtor(
44               &self->base,
45               kNaClSecureServiceHandlers,
46               NaClThreadInterfaceThreadFactory,
47               (void *) self,
48               service_port,
49               sock_addr))) {
50     goto done;
51   }
52   if (!NaClMutexCtor(&self->mu)) {
53     NaClLog(4, "NaClMutexCtor failed\n");
54     goto failure_mutex_ctor;
55   }
56   if (!NaClCondVarCtor(&self->cv)) {
57     NaClLog(4, "NaClCondVar failed\n");
58     goto failure_condvar_ctor;
59   }
60   NaClXMutexCtor(&self->mu);
61   NaClXCondVarCtor(&self->cv);
62   self->nap = nap;
63   self->reverse_channel_initialization_state =
64       NACL_REVERSE_CHANNEL_UNINITIALIZED;
65   self->reverse_client = NULL;
66   self->conn_count = 0;
67   NACL_VTBL(NaClRefCount, self) =
68       (struct NaClRefCountVtbl *) &kNaClSecureServiceVtbl;
69   return 1;
70
71  failure_condvar_ctor:
72   NaClMutexDtor(&self->mu);
73  failure_mutex_ctor:
74   (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
75  done:
76   return 0;
77 }
78
79 void NaClSecureServiceDtor(struct NaClRefCount *vself) {
80   struct NaClSecureService *self = (struct NaClSecureService *) vself;
81
82   NaClXMutexLock(&self->mu);
83   if (NACL_REVERSE_CHANNEL_UNINITIALIZED !=
84       self->reverse_channel_initialization_state) {
85     while (NACL_REVERSE_CHANNEL_INITIALIZED !=
86            self->reverse_channel_initialization_state) {
87       NaClXCondVarWait(&self->cv, &self->mu);
88     }
89   }
90
91   if (0 != self->conn_count) {
92     NaClLog(LOG_FATAL,
93             "SecureService dtor when connection count is nonzero\n");
94   }
95   self->conn_count = 0;
96
97   if (NACL_REVERSE_CHANNEL_INITIALIZED ==
98       self->reverse_channel_initialization_state) {
99     NaClSrpcDtor(&self->reverse_channel);
100   }
101   if (NULL != self->reverse_client) {
102     NaClRefCountUnref((struct NaClRefCount *) self->reverse_client);
103   }
104   NaClXMutexUnlock(&self->mu);
105
106   NaClCondVarDtor(&self->cv);
107   NaClMutexDtor(&self->mu);
108
109   NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl const *)
110       &kNaClSimpleServiceVtbl;
111   (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
112 }
113
114 int NaClSecureServiceConnectionFactory(
115     struct NaClSimpleService            *vself,
116     struct NaClDesc                     *conn,
117     struct NaClSimpleServiceConnection  **out) {
118   /* our instance_data is not connection specific */
119   return NaClSimpleServiceConnectionFactoryWithInstanceData(
120       vself, conn, (struct NaClSecureService *) vself, out);
121 }
122
123 static void NaClSecureServiceConnectionCountIncr(
124     struct NaClSecureService *self) {
125   NaClLog(5, "NaClSecureServiceThreadCountIncr\n");
126   NaClXMutexLock(&self->mu);
127   if (0 == ++self->conn_count) {
128     NaClLog(LOG_FATAL,
129             "NaClSecureServiceThreadCountIncr: "
130             "thread count overflow!\n");
131   }
132   NaClXMutexUnlock(&self->mu);
133 }
134
135 static void NaClSecureServiceConnectionCountDecr(
136     struct NaClSecureService *self) {
137   uint32_t conn_count;
138
139   NaClLog(5, "NaClSecureServiceThreadCountDecr\n");
140   NaClXMutexLock(&self->mu);
141   if (0 == self->conn_count) {
142     NaClLog(LOG_FATAL,
143             "NaClSecureServiceThreadCountDecr: "
144             "decrementing thread count when count is zero\n");
145   }
146   conn_count = --self->conn_count;
147   NaClXMutexUnlock(&self->mu);
148
149   if (0 == conn_count) {
150     NaClLog(4, "NaClSecureServiceThread: all channels closed, exiting.\n");
151     /*
152      * Set that we are killed by SIGKILL so that debug stub could report
153      * this to debugger.
154      */
155     NaClAppShutdown(self->nap, NACL_ABI_W_EXITCODE(0, NACL_ABI_SIGKILL));
156   }
157 }
158
159 int NaClSecureServiceAcceptConnection(
160     struct NaClSimpleService            *vself,
161     struct NaClSimpleServiceConnection  **vconn) {
162   struct NaClSecureService *self =
163     (struct NaClSecureService *) vself;
164   int status;
165
166   NaClLog(4, "NaClSecureServiceAcceptConnection\n");
167   status = (*kNaClSimpleServiceVtbl.AcceptConnection)(vself, vconn);
168   if (0 == status) {
169     NaClSecureServiceConnectionCountIncr(self);
170   }
171   NaClLog(4, "Leaving NaClSecureServiceAcceptConnection, status %d.\n", status);
172   return status;
173 }
174
175 void NaClSecureServiceRpcHandler(struct NaClSimpleService           *vself,
176                                  struct NaClSimpleServiceConnection *vconn) {
177   struct NaClSecureService *self =
178     (struct NaClSecureService *) vself;
179
180   NaClLog(4, "NaClSecureChannelThread started\n");
181   (*kNaClSimpleServiceVtbl.RpcHandler)(vself, vconn);
182   NaClLog(4, "NaClSecureChannelThread closed.\n");
183   NaClSecureServiceConnectionCountDecr(self);
184 }
185
186 static void NaClSecureServiceLoadModuleRpcCallback(
187     void            *instance_data,
188     NaClErrorCode   status) {
189   struct NaClSrpcClosure *done_cls =
190       (struct NaClSrpcClosure *) instance_data;
191   UNREFERENCED_PARAMETER(status);
192   NaClLog(4, "NaClSecureChannelLoadModuleRpcCallback: status %d\n", status);
193   (*done_cls->Run)(done_cls);
194 }
195
196 static void NaClSecureServiceLoadModuleRpc(
197     struct NaClSrpcRpc      *rpc,
198     struct NaClSrpcArg      **in_args,
199     struct NaClSrpcArg      **out_args,
200     struct NaClSrpcClosure  *done_cls) {
201   struct NaClSecureService        *nssp =
202       (struct NaClSecureService *) rpc->channel->server_instance_data;
203   struct NaClDesc                 *nexe = in_args[0]->u.hval;
204   UNREFERENCED_PARAMETER(out_args);
205
206   NaClLog(4, "NaClSecureServiceLoadModuleRpc: loading module\n");
207   rpc->result = NACL_SRPC_RESULT_OK;
208   NaClAppLoadModule(nssp->nap,
209                     nexe,
210                     NaClSecureServiceLoadModuleRpcCallback,
211                     (void *) done_cls);
212   NaClDescUnref(nexe);
213   nexe = NULL;
214
215   NaClLog(4, "NaClSecureServiceLoadModuleRpc: done\n");
216 }
217
218 /*
219  * The first connection is performed by this callback handler.  This
220  * spawns a client thread that will bootstrap the other connections by
221  * stashing the connection represented by |conn| to make reverse RPCs
222  * to ask the peer to connect to us.  No thread is spawned; we just
223  * wrap access to the connection with a lock.
224  *
225  * Subsequent connection callbacks will pass the connection to the
226  * actual thread that made the connection request using |conn|
227  * received in the first connection.
228  */
229 static void NaClSecureReverseClientCallback(
230     void                        *state,
231     struct NaClThreadInterface  *tif,
232     struct NaClDesc             *new_conn) {
233   struct NaClSecureService          *self =
234       (struct NaClSecureService *) state;
235   struct NaClApp                    *nap = self->nap;
236   struct NaClManifestProxy          *manifest_proxy;
237   struct NaClReverseHostInterface   *reverse_host_interface;
238   struct NaClReverseQuotaInterface  *reverse_quota_interface;
239   UNREFERENCED_PARAMETER(tif);
240
241   NaClLog(4,
242           ("Entered NaClSecureReverseClientCallback: self 0x%"NACL_PRIxPTR","
243            " nap 0x%"NACL_PRIxPTR", new_conn 0x%"NACL_PRIxPTR"\n"),
244           (uintptr_t) self, (uintptr_t) nap, (uintptr_t) new_conn);
245
246   NaClXMutexLock(&self->mu);
247   if (NACL_REVERSE_CHANNEL_INITIALIZATING !=
248       self->reverse_channel_initialization_state) {
249     /*
250      * The reverse channel connection capability is used to make the
251      * RPC that invokes this callback (this callback is invoked on a
252      * reverse channel connect), so the plugin wants to initialize the
253      * reverse channel and in particular the state must be either be
254      * in-progress or finished.
255      */
256     NaClLog(LOG_FATAL, "Reverse channel already initialized\n");
257   }
258   NaClXMutexUnlock(&self->mu);
259   if (!NaClSrpcClientCtor(&self->reverse_channel, new_conn)) {
260     NaClLog(LOG_FATAL, "Reverse channel SRPC Client Ctor failed\n");
261     goto done;
262   }
263   reverse_host_interface = (struct NaClReverseHostInterface *)
264     malloc(sizeof *reverse_host_interface);
265   if (NULL == reverse_host_interface ||
266       NACL_FI_ERROR_COND(
267           ("NaClSecureReverseClientCallback"
268            "__NaClReverseInterfaceCtor"),
269           !NaClReverseHostInterfaceCtor(reverse_host_interface,
270                                         self))) {
271     NaClLog(LOG_FATAL, "Reverse interface ctor failed\n");
272     goto cleanup_reverse_host_interface;
273   }
274   NaClAppRuntimeHostSetup(nap, (struct NaClRuntimeHostInterface *)
275       reverse_host_interface);
276
277   reverse_quota_interface = (struct NaClReverseQuotaInterface *)
278     malloc(sizeof *reverse_quota_interface);
279   if (NULL == reverse_quota_interface ||
280       NACL_FI_ERROR_COND(
281           ("NaClSecureReverseClientCallback"
282            "__NaClReverseQuotaInterfaceCtor"),
283           !NaClReverseQuotaInterfaceCtor(reverse_quota_interface,
284                                          self))) {
285     NaClLog(LOG_FATAL, "Reverse quota interface ctor failed\n");
286     goto cleanup_reverse_quota_interface;
287   }
288   NaClAppDescQuotaSetup(nap, (struct NaClDescQuotaInterface *)
289       reverse_quota_interface);
290
291   NaClRefCountSafeUnref((struct NaClRefCount *) reverse_quota_interface);
292   reverse_quota_interface = NULL;
293
294   manifest_proxy = (struct NaClManifestProxy *)
295       malloc(sizeof *manifest_proxy);
296   if (NULL == manifest_proxy ||
297       !NaClManifestProxyCtor(manifest_proxy,
298                              NaClAddrSpSquattingThreadIfFactoryFunction,
299                              (void *) nap,
300                              self)) {
301     NaClLog(LOG_FATAL, "Manifest proxy ctor failed\n");
302     goto cleanup_manifest_proxy;
303   }
304
305   /*
306    * NaClSimpleServiceStartServiceThread requires the nap->mu lock.
307    */
308   if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
309                                            manifest_proxy)) {
310     NaClLog(LOG_FATAL, "ManifestProxy start service failed\n");
311     goto cleanup_manifest_proxy;
312   }
313
314   NaClXMutexLock(&nap->mu);
315   (*NACL_VTBL(NaClNameService, nap->name_service)->
316     CreateDescEntry)(nap->name_service,
317                      "ManifestNameService", NACL_ABI_O_RDWR,
318                      NaClDescRef(manifest_proxy->base.bound_and_cap[1]));
319   NaClXMutexUnlock(&nap->mu);
320
321   NaClXMutexLock(&self->mu);
322   self->reverse_channel_initialization_state =
323     NACL_REVERSE_CHANNEL_INITIALIZED;
324   NaClXCondVarBroadcast(&self->cv);
325   NaClXMutexUnlock(&self->mu);
326
327  cleanup_manifest_proxy:
328   NaClRefCountSafeUnref((struct NaClRefCount *) manifest_proxy);
329  cleanup_reverse_quota_interface:
330   NaClRefCountSafeUnref((struct NaClRefCount *) reverse_quota_interface);
331  cleanup_reverse_host_interface:
332   NaClRefCountSafeUnref((struct NaClRefCount *) reverse_host_interface);
333  done:
334   NaClLog(4, "Leaving NaClSecureReverseClientCallback\n");
335 }
336
337 static void NaClSecureServiceReverseSetupRpc(
338     struct NaClSrpcRpc      *rpc,
339     struct NaClSrpcArg      **in_args,
340     struct NaClSrpcArg      **out_args,
341     struct NaClSrpcClosure  *done_cls) {
342   struct NaClSecureService        *nssp =
343       (struct NaClSecureService *) rpc->channel->server_instance_data;
344   struct NaClDesc                 *rev_addr = NULL;
345   struct NaClSecureReverseClient  *rev;
346   UNREFERENCED_PARAMETER(in_args);
347
348   NaClLog(4, "NaClSecureServiceReverseSetupRpc: reverse setup\n");
349
350   NaClXMutexLock(&nssp->mu);
351   if (NACL_REVERSE_CHANNEL_UNINITIALIZED !=
352       nssp->reverse_channel_initialization_state) {
353     NaClLog(LOG_ERROR, "NaClSecureServiceReverseSetupRpc:"
354             " reverse channel initialization state not uninitialized\n");
355     rpc->result = NACL_SRPC_RESULT_APP_ERROR;
356     goto cleanup;
357   }
358   nssp->reverse_channel_initialization_state =
359       NACL_REVERSE_CHANNEL_INITIALIZATING;
360   NaClXCondVarBroadcast(&nssp->cv);
361
362   /* the reverse connection is still coming */
363   rev = (struct NaClSecureReverseClient *) malloc(sizeof *rev);
364   if (NULL == rev) {
365     rpc->result = NACL_SRPC_RESULT_NO_MEMORY;
366     goto cleanup;
367   }
368   NaClLog(4, "NaClSecureServiceReverseSetupRpc:"
369           " invoking NaClSecureReverseClientCtor\n");
370   if (!NaClSecureReverseClientCtor(rev,
371                                    NaClSecureReverseClientCallback,
372                                    (void *) nssp)) {
373     free(rev);
374     rpc->result = NACL_SRPC_RESULT_APP_ERROR;
375     goto cleanup;
376   }
377
378   if (!NaClSimpleRevClientStartServiceThread(&rev->base)) {
379     rpc->result = NACL_SRPC_RESULT_APP_ERROR;
380     goto cleanup;
381   }
382
383   nssp->reverse_client = (struct NaClSecureReverseClient *) NaClRefCountRef(
384       (struct NaClRefCount *) rev);
385
386   out_args[0]->u.hval = NaClDescRef(rev->base.bound_and_cap[1]);
387   rpc->result = NACL_SRPC_RESULT_OK;
388  cleanup:
389   NaClXMutexUnlock(&nssp->mu);
390   NaClLog(4, "NaClSecureServiceReverseSetupRpc: done, "
391           " rev_addr 0x%08"NACL_PRIxPTR"\n",
392           (uintptr_t) rev_addr);
393   (*done_cls->Run)(done_cls);
394 }
395
396 struct StartModuleCallbackState {
397   int                    *out_status;
398   struct NaClSrpcClosure *cls;
399 };
400
401 static void NaClSecureServiceStartModuleRpcCallback(
402     void            *instance_data,
403     NaClErrorCode   status) {
404   struct StartModuleCallbackState *state =
405       (struct StartModuleCallbackState *) instance_data;
406   NaClLog(4, "NaClSecureChannelStartModuleRpcCallback: status %d\n", status);
407
408   /*
409    * The RPC reply is now sent.  This has to occur before we signal
410    * the main thread to possibly start, since in the case of a failure
411    * the main thread may quickly exit.  If the main thread does this
412    * before we sent the RPC reply, then the plugin will be left
413    * without an answer.
414    */
415   *state->out_status = (int) status;
416   (*state->cls->Run)(state->cls);
417   free(state);
418 }
419
420 static void NaClSecureServiceStartModuleRpc(
421     struct NaClSrpcRpc      *rpc,
422     struct NaClSrpcArg      **in_args,
423     struct NaClSrpcArg      **out_args,
424     struct NaClSrpcClosure  *done_cls) {
425   struct NaClSecureService        *nssp =
426       (struct NaClSecureService *) rpc->channel->server_instance_data;
427   struct StartModuleCallbackState *state;
428   UNREFERENCED_PARAMETER(in_args);
429
430   NaClLog(4, "NaClSecureChannelStartModuleRpc: starting module\n");
431
432   /*
433    * When reverse setup is being used, we have to block and wait for reverse
434    * channel to become initialized before we can proceed with start module.
435    */
436   NaClXMutexLock(&nssp->mu);
437   if (NACL_REVERSE_CHANNEL_UNINITIALIZED !=
438       nssp->reverse_channel_initialization_state) {
439     while (NACL_REVERSE_CHANNEL_INITIALIZED !=
440            nssp->reverse_channel_initialization_state) {
441       NaClXCondVarWait(&nssp->cv, &nssp->mu);
442     }
443   }
444   NaClXMutexUnlock(&nssp->mu);
445
446   state = (struct StartModuleCallbackState *) malloc(sizeof *state);
447   if (NULL == state) {
448     rpc->result = NACL_SRPC_RESULT_NO_MEMORY;
449     (*done_cls->Run)(done_cls);
450     return;
451   }
452   state->out_status = &out_args[0]->u.ival;
453   state->cls = done_cls;
454
455   rpc->result = NACL_SRPC_RESULT_OK;
456   NaClAppStartModule(nssp->nap,
457                      NaClSecureServiceStartModuleRpcCallback,
458                      (void *) state);
459
460   NaClLog(4, "NaClSecureChannelStartModuleRpc: done\n");
461 }
462
463 static void NaClSecureServiceLogRpc(
464     struct NaClSrpcRpc      *rpc,
465     struct NaClSrpcArg      **in_args,
466     struct NaClSrpcArg      **out_args,
467     struct NaClSrpcClosure  *done_cls) {
468   int   severity = in_args[0]->u.ival;
469   char  *msg = in_args[1]->arrays.str;
470   UNREFERENCED_PARAMETER(out_args);
471
472   NaClLog(5, "NaClSecureChannelLogRpc\n");
473   NaClLog(severity, "%s\n", msg);
474   NaClLog(5, "NaClSecureChannelLogRpc\n");
475   rpc->result = NACL_SRPC_RESULT_OK;
476   (*done_cls->Run)(done_cls);
477 }
478
479 static void NaClSecureServiceShutdownRpc(
480     struct NaClSrpcRpc      *rpc,
481     struct NaClSrpcArg      **in_args,
482     struct NaClSrpcArg      **out_args,
483     struct NaClSrpcClosure  *done) {
484   struct NaClSecureService  *nssp =
485       (struct NaClSecureService *) rpc->channel->server_instance_data;
486   UNREFERENCED_PARAMETER(rpc);
487   UNREFERENCED_PARAMETER(in_args);
488   UNREFERENCED_PARAMETER(out_args);
489   UNREFERENCED_PARAMETER(done);
490
491   NaClAppShutdown(nssp->nap, 0);
492 }
493
494 struct NaClSrpcHandlerDesc const kNaClSecureServiceHandlers[] = {
495   { NACL_SECURE_SERVICE_LOAD_MODULE, NaClSecureServiceLoadModuleRpc, },
496   { NACL_SECURE_SERVICE_REVERSE_SETUP, NaClSecureServiceReverseSetupRpc, },
497   { NACL_SECURE_SERVICE_START_MODULE, NaClSecureServiceStartModuleRpc, },
498   { NACL_SECURE_SERVICE_LOG, NaClSecureServiceLogRpc, },
499   { NACL_SECURE_SERVICE_HARD_SHUTDOWN, NaClSecureServiceShutdownRpc, },
500   { (char const *) NULL, (NaClSrpcMethod) NULL, },
501 };
502
503 struct NaClSimpleServiceVtbl const kNaClSecureServiceVtbl = {
504   {
505     NaClSecureServiceDtor,
506   },
507   NaClSecureServiceConnectionFactory,
508   NaClSecureServiceAcceptConnection,
509   NaClSimpleServiceAcceptAndSpawnHandler,
510   NaClSecureServiceRpcHandler,
511 };
512
513 struct NaClSecureRevClientConnHandler {
514   struct NaClSecureRevClientConnHandler  *next;
515
516   /* used by NaClSimpleRevServiceClient's ClientCallback fn */
517   void                                   (*handler)(
518       void                                          *state,
519       struct NaClThreadInterface                    *tif,
520       struct NaClDesc                               *conn);
521   void                                   *state;
522 };
523
524 static void NaClSecureReverseClientInternalCallback(
525     void                        *state,
526     struct NaClThreadInterface  *tif,
527     struct NaClDesc             *conn) {
528   struct NaClSecureReverseClient *self =
529       (struct NaClSecureReverseClient *) state;
530   struct NaClSecureRevClientConnHandler *hand_ptr;
531
532   NaClLog(4, "Entered NaClSecureReverseClientInternalCallback\n");
533   hand_ptr = (*NACL_VTBL(NaClSecureReverseClient, self)->RemoveHandler)(self);
534   NaClLog(4, " got callback object %"NACL_PRIxPTR"\n", (uintptr_t) hand_ptr);
535   NaClLog(4,
536           " callback:0x%"NACL_PRIxPTR"(0x%"NACL_PRIxPTR",0x%"NACL_PRIxPTR")\n",
537           (uintptr_t) hand_ptr->handler,
538           (uintptr_t) hand_ptr->state,
539           (uintptr_t) conn);
540   (*hand_ptr->handler)(hand_ptr->state, tif, conn);
541   NaClLog(4, "NaClSecureReverseClientInternalCallback: freeing memory\n");
542   free(hand_ptr);
543   NaClLog(4, "Leaving NaClSecureReverseClientInternalCallback\n");
544 }
545
546 /*
547  * Require an initial connection handler in the Ctor, so that it's
548  * obvious that a reverse client needs to accept an IMC connection
549  * from the server to get things bootstrapped.
550  */
551 int NaClSecureReverseClientCtor(
552     struct NaClSecureReverseClient  *self,
553     void                            (*client_callback)(
554         void *, struct NaClThreadInterface*, struct NaClDesc *),
555     void                            *state) {
556   NaClLog(4,
557           "Entered NaClSecureReverseClientCtor, self 0x%"NACL_PRIxPTR"\n",
558           (uintptr_t) self);
559   if (!NaClSimpleRevClientCtor(&self->base,
560                                NaClSecureReverseClientInternalCallback,
561                                (void *) self,
562                                NaClThreadInterfaceThreadFactory,
563                                (void *) NULL)) {
564     goto failure_simple_ctor;
565   }
566   NaClLog(4, "NaClSecureReverseClientCtor: Mutex\n");
567   if (!NaClMutexCtor(&self->mu)) {
568     goto failure_mutex_ctor;
569   }
570   self->queue_head = (struct NaClSecureRevClientConnHandler *) NULL;
571   self->queue_insert = &self->queue_head;
572
573   NACL_VTBL(NaClRefCount, self) =
574       (struct NaClRefCountVtbl *) &kNaClSecureReverseClientVtbl;
575
576   NaClLog(4, "NaClSecureReverseClientCtor: InsertHandler\n");
577   if (!(*NACL_VTBL(NaClSecureReverseClient, self)->
578         InsertHandler)(self, client_callback, state)) {
579     goto failure_handler_insert;
580   }
581
582   NaClLog(4, "Leaving NaClSecureReverseClientCtor\n");
583   return 1;
584
585  failure_handler_insert:
586   NaClLog(4, "NaClSecureReverseClientCtor: InsertHandler failed\n");
587   NACL_VTBL(NaClRefCount, self) =
588       (struct NaClRefCountVtbl *) &kNaClSimpleRevClientVtbl;
589
590   self->queue_insert = (struct NaClSecureRevClientConnHandler **) NULL;
591   NaClMutexDtor(&self->mu);
592
593  failure_mutex_ctor:
594   NaClLog(4, "NaClSecureReverseClientCtor: Mutex failed\n");
595   (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
596  failure_simple_ctor:
597   NaClLog(4, "Leaving NaClSecureReverseClientCtor\n");
598   return 0;
599 }
600
601 void NaClSecureReverseClientDtor(struct NaClRefCount *vself) {
602   struct NaClSecureReverseClient *self =
603       (struct NaClSecureReverseClient *) vself;
604
605   struct NaClSecureRevClientConnHandler  *entry;
606   struct NaClSecureRevClientConnHandler  *next;
607
608   for (entry = self->queue_head; NULL != entry; entry = next) {
609     next = entry->next;
610     free(entry);
611   }
612   NaClMutexDtor(&self->mu);
613
614   NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl const *)
615       &kNaClSimpleRevClientVtbl;
616   (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
617 }
618
619 /*
620  * Caller must set up handler before issuing connection request RPC on
621  * nap->reverse_channel, since otherwise the connection handler queue
622  * may be empty and the connect code would abort.  Because the connect
623  * doesn't wait for a handler, we don't need a condvar.
624  *
625  * We do not need to serialize on the handlers, since the
626  * RPC-server/IMC-client implementation should not distinguish one
627  * connection from another: it is okay for two handlers to be
628  * inserted, and two connection request RPCs to be preformed
629  * (sequentially, since they are over a single channel), and have the
630  * server side spawn threads that asynchronously connect twice, in the
631  * "incorrect" order, etc.
632  */
633 int NaClSecureReverseClientInsertHandler(
634     struct NaClSecureReverseClient  *self,
635     void                            (*handler)(
636         void                        *handler_state,
637         struct NaClThreadInterface  *thread_if,
638         struct NaClDesc             *new_conn),
639     void                            *state) {
640   struct NaClSecureRevClientConnHandler *entry;
641   int                                   retval = 0; /* fail */
642
643   NaClLog(4,
644           ("NaClSecureReverseClientInsertHandler: "
645            "handler 0x%"NACL_PRIxPTR", state 0x%"NACL_PRIxPTR"\n"),
646           (uintptr_t) handler, (uintptr_t) state);
647
648   NaClXMutexLock(&self->mu);
649
650   entry = (struct NaClSecureRevClientConnHandler *) malloc(sizeof *entry);
651   if (NULL == entry) {
652     goto cleanup;
653   }
654   entry->handler = handler;
655   entry->state = state;
656   entry->next = (struct NaClSecureRevClientConnHandler *) NULL;
657   *self->queue_insert = entry;
658   self->queue_insert = &entry->next;
659   retval = 1;
660
661  cleanup:
662   NaClXMutexUnlock(&self->mu);
663   return retval;
664 }
665
666 struct NaClSecureRevClientConnHandler *NaClSecureReverseClientRemoveHandler(
667     struct NaClSecureReverseClient *self) {
668   struct NaClSecureRevClientConnHandler *head;
669
670   NaClLog(4, "Entered NaClSecureReverseClientRemoveHandler, acquiring lock\n");
671   NaClXMutexLock(&self->mu);
672   NaClLog(4, "NaClSecureReverseClientRemoveHandler, got lock\n");
673   head = self->queue_head;
674   if (NULL == head) {
675     NaClLog(LOG_FATAL,
676             "NaClSecureReverseClientRemoveHandler:  empty handler queue\n");
677   }
678   if (NULL == (self->queue_head = head->next)) {
679     NaClLog(4, "NaClSecureReverseClientRemoveHandler, last elt patch up\n");
680     self->queue_insert = &self->queue_head;
681   }
682   NaClLog(4, "NaClSecureReverseClientRemoveHandler, unlocking\n");
683   NaClXMutexUnlock(&self->mu);
684
685   head->next = NULL;
686   NaClLog(4,
687           ("Leaving NaClSecureReverseClientRemoveHandler:"
688            " returning %"NACL_PRIxPTR"\n"),
689           (uintptr_t) head);
690   return head;
691 }
692
693 struct NaClSecureReverseClientVtbl const kNaClSecureReverseClientVtbl = {
694   {
695     {
696       NaClSecureReverseClientDtor,
697     },
698   },
699   NaClSecureReverseClientInsertHandler,
700   NaClSecureReverseClientRemoveHandler,
701 };