Modularizando o src

Dependencies:   EALib EthernetInterface_vz mbed-rtos mbed

Fork of header_main_colinas_V0-20-09-14 by VZTECH

sip.cpp

Committer:
klauss
Date:
2015-04-30
Revision:
119:ee6a53069455
Parent:
114:472502b31a12
Child:
121:ee02790d00b7

File content as of revision 119:ee6a53069455:

#include "sip.h"

void Sip::__init_sock__( void ){
    sip_server.set_address( this->server_ip , this->server_port );
    sock.set_blocking( false, 0 );
    sock.bind( this->my_port );
}

void Sip::__end_sock__( void ){
    sock.close(); 
}

void Sip::__reconnect__( void ){
    __end_sock__(); 
    sock.init();
    sock.bind( this->my_port );
}
  
Sip::Sip( int new_ext, uint16_t my_port ){
    FILE * fp = NULL;
    char inner_tmp[ 20 ];
    
    if( debug_sip ) debug_msg("[%d, %d] Building SIP", new_ext, my_port );
    
    this->my_ext = new_ext;
    this->my_port = my_port;
        
    fp = fopen( "/qspi/serverip.txt", "r");
    if( fp == NULL){
        if( debug_sip ) debug_msg("[%d] Failed to open /qspi/serverip.txt", this->my_ext );
        strncpy( this->server_ip, SERVER_IP, 20 );    
    }else{
        char tmp[ 16 ] = "\0";
        int read = fread( tmp, 1, 15, fp );
        if( read > 0 ){
            for( int i = 0; i < read; i++ ) 
                if( tmp[ i ] == '\n' || tmp[ i ] == '\r' ){
                    tmp[ i ] = '\0';
                    break;
                }
            strcpy( this->server_ip, tmp );
            if( debug_sip ) debug_msg("[%d] ip server%s( read %d chars ), valid %d", this->my_ext, this->server_ip, read, strlen( this->server_ip )  );
        }else{
            if( debug_sip ) debug_msg("[%d] Failed to read /qspi/serverip.txt", this->my_ext );
            strncpy( this->server_ip, SERVER_IP, 20 );
        }
    }
    fclose( fp );
    this->server_ip[ 15 ] = '\0';
    
    fp = fopen( "/qspi/serverport.txt", "r");
    if( fp == NULL ){
        if( debug_sip ) debug_msg("[%d] Failed to open /qspi/serverport.txt", this->my_ext );
        this->server_port = SERVER_PORT;
    }else{
        if( fread( (void *)inner_tmp, 1, 20, fp ) > 0 ){
            server_port = atoi( inner_tmp );
            if( debug_sip ) debug_msg("[%d] server port %d", this->my_ext, this->server_port );
        }else{
            if( debug_sip ) debug_msg("F[%d] failed to read /qspi/serverport.txt", this->my_ext );
            this->server_port = SERVER_PORT;
        }
    }
    fclose( fp );
    
    fp = fopen( "/qspi/myip.txt", "r");
    if (fp == NULL){
        if( debug_sip ) debug_msg("[%d] Failed to open /qspi/myip.txt", this->my_ext );
        strncpy( this->my_ip, MY_IP, 20 );    
    }else{
        char tmp[ 16 ] = "\0";
        int read = fread( tmp, 1, 15, fp );
        if( read > 0 ){
            for( int i = 0; i < read; i++ ) 
                if( tmp[ i ] == '\n' || tmp[ i ] == '\r' ){
                    tmp[ i ] = '\0';
                    break;
                }
            strcpy( this->my_ip, tmp );
            if( debug_sip ) debug_msg("[%d] ip %s( lidos %d chars ), valid %d", this->my_ext, this->my_ip, read, strlen( this->my_ip ) );
        }else{
            if( debug_sip ) debug_msg("[%d] Failed to read /qspi/myip.txt", this->my_ext );
            strncpy( this->my_ip, MY_IP, 20 );
        }
    }
    fclose( fp );
    
    this->my_ip[ 15 ] = '\0';
    
    if( debug_sip ) debug_msg("[%d] port %d", this->my_ext, this->my_port );
    
    itoa( this->my_ext, this->my_display, 10 );
    
    this->my_rtp_port = 0;
    if( debug_rtp ) debug_msg("[%d] rtp port %d ", this->my_ext, this->my_rtp_port );

    fp = fopen( "/qspi/peerext.txt", "r");
    if( fp == NULL ) {
        if( debug_sip ) debug_msg("[%d] Failed to open /qspi/peerext.txt", this->my_ext );
        this->peer_ext = PEER_EXT;
    } else {
        if( fread( (void *)inner_tmp, 1, 32, fp ) > 0 ) {
            this->peer_ext = atoi( inner_tmp );
            if( debug_sip ) debug_msg("[%d] server ext %d", this->my_ext, this->peer_ext );
        } else {
            if( debug_sip ) debug_msg("Failed to read /qspi/peerext.txt" );
            this->peer_ext = PEER_EXT;
        }
    }
    fclose( fp );
    
    strcpy( this->last_invite_tag, "" );
    strcpy( this->last_invite_callid, "");
    strcpy( this->last_branch, "" );
    strcpy( this->SVNREV, "COLA" );
    status = sip_idle;
    
    __init_sock__();
    
    call = NULL;
    
    waiting = false;
    
    listen_SIP_server_return = 0;
    
    last_cseq = 0;
    
    sip_new_counter++;
}

