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 : /*
8 : * NaCl service library. a primitive rpc library
9 : */
10 :
11 : #include <stdarg.h>
12 : #include <stdlib.h>
13 : #include <string.h>
14 :
15 : #ifndef __native_client__
16 : #include "native_client/src/include/portability.h"
17 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
18 : #endif /* __native_client__ */
19 : #include "native_client/src/shared/srpc/nacl_srpc.h"
20 : #include "native_client/src/shared/platform/nacl_check.h"
21 : #include "native_client/src/shared/srpc/nacl_srpc_internal.h"
22 : #include "native_client/src/shared/srpc/nacl_srpc_message.h"
23 :
24 : /*
25 : * Service discovery is used to build an interface description that
26 : * is searched for rpc dispatches.
27 : */
28 24 : static NaClSrpcService* BuildClientService(NaClSrpcChannel* channel) {
29 24 : NaClSrpcArg* ins[] = { NULL };
30 : NaClSrpcArg out_carray;
31 : NaClSrpcArg* outs[2];
32 24 : NaClSrpcService* tmp_service = NULL;
33 24 : NaClSrpcService* service = NULL;
34 24 : NaClSrpcHandlerDesc basic_services[] = { { NULL, NULL } };
35 : NaClSrpcError service_discovery_result;
36 24 : NaClSrpcService* returned_service = NULL;
37 :
38 : /*
39 : * Service discovery requires a temporary setting of channel->client.
40 : * To ensure that this does not clobber a previous setting, enforce
41 : * a precondition that it is NULL beforehand.
42 : */
43 24 : CHECK(NULL == channel->client);
44 : /* Set up the output parameters for service discovery. */
45 24 : NaClSrpcArgCtor(&out_carray);
46 24 : outs[0] = &out_carray;
47 24 : outs[1] = NULL;
48 24 : out_carray.tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
49 24 : out_carray.u.count = NACL_SRPC_MAX_SERVICE_DISCOVERY_CHARS;
50 : /*
51 : * Add one guaranteed NUL byte to make sure the string will be NUL-terminated.
52 : */
53 24 : out_carray.arrays.carr = calloc(NACL_SRPC_MAX_SERVICE_DISCOVERY_CHARS + 1, 1);
54 24 : if (NULL == out_carray.arrays.carr) {
55 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
56 : "BuildClientService(channel=%p):"
57 : " service discovery malloc failed\n",
58 : (void*) channel);
59 0 : goto cleanup;
60 : }
61 : /* Set up the basic service descriptor to make the service discovery call. */
62 24 : tmp_service = (NaClSrpcService*) malloc(sizeof(*tmp_service));
63 24 : if (NULL == tmp_service) {
64 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
65 : "BuildClientService(channel=%p):"
66 : " temporary service malloc failed\n",
67 : (void*) channel);
68 0 : goto cleanup;
69 : }
70 24 : if (!NaClSrpcServiceHandlerCtor(tmp_service, basic_services)) {
71 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
72 : "BuildClientService(channel=%p):"
73 : " NaClSrpcServiceHandlerCtor failed\n",
74 : (void*) channel);
75 0 : free(tmp_service);
76 0 : tmp_service = NULL;
77 0 : goto cleanup;
78 : }
79 : /* Temporarily assign channel->client to allow Invoke. */
80 24 : channel->client = tmp_service;
81 : /* Invoke service discovery, getting description string */
82 24 : service_discovery_result = NaClSrpcInvokeV(channel, 0, ins, outs);
83 : /* Disconnect the temporary service. */
84 24 : channel->client = NULL;
85 24 : if (NACL_SRPC_RESULT_OK != service_discovery_result) {
86 1 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
87 : "BuildClientService(channel=%p):"
88 : " service discovery invoke failed\n",
89 : (void*) channel);
90 1 : goto cleanup;
91 : }
92 : /* Allocate the real service. */
93 23 : service = (NaClSrpcService*) malloc(sizeof(*service));
94 23 : if (NULL == service) {
95 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
96 : "BuildClientService(channel=%p):"
97 : " service discovery malloc failed\n",
98 : (void*) channel);
99 0 : goto cleanup;
100 : }
101 : /* Build the real service from the resulting string. */
102 23 : if (!NaClSrpcServiceStringCtor(service, out_carray.arrays.carr)) {
103 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
104 : "BuildClientService(channel=%p):"
105 : " NaClSrpcServiceStringCtor failed\n",
106 : (void*) channel);
107 0 : goto cleanup;
108 : }
109 : /* Caller takes ownership of service. */
110 23 : returned_service = service;
111 23 : service = NULL;
112 24 : cleanup:
113 24 : free(service);
114 24 : NaClSrpcServiceDtor(tmp_service);
115 24 : free(tmp_service);
116 24 : free(out_carray.arrays.carr);
117 24 : return returned_service;
118 : }
119 :
120 : /*
121 : * The constructors and destructor.
122 : * Clients and Servers are both NaClSrpcChannels, but they are constructed
123 : * by different methods reflecting how they get their table of rpc methods.
124 : */
125 :
126 31 : void NaClSrpcChannelInitialize(NaClSrpcChannel* channel) {
127 31 : channel->message_channel = NULL;
128 31 : channel->server = NULL;
129 31 : channel->client = NULL;
130 31 : channel->server_instance_data = NULL;
131 31 : }
132 :
133 : static int NaClSrpcChannelCtorHelper(NaClSrpcChannel* channel,
134 31 : NaClSrpcImcDescType handle) {
135 31 : NaClSrpcLog(1,
136 : "NaClSrpcChannelCtorHelper(channel=%p, handle=%p)\n",
137 : (void*) channel,
138 : (void*) handle);
139 : /* Initialize the channel to allow errors to be handled. */
140 31 : NaClSrpcChannelInitialize(channel);
141 : /* Create the message fragmentation layer. */
142 31 : channel->message_channel = NaClSrpcMessageChannelNew(handle);
143 31 : if (NULL == channel->message_channel) {
144 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
145 : "NaClSrpcChannelCtorHelper(channel=%p):"
146 : " NaClSrpcMessageChannelNew failed\n",
147 : (void*) channel);
148 0 : return 0;
149 : }
150 31 : return 1;
151 : }
152 :
153 30 : static void NaClSrpcChannelDtorHelper(NaClSrpcChannel* channel) {
154 30 : NaClSrpcLog(1, "NaClSrpcChannelDtorHelper(channel=%p)\n", (void*) channel);
155 30 : channel->server_instance_data = NULL;
156 30 : NaClSrpcMessageChannelDelete(channel->message_channel);
157 30 : channel->message_channel = NULL;
158 30 : }
159 :
160 24 : int NaClSrpcClientCtor(NaClSrpcChannel* channel, NaClSrpcImcDescType handle) {
161 24 : int return_value = 0;
162 24 : NaClSrpcService* client_service = NULL;
163 24 : NaClSrpcLog(1,
164 : "NaClSrpcClientCtor(channel=%p, handle=%p)\n",
165 : (void*) channel,
166 : (void*) handle);
167 24 : if (!NaClSrpcChannelCtorHelper(channel, handle)) {
168 0 : goto cleanup;
169 : }
170 : /* Do service discovery to speed method invocation. */
171 24 : client_service = BuildClientService(channel);
172 24 : if (NULL == client_service) {
173 1 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
174 : "NaClSrpcClientCtor(channel=%p):"
175 : " BuildClientService failed\n",
176 : (void*) channel);
177 1 : NaClSrpcChannelDtorHelper(channel);
178 1 : goto cleanup;
179 : }
180 : /* Channel takes ownership of client_service. */
181 23 : channel->client = client_service;
182 23 : client_service = NULL;
183 23 : return_value = 1;
184 24 : cleanup:
185 24 : NaClSrpcServiceDtor(client_service);
186 24 : return return_value;
187 : }
188 :
189 : int NaClSrpcServerCtor(NaClSrpcChannel* channel,
190 : NaClSrpcImcDescType handle,
191 : NaClSrpcService* service,
192 7 : void* server_instance_data) {
193 7 : int return_value = 0;
194 7 : NaClSrpcLog(1,
195 : "NaClSrpcServerCtor(channel=%p, handle=%p,"
196 : " service=%p, server_instance_data=%p)\n",
197 : (void*) channel,
198 : (void*) handle,
199 : (void*) service,
200 : (void*) server_instance_data);
201 7 : if (!NaClSrpcChannelCtorHelper(channel, handle)) {
202 0 : goto cleanup;
203 : }
204 : /* Channel takes ownership of service. */
205 7 : channel->server = service;
206 : /* Channel does not take ownership of server_instance_data. */
207 7 : channel->server_instance_data = server_instance_data;
208 7 : return_value = 1;
209 7 : cleanup:
210 7 : return return_value;
211 : }
212 :
213 29 : void NaClSrpcDtor(NaClSrpcChannel* channel) {
214 29 : NaClSrpcLog(1,
215 : "NaClSrpcDtor(channel=%p)\n",
216 : (void*) channel);
217 29 : if (NULL == channel) {
218 0 : return;
219 : }
220 29 : channel->server_instance_data = NULL;
221 29 : NaClSrpcServiceDtor(channel->client);
222 29 : free(channel->client);
223 29 : channel->client = NULL;
224 29 : NaClSrpcServiceDtor(channel->server);
225 29 : free(channel->server);
226 29 : channel->server = NULL;
227 : /* Do the common part destruction. */
228 29 : NaClSrpcChannelDtorHelper(channel);
229 : }
230 :
231 324 : void NaClSrpcArgCtor(NaClSrpcArg* arg) {
232 324 : memset(arg, 0, sizeof *arg);
233 324 : }
234 :
235 : /*
236 : * A standalone SRPC server is not a subprocess of the browser or
237 : * sel_universal. As this is a mode used for testing, the parent environment
238 : * must set the following variable to indicate that fact.
239 : */
240 : const char kSrpcStandalone[] = "NACL_SRPC_STANDALONE";
241 :
242 0 : int NaClSrpcIsStandalone() {
243 0 : return (NULL != getenv(kSrpcStandalone));
244 : }
|