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