OSDN Git Service

Reorganize files.
[android-x86/hardware-ril.git] / mock-ril / src / cpp / ctrl_server.cpp
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 "msgheader.pb.h"
35
36 #include "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
71     Buffer *ObtainBuffer(int length) {
72         Buffer *b = Buffer::New(length);
73         return b;
74     }
75
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
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
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:
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
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
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
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
252     virtual bool isRunning() {
253         bool rv = done_ || WorkerThread::isRunning();
254         return rv;
255     }
256
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
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
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  */
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
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 }