win_sock.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           win_sock.cpp  -  description
00003                              -------------------
00004     begin                : Thu Dec 9 2004
00005     copyright            : (C) 2004 by VooDooMan
00006     email                : vdmfun@hotmail.com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010 
00011 VooDoo cIRCle - an IRC (ro)bot
00012 Copyright (C) 2004 by Marian VooDooMan Meravy (vdmfun@hotmail.com)
00013 
00014 This program is free software; you can redistribute it and/or
00015 modify it under the terms of the GNU General Public License
00016 as published by the Free Software Foundation; either version 2
00017 of the License, or (at your option) any later version.
00018 
00019 This program is distributed in the hope that it will be useful,
00020 but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 
00023 GNU General Public License for more details.
00024 
00025 You should have received a copy of the GNU General Public License
00026 along with this program; if not, write to the Free Software
00027 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00028 
00029 ****************************************************************************/
00030 
00031 /*!
00032     \file
00033     \brief Provides low-level implementation of IP sockets (formely Windows(TM) only)
00034 */
00035 
00036 //---------------------------------------------------------------------------
00037 
00038 #include "params.h"
00039 
00040 #include <stdio.h>
00041 #ifndef _WIN32
00042 #   include <string.h>
00043 
00044 #    include <sys/time.h>
00045 #    include <sys/types.h>
00046 #    include <unistd.h>
00047 #endif
00048 
00049 #include "win_sock.h"
00050 #include "sock_shared.h"
00051 #include "match.h"
00052 #include "log.h"
00053 
00054 #ifdef IPv6
00055 #   ifdef _WIN32
00056 #       include <Ws2tcpip.h>
00057 #   endif
00058 #endif
00059 
00060 #include "params.h"
00061 
00062 //#include "stdafx.h"
00063 
00064 #pragma hdrstop
00065 
00066 //---------------------------------------------------------------------------
00067 #ifndef _MSC_VER
00068 #pragma package(smart_init)
00069 #endif
00070 
00071 #ifdef _MSC_VER
00072 #   define __FUNC__ __FUNCTION__
00073 #endif
00074 
00075 #ifdef __GNUC__
00076 #define __FUNC__ "<unknown>"
00077 #endif
00078 
00079 #ifdef _WIN32
00080 WSADATA WSAData;                                    //!< Stores "WSAStartup()"'s data
00081 #   define socklen_t int
00082 #endif
00083 
00084 extern void sock_create_later(s_socket& socket, bool using_window);
00085 extern void sock_flush_later(s_socket& socket);
00086 extern void sock_erase_later(s_socket& socket);
00087 extern void sock_async(s_socket& socket);
00088 
00089 #ifdef _WIN32
00090 # ifndef WINSOCK_VERSION
00091 #   define WINSOCK_VERSION 0x0002
00092 # endif
00093 #endif
00094 
00095 /*!
00096     \brief Returns OS's error string from socket I/O error
00097     \author VooDooMan
00098     \version 1
00099     \date 2004
00100     \param code Socket I/O error
00101     \return OS's error string
00102 */
00103 const char* sock_error(int code)
00104 {
00105     char* result=0;
00106 #ifdef _WIN32
00107     switch(code) {
00108         case WSAEACCES:
00109             result="Permission denied"; break;
00110         case WSAEADDRINUSE:
00111             result="Address already in use"; break;
00112         case WSAEADDRNOTAVAIL:
00113             result="Cannot assign requested address"; break;
00114         case WSAEAFNOSUPPORT:
00115             result="Address family not supported by protocol family"; break;
00116         case WSAEALREADY:
00117             result="Operation already in progress"; break;
00118         case WSAECONNABORTED:
00119             result="Software caused connection abort"; break;
00120         case WSAECONNREFUSED:
00121             result="Connection refused"; break;
00122         case WSAECONNRESET:
00123             result="Connection reset by peer"; break;
00124         case WSAEDESTADDRREQ:
00125             result="Destination address required"; break;
00126         case WSAEFAULT:
00127             result="Bad address"; break;
00128         case WSAEHOSTDOWN:
00129             result="Host is down"; break;
00130         case WSAEHOSTUNREACH:
00131             result="No route to host"; break;
00132         case WSAEINPROGRESS:
00133             result="Operation now in progress"; break;
00134         case WSAEINTR:
00135             result="Interrupted function call"; break;
00136         case WSAEINVAL:
00137             result="Invalid argument"; break;
00138         case WSAEISCONN:
00139             result="Socket is already connected"; break;
00140         case WSAEMFILE:
00141             result="Too many open files"; break;
00142         case WSAEMSGSIZE:
00143             result="Message too long"; break;
00144         case WSAENETDOWN:
00145             result="Network is down"; break;
00146         case WSAENETRESET:
00147             result="Network dropped connection on reset"; break;
00148         case WSAENETUNREACH:
00149             result="Network is unreachable"; break;
00150         case WSAENOBUFS:
00151             result="No buffer space available"; break;
00152         case WSAENOPROTOOPT:
00153             result="Bad protocol option"; break;
00154         case WSAENOTCONN:
00155             result="Socket is not connected"; break;
00156         case WSAENOTSOCK:
00157             result="Socket operation on non-socket"; break;
00158         case WSAEOPNOTSUPP:
00159             result="Operation not supported"; break;
00160         case WSAEPFNOSUPPORT:
00161             result="Protocol family not supported"; break;
00162         case WSAEPROCLIM:
00163             result="Too many processes"; break;
00164         case WSAEPROTONOSUPPORT:
00165             result="Protocol not supported"; break;
00166         case WSAEPROTOTYPE:
00167             result="Protocol wrong type for socket"; break;
00168         case WSAESHUTDOWN:
00169             result="Cannot send after socket shutdown"; break;
00170         case WSAESOCKTNOSUPPORT:
00171             result="Socket type not supported"; break;
00172         case WSAETIMEDOUT:
00173             result="Connection timed out"; break;
00174         case WSATYPE_NOT_FOUND:
00175             result="Class type not found"; break;
00176         case WSAEWOULDBLOCK:
00177             result="Resource temporarily unavailable"; break;
00178         case WSAHOST_NOT_FOUND:
00179             result="Host not found"; break;
00180         case WSANOTINITIALISED:
00181             result="Successful WSAStartup not yet performed"; break;
00182         case WSANO_DATA:
00183             result="Valid name, no data record of requested type"; break;
00184         case WSANO_RECOVERY:
00185             result="This is a non-recoverable error"; break;
00186         case WSASYSCALLFAILURE:
00187             result="System call failure"; break;
00188         case WSASYSNOTREADY:
00189             result="Network subsystem is unavailable"; break;
00190         case WSATRY_AGAIN:
00191             result="Non-authoritative host not found"; break;
00192         case WSAVERNOTSUPPORTED:
00193             result="WINSOCKDLL version out of range"; break;
00194         case WSAEDISCON:
00195             result="Graceful shutdown in progress"; break;
00196 
00197         case -1:
00198             result="(Unknown error, based on select() fuction)"; break;
00199             
00200         case -2:
00201             result="(Not compiled with IPv6 support)"; break;
00202 
00203         default:
00204             result="Unknown error"; break;
00205     }
00206 #else
00207     if(code!=-2)
00208         result=strerror(code);
00209     else
00210         result="(Not compiled with IPv6 support)";
00211 #endif
00212     return(result);
00213 }
00214 
00215 /*!
00216     \brief Initializes WinSock
00217     \author VooDooMan
00218     \version 1
00219     \date 2004
00220     \return OS's socket error
00221     \warning Only for Windows(TM)
00222 */
00223 int sock_startup()
00224 {
00225 #ifdef _WIN32
00226     int ec=WSAStartup(WINSOCK_VERSION,&WSAData);
00227     int la=WSAGetLastError();
00228     if(ec==0)
00229         la=0;
00230     return la;
00231 #else
00232     return 0;
00233 #endif
00234 }
00235 
00236 /*!
00237     \brief Shuts down WinSock
00238     \author VooDooMan
00239     \version 1
00240     \date 2004
00241     \return OS's socket error
00242     \warning Only for Windows(TM)
00243 */
00244 int sock_shutdown()
00245 {
00246 #ifdef _WIN32
00247     int ec=WSACleanup();
00248     int la=WSAGetLastError();
00249     if(ec==0)
00250         la=0;
00251     return la;
00252 #else
00253     return 0;
00254 #endif
00255 }
00256 
00257 /*!
00258     \brief Connects to remote host
00259     \author VooDooMan
00260     \version 1
00261     \date 2004
00262     \param localIP Local IPv4 address as text to bind, if we are using IPv4 as destination, otherwise ignored
00263     \param remote Remote IPv4/IPv6 address as text, or IPv4/IPv6 host name
00264     \param remote_port Remote port
00265     \param error_code Returns OS's socket error
00266     \param async If true, it calls WSAAsyncSelect and creates cache buffers
00267     \return If error_code == zero, returns socket handle of connected socket, else undefined
00268 */
00269 s_socket sock_connect(char* localIP, char* remote, unsigned short remote_port, int& error_code, bool async)
00270 {
00271     s_socket Socket;
00272 
00273 #ifdef IPv6
00274 
00275     addrinfo Hints;
00276     addrinfo* AddrInfo=NULL;
00277 
00278     char port_name[64];
00279     sprintf(port_name,"%u",(unsigned int)remote_port);
00280 
00281     memset(&Hints,0,sizeof(Hints));
00282     Hints.ai_family=PF_UNSPEC;
00283     Hints.ai_socktype=SOCK_STREAM;
00284     if(getaddrinfo(remote,port_name,&Hints,&AddrInfo)) {
00285         int ec=WSAGetLastError();
00286         if(ec)
00287             log_socket(ec,sock_error(ec),"Cannot resolve addres and port, while calling getaddrinfo() in file " __FILE__ " in function " __FUNC__);
00288         s_socket nul;
00289         nul.clear();
00290         freeaddrinfo(AddrInfo);
00291         return nul;
00292     }
00293 
00294     //
00295     // Try each address getaddrinfo returned, until we find one to which
00296     // we can sucessfully connect.
00297     //
00298     addrinfo* AI;
00299     for(AI=AddrInfo; AI; AI=AI->ai_next) {
00300 
00301         // Open a socket with the correct address family for this address.
00302         Socket.handle=socket(AI->ai_family,AI->ai_socktype,AI->ai_protocol);
00303         if(Socket.handle==INVALID_SOCKET) {
00304             int ec=WSAGetLastError();
00305             if(ec)
00306                 log_socket(ec,sock_error(ec),"Error opening socket, while calling socket() in file " __FILE__ " in function " __FUNC__);
00307             continue;
00308         }
00309 
00310         if(async)
00311             sock_create_later(Socket,true);
00312 
00313         if(connect(Socket.handle,AI->ai_addr,AI->ai_addrlen)==SOCKET_ERROR) {
00314             sock_erase_later(Socket);
00315             closesocket(Socket.handle);
00316             int ec=WSAGetLastError();
00317             if(ec)
00318                 log_socket(ec,sock_error(ec),"Error connecting socket, while calling connect() in file " __FILE__ " in function " __FUNC__);
00319             continue;
00320         }
00321         break;
00322     }
00323 
00324     freeaddrinfo(AddrInfo);
00325 
00326     if(!AI) {
00327         sock_erase_later(Socket);
00328         s_socket nul;
00329         nul.clear();
00330         return nul;
00331     }
00332 
00333 #else
00334 
00335     sockaddr_in SockAddrIn;
00336     SockAddrIn.sin_family=AF_INET;
00337     SockAddrIn.sin_addr=sock_resolve(remote,NULL);
00338     SockAddrIn.sin_port=htons(remote_port);
00339 
00340     PROTOENT* PProtoEnt=getprotobyname("tcp");
00341 
00342     if(PProtoEnt==0) {
00343         int la=error_code=WSAGetLastError();
00344         if(la!=0) {
00345             s_socket nul;
00346             nul.clear();
00347             return nul;
00348         }
00349     }
00350 
00351     Socket.handle=socket(PF_INET,SOCK_STREAM,PProtoEnt->p_proto);
00352     if(Socket.handle==SOCKET_ERROR) {
00353         int la=error_code=WSAGetLastError();
00354         if(la!=0) {
00355             s_socket nul;
00356             nul.clear();
00357             return nul;
00358         }
00359     }
00360 
00361     sockaddr_in LocalName;
00362     LocalName.sin_family=AF_INET;
00363     LocalName.sin_port=0;
00364 #ifdef _WIN32
00365     LocalName.sin_addr.S_un.S_addr=inet_addr(localIP);
00366 #else
00367     LocalName.sin_addr.s_addr=inet_addr(localIP);
00368 #endif
00369     int ErrorCode=bind(Socket.handle,reinterpret_cast<sockaddr *>(&LocalName),sizeof(LocalName));
00370     if(ErrorCode!=0) {
00371         int la=error_code=WSAGetLastError();
00372         if(la!=0) {
00373             s_socket nul;
00374             nul.clear();
00375             return nul;
00376         }
00377     }
00378 
00379     if(async)
00380         sock_create_later(Socket,true);
00381 
00382     ErrorCode=connect(Socket.handle,reinterpret_cast<sockaddr *>(&SockAddrIn),sizeof(SockAddrIn));
00383     if(ErrorCode!=0) {
00384         int la=error_code=WSAGetLastError();
00385         if(la!=0) {
00386             sock_erase_later(Socket);
00387             closesocket(Socket.handle);
00388 
00389             s_socket nul;
00390             nul.clear();
00391             return nul;
00392         }
00393     }
00394 
00395 #endif
00396 
00397     if(async)
00398         sock_async(Socket);
00399 
00400     error_code=0;
00401     return Socket;
00402 }
00403 
00404 /*!
00405     \brief Closes connected socket
00406     \author VooDooMan
00407     \version 1
00408     \date 2004
00409     \param socket Socket handle of connected socket
00410 */
00411 void sock_close(s_socket& socket)
00412 {
00413     sock_flush_later(socket);
00414     sock_erase_later(socket);
00415     closesocket(socket.handle);
00416 }
00417 
00418 /*
00419     \brief Resolves DNS name or text IPv4 address to IPv4 address via DNS
00420     \author VooDooMan
00421     \version 1
00422     \date 2004
00423     \param domain DNS name or IPv4 address as text to resolve
00424     \param ip_string Buffer of at least 15 + 1 NUL terminator bytes size to receive IPv4 address as text
00425     \return Returns IPv4 address
00426 */
00427 in_addr sock_resolve(const char* domain, char* ip_string)
00428 {
00429     in_addr ip;
00430 
00431     hostent* remoteHost=NULL;
00432     unsigned int addr;
00433 
00434     // If the user input is an alpha name for the host, use gethostbyname()
00435     // If not, get host by addr (assume IPv4)
00436     int type=sock_get_address_type(domain);
00437     //if(!(domain[0]>='0' && domain[0]<='9')) {   // host address is a name
00438     if(type==0) {   // host address is a name
00439         remoteHost=gethostbyname(domain);
00440 
00441         memset(&ip,0,sizeof(ip));
00442         if(WSAGetLastError()!=0 || remoteHost==NULL) {
00443             if(WSAGetLastError()==11001) {
00444                 // Win32: host not found
00445             }
00446         } else
00447             memcpy(&ip,remoteHost->h_addr_list[0],4);
00448     } else {
00449         addr=inet_addr(domain);
00450         //remoteHost=gethostbyaddr((char *)&addr, 4, AF_INET);
00451         memcpy(&ip,&addr,4);
00452     }
00453 
00454 #ifdef _WIN32
00455     if(ip_string)
00456         sprintf(ip_string,"%u.%u.%u.%u",ip.S_un.S_un_b.s_b1,ip.S_un.S_un_b.s_b2,ip.S_un.S_un_b.s_b3,ip.S_un.S_un_b.s_b4);
00457 #else
00458     if(ip_string) {
00459         unsigned char* x=(unsigned char*)&ip.s_addr;
00460         sprintf(ip_string,"%u.%u.%u.%u",x[0],x[1],x[2],x[3]);
00461     }
00462 #endif
00463     return ip;
00464 }
00465 
00466 /*!
00467     \brief Resolves IPv4 address to DNS name via DNS (reverse lookup)
00468     \author VooDooMan
00469     \version 1
00470     \date 2004
00471     \param address IPv4 address as text (dotted format)
00472     \param dns_name Buffer that receives DNS name (should be long enough)
00473     \param dns_max_size Length of dns_name buffer
00474 */
00475 void sock_reverse(char* address, char* dns_name, int dns_max_size)
00476 {
00477     hostent* remoteHost;
00478     unsigned int addr=inet_addr(address);
00479     remoteHost=gethostbyaddr((char *)&addr, 4, AF_INET);
00480 
00481     if(WSAGetLastError()==0 && remoteHost) {
00482         strncpy(dns_name,remoteHost->h_name,dns_max_size);
00483         dns_name[dns_max_size-1]=0;
00484     } else
00485         dns_name[0]=0;
00486 }
00487 
00488 /*!
00489     \brief Binds server socket and start listening
00490     \author VooDooMan
00491     \version 1
00492     \date 2004
00493     \param local Local IPv4 address to bind to
00494     \param port Local port to bind
00495     \param error_code Returns OS's socket error
00496     \return If error_code == zero, returns server socket handle, else undefined
00497 */
00498 s_socket sock_bind(in_addr local, unsigned short port, int& error_code)
00499 {
00500     sockaddr_in SockAddrIn;
00501 
00502     SockAddrIn.sin_family=AF_INET;
00503     SockAddrIn.sin_addr=local;
00504     SockAddrIn.sin_port=htons(port);
00505     PROTOENT* PProtoEnt=getprotobyname("tcp");
00506     if(PProtoEnt==0) {
00507         int la=error_code=WSAGetLastError();
00508         if(la!=0) {
00509             s_socket nul;
00510             nul.clear();
00511             return nul;
00512         }
00513     }
00514 
00515     s_socket Socket;
00516     Socket.handle=socket(PF_INET,SOCK_STREAM,PProtoEnt->p_proto);
00517     if(Socket.handle==SOCKET_ERROR) {
00518         error_code=WSAGetLastError();
00519         s_socket nul;
00520         nul.clear();
00521         if(error_code!=0)
00522             return nul;
00523     }
00524     int ErrorCode=0;
00525 #ifndef _WIN32
00526     // on Win32 this would be harmfull, only on POSIX it makes sense,
00527     // if socket is in TIME_WAIT state; on Win32 we would never get
00528     // "address already in use" error while socket is in TIME_WAIT,
00529     // but more dangerous on Win32 is that we will never get that error even
00530     // if address/port is really busy listening after setting socket option SO_REUSEADDR.
00531     int tmp=1;
00532     ErrorCode=setsockopt(Socket.handle,SOL_SOCKET,SO_REUSEADDR,(const char*)&tmp,sizeof(tmp));
00533     if(ErrorCode!=0) {
00534         error_code=WSAGetLastError();
00535         s_socket nul;
00536         nul.clear();
00537         if(error_code!=0)
00538             return nul;
00539     }
00540 #endif
00541     ErrorCode=bind(Socket.handle,reinterpret_cast<sockaddr*>(&SockAddrIn),sizeof(SockAddrIn));
00542     if(ErrorCode!=0) {
00543         error_code=WSAGetLastError();
00544         s_socket nul;
00545         nul.clear();
00546         if(error_code!=0)
00547             return nul;
00548     }
00549     socklen_t i1=sizeof(SockAddrIn);
00550     ErrorCode=getsockname(Socket.handle,reinterpret_cast<sockaddr*>(&SockAddrIn),&i1);
00551     if(ErrorCode!=0) {
00552         error_code=WSAGetLastError();
00553         s_socket nul;
00554         nul.clear();
00555         if(error_code!=0)
00556             return nul;
00557     }
00558     ErrorCode=listen(Socket.handle,5);
00559     if(ErrorCode!=0) {
00560         error_code=WSAGetLastError();
00561         s_socket nul;
00562         nul.clear();
00563         if(error_code!=0)
00564             return nul;
00565     }
00566 #ifdef _WIN32
00567     unsigned long non_blocking=1;
00568     ErrorCode=ioctlsocket(Socket.handle,FIONBIO,&non_blocking);
00569 #else
00570     int flags=fcntl(Socket.handle,F_GETFL,0);
00571     flags|=O_NONBLOCK;
00572     fcntl(Socket.handle,F_SETFL,flags);
00573     ErrorCode=0;
00574 #endif
00575     if(ErrorCode!=0) {
00576         error_code=WSAGetLastError();
00577         s_socket nul;
00578         nul.clear();
00579         if(error_code!=0)
00580             return nul;
00581     }
00582 
00583     return Socket;
00584 }
00585 
00586 /*!
00587     \brief Binds server socket and start listening
00588     \author VooDooMan
00589     \version 1
00590     \date 2004
00591     \param local Local IPv6 address to bind to
00592     \param port Local port to bind
00593     \param error_code Returns OS's socket error
00594     \return If error_code == zero, returns server socket handle, else undefined
00595 */
00596 s_socket sock_bind6(char* local, unsigned short port, int& error_code)
00597 {
00598 #ifdef IPv6
00599     struct sockaddr_in6 saGNI;
00600     char servInfo[256];
00601 
00602     addrinfo Hints;
00603     addrinfo* AddrInfo=NULL;
00604 
00605     char port_name[64];
00606     sprintf(port_name,"%u",(unsigned int)port);
00607 
00608     memset(&Hints,0,sizeof(Hints));
00609     Hints.ai_family=PF_INET6;
00610     Hints.ai_socktype=SOCK_STREAM;
00611     Hints.ai_flags=AI_NUMERICHOST /*AI_PASSIVE*/;
00612 
00613     if(getaddrinfo(local,port_name,&Hints,&AddrInfo)) {
00614         int ec=WSAGetLastError();
00615         if(ec)
00616             log_socket(ec,sock_error(ec),"Cannot resolve addres and port, while calling getaddrinfo() in file " __FILE__ " in function " __FUNC__);
00617         freeaddrinfo(AddrInfo);
00618         s_socket nul;
00619         nul.clear();
00620         return nul;
00621     }
00622 
00623     addrinfo* AI;
00624     for(AI=AddrInfo; AI; AI=AI->ai_next) {
00625         if(AI->ai_family!=AF_INET6)
00626             continue;
00627 
00628         s_socket Socket;
00629 
00630         Socket.handle=socket(AI->ai_family,AI->ai_socktype,AI->ai_protocol);
00631         if(Socket.handle==SOCKET_ERROR)
00632             continue;
00633 
00634         int ErrorCode=bind(Socket.handle,AI->ai_addr,AI->ai_addrlen);
00635         if(ErrorCode!=0) {
00636             closesocket(Socket.handle);
00637             continue;
00638         }
00639 
00640         ErrorCode=listen(Socket.handle,5);
00641         if(ErrorCode!=0) {
00642             closesocket(Socket.handle);
00643             continue;
00644         }
00645     
00646 #ifdef _WIN32
00647         unsigned long non_blocking=1;
00648         ErrorCode=ioctlsocket(Socket.handle,FIONBIO,&non_blocking);
00649 #else
00650         int flags=fcntl(Socket.handle,F_GETFL,0);
00651         flags|=O_NONBLOCK;
00652         fcntl(Socket.handle,F_SETFL,flags);
00653         ErrorCode=0;
00654 #endif
00655         if(ErrorCode!=0) {
00656             closesocket(Socket.handle);
00657             continue;
00658         }
00659 
00660         error_code=0;
00661         return Socket;
00662     }
00663 
00664     error_code=WSAGetLastError();
00665     s_socket nul;
00666     nul.clear();
00667     return nul;
00668 
00669 #else
00670     error_code=-2;
00671     s_socket nul;
00672     nul.clear();
00673     return nul;
00674 #endif
00675 }
00676 
00677 /*!
00678     \brief Accepts client connection on listening server socket
00679     \author VooDooMan
00680     \version 1
00681     \date 2004
00682     \param socket Socket handle of listening server socket
00683     \return Returns socket handle of client connection
00684 */
00685 s_socket sock_accept(s_socket& socket)
00686 {
00687     fd_set s_;
00688     FD_ZERO(&s_);
00689     FD_SET(socket.handle,&s_);
00690     timeval timeout;
00691     timeout.tv_sec=0;
00692     timeout.tv_usec=100;
00693     int num=select((int)socket.handle+1,&s_,NULL,NULL,&timeout);
00694 
00695     s_socket nul;
00696     nul.clear();
00697 
00698     if(num==0)
00699         return nul;
00700     sockaddr_in SockAddrIn;
00701     socklen_t i1=sizeof(SockAddrIn);
00702     SOCKET ec=accept(socket.handle,reinterpret_cast<sockaddr *>(&SockAddrIn),&i1);
00703 
00704     if(ec!=INVALID_SOCKET) {
00705         s_socket s;
00706         s.clear();
00707         s.handle=ec;
00708 
00709         sock_create_later(s,false);
00710         //sock_async(ec);
00711 
00712         return s;
00713     }
00714 
00715     return nul;
00716 }
00717 
00718 /*!
00719     \brief Accepts client connection on listening server socket
00720     \author VooDooMan
00721     \version 1
00722     \date 2004
00723     \param socket Socket handle of listening server socket
00724     \return Returns socket handle of client connection
00725 */
00726 s_socket sock_accept6(s_socket& socket)
00727 {
00728     s_socket nul;
00729     nul.clear();
00730 #ifdef IPv6
00731     fd_set s_;
00732     FD_ZERO(&s_);
00733     FD_SET(socket.handle,&s_);
00734     timeval timeout;
00735     timeout.tv_sec=0;
00736     timeout.tv_usec=100;
00737     int num=select(socket.handle+1,&s_,NULL,NULL,&timeout);
00738 
00739     if(num==0)
00740         return nul;
00741     sockaddr_in6 SockAddrIn;
00742     socklen_t i1=sizeof(SockAddrIn);
00743     SOCKET ec=accept(socket.handle,reinterpret_cast<sockaddr *>(&SockAddrIn),&i1);
00744 
00745     if(ec!=INVALID_SOCKET) {
00746         s_socket s;
00747         s.clear();
00748         s.handle=ec;
00749 
00750         if(getnameinfo(reinterpret_cast<sockaddr *>(&SockAddrIn),sizeof(SockAddrIn),s.host,sizeof(s.host),NULL,0,NI_NUMERICHOST)!=0)
00751             s.host[0]=0;
00752 
00753         sock_create_later(s,false);
00754         //sock_async(ec);
00755 
00756         return s;
00757     }
00758 
00759 #endif
00760     return nul;
00761 }
00762 
00763 /*!
00764     \brief Gets remote IPv4 address of remote host
00765     \author VooDooMan
00766     \version 1
00767     \date 2004
00768     \param socket Socket handle of connected socket
00769     \param error_code Returns OS's socket error
00770     \return If error_code == zero, returns IPv4 address of remote host, else undefined
00771 */
00772 in_addr sock_get_remote_addr(s_socket& socket, int& error_code)
00773 {
00774     sockaddr_in addr;
00775     socklen_t i2=sizeof(addr);
00776     error_code=getpeername(socket.handle,reinterpret_cast<sockaddr*>(&addr),&i2);
00777     return addr.sin_addr;
00778 }
00779 
00780 /*!
00781     \brief Gets remote IPv6 address of remote host
00782     \author VooDooMan
00783     \version 1
00784     \date 2004
00785     \param socket Socket handle of connected socket
00786     \return Returns IPv6 address of remote host, or zero
00787 */
00788 in_addr6_ sock_get_remote_addr6(s_socket& socket)
00789 {
00790 #ifdef IPv6
00791     char tmp[2048];
00792     strcpy(tmp,socket.host);
00793     if(strstr(tmp,"%"))
00794         *strstr(tmp,"%")=0;
00795     in_addr6_ addr;
00796     inetpton(AF_INET6,(const char*)tmp,&addr);
00797     return addr;
00798 #else
00799     in_addr6_ nul;
00800     memset(&nul,0,sizeof(nul));
00801     return nul;
00802 #endif
00803 }
00804 
00805 /*!
00806     \brief Low-level send to socket (Windows(TM) only)
00807     \author VooDooMan
00808     \version 1
00809     \date 2004
00810     \param socket Socket handle
00811     \param buff Buffer to send
00812     \param len Length of the buffer
00813     \return Returns number of bytes actually sent
00814 */
00815 size_t sock_lo_send(s_socket& socket, char* buff, size_t len)
00816 {
00817     size_t sent=send(socket.handle,buff,(int)len,0);
00818     if(sent>0) {
00819         socket.last_io=time(NULL);
00820         socket.sent+=sent;
00821     }
00822     return sent;
00823 }
00824 
00825 /*!
00826     \brief Low-level: receives data from the socket input queue, but leaves it in it (can be used for check how mush data is waiting)
00827     \author VooDooMan
00828     \version 2
00829     \date 2005
00830     \param socket Socket handle
00831     \param buff Buffer to receive
00832     \param len Length of the buffer
00833     \return Returns number of bytes waiting in queue
00834 */
00835 size_t sock_lo_get_input_amount(s_socket& socket, char* buff, size_t len)
00836 {
00837     //return recv(socket.handle,buff,len,MSG_PEEK);
00838     return recvfrom(socket.handle,buff,(int)len,MSG_PEEK,NULL,NULL);
00839 }
00840 
00841 /*!
00842     \brief Low-level read from socket (Windows(TM) only)
00843     \author VooDooMan
00844     \version 2
00845     \date 2005
00846     \param socket Socket handle
00847     \param buff Buffer to store received data
00848     \param len Maximum length of the buffer
00849     \return Returns number of bytes actually received
00850 */
00851 size_t sock_lo_recv(s_socket& socket, char* buff, size_t len)
00852 {
00853     //size_t received=recv(socket.handle,buff,len,0);
00854     size_t received=recvfrom(socket.handle,buff,(int)len,0,NULL,NULL);
00855     if(received>0) {
00856         socket.last_io=time(NULL);
00857         socket.received+=received;
00858     }
00859     return received;
00860 }
00861 
00862 /*
00863     \brief Resolves DNS name or text IPv6 address to IPv6 address via DNS
00864     \author VooDooMan
00865     \version 1
00866     \date 2004
00867     \param domain DNS name or IPv6 address as text to resolve
00868     \return Returns IPv6 address
00869 */
00870 in_addr6_ sock_resolve6(char* domain)
00871 {
00872 #ifdef IPv6
00873     struct sockaddr_in6 saGNI;
00874     char servInfo[256];
00875 
00876     addrinfo Hints;
00877     addrinfo* AddrInfo=NULL;
00878 
00879     char port_name[64];
00880     sprintf(port_name,"%u",(unsigned int)80); // something must be set as port...
00881 
00882     memset(&Hints,0,sizeof(Hints));
00883     Hints.ai_family=PF_INET6;
00884     Hints.ai_socktype=SOCK_STREAM;
00885     Hints.ai_flags=AI_PASSIVE;
00886 
00887     if(getaddrinfo(domain,port_name,&Hints,&AddrInfo)) {
00888         int ec=WSAGetLastError();
00889         if(ec)
00890             log_socket(ec,sock_error(ec),"Cannot resolve addres and port, while calling getaddrinfo() in file " __FILE__ " in function " __FUNC__);
00891         in_addr6_ a6;
00892         memset(&a6,0,sizeof(a6));
00893         freeaddrinfo(AddrInfo);
00894         return a6;
00895     }
00896 
00897     char host[2048];
00898 
00899     addrinfo* AI;
00900     for(AI=AddrInfo; AI; AI=AI->ai_next) {
00901         if(AI->ai_family!=AF_INET6)
00902             continue;
00903 
00904         if(getnameinfo(AI->ai_addr,AI->ai_addrlen, host, sizeof(host), servInfo, sizeof(servInfo), NI_NUMERICHOST)!=0) {
00905             int ec=WSAGetLastError();
00906             if(ec)
00907                 log_socket(ec,sock_error(ec),"Cannot resolve addres and port, while calling getnameinfo() in file " __FILE__ " in function " __FUNC__);
00908             continue;
00909         }
00910         break;
00911     }
00912     if(!AI) {
00913         in_addr6_ a6;
00914         memset(&a6,0,sizeof(a6));
00915         freeaddrinfo(AddrInfo);
00916         return a6;
00917     } else {
00918         in_addr6_ a6;
00919         if(inetpton(AF_INET6,(const char*)host,&a6)!=1) {
00920             memset(&a6,0,sizeof(a6));
00921             freeaddrinfo(AddrInfo);
00922             return a6;
00923         }
00924         freeaddrinfo(AddrInfo);
00925         return a6;
00926     }
00927 #else
00928     in_addr6_ a6;
00929     memset(&a6,0,sizeof(a6));
00930     return a6;
00931 #endif
00932 }
00933 
00934 /*!
00935     \brief Resolves IPv6 address to DNS name via DNS (reverse lookup)
00936     \author VooDooMan
00937     \version 1
00938     \date 2004
00939     \param address IPv4 address as text (dotted format)
00940     \param dns_name Buffer that receives DNS name (should be long enough)
00941     \param dns_max_size Length of dns_name buffer
00942     \warning Only for Windows(TM)
00943     \bug Doesn't work :-(
00944 */
00945 void sock_reverse(in_addr6_ address, char* dns_name, int dns_max_size)
00946 {
00947 #ifdef IPv6
00948     char host[2048];
00949     char servInfo[256];
00950 
00951     sockaddr_in6 a;
00952     memset(&a,0,sizeof(a));
00953     memcpy(&a.sin6_addr,&address,sizeof(a.sin6_addr));
00954     a.sin6_family=AF_INET6;
00955     a.sin6_port=80; // something for port...
00956     if(getnameinfo((sockaddr*)&a, sizeof(a), host, sizeof(host), servInfo, sizeof(servInfo), NI_NAMEREQD)!=0) {
00957         int ec=WSAGetLastError();
00958         if(ec)
00959             log_socket(ec,sock_error(ec),"Error while calling getnameinfo() in file " __FILE__ " in function " __FUNC__);
00960         host[0]=0;
00961     }
00962     memset(dns_name,0,dns_max_size);
00963     strncpy(dns_name,host,(dns_max_size<strlen(host))?dns_max_size:strlen(host));
00964 #else
00965     dns_name[0]=0;
00966 #endif
00967 }
00968 
00969 /*!
00970     \brief Sets or unsets the non-blocking mode for the socket
00971     \author VooDooMan
00972     \version 1
00973     \date 2004
00974     \param socket Socket handle
00975     \param non_blocking true if to set non-blocking mode
00976 */
00977 void sock_set_blocking(s_socket& socket, bool non_blocking)
00978 {
00979     /*unsigned long non_blocking_=non_blocking?1:0;
00980     ioctlsocket(socket.handle,FIONBIO,&non_blocking_);*/
00981 #ifdef _WIN32
00982     unsigned long non_blocking_=non_blocking?1:0;
00983     ioctlsocket(socket.handle,FIONBIO,&non_blocking_);
00984 #else
00985     int flags=fcntl(socket.handle,F_GETFL,0);
00986     flags&=~O_NONBLOCK;
00987     flags|=non_blocking?O_NONBLOCK:0;
00988     fcntl(socket.handle,F_SETFL,flags);
00989 #endif
00990 }
00991 

Generated on Sun Jul 10 03:23:04 2005 for VooDoo cIRCle by doxygen 1.4.3

Hosted by SourceForge.net Logo