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 49 : static NaClSrpcService* BuildClientService(NaClSrpcChannel* channel) {
29 49 : NaClSrpcArg* ins[] = { NULL };
30 49 : NaClSrpcArg out_carray;
31 49 : NaClSrpcArg* outs[2];
32 49 : NaClSrpcService* tmp_service = NULL;
33 49 : NaClSrpcService* service = NULL;
34 49 : NaClSrpcHandlerDesc basic_services[] = { { NULL, NULL } };
35 49 : NaClSrpcError service_discovery_result;
36 49 : 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 147 : CHECK(NULL == channel->client);
44 : /* Set up the output parameters for service discovery. */
45 49 : NaClSrpcArgCtor(&out_carray);
46 49 : outs[0] = &out_carray;
47 49 : outs[1] = NULL;
48 49 : out_carray.tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
49 49 : 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 49 : out_carray.arrays.carr = calloc(NACL_SRPC_MAX_SERVICE_DISCOVERY_CHARS + 1, 1);
54 49 : 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 49 : tmp_service = (NaClSrpcService*) malloc(sizeof(*tmp_service));
63 49 : 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 49 : 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 49 : channel->client = tmp_service;
81 : /* Invoke service discovery, getting description string */
82 49 : service_discovery_result = NaClSrpcInvokeV(channel, 0, ins, outs);
83 : /* Disconnect the temporary service. */
84 49 : channel->client = NULL;
85 49 : 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 48 : service = (NaClSrpcService*) malloc(sizeof(*service));
94 48 : 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 48 : 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 48 : returned_service = service;
111 48 : service = NULL;
112 : cleanup:
113 49 : free(service);
114 49 : NaClSrpcServiceDtor(tmp_service);
115 49 : free(tmp_service);
116 49 : free(out_carray.arrays.carr);
117 49 : 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 74 : void NaClSrpcChannelInitialize(NaClSrpcChannel* channel) {
127 74 : channel->message_channel = NULL;
128 74 : channel->server = NULL;
129 74 : channel->client = NULL;
130 74 : channel->server_instance_data = NULL;
131 74 : }
132 :
133 74 : static int NaClSrpcChannelCtorHelper(NaClSrpcChannel* channel,
134 74 : NaClSrpcImcDescType handle) {
135 74 : 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 74 : NaClSrpcChannelInitialize(channel);
141 : /* Create the message fragmentation layer. */
142 74 : channel->message_channel = NaClSrpcMessageChannelNew(handle);
143 74 : 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 74 : return 1;
151 74 : }
152 :
153 59 : static void NaClSrpcChannelDtorHelper(NaClSrpcChannel* channel) {
154 59 : NaClSrpcLog(1, "NaClSrpcChannelDtorHelper(channel=%p)\n", (void*) channel);
155 59 : channel->server_instance_data = NULL;
156 59 : NaClSrpcMessageChannelDelete(channel->message_channel);
157 59 : channel->message_channel = NULL;
158 59 : }
159 :
160 49 : int NaClSrpcClientCtor(NaClSrpcChannel* channel, NaClSrpcImcDescType handle) {
161 49 : int return_value = 0;
162 49 : NaClSrpcService* client_service = NULL;
163 49 : NaClSrpcLog(1,
164 : "NaClSrpcClientCtor(channel=%p, handle=%p)\n",
165 : (void*) channel,
166 : (void*) handle);
167 49 : if (!NaClSrpcChannelCtorHelper(channel, handle)) {
168 0 : goto cleanup;
169 : }
170 : /* Do service discovery to speed method invocation. */
171 49 : client_service = BuildClientService(channel);
172 49 : 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 48 : channel->client = client_service;
182 48 : client_service = NULL;
183 48 : return_value = 1;
184 : cleanup:
185 49 : NaClSrpcServiceDtor(client_service);
186 49 : return return_value;
187 : }
188 :
189 25 : int NaClSrpcServerCtor(NaClSrpcChannel* channel,
190 25 : NaClSrpcImcDescType handle,
191 25 : NaClSrpcService* service,
192 25 : void* server_instance_data) {
193 25 : int return_value = 0;
194 25 : 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 25 : if (!NaClSrpcChannelCtorHelper(channel, handle)) {
202 0 : goto cleanup;
203 : }
204 : /* Channel takes ownership of service. */
205 25 : channel->server = service;
206 : /* Channel does not take ownership of server_instance_data. */
207 25 : channel->server_instance_data = server_instance_data;
208 25 : return_value = 1;
209 : cleanup:
210 25 : return return_value;
211 : }
212 :
213 58 : void NaClSrpcDtor(NaClSrpcChannel* channel) {
214 58 : NaClSrpcLog(1,
215 : "NaClSrpcDtor(channel=%p)\n",
216 : (void*) channel);
217 58 : if (NULL == channel) {
218 0 : return;
219 : }
220 58 : channel->server_instance_data = NULL;
221 58 : NaClSrpcServiceDtor(channel->client);
222 58 : free(channel->client);
223 58 : channel->client = NULL;
224 58 : NaClSrpcServiceDtor(channel->server);
225 58 : free(channel->server);
226 58 : channel->server = NULL;
227 : /* Do the common part destruction. */
228 58 : NaClSrpcChannelDtorHelper(channel);
229 116 : }
230 :
231 648 : void NaClSrpcArgCtor(NaClSrpcArg* arg) {
232 1944 : memset(arg, 0, sizeof *arg);
233 648 : }
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 : int NaClSrpcIsStandalone(void) {
243 0 : return (NULL != getenv(kSrpcStandalone));
244 : }
|