u8 modem_pftp( u8 *ucBuffer ) { u8 *ucParams[ 3 ], ucLen, *ucCommand, *ucFileName, *ucSubString, ucCMD; ucLen = getAllSubStrings( ucBuffer, ucParams, 3, WHITESPACE|NEWLINE ); ucCommand = ucParams[ 0 ]; ucFileName = ucParams[ 1 ]; ucSubString = ucParams[ 2 ]; if( ucCommand ){ if( isStringSame( ucCommand, "get" ) ){ ucCMD = 0; } else if( isStringSame( ucCommand, "put" ) ){ ucCMD = 1; } else{ return( FALSE ); } // else }// if if( ucFileName ){ copyString( ucFileName, globalModemPFTP.File.Name ); } else{ return( FALSE ); } // else // Next test for pcmp tag, if used the file will be decompressed with PCMP as it's saved globalModemPFTP.CurrentChunk = 1; // 0 is reserved for error if ( ucSubString ){ // Second optional parameter is start chunk for resume globalModemPFTP.CurrentChunk = convertStringToInt( ucSubString ); if( globalModemPFTP.CurrentChunk < 1 ){ globalModemPFTP.CurrentChunk = 1; } // if } // if globalModemTCPPort = 80; // HTTP Port globalModemStatus &= ~( MODEM_HTTPINPROGRESS|MODEM_PFTPINPROGRESS|MODEM_SMSINPROGRESS|MODEM_EMAILINPROGRESS); globalModemStatus |= MODEM_BUSY; globalModemPFTP.ChunkSize = 256; // 256 is default, no sz parameter will be sent, saves bandwidth modem_close( "" ); // Clear command queue modem_close( "" ); // close any open connections modem_portal( "" );//Configure internet portal ( APN ) modem_attach( "" );//Attach, always to default context 1 modem_sd( "" ); // Socket dial if( ucCMD ){ if( !fileOpen( &globalModemPFTP.File, globalModemPFTP.File.Name, READ ) ){ return( FALSE ); } // if globalModemStatus |= MODEM_PFTPPUT; pftp_put( "" ); // connection will be closed by server } else{ globalModemStatus &= ~MODEM_PFTPPUT; pftp_get( "" ); // connection will be closed by server } // else return( TRUE ); }
u8 modem_email( u8 *ucBuffer ) { modem_close( "now" ); // this clears the status bits modem_close( "" ); modem_portal( "" );//Configure internet portal ( APN ) modem_attach( "" );//Attach, always to default context 1 globalModemTCPPort = 25; modem_sd( "" ); // Socket dial email_wait(); email_HELO(); email_AUTHLOGIN(); email_user(); email_pw(); email_MAILFROM(); email_RCPT(); email_DATA(); email_body(); email_quit(); email_wait(); modem_suspend( "" ); // Connection must be suspended to close return( TRUE ); }
u8 pftp_put_handler( u8 *ucBuffer ) { u8 *ucParams[ 3 ], ucLen;//ucSubString1, *ucSubString2; ucLen = getAllSubStrings( ucBuffer, ucParams, 3, WHITESPACE|SEPARATORS ); if( ucLen < 3 || !isStringSame( ucParams[ 0 ], "PFTP" ) ){ return( FALSE ); } // if if( isStringSame( ucParams[ 1 ], (u8*)AT_ERROR ) ){ if( isStringSame( ucParams[ 2 ], "403" ) || isStringSame( ucParams[ 2 ], "400" ) ){ // 403 is Forbidden, transaction must be canceled // 400 is Unsupported globalModemStatus &= ~(MODEM_PFTPINPROGRESS|MODEM_BUSY); modem_close( "now" ); // Clear command queue return( TRUE ); } else { // Any other error requires a resend of last packet fileSetPosition( &globalModemPFTP.File, START, globalModemPFTP.CurrentChunk * globalModemPFTP.ChunkSize ); return( FALSE ); // utilize retries } // else } else if( isStringSame( ucParams[ 2 ], (u8*)AT_OK ) ){ print( MODEM_DEBUG, "." ); if( globalModemPFTP.File.Attributes & EOF ){ print( MODEM_DEBUG, "Upload Complete." ); globalModemStatus &= ~(MODEM_PFTPINPROGRESS|MODEM_BUSY|MODEM_PFTPPUT); modem_close( "now" ); // Clear command queue return( TRUE ); } // if ++globalModemPFTP.CurrentChunk; pftp_put( "" ); return( TRUE ); } // else if return( FALSE ); }
u8 email_get( u8 *ucBuffer ) { // This function doesn't "get" an e-mail, rather it acts as the equivalent to HTTP GET u8 *ucParam; ucParam = getNextSubString( ucBuffer, WHITESPACE|PUNCT ); if( ucParam ){ if( isStringSame( ucParam, (u8*)EMAIL_220 ) || // Greeting isStringSame( ucParam, (u8*)EMAIL_235 ) || // Authentication accepted isStringSame( ucParam, (u8*)EMAIL_250 ) || // Ack isStringSame( ucParam, (u8*)EMAIL_334 ) || // Ready for Login isStringSame( ucParam, (u8*)EMAIL_354 ) ){ // Ready for Data return( TRUE ); } else if( isStringSame( ucParam, "500" ) || isStringSame( ucParam, "503" ) ){ modem_close( "now" ); } else if( isStringSame( ucParam, (u8*)EMAIL_221 ) ){ modem_close( "now" ); return( TRUE ); } //else if } return( FALSE ); }
u8 modem_echo( u8 *ucBuffer ) { u8 *ucParam; ucParam = getNextSubString( ucBuffer, WHITESPACE | PUNCT ); modem_close( "now" ); if( isStringSame( ucParam, "on" ) ){ println( MODEM_COM, "ATE1&W" ); return( TRUE ); } else if( isStringSame( ucParam, "off" ) ){ println( MODEM_COM, "ATE0&W" ); return( TRUE ); } // else if return( FALSE ); }
u8 handler_ATGET( u8 *ucBuffer ) { u8 i, *ucParams[ 6 ], ucLen; ucLen = getAllSubStrings( ucBuffer, ucParams, 6, WHITESPACE|SEPARATORS|NEWLINE ); modem_close( "now" ); globalModemStatus &= ~(MODEM_HTTPINPROGRESS); // ToDo: Add code to process HTTP here // Check for pending failure and restart code as needed //if( !cmdRetries( &globalModemQueue ) ){ // This will restart connection process // modem_http( "" ); //} // if return( 0 ); }
static void deactivate_modems(void) { int max = globals.SOFT_MAX_MODEMS; int x; switch_mutex_lock(globals.mutex); for(x = 0; x < max; x++) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stopping Modem SLOT %d\n", x); modem_close(&globals.MODEM_POOL[x]); } switch_mutex_unlock(globals.mutex); /* Wait for Threads to die */ while (globals.THREADCOUNT) { switch_yield(100000); } }
u8 pftp_handler( u8 *ucBuffer ) { u8 *ucParams[ 5 ], ucLen, *ucSubString, *ucPayload; u16 uiCRC, uiLen, uiChunk; u32 i, ulPDIA; ucLen = getAllSubStrings( ucBuffer, ucParams, 5, WHITESPACE|PUNCT|SEPARATORS ); if( isStringSame( ucParams[ 0 ], "PFTP" ) ){ if( isStringSame( ucParams[ 1 ], (u8*)AT_ERROR ) ){ // ERROR is returned when resource is unavailable, such as incorrect filename globalModemStatus &= ~(MODEM_PFTPINPROGRESS|MODEM_BUSY); modem_close( "now" ); // Clear command queue return( TRUE ); // was 0, must test, but 1 cancels }else if( !isStringSame( ucSubString, "EOF" ) ){ uiChunk = convertStringToInt( ucParams[ 1 ] ); print( MODEM_DEBUG, "\rChunkReq: %d", globalModemPFTP.CurrentChunk ); print( MODEM_DEBUG, "\rChunkRcv: %d", uiChunk ); uiLen = convertStringToInt( ucParams[ 2 ] ); ucPayload = ucParams[ 3 ]; //getNextSubString( "", PYGMY_STRING_WHITE|PYGMY_STRING_SEPARATORS ); print( MODEM_DEBUG, "\rPayLen: %d", ucParams[ 3 ] ); if( convertHexEncodedStringToBuffer( ucPayload, ucPayload ) != uiLen ){ print( MODEM_DEBUG, "\rLEN Fail!" ); return( FALSE ); } // if // Updated to 32bit PDIA, single frame in HEX n 03/17/2011 pdiaEncode( 0, PDIA_NEW, 0 ); for( i = 0, ulPDIA = 0, uiCRC = 0; i < uiLen; i++ ){ pdiaEncode( ucPayload[ i ], PDIA_ADD, (u32*)&ulPDIA ); } // for pdiaEncode( 0, PDIA_END, (u32*)&ulPDIA ); //Next append h to mark string as hexadecimal i = len( ucParams[ 4 ] ); ucParams[ 4 ][ i++ ] = 'h'; ucParams[ 4 ][ i ] = '\0'; // Then convert hexadecimal string to integer // Now compare integer against that produced by PDIA encoder if( ulPDIA != convertStringToInt( ucParams[ 4 ] ) ){ // Contains CRC print( MODEM_DEBUG, "\rData Corrupt!" ); return( FALSE ); } // if if( uiChunk == globalModemPFTP.CurrentChunk ){ if( globalModemPFTP.CurrentChunk == 1 ){ //if( !Pygmy_PCMP_DecompressStreamToFile( ucPayload, uiLen, PYGMY_PCMP_START, // backlinkData.PFTP_Compressed, backlinkData.PFTP_File.Name ) ){ // return( 0 ); //} ++globalModemPFTP.CurrentChunk; pftp_get( "" ); return( TRUE ); } else{ //if( !Pygmy_PCMP_DecompressStreamToFile( ucPayload, uiLen, PYGMY_PCMP_DATA, // backlinkData.PFTP_Compressed, "" ) ){ // return( FALSE ); //} ++globalModemPFTP.CurrentChunk; pftp_get( "" ); return( TRUE ); } // else print( MODEM_DEBUG, "." ); } return( FALSE ); } else{ //Pygmy_PCMP_DecompressStreamToFile( "", uiLen, PYGMY_PCMP_STOP, backlinkData.PFTP_Compressed, "" ); globalModemStatus &= ~(MODEM_PFTPINPROGRESS|MODEM_BUSY); modem_close( "now" ); // Clear command queue } // else return( TRUE ); } // if return( FALSE ); }
int modem_connect(struct bbslist *bbs) { int ret; char respbuf[1024]; init_uifc(TRUE, TRUE); if(bbs->conn_type == CONN_TYPE_SERIAL) { if((com=comOpen(bbs->addr)) == COM_HANDLE_INVALID) { uifcmsg("Cannot Open Port", "`Cannot Open Port`\n\n" "Cannot open the specified serial device.\n"); conn_api.terminate=-1; return(-1); } if(bbs->bpsrate) { if(!comSetBaudRate(com, bbs->bpsrate)) { uifcmsg("Cannot Set Baud Rate", "`Cannot Set Baud Rate`\n\n" "Cannot open the specified serial device.\n"); conn_api.terminate=-1; comClose(com); return(-1); } } if(!comRaiseDTR(com)) { uifcmsg("Cannot Raise DTR", "`Cannot Raise DTR`\n\n" "comRaiseDTR() returned an error.\n"); conn_api.terminate=-1; comClose(com); return(-1); } } else { if((com=comOpen(settings.mdm.device_name)) == COM_HANDLE_INVALID) { uifcmsg("Cannot Open Modem", "`Cannot Open Modem`\n\n" "Cannot open the specified modem device.\n"); conn_api.terminate=-1; return(-1); } if(settings.mdm.com_rate) { if(!comSetBaudRate(com, settings.mdm.com_rate)) { uifcmsg("Cannot Set Baud Rate", "`Cannot Set Baud Rate`\n\n" "Cannot open the specified modem device.\n"); conn_api.terminate=-1; comClose(com); return(-1); } } if(!comRaiseDTR(com)) { uifcmsg("Cannot Raise DTR", "`Cannot Raise DTR`\n\n" "comRaiseDTR() returned an error.\n"); conn_api.terminate=-1; comClose(com); return(-1); } /* drain keyboard input to avoid accidental cancel */ while(kbhit()) getch(); uifc.pop("Initializing..."); comWriteString(com, settings.mdm.init_string); comWriteString(com, "\r"); /* Wait for "OK" */ while(1) { if((ret=modem_response(respbuf, sizeof(respbuf), 5))!=0) { modem_close(); uifc.pop(NULL); if(ret<0) uifcmsg("Modem Not Responding", "`Modem Not Responding`\n\n" "The modem did not respond to the initializtion string\n" "Check your init string and phone number.\n"); conn_api.terminate=-1; return(-1); } if(strstr(respbuf, settings.mdm.init_string)) /* Echo is on */ continue; break; } if(!strstr(respbuf, "OK")) { modem_close(); uifc.pop(NULL); uifcmsg(respbuf, "`Initialization Error`\n\n" "The modem did not respond favorably to your initialization string.\n"); conn_api.terminate=-1; return(-1); } uifc.pop(NULL); uifc.pop("Dialing..."); comWriteString(com, settings.mdm.dial_string); comWriteString(com, bbs->addr); comWriteString(com, "\r"); /* Wait for "CONNECT" */ while(1) { if((ret=modem_response(respbuf, sizeof(respbuf), 60))!=0) { modem_close(); uifc.pop(NULL); if(ret<0) uifcmsg(respbuf, "`No Answer`\n\n" "The modem did not connect within 60 seconds.\n"); conn_api.terminate=-1; return(-1); } if(strstr(respbuf, bbs->addr)) /* Dial command echoed */ continue; break; } if(!strstr(respbuf, "CONNECT")) { modem_close(); uifc.pop(NULL); uifcmsg(respbuf, "`Connection Failed`\n\n" "SyncTERM was unable to establish a connection.\n"); conn_api.terminate=-1; return(-1); } uifc.pop(NULL); uifc.pop(respbuf); SLEEP(1000); uifc.pop(NULL); } if(!create_conn_buf(&conn_inbuf, BUFFER_SIZE)) { conn_api.close(); return(-1); } if(!create_conn_buf(&conn_outbuf, BUFFER_SIZE)) { conn_api.close(); destroy_conn_buf(&conn_inbuf); return(-1); } if(!(conn_api.rd_buf=(unsigned char *)malloc(BUFFER_SIZE))) { conn_api.close(); destroy_conn_buf(&conn_inbuf); destroy_conn_buf(&conn_outbuf); return(-1); } conn_api.rd_buf_size=BUFFER_SIZE; if(!(conn_api.wr_buf=(unsigned char *)malloc(BUFFER_SIZE))) { conn_api.close(); destroy_conn_buf(&conn_inbuf); destroy_conn_buf(&conn_outbuf); FREE_AND_NULL(conn_api.rd_buf); return(-1); } conn_api.wr_buf_size=BUFFER_SIZE; if(bbs->conn_type == CONN_TYPE_SERIAL) { _beginthread(modem_output_thread, 0, (void *)-1); _beginthread(modem_input_thread, 0, (void *)-1); } else { _beginthread(modem_output_thread, 0, NULL); _beginthread(modem_input_thread, 0, NULL); } uifc.pop(NULL); return(0); }
int test_loopback() { int ret; pthread_t rx_thread; ret = setup_signal_handler(); if (ret < 0) return 1; ret = modem_setup(); if(ret) { perror(": Failed to setup modem"); return ret; } ret = modem_reset(); if(ret) { perror(": Failed to reset modem"); return 1; } ret = modem_start(); if(ret) { perror(": Failed to start modem"); return 1; } ret = pthread_create(&rx_thread, NULL, rx_thread_fnc, NULL); if(ret) { perror(": Error - pthread_create"); return 1; } printf("Setup modem defaults\n"); defaults(INTERNAL_PACKET_GEN, IP_LOOPBACK_MODE); if (INTERNAL_PACKET_GEN) { sleep(1); fill_in_internal_pgen_data(); printf("Sending 1 packet from internal IP\n"); reg_write(0x120, 1); reg_write(0x120, 0); sleep(3); } else { sleep(1); printf("Sending data\n"); ret = receive_data(); sleep(3); } modem_stop(); pthread_join(rx_thread, NULL); modem_close(); int i; bool b = false; for(i = 0; i < TX_BUF_SIZE-HEADER_DATA_SIZE; i++) { b |= rx_buffer[i] != tx_buffer[i+HEADER_DATA_SIZE]; } if (b) { printf("\n---------RX|TX---------\n"); for(i = 0; i < TX_BUF_SIZE-HEADER_DATA_SIZE; i++) { printf("%d %d\n", rx_buffer[i]>>0, tx_buffer[i+HEADER_DATA_SIZE]); } } printf("Exiting test\n"); return (int) b; }
int modem_close(modem_t *modem) { int r = 0; switch_status_t was_running = switch_test_flag(modem, MODEM_FLAG_RUNNING); switch_clear_flag(modem, MODEM_FLAG_RUNNING); #ifndef WIN32 if (modem->master > -1) { shutdown(modem->master, 2); close(modem->master); modem->master = -1; #else if (modem->master) { SetEvent(modem->threadAbort); CloseHandle(modem->threadAbort); CloseHandle(modem->master); modem->master = 0; #endif r++; } if (modem->slave > -1) { shutdown(modem->slave, 2); close(modem->slave); modem->slave = -1; r++; } if (modem->t31_state) { t31_free(modem->t31_state); modem->t31_state = NULL; } unlink(modem->devlink); if (was_running) { switch_mutex_lock(globals.mutex); globals.REF_COUNT--; switch_mutex_unlock(globals.mutex); } return r; } switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handler) { switch_status_t status = SWITCH_STATUS_SUCCESS; #ifdef WIN32 COMMTIMEOUTS timeouts={0}; #endif memset(modem, 0, sizeof(*modem)); modem->master = -1; modem->slave = -1; /* windows will have to try something like: http://com0com.cvs.sourceforge.net/viewvc/com0com/com0com/ReadMe.txt?revision=RELEASED */ #if USE_OPENPTY if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL)) { if (modem->master < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize pty\n"); status = SWITCH_STATUS_FALSE; goto end; } modem->stty = ttyname(modem->slave); #else #if WIN32 modem->slot = 4+globals.NEXT_ID++; /* need work here we start at COM4 for now*/ snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot); modem->master = CreateFile(modem->devlink, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if(modem->master==INVALID_HANDLE_VALUE) { status = SWITCH_STATUS_FALSE; if(GetLastError()==ERROR_FILE_NOT_FOUND) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port does not exist\n"); goto end; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port open error\n"); goto end; } #elif !defined(HAVE_POSIX_OPENPT) modem->master = open("/dev/ptmx", O_RDWR); #else modem->master = posix_openpt(O_RDWR | O_NOCTTY); #endif #ifndef WIN32 if (modem->master < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n"); } if (grantpt(modem->master) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n"); } if (unlockpt(modem->master) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to unlock slave pty\n"); } modem->stty = ptsname(modem->master); if (modem->stty == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n"); } modem->slave = open(modem->stty, O_RDWR); if (modem->slave < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty); } #endif #ifdef SOLARIS ioctl(modem->slave, I_PUSH, "ptem"); /* push ptem */ ioctl(modem->slave, I_PUSH, "ldterm"); /* push ldterm*/ #endif #endif #ifndef WIN32 modem->slot = globals.NEXT_ID++; snprintf(modem->devlink, sizeof(modem->devlink), "/dev/FS%d", modem->slot); unlink(modem->devlink); if (symlink(modem->stty, modem->devlink)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master)); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } #else timeouts.ReadIntervalTimeout=50; timeouts.ReadTotalTimeoutConstant=50; timeouts.ReadTotalTimeoutMultiplier=10; timeouts.WriteTotalTimeoutConstant=50; timeouts.WriteTotalTimeoutMultiplier=10; SetCommMask(modem->master, EV_RXCHAR); if(!SetCommTimeouts(modem->master, &timeouts)){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } modem->threadAbort = CreateEvent(NULL, TRUE, FALSE, NULL); #endif if (!(modem->t31_state = t31_init(NULL, t31_at_tx_handler, modem, t31_call_control_handler, modem, NULL, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot initialize the T.31 modem\n"); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } if (spandsp_globals.modem_verbose) { span_log_set_message_handler(&modem->t31_state->logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v17_rx.logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v29_rx.logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging, spanfax_log_message, NULL); modem->t31_state->logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v17_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v29_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; } modem->control_handler = control_handler; modem->flags = 0; switch_set_flag(modem, MODEM_FLAG_RUNNING); switch_mutex_init(&modem->mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_mutex_init(&modem->cond_mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_thread_cond_create(&modem->cond, globals.pool); modem_set_state(modem, MODEM_STATE_INIT); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Modem [%s]->[%s] Ready\n", modem->devlink, modem->stty); switch_mutex_lock(globals.mutex); globals.REF_COUNT++; switch_mutex_unlock(globals.mutex); end: return status; } static switch_endpoint_interface_t *modem_endpoint_interface = NULL; struct private_object { switch_mutex_t *mutex; switch_core_session_t *session; switch_channel_t *channel; switch_codec_t read_codec; switch_codec_t write_codec; switch_frame_t read_frame; unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_timer_t timer; modem_t *modem; switch_caller_profile_t *caller_profile; int dead; }; typedef struct private_object private_t; static switch_status_t channel_on_init(switch_core_session_t *session); static switch_status_t channel_on_hangup(switch_core_session_t *session); static switch_status_t channel_on_destroy(switch_core_session_t *session); static switch_status_t channel_on_routing(switch_core_session_t *session); static switch_status_t channel_on_exchange_media(switch_core_session_t *session); static switch_status_t channel_on_soft_execute(switch_core_session_t *session); static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); /* State methods they get called when the state changes to the specific state returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. */ static switch_status_t channel_on_init(switch_core_session_t *session) { switch_channel_t *channel; private_t *tech_pvt = NULL; int to_ticks = 60, ring_ticks = 10, rt = ring_ticks; int rest = 500000; tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { #ifndef WIN32 int tioflags; #endif char call_time[16]; char call_date[16]; switch_size_t retsize; switch_time_exp_t tm; switch_time_exp_lt(&tm, switch_micro_time_now()); switch_strftime(call_date, &retsize, sizeof(call_date), "%m%d", &tm); switch_strftime(call_time, &retsize, sizeof(call_time), "%H%M", &tm); #ifndef WIN32 ioctl(tech_pvt->modem->slave, TIOCMGET, &tioflags); tioflags |= TIOCM_RI; ioctl(tech_pvt->modem->slave, TIOCMSET, &tioflags); #endif at_reset_call_info(&tech_pvt->modem->t31_state->at_state); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "DATE", call_date); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "TIME", call_time); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NAME", tech_pvt->caller_profile->caller_id_name); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NMBR", tech_pvt->caller_profile->caller_id_number); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "ANID", tech_pvt->caller_profile->ani); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "USER", tech_pvt->caller_profile->username); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "CDID", tech_pvt->caller_profile->context); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NDID", tech_pvt->caller_profile->destination_number); modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING); t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); while(to_ticks > 0 && switch_channel_up(channel) && modem_get_state(tech_pvt->modem) == MODEM_STATE_RINGING) { if (--rt <= 0) { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); rt = ring_ticks; } switch_yield(rest); to_ticks--; } if (to_ticks < 1 || modem_get_state(tech_pvt->modem) != MODEM_STATE_ANSWERED) { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_NO_ANSWER); switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER); } else { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ANSWERED); modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED); switch_channel_mark_answered(channel); } } switch_channel_set_state(channel, CS_ROUTING); return SWITCH_STATUS_SUCCESS; }
static void *SWITCH_THREAD_FUNC modem_thread(switch_thread_t *thread, void *obj) { modem_t *modem = obj; int r, avail; #ifdef WIN32 DWORD readBytes; OVERLAPPED o; #endif char buf[T31_TX_BUF_LEN], tmp[80]; switch_mutex_lock(globals.mutex); modem_init(modem, control_handler); globals.THREADCOUNT++; switch_mutex_unlock(globals.mutex); if (switch_test_flag(modem, MODEM_FLAG_RUNNING)) { switch_mutex_lock(modem->cond_mutex); while (switch_test_flag(modem, MODEM_FLAG_RUNNING)) { #ifndef WIN32 r = modem_wait_sock(modem->master, -1, MODEM_POLL_READ | MODEM_POLL_ERROR); #else r = modem_wait_sock(modem, -1, MODEM_POLL_READ | MODEM_POLL_ERROR); #endif if (!switch_test_flag(modem, MODEM_FLAG_RUNNING)) { break; } if (r < 0 || !(r & MODEM_POLL_READ) || (r & MODEM_POLL_ERROR)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Read on master [%s] [%d]\n", modem->devlink, r); break; } modem->last_event = switch_time_now(); if (switch_test_flag(modem, MODEM_FLAG_XOFF)) { switch_thread_cond_wait(modem->cond, modem->cond_mutex); modem->last_event = switch_time_now(); } avail = sizeof(buf) - modem->t31_state->tx.in_bytes + modem->t31_state->tx.out_bytes - 1; if (avail == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Buffer Full, retrying....\n"); switch_yield(10000); continue; } #ifndef WIN32 r = read(modem->master, buf, avail); #else o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* Initialize the rest of the OVERLAPPED structure to zero. */ o.Internal = 0; o.InternalHigh = 0; o.Offset = 0; o.OffsetHigh = 0; assert(o.hEvent); if (!ReadFile(modem->master, buf, avail, &readBytes, &o)) { GetOverlappedResult(modem->master,&o,&readBytes,TRUE); } CloseHandle (o.hEvent); r = readBytes; #endif t31_at_rx(modem->t31_state, buf, r); memset(tmp, 0, sizeof(tmp)); if (!strncasecmp(buf, "AT", 2)) { int x; strncpy(tmp, buf, r); for(x = 0; x < r; x++) { if(tmp[x] == '\r' || tmp[x] == '\n') { tmp[x] = '\0'; } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Command on %s [%s]\n", modem->devlink, tmp); } } switch_mutex_unlock(modem->cond_mutex); if (switch_test_flag(modem, MODEM_FLAG_RUNNING)) { modem_close(modem); } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Thread ended for %s\n", modem->devlink); switch_mutex_lock(globals.mutex); globals.THREADCOUNT--; switch_mutex_unlock(globals.mutex); return NULL; }