Sip::~Sip(){
    __end_sock__();
    sip_delete_counter++;
}
 
int Sip::registry ()
{   
    build_registry_package( buffer );
    
    int send = sock.sendTo( sip_server, buffer, strlen( buffer ) ); // > 400
    if( send != strlen( buffer ) )
    {
        if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- Registry -- Sent %i of %i bytes", this->my_ext, send, strlen( buffer ) );
        __reconnect__();
        miss_sip_registry_send_pkg++;
    }

    if( debug_sip ) debug_msg("[%d %d] Registry -- Sent %i of %i bytes", this->my_ext, this->my_port, send, strlen( buffer ) );
    
    return( send ); 
}

VZ_call * Sip::invite(){
    char callbox_string[ 32 ];
    snprintf ( callbox_string, sizeof ( callbox_string ) -1, "%i", get_id () );
    
    if( status == sip_on_call ) return call;
    
    else if( status == sip_idle ){
        int cseq = 0;

        call = NULL;

        build_invite_package( buffer, callbox_string, &cseq );
        
        debug_msg ("cseq::%d", cseq );
        
        if ( drop_invite_to_ast_pkg )
        {
                debug_msg("[%d] Droped invite pkg to ast", this->my_ext );
        }
            else
        {
            int send = 0;
            do{
                send = sock.sendTo( sip_server, buffer, strlen( buffer ) );
            }while( send == 0 );
            
            //FIXME verificar se posso nao usar invite_pkg_sent
            if( send != strlen( buffer ) )
            {
                if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- Invite", this->my_ext );
                __reconnect__();
                miss_sip_invite_send_pkg++;
            }
         
            if( debug_invite || debug_reconnect ) debug_msg("[%d] Return value for invite pkg %d", this->my_ext, send );
        }
        
        invite_timer.stop();
        invite_timer.reset();
        invite_timer.start();
        
        sip_set_status( sip_waiting_trying );
        
        waiting = false;
    }
    
    if( invite_timer.read() > INVITE_MAX_WAITING_TIME ){
        if( debug_invite ) debug_msg("[%d] Invite call timeout :(", this->my_ext );
        invite_timer.stop();
        invite_timer.reset();
        sip_set_status ( sip_denied );
        send_bye();
        
        call = NULL;
        return( NULL );
    }
    
    if( waiting == true ){ return call; }
    
    else return( NULL );
}
 
