#include "stdafx.h" #include #include #include #include "TSServer.h" #ifdef TS_USE_MFC #else #ifndef TS_USE_WINSOCK #ifndef TS_USE_WININET #include #include #include #include #include #endif #endif BOOL CSocket::Create( unsigned int socketPort, int socketType, const char* socketAddress ) { if ( Socket( socketType )) { if ( Bind( socketPort,socketAddress )) { return TRUE; } #ifdef TS_USE_WINSOCK int result = GetLastError(); #endif Close(); #ifdef TS_USE_WINSOCK WSASetLastError( result ); #endif } return FALSE; } BOOL CSocket::Bind( unsigned int socketPort, const char* socketAddress ) { SOCKADDR_IN sockAddr; memset( &sockAddr, 0, sizeof( sockAddr )); //LPSTR lpszAscii = T2A((LPTSTR)lpszSocketAddress); sockAddr.sin_family = AF_INET; if ( socketAddress == NULL ) { sockAddr.sin_addr.s_addr = htonl( INADDR_ANY ); } else { unsigned long lResult = inet_addr( socketAddress ); if ( lResult == INADDR_NONE ) { #ifdef TS_USE_WINSOCK WSASetLastError( WSAEINVAL ); #endif return FALSE; } sockAddr.sin_addr.s_addr = lResult; } sockAddr.sin_port = htons(( u_short )socketPort ); return ( SOCKET_ERROR != bind( m_hSocket, (SOCKADDR*)&sockAddr, sizeof( sockAddr ))); } BOOL CSocket::Socket( int socketType, int protocolType, int addressFormat ) { m_hSocket = socket( addressFormat, socketType, protocolType ); if ( m_hSocket != INVALID_SOCKET ) { return TRUE; } return FALSE; } BOOL CSocket::Connect( const char* hostAddress, unsigned int portNumber ) { SOCKADDR_IN sockAddr; memset( &sockAddr, 0, sizeof( sockAddr )); //LPSTR lpszAscii = T2A((LPTSTR)hostAddress); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr( hostAddress ); if ( sockAddr.sin_addr.s_addr == INADDR_NONE ) { LPHOSTENT lphost; lphost = gethostbyname( hostAddress ); if ( lphost != NULL ) { sockAddr.sin_addr.s_addr = (( LPIN_ADDR )lphost->h_addr )->s_addr; } else { #ifdef TS_USE_WINSOCK WSASetLastError( WSAEINVAL ); #endif return FALSE; } } sockAddr.sin_port = htons(( u_short )portNumber ); return Connect( (SOCKADDR*)&sockAddr, sizeof( sockAddr )); } BOOL CSocket::Connect( const SOCKADDR* lpSockAddr, int sockAddrLen ) { if ( connect( m_hSocket, lpSockAddr, sockAddrLen ) == SOCKET_ERROR ) { return FALSE; } return TRUE; } void CSocket::Close() { #ifdef WIN32 closesocket( m_hSocket ); #else close( m_hSocket ); #endif } int CSocket::Send( const void* lpBuf, int nBufLen, int nFlags ) { int nLeft, nWritten; char* pBuf = (char *)lpBuf; nLeft = nBufLen; while ( nLeft > 0 ) { nWritten = send( m_hSocket, static_cast( lpBuf ), nBufLen, nFlags ); if ( nWritten == SOCKET_ERROR ) { return nWritten; } nLeft -= nWritten; pBuf += nWritten; } return nBufLen - nLeft; } int CSocket::Receive( void* lpBuf, int nBufLen, int nFlags ) { return recv( m_hSocket, static_cast( lpBuf ), nBufLen, nFlags ); } int CSocket::GetLastError() { #ifdef WIN32 return WSAGetLastError(); #else return errno; #endif } #endif TSSocket::TSSocket() : socketBuffer ( NULL ), socketBufferSize ( 8196 ), bufferStart ( 0 ), bufferEnd ( 0 ), connected ( FALSE ), #ifdef TS_USE_WININET hOpen ( NULL ), hConnect ( NULL ), hRequest ( NULL ), #endif protocolString ( NULL ), directoryName ( NULL ), dllName ( NULL ), authString ( NULL ), proxyString ( NULL ) { Initialize(); } TSSocket::~TSSocket() { if ( connected ) { Close(); } if ( socketBuffer ) { free( socketBuffer ); } } BOOL TSSocket::Create( const char* protocol, const char* directory, const char* dll, const char* auth, const char* proxy ) { bufferStart = 0; bufferEnd = 0; protocolString = protocol; directoryName = directory; dllName = dll; authString = auth; proxyString = proxy; #ifdef TS_USE_WININET hOpen = NULL; hConnect = NULL; hRequest = NULL; return TRUE; #else return CSocket::Create(); #endif } void TSSocket::Initialize() { bufferStart = bufferEnd = 0; socketBuffer = static_cast( malloc( socketBufferSize )); } BOOL TSSocket::Connect( const char* hostAddress, unsigned int portNumber ) { BOOL retval = FALSE; #ifdef TS_USE_WININET // Initializes the use of the Windows Internet functions if ( ( proxyString != NULL ) && ( *proxyString != '\0' ) ) { hOpen = InternetOpen( "TeamTrack API", INTERNET_OPEN_TYPE_PROXY, proxyString, 0, 0 ); } else { hOpen = InternetOpen( "TeamTrack API", INTERNET_OPEN_TYPE_DIRECT, NULL, 0, 0 ); } if (hOpen) { // Opens an HTTP session for a given site hConnect = InternetConnect( hOpen, hostAddress, portNumber, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 ); if ( hConnect ) { retval = TRUE; } } #else retval = CSocket::Connect(hostAddress, portNumber); #endif if(retval) { connected = TRUE; } return retval; } void TSSocket::Close() { #ifdef TS_USE_WININET if ( hOpen ) { InternetCloseHandle( hOpen ); hOpen = NULL; } if ( hConnect ) { InternetCloseHandle( hConnect ); hConnect = NULL; } if ( hRequest ) { InternetCloseHandle( hRequest ); hRequest = NULL; } #else CSocket::Close(); #endif } int TSSocket::Send(const void* lpBuf, int nBufLen, int nFlags) { TSString header; char lengthStr[64]; sprintf( lengthStr, "Content-length: %d\r\n\r\n", nBufLen); #ifdef TS_USE_WININET DWORD dwError; DWORD dwFlags; TSString object; // Build the header, object and flags header = authString; header += "\r\n"; header += lengthStr; object = "/"; object += this->directoryName; object += "/"; object += this->dllName; object += "APIPage"; dwFlags = (INTERNET_FLAG_RELOAD|INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE); if ( strcmp( protocolString, "https" ) == 0 ) { dwFlags |= (INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS ); } // Send http request while ( 1 ) { if ( !hRequest ) { // Opens an HTTP request handle hRequest = HttpOpenRequest( hConnect, "POST", object, NULL, NULL, NULL, dwFlags, 0 ); if ( !hRequest ) { return SOCKET_ERROR; } } if ( !HttpSendRequest( hRequest, header.GetBuffer(), header.Length(), (LPVOID)lpBuf, nBufLen ) ) { dwError = GetLastError(); switch ( dwError ) { case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: case ERROR_INTERNET_INCORRECT_PASSWORD: case ERROR_INTERNET_INVALID_CA: case ERROR_INTERNET_POST_IS_NON_SECURE: case ERROR_INTERNET_SEC_CERT_CN_INVALID: case ERROR_INTERNET_SEC_CERT_DATE_INVALID: if ( InternetErrorDlg( ::GetDesktopWindow(), hRequest, dwError, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL ) == ERROR_SUCCESS ) { // BUG here - this dialog returns ERROR_SUCCESS whether OK or Cancel was pressed char line[1024]; while ( ReadLine ( line, 1024 ) ); } else { return SOCKET_ERROR; } break; default: return SOCKET_ERROR; } } else { return nBufLen; } // Close the request handle so it can be re-opened at the top of the loop InternetCloseHandle( hRequest ); hRequest = NULL; } return nBufLen; #else header = "POST /"; header += directoryName; header += "/"; header += dllName; header += "APIPage HTTP/1.0\r\nContent-Type: html/text\r\n"; header += authString; header += "\r\n"; header += lengthStr; header += (const char*)lpBuf; header += "\r\n"; return CSocket::Send( header.GetBuffer(), header.Length(), nFlags ); #endif } BOOL TSSocket::GetHttpStatusCode( int& code ) { code = -1; char line[1024]; #ifdef TS_USE_WININET DWORD dwSize = sizeof(line); if ( !HttpQueryInfo( hRequest, HTTP_QUERY_STATUS_CODE, line, &dwSize, NULL ) ) { return FALSE; } code = atoi( line ); #else BOOL bFirst = TRUE; BOOL bError = FALSE; while( ReadLine( line, sizeof(line) ) > 0 && strlen( line ) != 0 ) { if ( bFirst ) { sscanf( line, "%*s %d", &code ); if( code != 200 ) { bError = TRUE; } } bFirst = FALSE; } if ( bError || bFirst ) { return FALSE; } #endif return TRUE; } // This works just like read except that the \n are stripped off // because that is what is convenient for out uses. int TSSocket::ReadLine( char* buffer, int size ) { int nRead = 0; for ( int ii = 0; ii < size; ii++ ) { if ( bufferStart == bufferEnd ) { if ( ( nRead = FillBuffer()) == 0 ) { return ii-1; } } if ( socketBuffer[bufferStart] == '\r' ) { bufferStart++; ii--; continue; } else if ( socketBuffer[bufferStart] == '\n' ) { bufferStart++; if ( ii < size ) { buffer[ii] = '\0'; } return ii; } buffer[ii] = socketBuffer[bufferStart]; bufferStart++; } return nRead; } int TSSocket::Read( char* buffer, int size ) { int bufferSize = bufferEnd - bufferStart; if ( bufferSize == size ) { memcpy( buffer, socketBuffer, size ); bufferStart = bufferEnd = 0; return size; } else if ( bufferSize < size ) { if ( bufferSize != 0 ) { memcpy( buffer, socketBuffer, bufferSize ); bufferStart = bufferEnd = 0; } if ( FillBuffer() > 0 ) { return bufferSize + Read( buffer + bufferSize, size - bufferSize ); } else { return bufferSize; } } else // bufferSize > size { memcpy( buffer, socketBuffer, size ); bufferStart += size; return size; } } char TSSocket::ReadChar() { if ( bufferStart == bufferEnd ) { if ( FillBuffer() == 0 ) { return 0; } } return socketBuffer[bufferStart++]; } int TSSocket::FillBuffer() { if ( bufferStart != bufferEnd ) { return 0; } bufferStart = 0; #ifdef TS_USE_WININET BOOL bValidRead; unsigned long nMessageLength; char pcMessage[256]; // Read more data bValidRead = InternetReadFile( hRequest, (LPVOID)socketBuffer, socketBufferSize, (unsigned long*)&bufferEnd ); // The following 2 if statements were put in place to help debug BUG05359 if ( !bValidRead ) { unsigned long nError = ::GetLastError(); nMessageLength = sizeof( pcMessage ); ::InternetGetLastResponseInfo( &nError, pcMessage, &nMessageLength ); bufferEnd = 0; } if ( bufferEnd < 0 ) { nMessageLength = sizeof( pcMessage ); HttpQueryInfo( hRequest, HTTP_QUERY_CONTENT_LENGTH, pcMessage, &nMessageLength, NULL ); bufferEnd = 0; } #else bufferEnd = Receive(socketBuffer, socketBufferSize, 0); if ( bufferEnd == SOCKET_ERROR || bufferEnd < 0 ) { int WSAerror = WSAGetLastError(); printf("Received a socket error: %d\r\n", WSAerror); bufferEnd = 0; } #endif return bufferEnd; } int TSSocket::ReceiveInt( int* val ) { char ch; TSString buf = ""; *val = 0; while (( ch = ReadChar() ) != 0 ) { if ( ch == '\n' || ch == '\r' || ch == ',' ) { break; } buf += ch; } if ( buf == "" ) { return TS_ERROR; } *val = atol( buf.GetBuffer() ); return TS_OK; } int TSSocket::ReceiveDouble( double* val ) { char ch; TSString buf = ""; *val = 0.0; while (( ch = ReadChar() ) != 0 ) { if ( ch == '\n' || ch == '\r' || ch == ',' ) { break; } if ( ch == '$' ) { char temp[3]; if (( temp[0] = ReadChar() ) == 0 ) { return TS_OK; } if (( temp[1] = ReadChar() ) == 0 ) { return TS_OK; } temp[2] = '\0'; int charVal; sscanf( temp, "%x", &charVal ); buf += (char)charVal; } else { buf += ch; } } if ( buf == "" ) { return TS_ERROR; } *val = strtod( buf.GetBuffer(), NULL ); return TS_ERROR; } int TSSocket::ReceiveString( char* str, int size ) { TSString tmp; ReceiveString( &tmp ); strncpy( str, tmp.GetBuffer(), size ); str[size-1] = '\0'; return TS_OK; } int TSSocket::ReceiveString( TSString* str ) { char ch; if (( ch = ReadChar()) == 0 ) { return TS_ERROR; } if ( ch == '\r' || ch == '\n' ) { ReadChar(); return TS_ERROR; } if ( ch != '"' ) { return TS_ERROR; } while (( ch = ReadChar() ) != 0 ) { if ( ch == '"' ) { ReadChar(); // Read the separating comma return TS_OK; } if ( ch == '$' ) { char temp[3]; if (( temp[0] = ReadChar() ) == 0 ) { return TS_OK; } if (( temp[1] = ReadChar() ) == 0 ) { return TS_OK; } temp[2] = '\0'; int val; sscanf( temp, "%x", &val ); (*str) += static_cast( val ); } else { (*str) += ch; } } // no ending quote return TS_ERROR; } // Encodes a string to be sent through the web server enclosed in quotes. void TSEncodeString( TSString& in, TSString& out ) { TSString text; TSEncodeText( in, text ); out = "\""; out += text; out += "\","; } void TSEncodeString( const char* in, TSString& out ) { static TSString tmp; if ( in == NULL ) { tmp = ""; } else { tmp = in; } TSEncodeString( tmp, out ); } // Encodes a string to be sent through the web server, but doesn't enclose // it in quotation marks. void TSEncodeText( const char* in, TSString& out ) { static TSString tmp; tmp = in; TSEncodeText( tmp, out ); } void TSEncodeText( TSString& in, TSString& out ) { char encode[16]; char* p = in.GetBuffer(); out = ""; while ( *p ) { if ( isalnum( *p ) || *p == '-' || *p == '_' || *p == '.' || *p == 13 || *p == 10 ) { out += ( *p ); } else { int n = 0x000000FF & *p; // stop it from sign-extending upper ASCII codes sprintf( encode, "$%02x", n ); out += encode; } p++; } } void TSEncodeInt( int in, TSString& out ) { static char tmp[24]; sprintf( tmp, "%d,", in ); out = tmp; } void TSEncodeDouble( double in, TSString& out ) { static char tmp[32]; sprintf( tmp, "%.16g,", in ); out = tmp; } #if defined( TS_USE_WINSOCK ) || defined( TS_USE_WININET ) int AFX_EXT_CLASS TSInitializeWinsock() { // This is the Windows socket startup stuff to initialize the Winsock DLL. #ifdef TS_USE_MFC if ( !AfxSocketInit() ) { printf( "Error intializing winsock!\n" ); return TS_ERROR; } printf( "Winsock initialized\n" ); #else WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return TS_ERROR; } #endif return TS_OK; } #endif