Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / name_service / name_service.c
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 <string.h>
8
9 #include "native_client/src/include/portability.h"
10 #include "native_client/src/include/portability_string.h"
11
12 #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
13
14 #include "native_client/src/public/name_service.h"
15
16 #include "native_client/src/shared/platform/nacl_log.h"
17 #include "native_client/src/shared/platform/nacl_sync.h"
18 #include "native_client/src/shared/platform/nacl_sync_checked.h"
19
20 #include "native_client/src/shared/srpc/nacl_srpc.h"
21
22 #include "native_client/src/trusted/desc/nacl_desc_base.h"
23 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
24 #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
25 #include "native_client/src/trusted/desc/nrd_xfer.h"
26
27 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
28 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
29
30 #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
31 #include "native_client/src/trusted/simple_service/nacl_simple_ltd_service.h"
32 #include "native_client/src/trusted/threading/nacl_thread_interface.h"
33
34
35 /*
36  * Name service is a linear linked list.  We could use a hash
37  * container eventually, but performance is not a goal for this simple
38  * bootstrap name service.  Static entry and factory-based generation
39  * are mutually exclusive; the |factory| function is used iff |entry|
40  * is NULL.  Client code is expected to cache lookup results.
41  */
42 struct NaClNameServiceEntry {
43   struct NaClNameServiceEntry *next;
44   char const                  *name;
45   int                         mode;
46   struct NaClDesc             *entry;  /* static entry, or, ... */
47
48   NaClNameServiceFactoryFn_t  factory;
49   void                        *state;
50 };
51
52 struct NaClSrpcHandlerDesc const kNaClNameServiceHandlers[];
53 /* fwd */
54
55 int NaClNameServiceCtor(struct NaClNameService      *self,
56                         NaClThreadIfFactoryFunction thread_factory_fn,
57                         void                        *thread_factory_data) {
58   int     retval = 0;  /* fail */
59
60   NaClLog(4, "Entered NaClNameServiceCtor\n");
61   if (!NaClSimpleLtdServiceCtor(&self->base,
62                                 kNaClNameServiceHandlers,
63                                 NACL_NAME_SERVICE_CONNECTION_MAX,
64                                 thread_factory_fn,
65                                 thread_factory_data)) {
66     NaClLog(4, "NaClSimpleLtdServiceCtor failed\n");
67     goto done;
68   }
69   if (!NaClMutexCtor(&self->mu)) {
70     NaClLog(4, "NaClMutexCtor failed\n");
71     goto abort_mu;
72   }
73   NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *)
74       &kNaClNameServiceVtbl;
75   /* success return path */
76   self->head = (struct NaClNameServiceEntry *) NULL;
77   retval = 1;
78   goto done;
79
80   /* cleanup unwind */
81  abort_mu:  /* mutex ctor failed */
82   (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
83  done:
84   return retval;
85 }
86
87 void NaClNameServiceDtor(struct NaClRefCount *vself) {
88   struct NaClNameService      *self = (struct NaClNameService *) vself;
89
90   struct NaClNameServiceEntry *p;
91   struct NaClNameServiceEntry *next;
92
93   for (p = self->head; NULL != p; p = next) {
94     next = p->next;
95     if (NULL != p->entry) {
96       NaClRefCountUnref((struct NaClRefCount *) p->entry);
97     } else {
98       /*
99        * Tell the factory fn that this particular use can be GC'd.
100        */
101       (void) (*p->factory)(p->state, p->name, 0, (struct NaClDesc **) NULL);
102     }
103     free(p);
104   }
105   NaClMutexDtor(&self->mu);
106   NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *)
107       &kNaClSimpleLtdServiceVtbl;
108   (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
109 }
110
111 static struct NaClNameServiceEntry **NameServiceSearch(
112     struct NaClNameServiceEntry **hd,
113     char const                  *name) {
114   while (NULL != *hd && 0 != strcmp((*hd)->name, name)) {
115     hd = &(*hd)->next;
116   }
117   return hd;
118 }
119
120
121 int NaClNameServiceCreateDescEntry(
122     struct NaClNameService  *nnsp,
123     char const              *name,
124     int                     mode,
125     struct NaClDesc         *new_desc) {
126   int                         retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES;
127   struct NaClNameServiceEntry *name_entry = NULL;
128   struct NaClNameServiceEntry *found = NULL;
129   char                        *dup_name = STRDUP(name);
130
131   NaClLog(3,
132           "NaClNameServiceCreateDescEntry: entering %s, %d (0x%x)\n",
133           name,
134           mode, mode);
135   /*
136    * common case is insertion success, so we pre-allocate memory
137    * (strdup, malloc) to avoid doing memory allocations while holding
138    * the name service lock.
139    */
140   if (NULL == dup_name) {
141     goto dup_failed;
142   }
143   name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry);
144   if (NULL == name_entry) {
145     goto entry_alloc_failed;
146   }
147
148   NaClXMutexLock(&nnsp->mu);
149   found = *NameServiceSearch(&nnsp->head, name);
150   if (NULL != found) {
151     retval = NACL_NAME_SERVICE_DUPLICATE_NAME;
152     goto unlock_and_cleanup;
153   }
154   name_entry->next = nnsp->head;
155   name_entry->name = dup_name;
156   dup_name = (char *) NULL;
157   name_entry->mode = mode;
158   name_entry->entry = new_desc;
159   name_entry->factory = (NaClNameServiceFactoryFn_t) NULL;
160   name_entry->state = (void *) NULL;
161   nnsp->head = name_entry;
162   name_entry = NULL;
163   retval = NACL_NAME_SERVICE_SUCCESS;
164
165  unlock_and_cleanup:
166   NaClXMutexUnlock(&nnsp->mu);
167   free(name_entry);
168  entry_alloc_failed:
169   free(dup_name);
170  dup_failed:
171   return retval;
172 }
173
174 int NaClNameServiceCreateFactoryEntry(
175     struct NaClNameService      *nnsp,
176     char const                  *name,
177     NaClNameServiceFactoryFn_t  factory_fn,
178     void                        *factory_state) {
179   int                         retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES;
180   struct NaClNameServiceEntry *name_entry = NULL;
181   struct NaClNameServiceEntry *found = NULL;
182   char                        *dup_name = STRDUP(name);
183
184   NaClLog(3,
185           ("NaClNameServiceCreateFactoryEntry: entering %s,"
186            " 0x%"NACL_PRIxPTR", 0x%"NACL_PRIxPTR"\n"),
187           name,
188           (uintptr_t) factory_fn,
189           (uintptr_t) factory_state);
190   /*
191    * common case is insertion success, so we pre-allocate memory
192    * (strdup, malloc) to avoid doing memory allocation while holding
193    * the name service lock.
194    */
195   if (NULL == dup_name) {
196     goto dup_failed;
197   }
198   name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry);
199   if (NULL == name_entry) {
200     goto entry_alloc_failed;
201   }
202
203   NaClXMutexLock(&nnsp->mu);
204   found = *NameServiceSearch(&nnsp->head, name);
205   if (NULL != found) {
206     retval = NACL_NAME_SERVICE_DUPLICATE_NAME;
207     goto unlock_and_cleanup;
208   }
209   name_entry->next = nnsp->head;
210   name_entry->name = dup_name;
211   dup_name = (char *) NULL;
212   name_entry->entry = (struct NaClDesc *) NULL;
213   name_entry->factory = factory_fn;
214   name_entry->state = factory_state;
215   nnsp->head = name_entry;
216   name_entry = NULL;
217   retval = NACL_NAME_SERVICE_SUCCESS;
218
219  unlock_and_cleanup:
220   NaClXMutexUnlock(&nnsp->mu);
221   free(name_entry);
222  entry_alloc_failed:
223   free(dup_name);
224  dup_failed:
225   return retval;
226 }
227
228 int NaClNameServiceResolveName(struct NaClNameService  *nnsp,
229                                char const              *name,
230                                int                     flags,
231                                struct NaClDesc         **out) {
232   struct NaClNameServiceEntry *nnsep;
233   int                         status = NACL_NAME_SERVICE_NAME_NOT_FOUND;
234
235   NaClLog(3,
236           "NaClNameServiceResolveName: looking up %s, flags %d (0x%x)\n",
237           name,
238           flags, flags);
239   if (0 != (flags & ~NACL_ABI_O_ACCMODE)) {
240     NaClLog(2, "NaClNameServiceResolveName:  bad flags!\n");
241     status = NACL_NAME_SERVICE_PERMISSION_DENIED;
242     goto quit;
243   }
244
245   NaClXMutexLock(&nnsp->mu);
246   nnsep = *NameServiceSearch(&nnsp->head, name);
247   if (NULL != nnsep) {
248     if (NULL != nnsep->entry) {
249       NaClLog(3,
250               "NaClNameServiceResolveName: found %s, mode %d (0x%x)\n",
251               name,
252               nnsep->mode, nnsep->mode);
253       /* check flags against nnsep->mode */
254       NaClLog(4,
255               ("NaClNameServiceResolveName: checking mode/flags"
256                " compatibility\n"));
257       switch (flags) {
258         case NACL_ABI_O_RDONLY:
259           if (NACL_ABI_O_WRONLY == nnsep->mode) {
260             status = NACL_NAME_SERVICE_PERMISSION_DENIED;
261             NaClLog(4,
262                     "NaClNameServiceResolveName: incompatible,"
263                     " not readable\n");
264             goto unlock_and_quit;
265           }
266           break;
267         case NACL_ABI_O_WRONLY:
268           if (NACL_ABI_O_RDONLY == nnsep->mode) {
269             status = NACL_NAME_SERVICE_PERMISSION_DENIED;
270             NaClLog(4,
271                     "NaClNameServiceResolveName: incompatible,"
272                     " not writeable\n");
273             goto unlock_and_quit;
274           }
275           break;
276         case NACL_ABI_O_RDWR:
277           if (NACL_ABI_O_RDWR != nnsep->mode) {
278             status = NACL_NAME_SERVICE_PERMISSION_DENIED;
279             NaClLog(4, "NaClNameServiceResolveName: incompatible,"
280                     " not for both read and write\n");
281             goto unlock_and_quit;
282           }
283           break;
284         default:
285           status = NACL_NAME_SERVICE_INVALID_ARGUMENT;
286           NaClLog(4, "NaClNameServiceResolveName: invalid flag\n");
287           goto unlock_and_quit;
288       }
289       NaClLog(4, "NaClNameServiceResolveName: mode and flags are compatible\n");
290       *out = NaClDescRef(nnsep->entry);
291       status = NACL_NAME_SERVICE_SUCCESS;
292     } else {
293       status = (*nnsep->factory)(nnsep->state, name, flags, out);
294     }
295   }
296  unlock_and_quit:
297   nnsep = NULL;
298   NaClXMutexUnlock(&nnsp->mu);
299  quit:
300   return status;
301 }
302
303 int NaClNameServiceDeleteName(struct NaClNameService *nnsp,
304                               char const             *name) {
305   struct NaClNameServiceEntry **nnsepp;
306   struct NaClNameServiceEntry *to_free = NULL;
307   int                         status = NACL_NAME_SERVICE_NAME_NOT_FOUND;
308
309   NaClXMutexLock(&nnsp->mu);
310   nnsepp = NameServiceSearch(&nnsp->head, name);
311   if (NULL != *nnsepp) {
312     to_free = *nnsepp;
313     *nnsepp = to_free->next;
314     status = NACL_NAME_SERVICE_SUCCESS;
315   }
316   NaClXMutexUnlock(&nnsp->mu);
317
318   /* do the free operations w/o holding the lock */
319   if (NULL != to_free) {
320     NaClDescSafeUnref(to_free->entry);
321     if (NULL != to_free->factory) {
322       (void) (*to_free->factory)(to_free->state,
323                                  to_free->name,
324                                  0,
325                                  (struct NaClDesc **) NULL);
326     }
327     free((void *) to_free->name);
328     free(to_free);
329   }
330   return status;
331 }
332
333 static void NaClNameServiceNameInsertRpc(
334     struct NaClSrpcRpc      *rpc,
335     struct NaClSrpcArg      **in_args,
336     struct NaClSrpcArg      **out_args,
337     struct NaClSrpcClosure  *done_cls) {
338   struct NaClNameService  *nnsp =
339       (struct NaClNameService *) rpc->channel->server_instance_data;
340   char                    *name = in_args[0]->arrays.str;
341   int                     mode  = in_args[1]->u.ival;
342   struct NaClDesc         *desc = in_args[2]->u.hval;
343
344   NaClLog(3,
345           "NaClNameServiceNameInsertRpc: inserting %s, %d (0x%x)\n",
346           name,
347           mode, mode);
348   out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->CreateDescEntry)(
349       nnsp, name, mode, desc);
350   rpc->result = NACL_SRPC_RESULT_OK;
351   (*done_cls->Run)(done_cls);
352 }
353
354 static void NaClNameServiceNameLookupOldRpc(
355     struct NaClSrpcRpc      *rpc,
356     struct NaClSrpcArg      **in_args,
357     struct NaClSrpcArg      **out_args,
358     struct NaClSrpcClosure  *done_cls) {
359   struct NaClNameService  *nnsp =
360       (struct NaClNameService *) rpc->channel->server_instance_data;
361   char                    *name = in_args[0]->arrays.str;
362   int                     status;
363   struct NaClDesc         *desc;
364
365   NaClLog(LOG_WARNING,
366           "NaClNameServiceNameLookupOldRpc: DEPRECATED interface used.\n");
367   NaClLog(3, "NaClNameServiceNameLookupOldRpc: looking up %s\n", name);
368   status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)(
369       nnsp, name, NACL_ABI_O_RDONLY, &desc);
370   out_args[0]->u.ival = status;
371   out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status)
372       ? desc
373       : (struct NaClDesc *) NaClDescInvalidMake();
374   rpc->result = NACL_SRPC_RESULT_OK;
375   (*done_cls->Run)(done_cls);
376 }
377
378 static void NaClNameServiceNameLookupRpc(
379     struct NaClSrpcRpc      *rpc,
380     struct NaClSrpcArg      **in_args,
381     struct NaClSrpcArg      **out_args,
382     struct NaClSrpcClosure  *done_cls) {
383   struct NaClNameService  *nnsp =
384       (struct NaClNameService *) rpc->channel->server_instance_data;
385   char                    *name = in_args[0]->arrays.str;
386   int                     flags = in_args[1]->u.ival;
387   int                     status;
388   struct NaClDesc         *desc;
389
390   NaClLog(3, "NaClNameServiceNameLookupRpc: looking up %s\n", name);
391   NaClLog(3, "NaClNameServiceNameLookupRpc: flags %d (0x%x)\n", flags, flags);
392   status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)(
393       nnsp, name, flags, &desc);
394   out_args[0]->u.ival = status;
395   out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status)
396       ? desc
397       : (struct NaClDesc *) NaClDescInvalidMake();
398   NaClLog(3, "NaClNameServiceNameLookupRpc: status %d\n", status);
399   NaClLog(3, "NaClNameServiceNameLookupRpc: desc 0x%"NACL_PRIxPTR"\n",
400           (uintptr_t) desc);
401   rpc->result = NACL_SRPC_RESULT_OK;
402   (*done_cls->Run)(done_cls);
403 }
404
405 static void NaClNameServiceNameDeleteRpc(
406     struct NaClSrpcRpc      *rpc,
407     struct NaClSrpcArg      **in_args,
408     struct NaClSrpcArg      **out_args,
409     struct NaClSrpcClosure  *done_cls) {
410   struct NaClNameService  *nnsp =
411       (struct NaClNameService *) rpc->channel->server_instance_data;
412   char                    *name = in_args[0]->arrays.str;
413
414   out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->DeleteName)(
415       nnsp, name);
416   rpc->result = NACL_SRPC_RESULT_OK;
417   (*done_cls->Run)(done_cls);
418 }
419
420 struct NaClSrpcHandlerDesc const kNaClNameServiceHandlers[] = {
421   { NACL_NAME_SERVICE_INSERT, NaClNameServiceNameInsertRpc, },
422   { NACL_NAME_SERVICE_LOOKUP_DEPRECATED, NaClNameServiceNameLookupOldRpc, },
423   { NACL_NAME_SERVICE_LOOKUP, NaClNameServiceNameLookupRpc, },
424   { NACL_NAME_SERVICE_DELETE, NaClNameServiceNameDeleteRpc, },
425   { (char const *) NULL, (NaClSrpcMethod) NULL, },
426 };
427
428 void NaClNameServiceLaunch(struct NaClNameService *self) {
429
430   NaClLog(4, "NaClNameServiceThread: starting service\n");
431   NaClSimpleServiceStartServiceThread((struct NaClSimpleService *) self);
432 }
433
434 struct NaClNameServiceVtbl kNaClNameServiceVtbl = {
435   {
436     /* really NaClSimpleLtdServiceVtbl contents */
437     {
438       NaClNameServiceDtor,
439     },
440     NaClSimpleServiceConnectionFactory,
441     /*
442      * To implement name service ownership, the ConnectionFactory will
443      * need to build a subclass of a NaClSimpleServiceConnection where
444      * the connection can be marked as an owner, and the NameService
445      * would contain a mutex protected flag specifying whether it is
446      * owned that blocks mutations by all but the owning connection.
447      * The Connection object's Dtor can release ownership.
448      */
449     NaClSimpleLtdServiceAcceptConnection,
450     NaClSimpleServiceAcceptAndSpawnHandler,
451     NaClSimpleLtdServiceRpcHandler,
452   },
453   NaClNameServiceCreateDescEntry,
454   NaClNameServiceCreateFactoryEntry,
455   NaClNameServiceResolveName,
456   NaClNameServiceDeleteName,
457 };