char * Sip::build_registry_package( char * buffer ){
    char branch[ SIP_MAXFIELDSIZE ];
    char tag[ SIP_MAXFIELDSIZE ];
    char callid[ SIP_MAXFIELDSIZE ];
    fill_random16h( branch );
    fill_random( tag, 18 );
    fill_random16h( callid );
    
    
    /*
    snprintf(s, SIP_MAXMSGSIZE,
        "REGISTER sip:%s:%d SIP/2.0\r\n"  //sip_server_ip, sip_server_port,
        "Via: SIP/2.0/UDP %s:%d;branch=%s\r\n" //sip_myself_ip, sip_myself_port, branch,
        "From: %s <sip:%d@%s:%d>;tag=%s\r\n"  // sip_myself_display, sip_myself_ext, sip_server_ip, sip_server_port, tag,
        "To: %s <sip:%d@%s:%d>\r\n" //  sip_myself_display, sip_myself_ext, sip_server_ip, sip_server_port,
        "Call-ID: %s@%s\r\n"  // callid, sip_myself_ip,
        "CSeq: %d REGISTER\r\n"
        "Max-Forwards: 70\r\n"
        "Contact: %s <sip:%d@%s:%d>;expires=%i\r\n"
        "User-Agent: VZtech/pabxdriver-%s\r\n"
        "Content-Length: 0\r\n"
        SIP_ALLOW "\r\n\r\n",
        sip_server_ip, sip_server_port,
        sip_myself_ip, sip_myself_port, branch,
        sip_myself_display, sip_myself_ext, sip_server_ip, sip_server_port, tag,
        sip_myself_display, sip_myself_ext, sip_server_ip, sip_server_port,
        callid, sip_myself_ip,
        get_cseq(),
        sip_myself_display, sip_myself_ext, sip_myself_ip, sip_myself_port, SIP_REGISTER_EXPIRES,
        SVNREV
    );
    s[SIP_MAXMSGSIZE-1] = 0;
    */
    
    char itoa_buffer[ 65 ];
    strcpy( buffer, "REGISTER sip:" );
    strcat( buffer, server_ip );
    strcat( buffer, ":" );
    itoa( server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " SIP/2.0\r\nVia: SIP/2.0/UDP " );
    strcat( buffer, my_ip );
    strcat( buffer, ":" );
    itoa( my_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ";branch=" );
    strcat( buffer, branch );
    strcat( buffer, "\r\nFrom: " );
    itoa( my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " <sip:" );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" ); 
    strcat( buffer, server_ip );
    strcat( buffer, ":" );
    itoa( server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ">;tag=" );
    strcat( buffer, tag );
    strcat( buffer, "\r\nTo: " );
    itoa( my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " <sip:" );
    itoa( my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, server_ip );
    strcat( buffer, ":" );
    itoa( server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ">\r\nCall-ID: " );
    strcat( buffer, callid );
    strcat( buffer, "\r\nCSeq: " );
    itoa( get_cseq(), itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " REGISTER\r\n" );
    strcat( buffer, "Max-Forwards: " );
    itoa( 70, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "Contact: " );
    itoa( my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " <sip:" );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, my_ip );
    strcat( buffer, ":" );
    itoa( server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ">;expires=270" );
    //itoa( 1200, itoa_buffer, 10 );
    //strcat( buffer, itoa_buffer );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "User-Agent: VZtech/pabxdriver-" );
    strcat( buffer, SVNREV );
    strcat( buffer, "\r\nContent-Length: 0\r\n" );
    strcat( buffer, SIP_ALLOW );
    strcat( buffer, "\r\n\r\n" );              
    //buffer[ SIP_MAXMSGSIZE - 1 ] = 0;
    return buffer;
}
 
char * Sip::build_invite_package( char * pkg, char * callbox_string, int * cseq, bool retry ){
    char header[ SIP_MAXMSGSIZE ], body[ SIP_MAXMSGSIZE ];
    char branch[ SIP_MAXFIELDSIZE ];
    char tag[ SIP_MAXFIELDSIZE ];
    char callid[ SIP_MAXFIELDSIZE ];
    
    if ( !retry )
    {
        *cseq = get_cseq();
        last_cseq = *cseq;
        
        fill_random16h( branch );
        strcpy( last_branch, branch );
        
        fill_random( tag,18 );
        strcpy( last_invite_tag, tag );
        
        fill_random16h( callid );
        strcpy( last_invite_callid, callid );
        
        this->my_rtp_port = fill_random_rtp_port ();
    }
        else
    {
        *cseq = last_cseq;
        
        strcpy( branch, last_branch  );
        
        strcpy( tag, last_invite_tag );
        
        strcpy( callid, last_invite_callid );
    }
    
    if ( debug_invite ) debug_msg("[%d] \r\nbranch :: %s\r\ntag :: %s\r\ncallid :: %s", this->my_ext, branch, tag, callid );
    
    if( debug_rtp || debug_invite ) debug_msg("[%d] Invite PKG rtp port ( %d )", this->my_ext, this->my_rtp_port );

    snprintf( header, SIP_MAXMSGSIZE,
        "INVITE sip:%i@%s:%i SIP/2.0\r\n"
        "Via: SIP/2.0/UDP %s:%i;branch=%s\r\n"
        "From: %s <sip:%i@%s:%i>;tag=%s\r\n"
        "To: <sip:%i@%s:%i>\r\n"
        "Call-ID: %s@%s\r\n"
        "CSeq: %i INVITE\r\n"
        "Contact: %i <sip:%i@%s:%i>\r\n"
        "Max-Forwards: 20\r\n"
        "User-Agent: VZtech/pabxdriver-%s\r\n"
        "Expires: 71\r\n"
        "%s\r\n"
        "Content-Type: application/sdp\r\n",
        this->peer_ext, this->server_ip, this->server_port, 
        this->my_ip, this->my_port, branch, 
        callbox_string, this->my_ext, this->server_ip, this->server_port, tag,
        this->peer_ext, this->server_ip, this->server_port, 
        callid, this->my_ip, 
        *cseq,
        this->my_ext, this->my_ext, this->my_ip, this->my_port, 
        SVNREV, 
        SIP_ALLOW
    );
    
    snprintf( body, SIP_MAXMSGSIZE,
        "v=0\r\no=- 7377 18176 IN IP4 %s\r\n"
        "s=-\r\n"
        "c=IN IP4 %s\r\n"
        "t=0 0\r\n"
        "i=UDP %i\r\n"
        "m=audio %i RTP/AVP 8 101\r\n"
        "a=rtpmap:8 PCMA/8000/1\r\n"
        "a=rtpmap:101 telephone-event/8000\r\n"
        "a=fmtp: 101 0-11",
        this->my_ip,
        this->my_ip,
        this->my_rtp_port,
        this->my_rtp_port
    );
    
    make_content_length( header, body, pkg );
    
    return( pkg );
}
 
char * Sip::make_content_length( char * header, char * body, char * pkg ){
    int size;
    char itoa_buffer[ 65 ];
    size = strlen( body );
    strcpy( pkg, header );
    strcat( pkg, "Content-Length: " );
    itoa( size, itoa_buffer, 10 );
    strcat( pkg, itoa_buffer );
    strcat( pkg, "\r\n\r\n" );
    strcat( pkg, body );
    //pkg[ SIP_MAXMSGSIZE - 1 ] = 0;
    return pkg;
}
 
char * Sip::build_bye_package( char * buffer ){
    char branch[SIP_MAXFIELDSIZE];
    char tag[SIP_MAXFIELDSIZE];
    char itoa_buffer[ 65 ];
    fill_random16h(branch);
    fill_random(tag,18);
    
    strcpy( buffer, "BYE sip:" );
    itoa( this->peer_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, this->server_ip );
    strcat( buffer, ":" );
    itoa( this->server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " SIP/2.0\r\n" );
    strcat( buffer, "Via: SIP/2.0/UDP " );
    strcat( buffer, this->my_ip );
    strcat( buffer, ":" );
    itoa( this->my_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ";branch=" );
    strcat( buffer, branch );
    strcat( buffer, "\r\n" );
    strcat( buffer, "From: " );          
    itoa( this->my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " <sip:" );
    itoa( this->my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, this->server_ip );
    strcat( buffer, ":" );
    itoa( this->server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ">;tag=" );
    strcat( buffer, last_invite_tag );
    strcat( buffer, "\r\n" );
    strcat( buffer, "To: <sip:" );
    itoa( this->peer_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, this->server_ip );
    strcat( buffer, ":" );
    itoa( this->server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ">;tag=" );
    strcat( buffer, tag );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Call-ID: " );
    strcat( buffer, last_invite_callid );
    strcat( buffer, "@" );
    strcat( buffer, this->my_ip );
    strcat( buffer, "\r\n" );
    strcat( buffer, "CSeq: " );
    itoa( get_cseq(), itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " BYE\r\n" );
    strcat( buffer, "Max-Forwards: 70\r\n" );
    strcat( buffer, "User-Agent: VZtech/pabxdriver-" );
    strcat( buffer, SVNREV );
    strcat( buffer, "\r\n" );          
    strcat( buffer, "Content-Length: 0\r\n\r\n" );
    return( buffer );
}
char * Sip::build_ack_package( char * buffer, unsigned char * orig ){
    char to[ SIP_MAXFIELDSIZE ];
    char from[ SIP_MAXFIELDSIZE ];
    char callid[ SIP_MAXFIELDSIZE ];
    char via[ SIP_MAXFIELDSIZE ];
    char branch[ SIP_MAXFIELDSIZE ];
    char cseq[ SIP_MAXFIELDSIZE ];
    char itoa_buffer[ 65 ];
    // FIXME confirmar se nao preciso converter todos os ints com itoa
    if( decode_gettag( orig, "to: ", to ) == 0) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "from: ", from ) == 0) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "call-id: ", callid ) == 0) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    decode_branch( orig, branch );
    decode_cseq( orig, cseq );
 
    if( strlen( via ) > 6 ) {
        if( strcasecmp( ";rport", via+strlen( via )-6) == 0) {
            via[strlen(via)-6] = 0;
        }
    }
    strcpy( buffer, "ACK sip:" );
    itoa( this->peer_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, this->server_ip );
    strcat( buffer, ":" );
    itoa( this->server_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " SIP/2.0\r\n" );
    strcat( buffer, "Via: SIP/2.0/UDP " );
    strcat( buffer, this->my_ip );
    strcat( buffer, ":" );
    itoa( this->my_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ";branch=" );
    strcat( buffer, branch );
    strcat( buffer, "\r\n" );
    strcat( buffer, "From: " );
    strcat( buffer, from );
    strcat( buffer, "\r\n" );
    strcat( buffer, "To: " );
    strcat( buffer, to );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Call-ID: " );
    strcat( buffer, callid );
    strcat( buffer, "\r\n" );
    strcat( buffer, "CSeq: " );
    strcat( buffer, cseq );
    strcat( buffer, " ACK\r\n" );
    strcat( buffer, "Max-Forwards: 70\r\n" );
    strcat( buffer, "Contact: " );
    itoa( this->my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, " <sip:" );
    itoa( this->my_ext, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, "@" );
    strcat( buffer, this->my_ip );
    strcat( buffer, ":" );
    itoa( this->my_port, itoa_buffer, 10 );
    strcat( buffer, itoa_buffer );
    strcat( buffer, ">\r\n" );
    strcat( buffer, "User-Agent: VZtech/pabxdriver-" );
    strcat( buffer, SVNREV );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Content-Length: 0\r\n\r\n" );
    //buffer[SIP_MAXMSGSIZE-1] = 0;
    return( buffer );
}
 
