Пример #1
0
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 );
} 
Пример #2
0
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 );
}
Пример #3
0
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 );
}
Пример #4
0
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 );
}
Пример #5
0
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 );
}
Пример #6
0
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);
	}
}
Пример #8
0
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 );
}
Пример #9
0
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);
}
Пример #10
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;
}
Пример #11
0
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;
}
Пример #12
0
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;
}