📄 udpmessagesocket.cpp
字号:
#include <sys/types.h>#include <sys/socket.h>#include <netinet/ip.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/nameser.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/time.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <strings.h>#include <errno.h>#include <fcntl.h>#include <resolv.h>#include <qwidget.h>#include "udpmessagesocket.h"#include "sipclient.h"UDPMessageSocket::UDPMessageSocket( void ){ type = SocketUDP; if ( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::UDPMessageSocket(): socket() failed\n" ); } didcomplain = false;}UDPMessageSocket::UDPMessageSocket( int newfd ){ type = SocketUDP; socketfd = newfd; didcomplain = false;}UDPMessageSocket::~UDPMessageSocket( void ){ close( socketfd );}int UDPMessageSocket::connect( unsigned int portnum ){ socketaddress.sin_family = AF_INET; socketaddress.sin_port = htons( portnum ); socketaddress.sin_addr = *( (struct in_addr *) he->h_addr ); bzero( &(socketaddress.sin_zero), 8 ); // is this portable? remoteaddress = socketaddress; return 0;}int UDPMessageSocket::SetTOS( void ){ unsigned char tos; socklen_t optlen; //tos=IPTOS_PREC_CRITIC_ECP; tos=IPTOS_LOWDELAY; optlen=1; if(setsockopt(socketfd,SOL_IP,IP_TOS,&tos,optlen) != 0){ printf("UDPMessageSocket::SetTOS"); } return 0;}int UDPMessageSocket::send( const char *sendbuffer, unsigned int length ){ int numbytes; if( ( numbytes = sendto( socketfd, sendbuffer, length, 0, (struct sockaddr *) &remoteaddress, sizeof( struct sockaddr ) ) ) == -1 ) { if( !didcomplain ) { printf( "UDPMessageSocket::send(): sendto() failed\n" ); didcomplain = true; } return -1; } return 0;}int UDPMessageSocket::receive( char *recvbuffer, unsigned int maxlength ){ socklen_t addrlength; int numbytes; addrlength = sizeof( struct sockaddr ); if( ( numbytes = recvfrom( socketfd, recvbuffer, maxlength, 0, \ (struct sockaddr *) &remoteaddress, &addrlength ) ) == -1 ) { printf( "UDPMessageSocket::recieve(): recvfrom() failed\n" ); return -1; } return numbytes;}unsigned int UDPMessageSocket::listen( unsigned int portnum ){ struct sockaddr name; socklen_t namesize; socketaddress.sin_family = AF_INET; socketaddress.sin_port = htons( portnum ); socketaddress.sin_addr.s_addr = INADDR_ANY; bzero( &(socketaddress.sin_zero), 8 ); // is this portable? /* * if already bound then close this one and open * a new socket so we can bind it to different port * number */ if (bound) { close(socketfd); bound = false; if( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::listen: socket() failed\n" ); return 0; } } int count = 0; while ( bind( socketfd, (struct sockaddr *) &socketaddress, sizeof( struct sockaddr) ) == -1 && count <= 10 ) { count++; portnum += 2; socketaddress.sin_port = htons( portnum ); } if ( count > 10 ) { printf( "UDPMessageSocket::listen(): bind() failed\n" ); return 0; } bound = true; namesize = sizeof( struct sockaddr ); bzero( &name, sizeof( struct sockaddr ) ); if ( getsockname( socketfd, &name, &namesize ) == -1 ) { printf( "UDPMessageSocket::listen(): getsockname() failed\n" ); return 0; } ourport = ntohs( ((struct sockaddr_in *) &name)->sin_port ); return ourport;}/* * FIXME: There is no guarantee that the subsequent call * to socket and bind will return previous port number + 1 ! * This function can potentially allocate several file * descriptors and never close them * comment made by jan@iptel.org */int UDPMessageSocket::listenOnEvenPortOS( void ){ struct sockaddr name; socklen_t namesize; int oldsocketfd = 0; int portnum = 0; /* * if already bound then close this one and open * a new socket so we can bind it to different port * number */ if (bound) { close(socketfd); bound = false; if( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::listenOnEvenPortOS: socket() failed\n" ); return -1; } }getaddress: socketaddress.sin_family = AF_INET; socketaddress.sin_port = htons( portnum ); socketaddress.sin_addr.s_addr = INADDR_ANY; bzero( &(socketaddress.sin_zero), 8 ); // is this portable? if ( bind( socketfd, (struct sockaddr *) &socketaddress, sizeof( struct sockaddr) ) == -1 ) { printf( "UDPMessageSocket::listen(): bind() failed\n" ); return -1; } bound = true; namesize = sizeof( struct sockaddr ); bzero( &name, sizeof( struct sockaddr ) ); if ( getsockname( socketfd, &name, &namesize ) == -1 ) { printf( "UDPMessageSocket::listen(): getsockname() failed\n" ); return -1; } ourport = ntohs( ((struct sockaddr_in *) &name)->sin_port ); if( ( portnum == 0 ) && ( ourport % 2 ) != 0 ) { oldsocketfd = socketfd; if( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::UDPMessageSocket(): socket() failed\n" ); } goto getaddress; } if( oldsocketfd != 0 ) close( oldsocketfd ); return 0;}int UDPMessageSocket::listenOnEvenPort(int min, int max){ /* User didn't specify any range, let the OS * assign source port number */ if ((min == 0) && (max == 0)) { return listenOnEvenPortOS(); } /* Only max specified, set min to the lowest limit */ if (min == 0) min = 1024; /* Only min specified, set max to the highest port number */ if (max == 0) max = 65535; /* min not odd, increase */ if (min % 2) min++; /* Out of range ? Signal error */ if (min > max) goto error; /* * if already bound then close this one and open * a new socket so we can bind it to different port * number */ if (bound) { close(socketfd); bound = false; if( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::listenOnEvenPor: socket() failed\n" ); return -1; } }loop: socketaddress.sin_family = AF_INET; socketaddress.sin_port = htons(min); socketaddress.sin_addr.s_addr = INADDR_ANY; bzero(&(socketaddress.sin_zero), 8); if (bind(socketfd, (struct sockaddr*)&socketaddress, sizeof(struct sockaddr)) == -1) { min += 2; if (min <= max) goto loop; else goto error; } bound = true; /* * FIXME: Do some test for even port number here */ ourport = min; return 0;error: printf("UDPMessageSocket::listen(): Can't find a free port in specified range"); return -1; }int UDPMessageSocket::listenOnEvenPortForVideo( void ){ struct sockaddr name; socklen_t namesize; int oldsocketfd = 0; int portnum = 0; if ( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::UDPMessageSocket(): socket() failed\n" ); }getaddress: socketaddress.sin_family = AF_INET; socketaddress.sin_port = htons( portnum ); socketaddress.sin_addr.s_addr = INADDR_ANY; bzero( &(socketaddress.sin_zero), 8 ); // is this portable? int one = 1; if ( setsockopt( socketfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof( one ) ) == -1 ) { printf( "UDPMessageSocket::setsockopt SO_REUSEADDR\n" ); } if ( bind( socketfd, (struct sockaddr *) &socketaddress, sizeof( struct sockaddr) ) == -1 ) { printf( "UDPMessageSocket::listen(): bind() failed\n" ); return -1; } bound = true; namesize = sizeof( struct sockaddr ); bzero( &name, sizeof( struct sockaddr ) ); if ( getsockname( socketfd, &name, &namesize ) == -1 ) { printf( "UDPMessageSocket::listen(): getsockname() failed\n" ); return -1; } ourport = ntohs( ((struct sockaddr_in *) &name)->sin_port ); if( portnum == 0 && ( ourport % 4 ) != 0 ) { oldsocketfd = socketfd; if( ( socketfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) { printf( "UDPMessageSocket::UDPMessageSocket(): socket() failed\n" ); } goto getaddress; } if( oldsocketfd != 0 ) close( oldsocketfd ); return 0;}int UDPMessageSocket::accept( void ){ return socketfd;}int UDPMessageSocket::sendStunRequest( QString host, int port ){ setHostname( host); connect( port); StunRequestSimple req; req.msgHdr.msgType = htons(BindRequestMsg); req.msgHdr.msgLength = htons( sizeof(StunRequestSimple)-sizeof(StunMsgHdr) ); for ( int i=0; i<16; ++i ) { req.msgHdr.id.octet[i]=0; } int id = rand(); req.msgHdr.id.octet[0] = id; req.msgHdr.id.octet[1] = id>>8; req.msgHdr.id.octet[2] = id>>16; req.msgHdr.id.octet[3] = id>>24; return (send( (char *)&req, sizeof( req ) ) );}unsigned int UDPMessageSocket::receiveStunResponse(void ){ unsigned int port = 0; int i1,i2,i3,i4; char ip[17] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'}; char inputbuf[ 8000 ]; int bytesread; struct timeval timeout; fd_set read_fds; int highest_fd; timeout.tv_sec = 5; timeout.tv_usec = 0; FD_ZERO( &read_fds ); FD_SET( getFileDescriptor(), &read_fds ); highest_fd = getFileDescriptor() + 1;retry: if( select( highest_fd, &read_fds, NULL, NULL, &timeout ) == -1 ) { if( errno == EINTR ) goto retry; perror( "UDPMessageSocket: select() punted" ); exit( 1 ); } if( FD_ISSET( getFileDescriptor(), &read_fds ) ) { bytesread = read( getFileDescriptor(), inputbuf, 8000 - 1 ); StunMsgHdr* hdr = reinterpret_cast<StunMsgHdr*>( inputbuf ); if( hdr->msgType == BindResponseMsg ) { char* body = inputbuf + sizeof( StunMsgHdr ); unsigned int size = ntohs( hdr->msgLength ); while( size > 0 ) { StunAtrHdr* attr = reinterpret_cast<StunAtrHdr*>( body ); unsigned int hdrLen = ntohs( attr->length ); 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 ); 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( "UDPMessageSocket::receiveStunResponse %s:%d\n",ip,port); stunnedHost= QString((char *)&ip[0]); } } } body += hdrLen+4; size -= hdrLen+4; } } } return port;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -