remote_call.c revision 55f4e4a5ec657a017e3bf75299ad71fd1c968dd3
1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "remote_call.h"
13#include "android_utils.h"
14#include "sysdeps.h"
15#include "gsm.h"
16#include "android.h"
17#include "sockets.h"
18#include <stdlib.h>
19
20#define  DEBUG  1
21
22#if 1
23#  define  D_ACTIVE  VERBOSE_CHECK(modem)
24#else
25#  define  D_ACTIVE  DEBUG
26#endif
27
28#if 1
29#  define  S_ACTIVE  VERBOSE_CHECK(socket)
30#else
31#  define  S_ACTIVE  DEBUG
32#endif
33
34#if DEBUG
35#  include <stdio.h>
36#  define  D(...)   do { if (D_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
37#  define  S(...)   do { if (S_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
38#else
39#  define  D(...)   ((void)0)
40#  define  S(...)   ((void)0)
41#endif
42
43/** By convention, remote numbers are the console ports, i.e. 5554, 5556, etc...
44 **/
45#define  REMOTE_NUMBER_BASE       5554
46#define  REMOTE_NUMBER_MAX        16
47#define  REMOTE_NUMBER_MAX_CHARS  4
48#define  REMOTE_CONSOLE_PORT      5554
49
50int
51remote_number_from_port( int  port )
52{
53    if (port & 1)  /* must be even */
54        return -1;
55
56    port = (port - REMOTE_CONSOLE_PORT) >> 1;
57    if ((unsigned)port >= REMOTE_NUMBER_MAX)
58        return -1;
59
60    return REMOTE_NUMBER_BASE + port*2;
61}
62
63int
64remote_number_to_port( int  number )
65{
66    if (number & 1)  /* must be even */
67        return -1;
68
69    number = (number - REMOTE_NUMBER_BASE) >> 1;
70    if ((unsigned)number >= REMOTE_NUMBER_MAX)
71        return -1;
72
73    return REMOTE_CONSOLE_PORT + number*2;
74}
75
76int
77remote_number_string_to_port( const char*  number )
78{
79    char*  end;
80    long   num = strtol( number, &end, 10 );
81
82    if (end == NULL || *end || (int)num != num )
83        return -1;
84
85    return remote_number_to_port( (int)num );
86}
87
88/** REMOTE CALL OBJECTS
89 **/
90
91typedef struct RemoteCallRec {
92    struct RemoteCallRec*   next;
93    struct RemoteCallRec**  pref;
94    RemoteCallType          type;
95    int                     to_port;
96    int                     from_port;
97    SysChannel              channel;
98    RemoteResultFunc        result_func;
99    void*                   result_opaque;
100
101    char                    quitting;
102
103    /* the output buffer */
104    char*                   buff;
105    int                     buff_pos;
106    int                     buff_len;
107    int                     buff_size;
108    char                    buff0[32];
109
110} RemoteCallRec, *RemoteCall;
111
112static void
113remote_call_done( RemoteCall  call )
114{
115    call->pref[0] = call->next;
116    call->next    = NULL;
117    call->pref    = &call->next;
118
119    if (call->buff && call->buff != call->buff0) {
120        free(call->buff);
121        call->buff      = call->buff0;
122        call->buff_size = (int) sizeof(call->buff0);
123    }
124
125    if ( call->channel ) {
126        sys_channel_close( call->channel );
127        call->channel = NULL;
128    }
129
130    call->buff_pos = 0;
131    call->buff_len = 0;
132}
133
134
135static void
136remote_call_free( RemoteCall  call )
137{
138    if (call) {
139        remote_call_done( call );
140        free(call);
141    }
142}
143
144
145static void  remote_call_event( void*  opaque, int  events );  /* forward */
146
147static RemoteCall
148remote_call_alloc( RemoteCallType  type, int  to_port, int  from_port )
149{
150    RemoteCall  rcall    = calloc( sizeof(*rcall), 1 );
151    int         from_num = remote_number_from_port(from_port);
152
153    if (rcall != NULL) {
154        char  *p, *end;
155
156        rcall->pref      = &rcall->next;
157        rcall->type      = type;
158        rcall->to_port   = to_port;
159        rcall->from_port = from_port;
160        rcall->buff      = rcall->buff0;
161        rcall->buff_size = sizeof(rcall->buff0);
162        rcall->buff_pos  = 0;
163
164        p   = rcall->buff;
165        end = p + rcall->buff_size;
166
167        switch (type) {
168            case REMOTE_CALL_DIAL:
169                p = bufprint(p, end, "gsm call %d\n", from_num );
170                break;
171
172            case REMOTE_CALL_BUSY:
173                p = bufprint(p, end, "gsm busy %d\n", from_num);
174                break;
175
176            case REMOTE_CALL_HOLD:
177                p = bufprint(p, end, "gsm hold %d\n", from_num);
178                break;
179
180            case REMOTE_CALL_ACCEPT:
181                p = bufprint(p, end, "gsm accept %d\n", from_num);
182                break;
183
184            case REMOTE_CALL_HANGUP:
185                p = bufprint(p, end, "gsm cancel %d\n", from_num );
186                break;
187
188            default:
189                ;
190        }
191        if (p >= end) {
192            D("%s: buffer too short\n", __FUNCTION__ );
193            remote_call_free(rcall);
194            return NULL;
195        }
196
197        rcall->buff_len = p - rcall->buff;
198
199        rcall->channel = sys_channel_create_tcp_client( "localhost", to_port );
200        if (rcall->channel == NULL) {
201            D("%s: could not create channel to port %d\n", __FUNCTION__, to_port);
202            remote_call_free(rcall);
203            return NULL;
204        }
205
206        sys_channel_on( rcall->channel, SYS_EVENT_WRITE, remote_call_event, rcall );
207    }
208    return  rcall;
209}
210
211
212static int
213remote_call_set_sms_pdu( RemoteCall  call,
214                         SmsPDU      pdu )
215{
216    char  *p, *end;
217    int    msg2len;
218
219    msg2len = 32 + smspdu_to_hex( pdu, NULL, 0 );
220    if (msg2len > call->buff_size) {
221        char*  old_buff = call->buff == call->buff0 ? NULL : call->buff;
222        char*  new_buff = realloc( old_buff, msg2len );
223        if (new_buff == NULL) {
224            D("%s: not enough memory to alloc %d bytes", __FUNCTION__, msg2len);
225            return -1;
226        }
227        call->buff      = new_buff;
228        call->buff_size = msg2len;
229    }
230
231    p   = call->buff;
232    end = p + call->buff_size;
233
234    p  = bufprint(p, end, "sms pdu ");
235    p += smspdu_to_hex( pdu, p, end-p );
236    *p++ = '\n';
237    *p = 0;
238
239    call->buff_len = p - call->buff;
240    call->buff_pos = 0;
241    return 0;
242}
243
244
245static void
246remote_call_add( RemoteCall   call,
247                 RemoteCall  *plist )
248{
249    RemoteCall  first = *plist;
250
251    call->next = first;
252    call->pref = plist;
253
254    if (first)
255        first->pref = &call->next;
256}
257
258static void
259remote_call_event( void*  opaque, int  events )
260{
261    RemoteCall  call = opaque;
262
263    S("%s: called for call (%d,%d), events=%02x\n", __FUNCTION__,
264       call->from_port, call->to_port, events);
265
266    if (events & SYS_EVENT_READ) {
267        /* simply drain the channel */
268        char  temp[32];
269        int  n = sys_channel_read( call->channel, temp, sizeof(temp) );
270        if (n <= 0) {
271            /* remote emulator probably quitted */
272            //S("%s: emulator %d quitted with %d: %s\n", __FUNCTION__, call->to_port, socket_errno, socket_errstr());
273            remote_call_free( call );
274            return;
275        }
276    }
277
278    if (events & SYS_EVENT_WRITE) {
279        int  n;
280
281        if (S_ACTIVE) {
282            int  nn;
283            S("%s: call (%d,%d) sending %d bytes '", __FUNCTION__,
284            call->from_port, call->to_port, call->buff_len - call->buff_pos );
285            for (nn = call->buff_pos; nn < call->buff_len; nn++) {
286                int  c = call->buff[nn];
287                if (c < 32) {
288                    if (c == '\n')
289                        S("\\n");
290                    else if (c == '\t')
291                        S("\\t");
292                    else if (c == '\r')
293                        S("\\r");
294                    else
295                        S("\\x%02x", c);
296                } else
297                    S("%c", c);
298            }
299            S("'\n");
300        }
301
302        n = sys_channel_write( call->channel,
303                               call->buff + call->buff_pos,
304                               call->buff_len - call->buff_pos );
305        if (n <= 0) {
306            /* remote emulator probably quitted */
307            S("%s: emulator %d quitted unexpectedly with error %d: %s\n",
308                    __FUNCTION__, call->to_port, socket_errno, socket_errstr());
309            if (call->result_func)
310                call->result_func( call->result_opaque, 0 );
311            remote_call_free( call );
312            return;
313        }
314        call->buff_pos += n;
315
316        if (call->buff_pos >= call->buff_len) {
317            /* cool, we sent everything */
318            S("%s: finished sending data to %d\n", __FUNCTION__, call->to_port);
319            if (!call->quitting) {
320                    call->quitting = 1;
321                    sprintf( call->buff, "quit\n" );
322                    call->buff_len = strlen(call->buff);
323                    call->buff_pos = 0;
324            } else {
325                call->quitting = 0;
326                if (call->result_func)
327                    call->result_func( call->result_opaque, 1 );
328
329                sys_channel_on( call->channel, SYS_EVENT_READ, remote_call_event, call );
330            }
331        }
332    }
333}
334
335static RemoteCall  _the_remote_calls;
336
337
338static int
339remote_from_number( const char*  from )
340{
341    char*  end;
342    long   num = strtol( from, &end, 10 );
343
344    if (end == NULL || *end)
345        return -1;
346
347    if ((unsigned)(num - REMOTE_NUMBER_BASE) >= REMOTE_NUMBER_MAX)
348        return -1;
349
350    return (int) num;
351}
352
353
354static RemoteCall
355remote_call_generic( RemoteCallType  type, const char*  to_number, int  from_port )
356{
357    int         to_port = remote_number_string_to_port(to_number);
358    RemoteCall  call;
359
360    if ( remote_number_from_port(from_port) < 0 ) {
361        D("%s: from_port value %d is not valid", __FUNCTION__, from_port);
362        return NULL;
363    }
364    if ( to_port < 0 ) {
365        D("%s: phone number '%s' is not decimal or remote", __FUNCTION__, to_number);
366        return NULL;
367    }
368    if (to_port == from_port) {
369        D("%s: trying to call self\n", __FUNCTION__);
370        return NULL;
371    }
372    call = remote_call_alloc( type, to_port, from_port );
373    if (call == NULL) {
374        return NULL;
375    }
376    remote_call_add( call, &_the_remote_calls );
377    D("%s: adding new call from port %d to port %d\n", __FUNCTION__, from_port, to_port);
378    return call;
379}
380
381
382int
383remote_call_dial( const char*       number,
384                  int               from,
385                  RemoteResultFunc  result_func,
386                  void*             result_opaque )
387{
388    RemoteCall   call = remote_call_generic( REMOTE_CALL_DIAL, number, from );
389
390    if (call != NULL) {
391        call->result_func   = result_func;
392        call->result_opaque = result_opaque;
393    }
394    return call ? 0 : -1;
395}
396
397
398void
399remote_call_other( const char*  to_number, int  from_port, RemoteCallType  type )
400{
401    remote_call_generic( type, to_number, from_port );
402}
403
404/* call this function to send a SMS to a remote emulator */
405int
406remote_call_sms( const char*   number,
407                 int           from,
408                 SmsPDU        pdu )
409{
410    RemoteCall   call = remote_call_generic( REMOTE_CALL_SMS, number, from );
411
412    if (call == NULL)
413        return -1;
414
415    if (call != NULL) {
416        if ( remote_call_set_sms_pdu( call, pdu ) < 0 ) {
417            remote_call_free(call);
418            return -1;
419        }
420    }
421    return call ? 0 : -1;
422}
423
424
425void
426remote_call_cancel( const char*  to_number, int  from_port )
427{
428    remote_call_generic( REMOTE_CALL_HANGUP, to_number, from_port );
429}
430