int Sip::get_return_code( char * buffer ){
    char a[32];
    int i = 0, j;
    if( strncmp( "SIP/", buffer, 4 ) != 0 ) return 0;
    if( strlen( buffer ) < 32) return 0;
    strncpy( a, buffer, 31 );
    a[ 31 ] = 0;
    while ( a[ i ] > ' ') i++;
    j = i+i;
    while( (a[ j ] >= '0') && ( a[ j ] <= '9') ) j++;
    a[ j ] = 0;
    return atoi( a + i + 1 );
}
 
char * Sip::build_generic_reply_package(char * buffer, unsigned char * orig, char * tag){
    char to[ SIP_MAXFIELDSIZE ];
    char from[ SIP_MAXFIELDSIZE ];
    char callid[ SIP_MAXFIELDSIZE ];
    char cseq[ SIP_MAXFIELDSIZE ];
    char via[ SIP_MAXFIELDSIZE ];
 
    if( decode_gettag( orig, "to: ", to ) == 0) {
        buffer[0] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "from: ", from ) == 0) {
        buffer[0] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "call-id: ", callid ) == 0) {
        buffer[0] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "cseq: ", cseq ) == 0) {
        buffer[0] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "via: ", via ) == 0) {
        buffer[0] = 0;
        return NULL;
    }
 
    if (strlen(via) > 6) {
        if (strcasecmp(";rport",via+strlen(via)-6)==0) {
            via[strlen(via)-6] = 0;
        }
    }
 
    strcpy( buffer, "SIP/2.0 " );
    strcat( buffer, tag );
    strcat( buffer, "\r\n" );
    strcat( buffer, "To: " );
    strcat( buffer, to );
    strcat( buffer, "\r\n" );
    strcat( buffer, "From: " );
    strcat( buffer, from );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Call-ID: " );
    strcat( buffer, callid );
    strcat( buffer, "\r\n" );
    strcat( buffer, "CSeq: " );
    strcat( buffer, cseq );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Via: " );
    strcat( buffer, via );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Server: VZtech/pabxdriver-" );
    strcat( buffer, SVNREV );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Content-Length: 0\r\n\r\n" );
    //buffer[ SIP_MAXMSGSIZE - 1 ] = 0;
    return( buffer );
}
char * Sip::build_trying_package( char * buffer, unsigned char * orig ){   
    // FIXME trocar 100 para itoa( 100 ... )
    build_generic_reply_package( buffer, orig, "100 Trying" );
    return( buffer );
}
 
char * Sip::build_busy_package( char * buffer, unsigned char * orig ){   
    // FIXME trocar 100 para itoa( 100 ... )
    build_generic_reply_package( buffer, orig, "486 Busy Here");
    return( buffer );
}
char * Sip::build_reply_package( char * buffer, unsigned char * orig ){
    char to[ SIP_MAXFIELDSIZE ];
    char from[ SIP_MAXFIELDSIZE ];
    char callid[ SIP_MAXFIELDSIZE ];
    char cseq[ SIP_MAXFIELDSIZE ];
    char via[ SIP_MAXFIELDSIZE ];
    char tag[ SIP_MAXFIELDSIZE ];
 
    if( decode_gettag( orig, "to: ", to ) == 0) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "from: ", from ) == 0) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "call-id: ", callid ) == 0 ) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "cseq: ", cseq) == 0 ) {
        buffer[ 0 ] = 0;
        return NULL;
    }
    if( decode_gettag( orig, "via: ", via) == 0 ) {
        buffer[ 0 ] = 0;
        return NULL;
    }
 
    if (strlen(via) > 6) {
        if (strcasecmp(";rport",via+strlen(via)-6)==0) {
            via[strlen(via)-6] = 0;
        }
    }
    fill_random(tag,18);
    
    strcpy( buffer, "SIP/2.0 200 OK\r\n" );
    strcat( buffer, "To: " );
    strcat( buffer, to );
    strcat( buffer, ";tag=" );
    strcat( buffer, tag );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "From: " );
    strcat( buffer, from );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "Call-ID: " );
    strcat( buffer, callid );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "CSeq: " );
    strcat( buffer, cseq );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "Via: " );
    strcat( buffer, via );
    strcat( buffer, "\r\n" );
    
    strcat( buffer, "Server: VZtech/pabxdriver-" );
    strcat( buffer, SVNREV );
    strcat( buffer, "\r\n" );
    strcat( buffer, "Content-Length: 0\r\n" );
    strcat( buffer, SIP_ALLOW );
    strcat( buffer, "\r\n\r\n" );
    
    //buffer[ SIP_MAXMSGSIZE - 1 ] = 0;
    return( buffer );
}
char * Sip::fill_random16h(char * buffer ){
    fill_random( buffer, 16 );
    buffer[ 7 ] = '-';
    return( buffer );
}
 
