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