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(...) ALOGD(__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
53using communication::MsgHeader;
54
55class CtrlServerThread;
56static CtrlServerThread *g_ctrl_server;
57
58class 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            ALOGE("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            ALOGE("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            ALOGE("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            ALOGE("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                ALOGE("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            ALOGE("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                        ALOGD("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 */
392v8::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        ALOGE("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
445void 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        ALOGE("mock_ril control server could not start");
452    } else {
453        ALOGD("CtrlServer started");
454    }
455
456#if 0
457    ALOGD("Test CtrlServerThread stop sleeping 10 seconds...");
458    v8::Unlocker unlocker;
459    sleep(10);
460    ALOGD("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        ALOGE("mock_ril control server could not start");
469    } else {
470        DBG("mock_ril control server started");
471    }
472#endif
473}
474