//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // libSockets.cpp/h : keef's sockets library //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PA:keef~~ #include "libsockets.h" #include "libkeef.h" // for strmatch(), etc. #include #include // for time(), strftime(), etc. #ifdef sun4sol2 #include #include // for FIONBIO #else #include #endif //sun4sol2 #ifdef aix #include // for FIONBIO #endif //aix //#include "libMFC.h" // for BOOL, TRUE, and FALSE #ifdef WIN32 #include // for closesocket() #define sleep(SECS) Sleep(SECS*1000) #define usleep(MICROSECS) Sleep(MICROSECS*1000*1000) #define close(SOCKET) closesocket(SOCKET) #define read(SOCKET,BUF,LEN) recv(SOCKET,BUF,LEN,/*flags=*/0) #define write(SOCKET,BUF,LEN) send(SOCKET,BUF,LEN,/*flags=*/0) #define ioctl(SOCKET,FLAG,PTR) ioctlsocket(SOCKET,FLAG,PTR) #endif //UNIX /*public*/char pszEOBATCH[] = {cEOBATCH, 0}; //----------------------------------------------------------------------------- BOOL ParseWebURL (char* pszFullURL, WEBURL* pWebURL) //----------------------------------------------------------------------------- { // copy the source URL: strncpy (pWebURL->szWebFullURL, pszFullURL, MAXLEN_WEB_URL); pWebURL->szWebFullURL[MAXLEN_WEB_URL] = 0; // isolate the protocol: char* pColon = strchr (pszFullURL, ':'); if (!pColon) { DebugLog ("ParseWebURL(%s) -- missing : after protocol.\n", pszFullURL); return (FALSE); } *pColon = 0; strncpy (pWebURL->szWebProtocol, pszFullURL, MAXLEN_WEB_PROTOCOL); pWebURL->szWebProtocol[MAXLEN_WEB_PROTOCOL] = 0; *pColon = ':'; // translate the protocol: if (strmatch (pWebURL->szWebProtocol, "http")) pWebURL->iWebProtocol = WP_HTTP; else if (strmatch (pWebURL->szWebProtocol, "https")) pWebURL->iWebProtocol = WP_HTTPS; else if (strmatch (pWebURL->szWebProtocol, "news")) pWebURL->iWebProtocol = WP_NEWS; else if (strmatch (pWebURL->szWebProtocol, "ftp")) pWebURL->iWebProtocol = WP_FTP; else if (strmatch (pWebURL->szWebProtocol, "gopher")) pWebURL->iWebProtocol = WP_GOPHER; else { pWebURL->iWebProtocol = WP_UNKNOWN; DebugLog ("ParseWebURL(%s) -- unknown protocol '%s'.\n", pszFullURL, pWebURL->szWebProtocol); return (FALSE); } // set default port number, based on protocol: pWebURL->iPortNum = pWebURL->iWebProtocol; // isolate the hostname: if ((pColon[1] != '/') || (pColon[2] != '/')) { DebugLog ("ParseWebURL(%s) -- missing // after protocol.\n", pszFullURL); return (FALSE); } char* pSlash = strchr (pColon+3, '/'); if (!pSlash) { DebugLog ("ParseWebURL(%s) -- missing / after hostname.\n", pszFullURL); return (FALSE); } *pSlash = 0; strncpy (pWebURL->szWebHostname, pColon+3, MAXLEN_WEB_HOSTNAME); pWebURL->szWebHostname[MAXLEN_WEB_HOSTNAME] = 0; *pSlash = '/'; // look for optional port number: pColon = strchr (pSlash+1, ':'); if (pColon) *pColon = 0; // isolate "rest" of URL: strncpy (pWebURL->szWebRestURL, pSlash, MAXLEN_WEB_URL); pWebURL->szWebRestURL[MAXLEN_WEB_URL] = 0; // finish dealing with optional port number: if (pColon) { *pColon = ':'; pWebURL->iPortNum = atoi (pColon+1); } return (TRUE); } // ParseWebURL //----------------------------------------------------------------------------- BOOL ValidateHost (struct sockaddr_in* pAddrServer, char* pszHostname, char* szCanonical/*=NULL*/, int iLenCanonical/*=0*/) //----------------------------------------------------------------------------- // performs hostname to IP address resolution // reverse lookups the IP into a canonical hostname { if (szCanonical && (iLenCanonical <= 0)) { ErrorLog ("ValidateHost(): usage error: szCanonical non-null, but iLenCanonical=%d\n", pszHostname, iLenCanonical); return (FALSE); } memset ((void *)pAddrServer, 0, sizeof(struct sockaddr_in)); pAddrServer->sin_family = AF_INET; //pAddrServer->sin_port = htons(iPortNum); // - - - - - - - - - - - - - - - - - - - - - - // look at first char to determine if hostname or IP address: // - - - - - - - - - - - - - - - - - - - - - - if ((pszHostname[0] >= '0') && (pszHostname[0] <= '9')) { u_long ulAddress = inet_addr (pszHostname); if ((int)ulAddress == -1) { ErrorLog ("invalid hostname IP address '%s'\n", pszHostname); return (FALSE); } #if defined(hp) || defined(aix) || defined(bsd) pAddrServer->sin_addr.s_addr = ulAddress; //see: /usr/include/netinet/in.h, line 99 #else pAddrServer->sin_addr.S_un.S_addr = ulAddress; //see: /usr/include/netinet/in.h, line 118 #endif // see if we can translate the IP address into canonical hostname... if (szCanonical) { struct hostent* pHost = gethostbyaddr ((char*)&ulAddress, sizeof(ulAddress), AF_INET); if (pHost) { strncpy (szCanonical, pHost->h_name, iLenCanonical-1); szCanonical[iLenCanonical-1] = 0; } } } // - - - - - - - - - - - - - - - - - - - - - - // resolve hostname into an IP address: // - - - - - - - - - - - - - - - - - - - - - - else { struct hostent* pHost = gethostbyname (pszHostname); if (!pHost) { ErrorLog ("could not resolve hostname '%s' into an IP address\n", pszHostname); return (FALSE); } memcpy (&(pAddrServer->sin_addr), pHost->h_addr_list[0], sizeof(pAddrServer->sin_addr)); u_long ulAddress; #if defined(hp) || defined(aix) || defined(bsd) ulAddress = pAddrServer->sin_addr.s_addr; #else ulAddress = pAddrServer->sin_addr.S_un.S_addr; #endif if (szCanonical) { strncpy (szCanonical, pHost->h_name, iLenCanonical-1); szCanonical[iLenCanonical-1] = 0; } } return (TRUE); } // ValidateHost //---------------------------------------------------------------------- int SocketOpenForListen (unsigned short iPortNum, BOOL fDebug/*=FALSE*/) //------------------------------------------------------------------keef // // Opens a new "server" socket on current host, listening to // the given port number. // If socket cannot be opened, returns neg. int and calls ErrorLog(), // otherwise returns file descriptor of opened socket. // { int fdSocket; if (fDebug) DebugLog ("sockets(debug): opening socket...\n"); #ifdef UNIX int iAddrFormat = AF_INET; #else int iAddrFormat = PF_INET; #endif //UNIX if ((fdSocket = socket (iAddrFormat, SOCK_STREAM, 0)) < 0) { ErrorLog ("sockets(error): can't open stream socket (errno=%d).\n", errno); TranslateErrno (); return (fdSocket); } const char one = 1; /*see: /usr/include/sys/socket.h", line 305*/ setsockopt (fdSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); if (fDebug) DebugLog ("sockets(debug): binding local address so client can respond...\n"); struct sockaddr_in addrServer; memset ((char *) &addrServer, 0, sizeof(addrServer)); addrServer.sin_family = AF_INET; addrServer.sin_addr.s_addr = htonl(INADDR_ANY); addrServer.sin_port = htons(iPortNum); int iTries = 10; int iReturn; while ( (iReturn = bind (fdSocket, (struct sockaddr *) &addrServer, sizeof(addrServer))) < 0) { if (--iTries == 0) { ErrorLog ("sockets(error): gave up trying to bind local address on socket\n"); TranslateErrno (); close (fdSocket); return (iReturn); } sleep (1); } if (fDebug) DebugLog ("sockets(debug): listening on socket %d...\n", iPortNum); if ( (iReturn = listen (fdSocket, 5)) < 0) { ErrorLog ("sockets(error): listen() failed, errno=%d\n", errno); TranslateErrno (); close (fdSocket); return (iReturn); } return (fdSocket); } // SocketOpenForListen //---------------------------------------------------------------------- int SocketWaitForNextConnection (int fdListen, int iMSecDelay/*=250*/, BOOL fDebug/*=FALSE*/) //------------------------------------------------------------------keef // // Listens on port until a connect with a client is established. // // Returns: // * zero of greater indicatate a bi-directional connection // with a new client // * neg. int. indicates an error, calls ErrorLog() // // The millisecond delay parameter is used to slow down the loop so // that it does not take over the machine. Note that this function // should not be used by normal MSWindows programs (as opposed to // Win32 console apps), since the loop below will prevent the windows // message loop from being pumped. // { int iNewConnection = g_iNoConnectionYet; while (iNewConnection == g_iNoConnectionYet) { iNewConnection = SocketPeekForNextConnection (fdListen, fDebug); usleep (iMSecDelay*1000); } return (iNewConnection); } // SocketWaitForNextConnection //---------------------------------------------------------------------- int SocketPeekForNextConnection (int fdListen, BOOL fDebug/*=FALSE*/) //------------------------------------------------------------------keef // // Checks port (once) to see if a sockets message is waiting, but // does not block until one comes. // // Returns: // * g_iNoConnectionYet if no connection is waiting // * zero of greater indicatate a bi-directional connection // with a new client // * neg. int. indicates an error, calls ErrorLog() // // Note that it returns the socket in blocking mode so that normal // communication with the other party can be handled easier. // { struct sockaddr_in addrClient; if (fDebug) DebugLog ("sockets(debug): listening for next socket accept()...\n"); #ifdef aix size_t iLenAddrClient = sizeof(addrClient); #else int iLenAddrClient = sizeof(addrClient); #endif //aix DWORD dwNonBlocking = 1; if (fDebug) { DebugLog ("sockets(debug): using ioctl() to make socket non-blocking...\n"); } int iReturn; if ( (iReturn = ioctl (fdListen, FIONBIO, &dwNonBlocking)) < 0) { ErrorLog ("ERROR(sockets): could not set socket to NON-BLOCKING mode.\n"); TranslateErrno (); return (iReturn); } int fdNewSocket = accept (fdListen, (struct sockaddr *) &addrClient, &iLenAddrClient); // Note: there are three cases for accept() returning: // 1. there's no connection (it would have blocked and waited) // 2. some error occurred: fdNewSocket cannot be used // 3. it found a legitimate connection: fdNewSocket appears kosher // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 1. there's no connection (it would have blocked and waited) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #if defined(WIN32) if ((fdNewSocket == INVALID_SOCKET) && (WSAGetLastError() == WSAEWOULDBLOCK)) #else if ((fdNewSocket < 0) && (errno == EWOULDBLOCK)) #endif { return (g_iNoConnectionYet); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 2. some error occurred: fdNewSocket cannot be used // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - else if (fdNewSocket < 0) { ErrorLog ("sockets(error): accept() failed, errno=%d\n", errno); TranslateErrno (); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 3. it found a legitimate connection: fdNewSocket is usable // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - else { if (fDebug) { DebugLog ("sockets(debug): accept() returned a good socket.\n"); DebugLog ("sockets(debug): setting port back to BLOCKING mode...\n"); } // now we should set the socket back to blocking mode (because // the other two-way communication probably depends on this): DWORD dwBlocking = 0; // blocking (synchronous) if ( (iReturn = ioctl (fdListen, FIONBIO, &dwBlocking)) < 0) { ErrorLog ("ERROR(sockets): could not set socket back to blocking mode.\n"); TranslateErrno (); return (iReturn); } return (fdNewSocket); } return (-1); // to satisfy compiler } // SocketPeekForNextConnection //---------------------------------------------------------------------- int SocketAcceptConnection (int fdListen, BOOL fDebug/*=FALSE*/) //------------------------------------------------------------------keef // // Checks port (once) to see if a sockets message is waiting, but // does not block until one comes. // // Returns: // * g_iNoConnectionYet if no connection is waiting // * zero of greater indicatate a bi-directional connection // with a new client // * neg. int. indicates an error, calls ErrorLog() // // Note that it returns the socket in blocking mode so that normal // communication with the other party can be handled easier. // { struct sockaddr_in addrClient; if (fDebug) DebugLog ("sockets(debug): listening for next socket accept()...\n"); #ifdef aix size_t iLenAddrClient = sizeof(addrClient); #else int iLenAddrClient = sizeof(addrClient); #endif //aix int fdNewSocket = accept (fdListen, (struct sockaddr *) &addrClient, &iLenAddrClient); // Note: there are three cases for accept() returning: // 1. there's no connection (it would have blocked and waited) // 2. some error occurred: fdNewSocket cannot be used // 3. it found a legitimate connection: fdNewSocket appears kosher // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 1. there's no connection (it would have blocked and waited) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #if defined(WIN32) if ((fdNewSocket == INVALID_SOCKET) && (WSAGetLastError() == WSAEWOULDBLOCK)) #else if ((fdNewSocket < 0) && (errno == EWOULDBLOCK)) #endif { return (g_iNoConnectionYet); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 2. some error occurred: fdNewSocket cannot be used // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - else if (fdNewSocket < 0) { ErrorLog ("sockets(error): accept() failed, errno=%d\n", errno); TranslateErrno (); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 3. it found a legitimate connection: fdNewSocket is usable // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - else { if (fDebug) DebugLog ("sockets(debug): accept() returned a good socket.\n"); return (fdNewSocket); } return (-1); // to satisfy compiler } // SocketAcceptConnection //---------------------------------------------------------------------- int SocketRead (int fdSocket, char* pszBuffer, int iMaxBytes, int iMinBytes) //------------------------------------------------------------------keef // // keeps looping until max bytes, or EOBATCH is encountered // returns #bytes on success, or a neg. int. on failure // { int iTotalRead = 0; int iLeft = iMaxBytes; int iRead = -1; while (iLeft && (iRead || (iTotalRead<=iMinBytes))) { iRead = read (fdSocket, pszBuffer, iLeft); if (iRead < 0) return (iRead); // error occurred iTotalRead += iRead; char *pEnd; if (iRead && ((pEnd=strchr(pszBuffer,cEOBATCH)) != NULL)) { *pEnd = 0; iRead = 0; // break 'for' loop } iLeft -= iRead; pszBuffer += iRead; } return (iTotalRead); } // SocketRead //----------------------------------------------------------------------------- BOOL SocketReadLine (int fdSocket, char* pszLine, int iMaxBytes) //----------------------------------------------------------------------------- // // keeps looping until max bytes, or newline is encountered // returns TRUE if it read a line, FALSE if EOBATCH // note: newline char is automatically shaved off (turned to nil) // { BOOL fGotALine = FALSE; int iTotalRead = 0; int iLeft = iMaxBytes; int iRead = -1; while (iLeft && iRead) { iRead = read (fdSocket, pszLine, 1); if (iRead < 0) { *pszLine = 0; return (FALSE); // error occurred } iTotalRead += iRead; if (iRead) { switch (*pszLine) { case '\n': *pszLine = 0; fGotALine = TRUE; iRead = 0; // break 'for' loop break; case cEOBATCH: *pszLine = 0; fGotALine = (iTotalRead > 1); iRead = 0; // break 'for' loop break; } } iLeft -= iRead; pszLine += iRead; } return (fGotALine); } // SocketReadLine //----------------------------------------------------------------------------- int SendCommand (struct sockaddr_in* pAddrServer, char* pszHostname, char* pszCommand) //----------------------------------------------------------------------------- // opens socket and connects to host // writes the given string (pszCommand) to the established socket { int fdSocket; DebugLog ("SendCommand(): opening new socket to daemon...\n"); if ((fdSocket = socket (AF_INET, SOCK_STREAM, 0)) < 0) { ErrorLog ("Can't open stream socket\n"); return (-1); // error } DebugLog ("SendCommand(): new fdSocket = %d, now trying a connect...\n", fdSocket); #ifdef UNIX // sanity check: 0=stdin, 1=stdout, 2=stderr, we should always be getting --> 3 <-- if (fdSocket != 3) { DebugLog ("SendCommand(): UNEXPECTED SOCKET NUMBER --> %d <--\n", fdSocket); DebugLog ("SendCommand(): 0=stdin, 1=stdout, 2=stderr, shouldn't we get 3 ???\n"); } #endif if (connect (fdSocket, (struct sockaddr *) pAddrServer, sizeof(struct sockaddr_in)) < 0) { DebugLog ("SendCommand(): connect returned and ERROR (errno=%d)\n", errno); ErrorLog ("Hostname '%s' is not reachable (errno=%d)\n", pszHostname, errno); TranslateErrno (); } DebugLog ("SendCommand(): connect happened, let's keep going...\n"); DebugLog ("SendCommand(): calling SocketWrite() to fdSocket = %d\n", fdSocket); SocketWrite (fdSocket, pszCommand); DebugLog ("SendCommand(): sent '%s'\n", pszCommand); return (fdSocket); } // SendCommand //---------------------------------------------------------------------- int SocketWrite (int fdSocket, char* pszBuffer) //------------------------------------------------------------------keef // // keeps looping until all bytes are written, or socket is closed // returns #bytes on success, or a neg. int. on failure // { int iBytesToSend = strlen(pszBuffer); int iTotalWritten = 0; int iLeft, iWritten; for (iWritten=0, iLeft=iBytesToSend; iLeft && (iWritten>=0); iLeft-=iWritten, pszBuffer+=iWritten) { iWritten = write (fdSocket, pszBuffer, iLeft); if (iWritten < 0) return (iWritten); // error occurred iTotalWritten += iWritten; } return (iTotalWritten); } // SocketWrite //----------------------------------------------------------------------------- void TranslateErrno () //----------------------------------------------------------------------------- { #ifdef WIN32 switch (WSAGetLastError()) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // list taken from VC++ 4.1 documentation: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case WSASYSNOTREADY: ErrorLog ("----> WSASYSNOTREADY: Indicates that the underlying network subsystem is not ready for network communication.\n"); break; case WSAVERNOTSUPPORTED: ErrorLog ("----> WSAVERNOTSUPPORTED: The version of Windows Sockets support requested is not provided by this particular Windows Sockets implementation.\n"); break; case WSAEINVAL: ErrorLog ("----> WSAEINVAL: The Windows Sockets version specified by the application is not supported by this DLL.\n"); break; case WSANOTINITIALISED: ErrorLog ("----> WSANOTINITIALISED: A successful WSAStartup must occur before using this function.\n"); break; case WSAENETDOWN: ErrorLog ("----> WSAENETDOWN: The Windows Sockets implementation has detected that the network subsystem has failed.\n"); break; case WSAEAFNOSUPPORT: ErrorLog ("----> WSAEAFNOSUPPORT: The specified address family is not supported.\n"); break; case WSAEINPROGRESS: ErrorLog ("----> WSAEINPROGRESS: A blocking Windows Sockets operation is in progress.\n"); break; case WSAEMFILE: ErrorLog ("----> WSAEMFILE: No more file descriptors are available.\n"); break; case WSAENOBUFS: ErrorLog ("----> WSAENOBUFS: No buffer space is available. The socket cannot be created.\n"); break; case WSAEPROTONOSUPPORT: ErrorLog ("----> WSAEPROTONOSUPPORT: The specified protocol is not supported.\n"); break; case WSAEPROTOTYPE: ErrorLog ("----> WSAEPROTOTYPE: The specified protocol is the wrong type for this socket.\n"); break; case WSAESOCKTNOSUPPORT: ErrorLog ("----> WSAESOCKTNOSUPPORT: The specified socket type is not supported in this address family. if (!errno)\n"); break; default: if (!errno) ErrorLog ("----> UNKNOWN ERROR\n"); break; } #endif //WIN32 if (!errno) return; switch (errno) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // list taken from /usr/include/sys/errno.h on Solaris 2.5: // subset verified against MSDEV/include/ERRNO.h (VC 4.1): // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case EPERM: ErrorLog ("----> EPERM: Not super-user\n"); break; case ENOENT: ErrorLog ("----> ENOENT No such file or directory\n"); break; case ESRCH: ErrorLog ("----> ESRCH No such process\n"); break; case EINTR: ErrorLog ("----> EINTR interrupted system call\n"); break; case EIO: ErrorLog ("----> EIO I/O error\n"); break; case ENXIO: ErrorLog ("----> ENXIO No such device or address\n"); break; case E2BIG: ErrorLog ("----> E2BIG Arg list too long\n"); break; case ENOEXEC: ErrorLog ("----> ENOEXEC Exec format error\n"); break; case EBADF: ErrorLog ("----> EBADF Bad file number\n"); break; case ECHILD: ErrorLog ("----> ECHILD No children\n"); break; case EAGAIN: ErrorLog ("----> EAGAIN Resource temporarily unavailable\n"); break; case ENOMEM: ErrorLog ("----> ENOMEM Not enough core\n"); break; case EACCES: ErrorLog ("----> EACCES Permission denied\n"); break; case EFAULT: ErrorLog ("----> EFAULT Bad address\n"); break; case EBUSY: ErrorLog ("----> EBUSY Mount device busy\n"); break; case EEXIST: ErrorLog ("----> EEXIST File exists\n"); break; case EXDEV: ErrorLog ("----> EXDEV Cross-device link\n"); break; case ENODEV: ErrorLog ("----> ENODEV No such device\n"); break; case ENOTDIR: ErrorLog ("----> ENOTDIR Not a directory\n"); break; case EISDIR: ErrorLog ("----> EISDIR Is a directory\n"); break; case EINVAL: ErrorLog ("----> EINVAL Invalid argument\n"); break; case ENFILE: ErrorLog ("----> ENFILE File table overflow\n"); break; case EMFILE: ErrorLog ("----> EMFILE Too many open files\n"); break; case ENOTTY: ErrorLog ("----> ENOTTY Inappropriate ioctl for device\n"); break; case EFBIG: ErrorLog ("----> EFBIG File too large\n"); break; case ENOSPC: ErrorLog ("----> ENOSPC No space left on device\n"); break; case ESPIPE: ErrorLog ("----> ESPIPE Illegal seek\n"); break; case EROFS: ErrorLog ("----> EROFS Read only file system\n"); break; case EMLINK: ErrorLog ("----> EMLINK Too many links\n"); break; case EPIPE: ErrorLog ("----> EPIPE Broken pipe\n"); break; case EDOM: ErrorLog ("----> EDOM Math arg out of domain of func\n"); break; case ERANGE: ErrorLog ("----> ERANGE Math result not representable\n"); break; case EDEADLK: ErrorLog ("----> EDEADLK Deadlock condition\n"); break; case ENOLCK: ErrorLog ("----> ENOLCK No record locks available\n"); break; #ifndef WIN32 case ENOTSOCK: ErrorLog ("----> ENOTSOCK Socket operation on non-socket\n"); break; case EDESTADDRREQ: ErrorLog ("----> EDESTADDRREQ Destination address required\n"); break; case EMSGSIZE: ErrorLog ("----> EMSGSIZE Message too long\n"); break; case EPROTOTYPE: ErrorLog ("----> EPROTOTYPE Protocol wrong type for socket\n"); break; case ENOPROTOOPT: ErrorLog ("----> ENOPROTOOPT Protocol not available\n"); break; case EPROTONOSUPPORT: ErrorLog ("----> EPROTONOSUPPORT Protocol not supported\n"); break; case ESOCKTNOSUPPORT: ErrorLog ("----> ESOCKTNOSUPPORT Socket type not supported\n"); break; case EOPNOTSUPP: ErrorLog ("----> EOPNOTSUPP Operation not supported on socket\n"); break; case EPFNOSUPPORT: ErrorLog ("----> EPFNOSUPPORT Protocol family not supported\n"); break; case EAFNOSUPPORT: ErrorLog ("----> EAFNOSUPPORT Address family not supported by\n"); break; case EADDRINUSE: ErrorLog ("----> EADDRINUSE Address already in use\n"); break; case EADDRNOTAVAIL: ErrorLog ("----> EADDRNOTAVAIL Can't assign requested address\n"); break; case ENETDOWN: ErrorLog ("----> ENETDOWN Network is down\n"); break; case ENETUNREACH: ErrorLog ("----> ENETUNREACH Network is unreachable\n"); break; case ENETRESET: ErrorLog ("----> ENETRESET Network dropped connection because\n"); break; case ECONNABORTED: ErrorLog ("----> ECONNABORTED Software caused connection abort\n"); break; case ECONNRESET: ErrorLog ("----> ECONNRESET Connection reset by peer\n"); break; case ENOBUFS: ErrorLog ("----> ENOBUFS No buffer space available\n"); break; case EISCONN: ErrorLog ("----> EISCONN Socket is already connected\n"); break; case ENOTCONN: ErrorLog ("----> ENOTCONN Socket is not connected\n"); break; #endif //!WIN32 default: ErrorLog ("----> UNKNOWN-ERRNO (%d)\n", errno); break; } } // TranslateErrno #ifdef WIN32 //----------------------------------------------------------------------------- LPCTSTR BindToWinsockDLL () //----------------------------------------------------------------------------- { static char szRtnMsgBuffer[200]; WORD wVersionRequested = MAKEWORD(WINSOCK_MAJVER,WINSOCK_MINVER); // defined in libsockets.h WSADATA wsaData; if (WSAStartup (wVersionRequested, &wsaData)) { sprintf (szRtnMsgBuffer, "ERROR: WINSOCK DLL (%s) does not support version %d.%d\n", wsaData.szDescription, WINSOCK_MAJVER, WINSOCK_MINVER); return ((LPCTSTR)szRtnMsgBuffer); // <-- error message (failure) } return (NULL); // <-- no error message (success) } // BindToWinsockDLL #endif //WIN32 #if 0 typedef struct { int iSOL_CONSTANT; char* szSOL_CONSTANT; char* szDescription; } SOCKOPT; //----------------------------------------------------------------------------- void QuerySocket (char* szWhere, int fdSocket) //----------------------------------------------------------------------------- { ErrorLog ("------------------------------------------------------------\n"); ErrorLog ("SOCKET(%d): %s:\n", fdSocket, szWhere); SOCKOPT SockOptArray[] = { { SO_LINGER, "SO_LINGER", "linger on close if data is present" }, #ifdef UNIX { SO_DEBUG, "SO_DEBUG", "enable/disable recording of debugging information" }, { SO_REUSEADDR, "SO_REUSEADDR", "enable/disable local address reuse" }, { SO_KEEPALIVE, "SO_KEEPALIVE", "enable/disable keep connections alive" }, { SO_DONTROUTE, "SO_DONTROUTE", "enable/disable routing bypass for outgoing messages" }, { SO_BROADCAST, "SO_BROADCAST", "enable/disable permission to transmit broadcast messages" }, { SO_OOBINLINE, "SO_OOBINLINE", "enable/disable reception of out-of-band data in band" }, { SO_SNDBUF, "SO_SNDBUF", "set buffer size for output" }, { SO_RCVBUF, "SO_RCVBUF", "set buffer size for input" }, { SO_TYPE, "SO_TYPE", "get the type of the socket (get only)" }, { SO_ERROR, "SO_ERROR", "get and clear error on the socket (get only)" }, #else { SO_ACCEPTCONN, "SO_ACCEPTCONN", "Socket is in listen mode." }, { SO_BROADCAST, "SO_BROADCAST", "Socket is configured for the transmission of broadcast messages." }, { SO_DEBUG, "SO_DEBUG", "Debugging is enabled. " }, { SO_DONTLINGER, "SO_DONTLINGER", "If true, the SO_LINGER option is disabled." }, { SO_DONTROUTE, "SO_DONTROUTE", "Routing is disabled." }, { SO_ERROR, "SO_ERROR", "Retrieve error status and clear." }, { SO_KEEPALIVE, "SO_KEEPALIVE", "Keepalive messages are being sent." }, { SO_OOBINLINE, "SO_OOBINLINE", "Out-of-band data is being received in the normal data stream. " }, { SO_RCVBUF, "SO_RCVBUF", "Buffer size for receive operations." }, { SO_REUSEADDR, "SO_REUSEADDR", "The socket may be bound to an address that is already in use." }, { SO_SNDBUF, "SO_SNDBUF", "Buffer size for send operations." }, { SO_TYPE, "SO_TYPE", "The type of the socket (for example, SOCK_STREAM)." }, { TCP_NODELAY, "TCP_NODELAY", "Disables the Nagle algorithm for send coalescing." }, #endif { NULL } }; struct linger { int state; int timeout; } sLinger; int iSizeOf = sizeof(sLinger); if (getsockopt (fdSocket, SOL_SOCKET, SO_LINGER, (char*)&sLinger, &iSizeOf)) { ErrorLog ("getsockopt(SO_LINGER): FAILED!!"); TranslateErrno(errno); } else { ErrorLog ("%-15s: state=%d, timeout=%d\n", SockOptArray[0].szSOL_CONSTANT, sLinger.state, sLinger.timeout); } for (int ii=1/*<--skip SO_LINGER*/; SockOptArray[ii].szSOL_CONSTANT; ++ii) { int iValue; iSizeOf = sizeof(iValue); if (getsockopt (fdSocket, SOL_SOCKET, SockOptArray[ii].iSOL_CONSTANT, (char*)&iValue, &iSizeOf)) { ErrorLog ("getsockopt(%s): FAILED!!", SockOptArray[ii].szSOL_CONSTANT); TranslateErrno(errno); } else { ErrorLog ("%-15s: %d (%s)\n", SockOptArray[ii].szSOL_CONSTANT, iValue, SockOptArray[ii].szDescription); } } ErrorLog ("------------------------------------------------------------\n"); } // QuerySocket #endif