/* * GTimer * * Copyright: * (C) 1999 Craig Knudsen, cknudsen@cknudsen.com * See accompanying file "COPYING". * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307, USA * * Description: * Helps you keep track of time spent on different tasks. * * Author: * Craig Knudsen, cknudsen@cknudsen.com, http://www.cknudsen.com * * Home Page: * http://www.cknudsen.com/gtimer/ * * History: * 19-May-1999 Created * * Limitations: * * 1. Winsock defines the type "SOCKET" to use with sockets * while we use "int" on UNIX. We defined sockfd which can * be used for either. * 2. Winsock must be initialized and cleaned up before exit. * 3. Winsock does not user errno for system errors like * UNIX does. * 4. Winsock must use send() and recv() to read and write * sockets. (UNIX can also use read() and write().) * 5. In summary, winsock sucks, and we most code accordingly. * *****************************************************************************/ /* system include files */ #include #include #include #ifndef SYSV #include #endif #include #include #include #ifdef WIN32 #include /* winsock API */ #else #include #include /* for gethostbyaddr() */ #include #include #include #endif #include #include #include #ifdef AIX #include #endif #include #include extern int errno; /* local include files */ #include "tcpt.h" #ifdef GTIMER_MEMDEBUG #include "memdebug/memdebug.h" #endif /* local variables */ typedef struct { unsigned char version; unsigned char command; unsigned short dst_port; unsigned long dst_addr; } socks_struct; static char socks_server[256]; static int socks_port = 1080; static int socks_enabled = 0; /* ** tcptErrorString - Translate a tcptError into a text string. */ char *tcptErrorString ( error_num ) tcptError error_num; { switch ( error_num ) { case TCPT_NO_ERROR: return ( "No error" ); case TCPT_SOCKET_ERROR: return ( "Socket connection error" ); case TCPT_INIT_ERROR: return ( "Error initializing TCP/IP" ); case TCPT_CONNECT_ERROR: return ( "Error connecting socket" ); case TCPT_SOCKS_CONNECT_ERROR: return ( "Error connecting to SOCKS server" ); case TCPT_SOCKS_CONNECT_REFUSED: return ( "SOCKS access refused" ); case TCPT_INVALID_SOCKS_HOST: return ( "Invalid SOCKS host" ); case TCPT_SOCKS_CONNECT_TIMEOUT: return ( "SOCKS connection timed out" ); case TCPT_SOCKS_CONNECTION_REFUSED: return ( "SOCKS connection refused" ); case TCPT_CONNECTION_REFUSED: return ( "Server connection refused" ); default: return ( "Unknown error" ); } } /* ** tcptInit - Initialize the TCP/IP stack. Not needed in UNIX. */ tcptError tcptInit () { #ifdef WIN32 WSADATA WSAData; if ( WSAStartup ( MAKEWORD ( 1, 1 ), &WSAData ) != 0 ) { WSACleanup (); return ( TCPT_INIT_ERROR ); } #endif return ( TCPT_NO_ERROR ); } /* ** tcptEnableSocks - Enable SOCKS usage. */ tcptError tcptEnableSocks ( server, port ) char *server; int port; { strcpy ( socks_server, server ); socks_port = port; socks_enabled = 1; return ( TCPT_NO_ERROR ); } /* ** tcptDisableSocks - Disable SOCKS usage */ tcptError tcptDisableSocks () { socks_enabled = 0; return ( TCPT_NO_ERROR ); } /* ** tcptConnect - Connect a TCP/IP socket. Uses SOCKS if enabled. */ tcptError tcptConnect ( sock, server, size ) sockfd sock; struct sockaddr_in *server; int size; { int count, rval; struct timeval tv; struct hostent *hp; unsigned long addr; socks_struct data; char temp[100]; fd_set fds; uid_t uid; struct passwd *pw; int datasize; if ( socks_enabled ) { hp = gethostbyname ( socks_server ); if ( ! hp ) { /* might be an IP address */ addr = inet_addr ( socks_server ); hp = gethostbyaddr ( (char *)&addr, sizeof ( struct in_addr ), AF_INET ); if ( ! hp ) return ( TCPT_INVALID_SOCKS_HOST ); } /* save destination port */ data.version = 4; data.command = 1; data.dst_port = server->sin_port; memcpy ( (char *)&data.dst_addr, (char *)&server->sin_addr, hp->h_length ); /* setup struct for socks server */ server->sin_family = AF_INET; memcpy ( (char *)&server->sin_addr, (char*)hp->h_addr, hp->h_length ); server->sin_port = htons ( socks_port ); } tv.tv_sec = 0; tv.tv_usec = 10000; /* in microseconds = 1/100 second */ count = errno = 0; while ( errno != EISCONN && count < 5 ) { if ( ( rval = connect ( sock, (struct sockaddr *)server, size ) ) ) { if ( errno == ECONNREFUSED ) { return ( socks_enabled ? TCPT_SOCKS_CONNECTION_REFUSED : TCPT_CONNECTION_REFUSED ); } /* use select since all systems (AIX) don't have usleep() */ select ( 32, NULL, NULL, NULL, &tv ); rval = errno; } count++; } if ( count >= 5 ) { closesocket ( sock ); tcptCleanup (); return ( socks_enabled ? TCPT_SOCKS_CONNECT_ERROR : TCPT_CONNECT_ERROR ); } /* ** Now connected to end host or socks host */ if ( socks_enabled ) { /* 5 second timeout waiting for socks host */ tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO ( &fds ); FD_SET ( sock, &fds ); if ( select( 32, NULL, &fds, NULL, &tv ) > 0 ) { datasize = sizeof ( data ); memcpy ( temp, (char *)&data, sizeof ( data ) ); if ( ( pw = getpwuid ( uid = getuid () ) ) == NULL ) sprintf ( temp + datasize, "Unknown user-id %d", (int)uid ); else strcpy ( temp + datasize, pw->pw_name ); datasize += strlen ( temp + datasize ) + 1; rval = send ( sock, temp, datasize, 0 ); if ( rval < 0 ) return ( TCPT_SOCKET_ERROR ); } else return ( TCPT_SOCKS_CONNECT_TIMEOUT ); /* get response from socks server */ FD_ZERO ( &fds ); FD_SET ( sock, &fds ); tv.tv_sec = 5; tv.tv_usec = 0; memset ( &data, '\0', sizeof ( data ) ); /* wait to data is ready to read */ if ( ( rval = select ( 32, &fds, NULL, NULL, &tv ) ) > 0 ) { if ( FD_ISSET ( sock, &fds ) ) { rval = recv ( sock, (char *)&data, sizeof ( data ), 0 ); if ( rval < 0 ) return ( TCPT_SOCKET_ERROR ); else if ( ! rval ) return ( TCPT_SOCKS_CONNECT_TIMEOUT ); else if ( data.command != 90 ) return ( TCPT_SOCKS_CONNECT_REFUSED ); } else { return ( TCPT_SOCKS_CONNECT_TIMEOUT ); } } else { return ( TCPT_SOCKS_CONNECT_TIMEOUT ); } /* successful connection via socks */ } return ( TCPT_NO_ERROR ); } /* ** tcptCleanup - Shutdown the TCP/IP stack. Does nothing in UNIX. */ tcptError tcptCleanup () { #ifdef WIN32 WSACleanup (); #endif return ( TCPT_NO_ERROR ); }