📄 sipclient.cpp
字号:
#include <pwd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/nameser.h>#include <resolv.h>#include <qdatetime.h>#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include "siputil.h"#include "sipuser.h"#include "sipvia.h"#include "sipcall.h"#include "tcpmessagesocket.h"#include "sipmessage.h"#include "mimecontenttype.h"#include "sipstatus.h"#include "siptransaction.h"#include "sipclient.h"typedef unsigned int u_int;typedef unsigned short u_short;typedef unsigned char u_char;struct s_SOA{ char *mname; char *rname; u_int serial; u_int refresh; u_int retry; u_int expire; u_int minimum;};struct s_NULL{ char *anything; u_short length; /* Length of valid data */};struct s_WKS{ struct in_addr address; char *bitmap; u_int maplength; u_char protocol;};struct s_HINFO{ char *cpu; char *os;};struct s_MINFO{ char *rmailbx; char *emailbx;};struct s_MX{ char *exchange; u_short preference;};struct s_TXT{ char *text; struct s_TXT *next; u_short len;};struct s_SRV{ u_short priority; u_short weight; u_short port; char *target;};struct s_NAPTR{ u_short order; u_short pref; char *flags; char *service; char *regexp; char *replacement;};/* AFS servers */struct s_AFSDB{ u_short subtype; char *hostname;};/* Responsible Person */struct s_RP{ char *mbox_dname; char *txt_dname;};/* ISDN Address */struct s_ISDN{ char *address; char *sa; /* optional */};/* Route Through */struct s_RT{ u_short preference; char *int_host;};/* Generic RDATA RR structure */union u_rdata{ char *string; /* Any simple string record */ u_int number; /* Any simple numeric record */ struct in_addr address; /* Simple address (A record) *//* other structured RR types */ struct s_SOA soa; struct s_NULL null; struct s_WKS wks; struct s_HINFO hinfo; struct s_MINFO minfo; struct s_MX mx; struct s_TXT txt; struct s_SRV srv; struct s_NAPTR naptr;/* RFC 1183 RR types */ struct s_AFSDB afsdb; struct s_RP rp; struct s_ISDN isdn; struct s_RT rt;};/* Full RR structure */typedef struct s_rr{ char *name; u_short type; u_short xclass; u_int ttl; u_int dlen; union u_rdata rdata;} s_rr;/* DNS Question sctructure */typedef struct s_question{ char *qname; u_short qtype; u_short qclass;} s_question;/* Full DNS message structure */typedef struct s_res_response{ HEADER header; s_question **question; s_rr **answer; s_rr **authority; s_rr **additional;} res_response;bool const traceMessageSending = true;bool const traceMessageReceived = true;SipClient::SipClient( QObject *parent, const char *name, unsigned int newListenport, bool newLooseRoute, bool newStrictRoute, QString socketStr ) : QObject( parent, name ){ if( !setupSocketStuff( newListenport, socketStr ) ) { printf("SipClient::setupSocketStuff() Failed.\n"); exit( 1 ); } setupContactUri(); useProxyDial = false; useExplicitProxy = false; proxyport = 5060; calls.setAutoDelete( false ); tcpSockets.setAutoDelete( true ); fwmode = false; busymode = false; user = 0; hidemode = DontHideVia; symmetricmode = false; maxforwards = 0; looseRoute = newLooseRoute; strictRoute = newStrictRoute; testOn = false; useStunProxy = false; tcpSocket = 0;}SipClient::~SipClient( void ){}void SipClient::setupContactUri( SipUser *user ){ if( user ) { contacturi.setFullname( user->getUri().getFullname() ); contacturi.setUsername( user->getUri().getUsername() ); } contacturi.setHostname( Sip::getLocalAddress() ); if( isTcpSocket() ) { contacturi.setPortNumber( TCP_listener.getPortNumber() ); contacturi.setTransportParam( SipUri::TCP ); } else { contacturi.setPortNumber( listener.getPortNumber() ); contacturi.setTransportParam( SipUri::UDP ); }}bool SipClient::setupSocketStuff( unsigned int newListenport, QString socketStr ){ unsigned int listenport; if( socketStr == "UDP" ) { SocketMode = UDP; } else { SocketMode = TCP; } listenport = QString::fromUtf8( getenv( "DISSIPATE_PORT" ) ).toUInt(); if( newListenport ) { listenport = newListenport; } if( listenport == 0 ) { listenport = 5060; } if( isTcpSocket() ) { listenport = TCP_listener.listen( listenport ); if( !listenport ) { return false; } TCP_listener.forcePortNumber( listenport ); printf( "SipClient: Listening TCP on port: %d\n", TCP_listener.getPortNumber() ); } listenport = listener.listen( listenport ); if( !listenport ) { return false; } listener.forcePortNumber( listenport ); printf( "SipClient: Listening UDP on port: %d\n", listener.getPortNumber() ); printf( "SipClient: Our address: %s\n", Sip::getLocalAddress().latin1() ); return true;}void SipClient::doSelect( bool block ){ struct timeval timeout; fd_set read_fds; int highest_fd; timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO( &read_fds ); FD_SET( listener.getFileDescriptor(), &read_fds ); highest_fd = listener.getFileDescriptor() + 1;retry: if( select( highest_fd, &read_fds, NULL, NULL, block ? NULL : &timeout ) == -1 ) { if( errno == EINTR ) goto retry; perror( "SipClient::doSelect(): select() punted" ); exit( 1 ); } if( FD_ISSET( listener.getFileDescriptor(), &read_fds ) ) { incomingMessage( listener.getFileDescriptor() ); } if( isTcpSocket() ) { FD_ZERO( &read_fds ); FD_SET( TCP_listener.getFileDescriptor(), &read_fds ); highest_fd = TCP_listener.getFileDescriptor() + 1;retry2: if( select( highest_fd, &read_fds, NULL, NULL, block ? NULL : &timeout ) == -1 ) { if( errno == EINTR ) goto retry2; perror( "SipClient::doSelect(): select() punted" ); exit( 1 ); } if( FD_ISSET( TCP_listener.getFileDescriptor(), &read_fds ) ) { clilen = sizeof(cli_addr); newsockfd = ::accept( TCP_listener.getFileDescriptor(), (struct sockaddr *) &cli_addr, (socklen_t*)&clilen); incomingMessage( newsockfd ); ::close( newsockfd ); } TCPMessageSocketIterator it( getTcpSocketList() ); for (it.toFirst(); it.current(); ++it) { tcpSocket = it.current(); if( tcpSocket != 0 ) { FD_ZERO( &read_fds ); FD_SET( tcpSocket->getFileDescriptor(), &read_fds ); highest_fd = tcpSocket->getFileDescriptor() + 1;retry3: if( select( highest_fd, &read_fds, NULL, NULL, block ? NULL : &timeout ) == -1 ) { if( errno == EINTR ) goto retry3; perror( "SipClient::doSelect(): select() punted" ); exit( 1 ); } if( FD_ISSET( tcpSocket->getFileDescriptor(), &read_fds ) ) { incomingMessage( tcpSocket->getFileDescriptor() ); } } } } else { auditPending(); }}void SipClient::auditPending( void ){ SipCall *curcall; SipTransaction *curtrans; for( curcall = calls.first(); curcall != 0; curcall = calls.next() ) { for( curtrans = curcall->getTransactionList().first(); curtrans != 0; curtrans = curcall->getTransactionList().next() ) { if( curtrans->auditPending() ) { return; } } }}void SipClient::incomingMessage( int socketfd ){ QString fullmessage; char inputbuf[ 8000 ]; int bytesread; int i1,i2,i3,i4; unsigned int port; char ip[16]; unsigned int contentLength = 0; // Receive the message printf( tr("SipClient: Receiving message...") + "\n" ); for(;;) { bytesread = read( socketfd, inputbuf, 8000 - 1 ); StunMsgHdr* hdr = reinterpret_cast<StunMsgHdr*>( inputbuf ); if( hdr->msgType == BindResponseMsg ) { // check that the size of the header isn't larger than what we've read if ((signed int)sizeof(StunMsgHdr) > bytesread) { printf("Malformed packet (sizeof(StunMsgHdr) > bytesread)\n"); return; } printf( "SipClient: STUN response\n" ); char* body = inputbuf + sizeof( StunMsgHdr ); unsigned int size = ntohs( hdr->msgLength ); port = listener.getPortNumber(); while( size > 0 ) { StunAtrHdr* attr = reinterpret_cast<StunAtrHdr*>( body ); unsigned int hdrLen = ntohs( attr->length ); // check that our attribute length is not larger than the remaining size if (hdrLen+4 > size) { printf("Malformed packet (hdrLen+4 > size)\n"); return; } if( ntohs( attr->type ) == MappedAddress ) { StunAtrAddress* attribute = reinterpret_cast<StunAtrAddress*>( body ); if ( attribute->address.addrHdr.family == IPv4Family ) { StunAtrAddress4* atrAdd4 = reinterpret_cast<StunAtrAddress4*>( body ); if ( hdrLen == sizeof( StunAtrAddress4 ) - 4 ) { port = ntohs( atrAdd4->addrHdr.port ); printf( " address_port: %d\n", port ); i1 = atrAdd4->v4addr & 0xFF; i2 = (atrAdd4->v4addr & 0xFF00) >> 8; i3 = (atrAdd4->v4addr & 0xFF0000) >> 16; i4 = (atrAdd4->v4addr & 0xFF000000) >> 24; sprintf( ip, "%d.%d.%d.%d", i1, i2, i3, i4 ); printf( " address: %s\n", ip ); } } } body += hdrLen+4; size -= hdrLen+4; } SipRegister *current; if( !QString(ip).contains( Sip::getLocalAddress() ) || listener.getPortNumber() != port ) { Sip::setLocalAddress( ip ); listener.forcePortNumber( port ); setupContactUri(); QPtrListIterator<SipRegister> reg = user->getSipRegisterList(); for( ; reg.current(); ++reg ) { current = reg.current(); if( current->getRegisterState() == SipRegister::Connected || current->getAutoRegister() ) { current->setAutoRegister( false ); current->requestRegister(); } } } else { QPtrListIterator<SipRegister> reg = user->getSipRegisterList(); for( ; reg.current(); ++reg ) { current = reg.current(); if( current->getAutoRegister() ) { current->setAutoRegister( false ); current->requestRegister(); } } } return; } else { fullmessage.append( QString::fromUtf8( inputbuf, bytesread ) ); } if( bytesread < 0 ) { perror( "SipClient::incomingMessage(): read failed" ); tcpSockets.remove( tcpSocket ); tcpSocket = 0; return; } QString s; if( isTcpSocket() ) { if( fullmessage.contains( "\r\n\r\n" ) > 0 ) { if( fullmessage.findRev( "Content-Length: " ) < fullmessage.findRev( "\r\n\r\n" ) ) { s = fullmessage.mid( fullmessage.findRev( "Content-Length: " ) + 16 ); s = s.left( s.find( '\r' ) ); if( s.toInt() == 0 ) { if( fullmessage.right( 4 ) == "\r\n\r\n" ) { break; } } else { contentLength = s.toInt(); s = fullmessage.mid( fullmessage.findRev( QString( "\r\n\r\n" ) ) + 4 ); if( s.utf8().length() == contentLength ) { break; } } } else if( fullmessage.right( 4 ) == "\r\n\r\n" ) { break; } } } else { break; } // Socket closed (so we're done) WRONG if( bytesread == 0 ) { tcpSockets.remove( tcpSocket ); tcpSocket = 0; break; } } // Parse input if( isTcpSocket() ) { int contentLength; QString s; while( !fullmessage.isEmpty() ) { contentLength = 0; if( fullmessage.contains( "Content-Length: " ) > 0 ) { if( fullmessage.find( "Content-Length: " ) < fullmessage.find( QString( "\r\n\r\n" ) ) ) { s = fullmessage.mid( fullmessage.find( "Content-Length: " ) + 16 ); s = s.left( s.find( '\r' ) ); contentLength = s.toInt(); } } s = fullmessage.left( fullmessage.find( QString( "\r\n\r\n" ) ) + 4 + contentLength ); parseMessage( s ); fullmessage.remove( 0, s.length() ); } } else { parseMessage( fullmessage ); }}void SipClient::parseMessage( QString fullmessage ){ SipMessage *curmessage = new SipMessage( fullmessage ); if( traceMessageReceived ) { printf( "\nSipClient: Received: %s.%03d\n---------------------------------\n%s\n", QTime::currentTime().toString().latin1(), QTime::currentTime().msec(), fullmessage.latin1() ); } if( !curmessage->isValid() ) { delete curmessage; return; }//#test if( testOn ) { incomingTestMessage(); delete curmessage; return; } QString callid = curmessage->getHeaderData( SipHeader::Call_ID ); // Grab address in To: header SipUri touri( curmessage->getHeaderData( SipHeader::To ) ); // Grab address in From: header SipUri fromuri( curmessage->getHeaderData( SipHeader::From ) ); if( curmessage->getStatus().getCode() == 487 ) { sendAck( curmessage ); delete curmessage; return; } QString cseq = curmessage->getHeaderData( SipHeader::CSeq ); if( curmessage->getMethod() == Sip::MESSAGE ) { if( callid == messageCID && cseq == messageCSeq ) { printf( "SipCient: Received what was likely a retransmission, badly ignoring...\n" ); delete curmessage; return; } messageCID = callid; messageCSeq = cseq; sendQuickResponse( curmessage, SipStatus( 200 ) ); incomingInstantMessage( curmessage ); delete curmessage; return; } if( curmessage->getMethod() == Sip::INFO ) { sendQuickResponse( curmessage, SipStatus( 200 ) ); } if( curmessage->getMethod() == Sip::SUBSCRIBE ) { if( callid == subscribeCID && cseq == subscribeCSeq ) { printf( "SipCient: Received what was likely a retransmission, badly ignoring...\n" ); delete curmessage; return; } subscribeCID = callid; subscribeCSeq = cseq; bool found = false; for( SipCall *curcall = calls.first(); curcall != 0; curcall = calls.next() ) { if( callid == curcall->getCallId() && curcall->getCallType() == SipCall::inSubscribeCall ) { curcall->incomingMessage( curmessage ); QString expires = curmessage->getHeaderData( SipHeader::Expires ); SipUri incominguri( curmessage->getHeaderData( SipHeader::From ) ); if( curcall->getMember( incominguri ) ) { if( expires == "0" ) { curcall->setCallStatus( SipCall::callUnconnected ); incomingSubscribe( 0, false ); delete curcall; for( SipCall *c = calls.first(); c != 0; c = calls.next() ) { if( c->getCallType() == SipCall::outSubscribeCall ) { if( c->getMember( incominguri ) ) { if( c->getCallStatus() != SipCall::callDead ) { c->setCallStatus( SipCall::callUnconnected ); } } } } } else { curcall->getMember( incominguri )->timerStart( expires.toInt() * 1000 ); curcall->setCallStatus( SipCall::callInProgress ); incomingSubscribe( curcall->getMember( incominguri ), false );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -