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