char * Sip::fill_random( char * buffer, int size ){
    static uint16_t seed = time( NULL );
    seed += 1;
    srand( seed );
 
    int i;
    for( i = 0; i < size - 1; i++ ) {
        buffer[ i ] = fill_random_aux[ rand() & 0x3f ];
    }
    
    buffer[ size - 1 ] = 0;
    return( buffer );
}
 
int Sip::get_cseq( void ){
    static unsigned int cseq = 0;
    if( cseq == 0 ) {
        /* initial value, random number */
        cseq = rand();
        cseq &= 0x7fff;
    }
    cseq++;
    cseq &= 0x7fff;
    if( cseq == 0 ) cseq++;
    return cseq;
}
 
char * Sip::decode_cseq( unsigned char * package, char * cseq ){
    char pkg[ 2048 ], cs[ 2048 ];
    if( decode_gettag( package, "cseq: ", pkg ) != 0) {
        int i = 0;
        strcpy( cs, pkg );
        while( ( cs[ i ] != 0 ) && ( cs[ i ] != ' ' ) ) i++;
        cs[ i ] = 0;
        strcpy( cseq, cs );
    } else {
        cseq[ 0 ] = 0;
    }
    return( cseq );
}
 
char * Sip::decode_branch( unsigned char * package, char * branch ){
    char pkg[ 2048 ];
    if( decode_gettag( package, "branch=", pkg ) != 0 ) {
        int i = 0;
        strcpy( branch, pkg );
        while( ( branch[ i ] != 0 ) && ( branch[ i ] != ';' ) ) i++;
        branch[ i ] = 0;
    } else {
        branch[ 0 ] = 0;
    }
    return( branch );
}
int Sip::decode_gettag( unsigned char * package, char * tag, char * out ){
    int size, i, cmpsize;
    cmpsize = strlen( tag );
    size = strlen( ( char * )package )-cmpsize;
    for ( i=0; i<size; i++) {
        if( strncasecmp( tag, (char*)package+i, cmpsize ) == 0) {
            char * s;
            s = (char*)package+i+cmpsize;
            register int j = 0;
            while ((s[ j ] != '\r') && (s[ j ] != '\n')) j++;
            strncpy( out, s, j ); // copy string to output
            out[ j ] = 0; // terminate string
            return 1; // found
        }
    }
    return 0; // not found
}
 
int Sip::get_id( void ){
    return this->my_ext;
}
int Sip::get_my_rtp_port( void ){
    return this->my_rtp_port;
}
int Sip::fill_random_rtp_port ()
{
    static uint16_t port = 0;
    port += 2;
    port &= 0x7fe; // 0 to 2046, always even
    return port + 16384;
}

void Sip::set_server_port( int new_server_port ){
    this->server_port = new_server_port;
}
void Sip::set_server_ext( int new_server_ext ){
    this->peer_ext = new_server_ext;
}
void Sip::set_server_ip( char * new_server_ip ){
    strcpy( this->server_ip, new_server_ip );
    this->server_ip[19] = 0;
}

/*  Retorna 
    = 0 :: ok
    < 0 :: tive problemas
    > 0 :: devo remover essa call do vetor de calls 
*/
int Sip::listen_SIP_server( void ){
    int ret = listen_SIP_server_return;
    listen_SIP_server_return = 0;
    return ret;
}

void Sip::set_ext( int ext ){
    my_ext = ext;
}

void Sip::set_port( int port ){
    my_port = port;
}

