1 /**
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <alloca.h>
18 #include <pthread.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/endian.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <unistd.h>
25
26 #include <cutils/sockets.h>
27
28 #include "logging.h"
29 #include "node_buffer.h"
30 #include "status.h"
31 #include "util.h"
32 #include "worker.h"
33
34 #include "hardware/ril/mock-ril/src/proto/msgheader.pb.h"
35
36 #include "hardware/ril/mock-ril/src/proto/ctrl.pb.h"
37 #include "ctrl_server.h"
38
39 //#define CONTROL_SERVER_DEBUG
40 #ifdef CONTROL_SERVER_DEBUG
41
42 #define DBG(...) LOGD(__VA_ARGS__)
43
44 #else
45
46 #define DBG(...)
47
48 #endif
49
50 #define MOCK_RIL_CONTROL_SERVER_STOPPING_SOCKET 54311
51 #define MOCK_RIL_CONTROL_SERVER_SOCKET 54312
52
53 using communication::MsgHeader;
54
55 class CtrlServerThread;
56 static CtrlServerThread *g_ctrl_server;
57
58 class CtrlServerThread : public WorkerThread {
59 private:
60 #define SOCKET_NAME_MOCK_RIL_CST_STOPPER "mock-ril-cst-stopper"
61 v8::Handle<v8::Context> context_;
62 int server_accept_socket_;
63 int server_to_client_socket_;
64 int stop_server_fd_;
65 int stop_client_fd_;
66 int stopper_fd_;
67 fd_set rd_fds_;
68 fd_set wr_fds_;
69 bool done_;
70
ObtainBuffer(int length)71 Buffer *ObtainBuffer(int length) {
72 Buffer *b = Buffer::New(length);
73 return b;
74 }
75
WriteAll(int s,void * data,int length)76 int WriteAll(int s, void *data, int length) {
77 int ret_value;
78 uint8_t *bytes = (uint8_t *)data;
79 int count = length;
80
81 while (length > 0) {
82 ret_value = send(s, bytes, length, 0);
83 if (ret_value < 0) {
84 return STATUS_ERR;
85 }
86 if (ret_value == 0) {
87 return STATUS_CLIENT_CLOSED_CONNECTION;
88 }
89 bytes += ret_value;
90 length -= ret_value;
91 }
92
93 return STATUS_OK;
94 }
95
ReadAll(int s,void * data,int length)96 int ReadAll(int s, void *data, int length) {
97 int ret_value;
98 uint8_t *bytes = (uint8_t *)data;
99 int count = length;
100
101 while (length != 0) {
102 ret_value = recv(s, bytes, length, 0);
103 if (ret_value < 0) {
104 return STATUS_ERR;
105 }
106 if (ret_value == 0) {
107 return STATUS_CLIENT_CLOSED_CONNECTION;
108 }
109 bytes += ret_value;
110 length -= ret_value;
111 }
112
113 return STATUS_OK;
114 }
115
ReadMessage(MsgHeader * mh,Buffer ** pBuffer)116 int ReadMessage(MsgHeader *mh, Buffer **pBuffer) {
117 int status;
118 int32_t len_msg_header;
119
120 // Reader header length
121 status = ReadAll(server_to_client_socket_, &len_msg_header, sizeof(len_msg_header));
122 len_msg_header = letoh32(len_msg_header);
123 DBG("rm: read len_msg_header=%d status=%d", len_msg_header, status);
124 if (status != STATUS_OK) return status;
125
126 // Read header into an array allocated on the stack and unmarshall
127 uint8_t *msg_header_raw = (uint8_t *)alloca(len_msg_header);
128 status = ReadAll(server_to_client_socket_, msg_header_raw, len_msg_header);
129 DBG("rm: read msg_header_raw=%p status=%d", msg_header_raw, status);
130 if (status != STATUS_OK) return status;
131 mh->ParseFromArray(msg_header_raw, len_msg_header);
132
133 // Read auxillary data
134 Buffer *buffer;
135 if (mh->length_data() > 0) {
136 buffer = ObtainBuffer(mh->length_data());
137 status = ReadAll(server_to_client_socket_, buffer->data(), buffer->length());
138 DBG("rm: read protobuf status=%d", status);
139 if (status != STATUS_OK) return status;
140 } else {
141 DBG("rm: NO protobuf");
142 buffer = NULL;
143 }
144
145 *pBuffer = buffer;
146 return STATUS_OK;
147 }
148
149 public:
WriteMessage(MsgHeader * mh,Buffer * buffer)150 int WriteMessage(MsgHeader *mh, Buffer *buffer) {
151 int status;
152 uint32_t i;
153 uint64_t l;
154
155 // Set length of data
156 if (buffer == NULL) {
157 mh->set_length_data(0);
158 } else {
159 mh->set_length_data(buffer->length());
160 }
161
162 // Serialize header
163 uint32_t len_msg_header = mh->ByteSize();
164 uint8_t *msg_header_raw = (uint8_t *)alloca(len_msg_header);
165 mh->SerializeToArray(msg_header_raw, len_msg_header);
166
167 // Write length in little endian followed by the header
168 i = htole32(len_msg_header);
169 status = WriteAll(server_to_client_socket_, &i, 4);
170 DBG("wm: write len_msg_header=%d status=%d", len_msg_header, status);
171 if (status != 0) return status;
172 status = WriteAll(server_to_client_socket_, msg_header_raw, len_msg_header);
173 DBG("wm: write msg_header_raw=%p status=%d", msg_header_raw, status);
174 if (status != 0) return status;
175
176 // Write data
177 if (mh->length_data() > 0) {
178 status = WriteAll(server_to_client_socket_, buffer->data(), buffer->length());
179 DBG("wm: protobuf data=%p len=%d status=%d",
180 buffer->data(), buffer->length(), status);
181 if (status != 0) return status;
182 }
183
184 return STATUS_OK;
185 }
186
CtrlServerThread(v8::Handle<v8::Context> context)187 CtrlServerThread(v8::Handle<v8::Context> context) :
188 context_(context),
189 server_accept_socket_(-1),
190 server_to_client_socket_(-1),
191 done_(false) {
192 }
193
Run()194 virtual int Run() {
195 DBG("CtrlServerThread::Run E");
196
197 // Create a server socket.
198 server_accept_socket_ = socket_inaddr_any_server(
199 MOCK_RIL_CONTROL_SERVER_SOCKET, SOCK_STREAM);
200 if (server_accept_socket_ < 0) {
201 LOGE("CtrlServerThread::Run error creating server_accept_socket_ '%s'",
202 strerror(errno));
203 return STATUS_ERR;
204 }
205
206 // Create a server socket that will be used for stopping
207 stop_server_fd_ = socket_loopback_server(
208 MOCK_RIL_CONTROL_SERVER_STOPPING_SOCKET, SOCK_STREAM);
209 if (stop_server_fd_ < 0) {
210 LOGE("CtrlServerThread::Run error creating stop_server_fd_ '%s'",
211 strerror(errno));
212 return STATUS_ERR;
213 }
214
215 // Create a client socket that will be used for sending a stop
216 stop_client_fd_ = socket_loopback_client(
217 MOCK_RIL_CONTROL_SERVER_STOPPING_SOCKET, SOCK_STREAM);
218 if (stop_client_fd_ < 0) {
219 LOGE("CtrlServerThread::Run error creating stop_client_fd_ '%s'",
220 strerror(errno));
221 return STATUS_ERR;
222 }
223
224 // Accept the connection of the stop_client_fd_
225 stopper_fd_ = accept(stop_server_fd_, NULL, NULL);
226 if (stopper_fd_ < 0) {
227 LOGE("CtrlServerThread::Run error accepting stop_client_fd '%s'",
228 strerror(errno));
229 return STATUS_ERR;
230 }
231
232 // Run the new thread
233 int ret_value = WorkerThread::Run(NULL);
234 DBG("CtrlServerThread::Run X");
235 return ret_value;
236 }
237
Stop()238 virtual void Stop() {
239 DBG("CtrlServerThread::Stop E");
240 if (BeginStopping()) {
241 done_ = true;
242 int rv = send(stop_client_fd_, &done_, sizeof(done_), 0);
243 if (rv <= 0) {
244 LOGE("CtrlServerThread::Stop could not send stop"
245 "WE WILL PROBABLY HANG");
246 }
247 WaitUntilStopped();
248 }
249 DBG("CtrlServerThread::Stop X");
250 }
251
isRunning()252 virtual bool isRunning() {
253 bool rv = done_ || WorkerThread::isRunning();
254 return rv;
255 }
256
WaitOnSocketOrStopping(fd_set * rfds,int s)257 int WaitOnSocketOrStopping(fd_set *rfds, int s) {
258 DBG("WaitOnSocketOrStopping E s=%d stopper_fd_=%d", s, stopper_fd_);
259 FD_ZERO(rfds);
260 FD_SET(s, rfds);
261 FD_SET(stopper_fd_, rfds);
262 int fd_number = s > stopper_fd_ ? s + 1 : stopper_fd_ + 1;
263 v8::Unlocker unlocker;
264 int rv = select(fd_number, rfds, NULL, NULL, NULL);
265 v8::Locker locker;
266 DBG("WaitOnSocketOrStopping X rv=%d s=%d stopper_fd_=%d", rv, s, stopper_fd_);
267 return rv;
268 }
269
sendToCtrlServer(MsgHeader * mh,Buffer * buffer)270 int sendToCtrlServer(MsgHeader *mh, Buffer *buffer) {
271 DBG("sendToCtrlServer E: cmd=%d token=%lld", mh->cmd(), mh->token());
272
273 int status = STATUS_OK;
274 v8::HandleScope handle_scope;
275 v8::TryCatch try_catch;
276 try_catch.SetVerbose(true);
277
278 // Get the onRilRequest Function
279 v8::Handle<v8::String> name = v8::String::New("onCtrlServerCmd");
280 v8::Handle<v8::Value> onCtrlServerCmdFunctionValue =
281 context_->Global()->Get(name);
282 v8::Handle<v8::Function> onCtrlServerCmdFunction =
283 v8::Handle<v8::Function>::Cast(onCtrlServerCmdFunctionValue);
284
285 // Create the CmdValue and TokenValue
286 v8::Handle<v8::Value> v8CmdValue = v8::Number::New(mh->cmd());
287 v8::Handle<v8::Value> v8TokenValue = v8::Number::New(mh->token());
288
289 // Invoke onRilRequest
290 const int argc = 3;
291 v8::Handle<v8::Value> buf;
292 if (mh->length_data() == 0) {
293 buf = v8::Undefined();
294 } else {
295 buf = buffer->handle_;
296 }
297 v8::Handle<v8::Value> argv[argc] = {
298 v8CmdValue, v8TokenValue, buf };
299 v8::Handle<v8::Value> result =
300 onCtrlServerCmdFunction->Call(context_->Global(), argc, argv);
301 if (try_catch.HasCaught()) {
302 ReportException(&try_catch);
303 status = STATUS_ERR;
304 } else {
305 v8::String::Utf8Value result_string(result);
306 DBG("sendToCtrlServer result=%s", ToCString(result_string));
307 status = STATUS_OK;
308 }
309
310 if (status != STATUS_OK) {
311 LOGE("sendToCtrlServer Error: status=%d", status);
312 // An error report complete now
313 mh->set_length_data(0);
314 mh->set_status(ril_proto::CTRL_STATUS_ERR);
315 g_ctrl_server->WriteMessage(mh, NULL);
316 }
317
318 DBG("sendToCtrlServer X: status=%d", status);
319 return status;
320 }
321
Worker(void * param)322 virtual void * Worker(void *param) {
323 DBG("CtrlServerThread::Worker E param=%p stopper_fd_=%d",
324 param, stopper_fd_);
325
326 v8::Locker locker;
327 v8::HandleScope handle_scope;
328 v8::Context::Scope context_scope(context_);
329
330 while (isRunning()) {
331 int ret_value;
332
333 // Wait on either server_accept_socket_ or stopping
334 DBG("CtrlServerThread::Worker wait on server for a client");
335 WaitOnSocketOrStopping(&rd_fds_, server_accept_socket_);
336 if (isRunning() != true) {
337 break;
338 }
339
340 if (FD_ISSET(server_accept_socket_, &rd_fds_)) {
341 server_to_client_socket_ = accept(server_accept_socket_, NULL, NULL);
342 DBG("CtrlServerThread::Worker accepted server_to_client_socket_=%d isRunning()=%d",
343 server_to_client_socket_, isRunning());
344
345 int status;
346 Buffer *buffer;
347 MsgHeader mh;
348 while ((server_to_client_socket_ > 0) && isRunning()) {
349 DBG("CtrlServerThread::Worker wait on client for message");
350 WaitOnSocketOrStopping(&rd_fds_, server_to_client_socket_);
351 if (isRunning() != true) {
352 break;
353 }
354
355 status = ReadMessage(&mh, &buffer);
356 if (status != STATUS_OK) break;
357
358 if (mh.cmd() == ril_proto::CTRL_CMD_ECHO) {
359 LOGD("CtrlServerThread::Worker echo");
360 status = WriteMessage(&mh, buffer);
361 if (status != STATUS_OK) break;
362 } else {
363 DBG("CtrlServerThread::Worker sendToCtrlServer");
364 status = sendToCtrlServer(&mh, buffer);
365 if (status != STATUS_OK) break;
366 }
367 }
368 close(server_to_client_socket_);
369 server_to_client_socket_ = -1;
370 }
371 }
372 close(stop_server_fd_);
373 stop_server_fd_ = -1;
374
375 close(stop_client_fd_);
376 stop_client_fd_ = -1;
377
378 close(stopper_fd_);
379 stopper_fd_ = -1;
380
381 close(server_accept_socket_);
382 server_accept_socket_ = -1;
383
384 DBG("CtrlServerThread::Worker X param=%p", param);
385 return NULL;
386 }
387 };
388
389 /**
390 * Send a control request complete response.
391 */
SendCtrlRequestComplete(const v8::Arguments & args)392 v8::Handle<v8::Value> SendCtrlRequestComplete(const v8::Arguments& args) {
393 DBG("SendCtrlRequestComplete E:");
394 v8::HandleScope handle_scope;
395 v8::Handle<v8::Value> retValue;
396
397 void *data;
398 size_t datalen;
399
400 Buffer* buffer;
401 MsgHeader mh;
402
403 /**
404 * Get the arguments. There should be at least 3, reqNum,
405 * ril error code and token. Optionally a Buffer containing
406 * the protobuf representation of the data to return.
407 */
408 if (args.Length() < 3) {
409 // Expecting a reqNum, ERROR and token
410 LOGE("SendCtrlRequestComplete X %d parameters"
411 " expecting at least 3: status, reqNum, and token",
412 args.Length());
413 return v8::Undefined();
414 }
415 v8::Handle<v8::Value> v8CtrlStatus(args[0]->ToObject());
416 mh.set_status(ril_proto::CtrlStatus(v8CtrlStatus->NumberValue()));
417 DBG("SendCtrlRequestComplete: status=%d", mh.status());
418
419 v8::Handle<v8::Value> v8ReqNum(args[1]->ToObject());
420 mh.set_cmd(int(v8ReqNum->NumberValue()));
421 DBG("SendCtrlRequestComplete: cmd=%d", mh.cmd());
422
423 v8::Handle<v8::Value> v8Token(args[2]->ToObject());
424 mh.set_token(int64_t(v8Token->NumberValue()));
425 DBG("SendCtrlRequestComplete: token=%lld", mh.token());
426
427 if (args.Length() >= 4) {
428 buffer = ObjectWrap::Unwrap<Buffer>(args[3]->ToObject());
429 mh.set_length_data(buffer->length());
430 DBG("SendCtrlRequestComplete: mh.length_data=%d",
431 mh.length_data());
432 } else {
433 mh.set_length_data(0);
434 buffer = NULL;
435 DBG("SendCtrlRequestComplete: NO PROTOBUF");
436 }
437
438 DBG("SendCtrlRequestComplete: WriteMessage");
439 int status = g_ctrl_server->WriteMessage(&mh, buffer);
440
441 DBG("SendCtrlRequestComplete E:");
442 return v8::Undefined();
443 }
444
ctrlServerInit(v8::Handle<v8::Context> context)445 void ctrlServerInit(v8::Handle<v8::Context> context) {
446 int status;
447
448 g_ctrl_server = new CtrlServerThread(context);
449 status = g_ctrl_server->Run();
450 if (status != STATUS_OK) {
451 LOGE("mock_ril control server could not start");
452 } else {
453 LOGD("CtrlServer started");
454 }
455
456 #if 0
457 LOGD("Test CtrlServerThread stop sleeping 10 seconds...");
458 v8::Unlocker unlocker;
459 sleep(10);
460 LOGD("Test CtrlServerThread call Stop");
461 g_ctrl_server->Stop();
462 v8::Locker locker;
463
464 // Restart
465 g_ctrl_server = new CtrlServerThread(context);
466 status = g_ctrl_server->Run();
467 if (status != STATUS_OK) {
468 LOGE("mock_ril control server could not start");
469 } else {
470 DBG("mock_ril control server started");
471 }
472 #endif
473 }
474