void Sip::send_bye ( void )
{
    int send = sock.sendTo( sip_server, build_bye_package( this->buffer ), strlen( this->buffer ) );
    
    if( debug_sip ) debug_msg( "[%d] sizeof( bye pkg ) :: %d", this->my_ext, strlen( buffer ) );
    
    if( send != strlen( this->buffer ) )
    {
        if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- BYE, %d, %d", this->my_ext, send, strlen( this->buffer ) );
        __reconnect__();
        miss_sip_bye_send_pkg++;
    }
}

int Sip::get_status( void ){
    return this->status;    
}

void Sip::sip_set_status( uint8_t status ){
    this->status = status;    
}

int Sip::get_socket_fd( void ){
    return sock.get_fd();
}

int Sip::udp_incomming_pkg( void ){
    Endpoint from;  
    
    int length = sock.receiveFrom( from, buffer, sizeof( buffer ) );
    
    if( memcmp( ( ( u8_t * )( &(from._remoteHost) ) ) + 2, ( ( u8_t * )( &(sip_server._remoteHost) ) ) + 2, 6 ) != 0 ) return 0;
    
    if( length == -1 )
    {
        if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- UDP Incomming", get_ext () );
        __reconnect__();
        miss_sip_inc_pkg++;
    }
    
    if( length > 0 ){
        if( sizeof( buffer ) > length ) buffer[ length ] = 0;
        
        int sip_response = -1;
        
        // faster than atoi() (: 
        if( buffer[ 7 ] == ' ' || buffer[ 11 ] == ' ' ){
            sip_response = ( buffer[ 8 ] - '0' ) * 100 + ( buffer[ 9 ] - '0' ) * 10 + ( buffer[ 10 ] - '0' );
        }
        
        if( ( status == sip_trying ) || ( status == sip_ringing ) || ( status == sip_waiting_trying ) || ( status == sip_on_call ) )
        { 
            if( sip_response == 200 ){ // Ok    
                char *ref = strstr( buffer, "audio" );
                if( debug_invite ) debug_msg("[%d] udp_incomming_pkg -- ok", this->my_ext );
                if( ref != NULL ){
                    
                    static uint8_t count = 0;
                    if ( ( count++ % 3 ) == 0 ) drop_ok_pkg = !drop_ok_pkg;
                        
                    if ( drop_this_amount_of_ack_to_ast-- )
                    {
                        debug_msg("[%d] Droped ok pkg received from ast (%d)", this->my_ext, drop_this_amount_of_ack_to_ast );
                        return -71;    
                    }
                                        
                    ref += 6; // audio 
                    ref = strtok( ref, " ");
                    if( call == NULL ){
                        call = new VZ_call( this->my_ext, this->my_rtp_port, this->peer_ext, atoi( ref ) );
                        if( debug_rtp ) debug_msg("[%d] Ok new call ( %d, %d, %d, %d ( %s ) ) ", this->my_ext, this->my_ext, this->my_rtp_port, this->peer_ext, atoi( ref ), ref );
                        if( call == NULL ) memory_is_over = true;
                    }
                    char ans[ 1024 ];
                    build_ack_package( ans, ( unsigned char *)buffer );
                    
                    int send = 0;
                    
                    if ( drop_ack_pkg )
                    {
                        debug_msg("[%d] Droped ack pkt to ast", this->my_ext );
                    }
                        else
                    {
                        send = sock.sendTo( sip_server, ans, strlen( ans ) );
                    
                        if( send != strlen( ans ) )
                        {
                            if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- Ok -- Call mode on", this->my_ext );
                            __reconnect__();
                            miss_sip_ok_send_pkg++;
                        }
                    }
                    
                    if( debug_invite ) debug_msg("[%d] Call alocada -- sizeof( ack ) :: %d - strlen( ans ):: %d", this->my_ext, send, strlen( ans ) );
                    sip_set_status ( sip_on_call );
                }
            }
        }
        if( ( status == sip_trying ) || ( status == sip_ringing ) ){                
            if( sip_response >= 400 && sip_response < 700 ){
                if( debug_invite ) { 
                    buffer[ 11 ] = 0; 
                    if( debug_invite ) debug_msg("[%d] Busy Here :: %s", this->my_ext, buffer + 8 );
                }
                send_bye();
                sip_set_status ( sip_busy );
                return( NULL );  
            }else // Session in Progress
                if( sip_response == 183 ){
                char *ref = strstr( buffer, "audio" );
                if( ref != NULL ){
                    ref += 6; // strlen( "audio" ) == 6
                    ref = strtok( ref, " ");
                    if( call == NULL ){
                        this->call = new VZ_call( this->my_ext, this->my_rtp_port, this->peer_ext, atoi( ref ) );
                        if( debug_rtp ) debug_msg("[%d] Session in Progress ( %d, %d, %d, %d ( %s ) ) ",this->my_ext, this->my_ext, this->my_rtp_port, this->peer_ext, atoi( ref ), ref );
                        if( call == NULL ) memory_is_over = true;
                    }
                    waiting = true;
                }
            }
        }
        if( status == sip_trying ){
            if( sip_response == 180 ){
                if( debug_invite ) debug_msg("[%d] ringing", this->my_ext );
                sip_set_status ( sip_ringing );
            }
        }
        if( status == sip_waiting_trying ){
            if( sip_response == 100 ){
                if( debug_invite ) debug_msg("[%d] trying", this->my_ext )
                sip_set_status ( sip_trying );
            }
        }
        if( status == sip_on_call ){
            if( !( strncasecmp( buffer, "bye ", 4 ) ) ){
                char ans[ 2000 ];
                build_reply_package( ans, (unsigned char*)buffer );
                
                int send = sock.sendTo( sip_server, ans, strlen( ans ) );
                if( send != strlen( ans ) )
                {
                    if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- RCV BYE from * -- ( expected, realized ) ( %d, %d )", this->my_ext, strlen( ans ), send );
                    __reconnect__();
                    miss_sip_rcv_bye_send_pkg++;
                }
                
                if( debug_invite ) debug_msg("[%d] Bye request received from * - sizeof( bye reply pkg ) :: %d", this->my_ext, strlen( ans ) );
                
                
                set_sip_rtp_port( 0 );
                
                listen_SIP_server_return = my_ext;
            }
        }
    }
    
    return length;
}

void Sip::reset_call( void ){
    if( call != NULL ) call = NULL;    
}

int Sip::get_ext( void ){ return my_ext; }

int Sip::get_port( void ){ return my_port; }

int Sip::get_sip_rtp_port( void ){ return my_rtp_port; }

void Sip::set_sip_rtp_port ( int new_my_rtp_port )
{ 
    this->my_rtp_port = new_my_rtp_port; 
    if( debug_rtp ) debug_msg( "[%d] this->my_rtp_port ( %d ) = new_my_rtp_port( %d )", this->my_ext, this->my_rtp_port, new_my_rtp_port );
}

int Sip::print_yourself ( void )
{
    send_msg ("");
    send_msg ("Values ::\r\n");
    send_msg("server_ip :: %s", server_ip );
    send_msg("server_port :: %d", server_port );
    send_msg("my_ip :: %s", my_ip );
    send_msg("my_port :: %d", my_port );
    send_msg("my_ext :: %d", my_ext );
    send_msg("my_rtp_port :: %d", my_rtp_port );
    send_msg("my_display :: %s", my_display );
    send_msg("peer_ext :: %d", peer_ext );
    send_msg("fill_random_aux :: %s", fill_random_aux );
    send_msg("last_invite_tag :: %s", last_invite_tag );
    send_msg("last_invite_callid :: %s", last_invite_callid );
    send_msg("SVNREV :: %s", SVNREV );
    send_msg("char buffer[ 1024 ] :: %p", ( void * ) buffer );
    
    //FIXME esse tipo de tag existe como metalinguagem ???
    //TOTHINK o que fazer pra entender melhor o estado dos sockets
    send_msg("UDPSocket sock :: %p", ( void * ) &sock );
    send_msg("Endpoint sip_server :: %p", ( void * ) &sip_server );
    
    send_msg("call :: %p", ( void * ) call );
    send_msg("invite_timer :: %d", ( int ) invite_timer.read () );
    send_msg("waiting ::  %s", ( waiting ) ? "true" : "false" );
    send_msg("listen_SIP_server_return :: %d", listen_SIP_server_return );
    send_msg ("");

    return( sizeof( Sip ) );    
}

int Sip::retry_send_last_invite_pkg_to_ast ( void )
{
    char callbox_string[ 32 ];
    snprintf ( callbox_string, sizeof ( callbox_string ) -1, "%i", get_id () );
    
    int cseq = 0;

    call = NULL;

    build_invite_package( buffer, callbox_string, &cseq, true );
    
    debug_msg ("cseq::%d", cseq );
    
    int send = 0;
    
    if ( drop_invite_to_ast_pkg )
    {
            debug_msg("[%d] Droped invite pkg to ast", this->my_ext );
    }
        else
    {
        do{
            send = sock.sendTo( sip_server, buffer, strlen( buffer ) );
        }while( send == 0 );
        
        if( send != strlen( buffer ) )
        {
            if( debug_reconnect ) debug_msg("[%d] Reconnect SIP -- Invite", this->my_ext );
            __reconnect__();
            miss_sip_invite_send_pkg++;
        }
     
        if( debug_invite || debug_reconnect ) debug_msg("[%d] Return value for invite pkg %d", this->my_ext, send );
    }
    
    return ( send );
}