#ifndef SOCKET__H_ #define SOCKET__H_ #ifdef MASS_SERVICE_SERVER #define FD_SETSIZE 2048 #endif #ifdef _WIN32 #pragma once //#pragma comment(lib, "wsock32.lib") // old ver #pragma comment(lib, "ws2_32.lib") #if _MSC_VER <= 1200 typedef int socklen_t; #else #include // getaddrinfo #endif #else #include #include #include // sockaddr_in #include // inet_ntoa() #include // gethostbyname() #include #include typedef int SOCKET; #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket close #define SD_BOTH SHUT_RDWR #endif // _WIN32 extern inline int SockErrorNo() { #ifdef _WIN32 return WSAGetLastError(); #else return errno; #endif } extern inline int GetAddrByHostName(const char * pAddress, struct sockaddr_in * pSai) // blocking operation { struct hostent * pHe; // resolve host address if ((pHe = gethostbyname(pAddress)) == NULL) { #if defined(_WIN32) && _MSC_VER <= 1200 return WSAGetLastError(); #else struct addrinfo aiHints; struct addrinfo *aiList = NULL; struct addrinfo *aiPtr = NULL; int retVal; memset(&aiHints, 0, sizeof(aiHints)); aiHints.ai_family = AF_INET; aiHints.ai_socktype = SOCK_STREAM; aiHints.ai_protocol = IPPROTO_TCP; if ((retVal = getaddrinfo(pAddress, NULL, &aiHints, &aiList))) return SockErrorNo(); for(aiPtr = aiList; aiPtr != NULL; aiPtr = aiPtr->ai_next) { if (aiPtr->ai_family == AF_INET) { memset(pSai, 0, sizeof(struct sockaddr_in)); memcpy(pSai, aiPtr->ai_addr, sizeof(struct sockaddr_in)); freeaddrinfo(aiList); return 0; // success } } freeaddrinfo(aiList); return SOCKET_ERROR; #endif } memset(pSai, 0, sizeof(struct sockaddr_in)); pSai->sin_addr.s_addr = *(u_long *)pHe->h_addr_list[0]; pSai->sin_family = AF_INET; return 0; // success } extern inline void SetSockAddr(struct sockaddr_in * pSai, const char * pIp, u_short nPort) { memset(pSai, 0, sizeof(struct sockaddr_in)); pSai->sin_addr.s_addr = inet_addr(pIp); pSai->sin_family = AF_INET; pSai->sin_port = htons(nPort); } ////////////////////////////////////////////////////////////////////////////// class HSocket : public HObject { public: enum { #ifdef _WIN32 ERR_TIMEOUT = WSAETIMEDOUT #else ERR_TIMEOUT = ETIMEDOUT #endif }; public: HSocket() { m_fdSocket = INVALID_SOCKET; } virtual ~HSocket() { if (m_fdSocket != INVALID_SOCKET) closesocket(m_fdSocket); } inline SOCKET GetSocket(); inline void SetSocket(SOCKET sock); inline SOCKET Create(int nDomain, int nType, int nProtocol = 0); inline int Close(); inline int Bind(u_short nPort); inline int Bind(struct sockaddr_in * psaiLocal); inline int Bind(const char * pAddress, u_short nPort); inline int Listen(int nBackLog); inline SOCKET Accept(HSocket & sockClient, char * pszPeerIp = NULL, u_short * pnPeerPort = NULL); inline int Connect(struct sockaddr_in * psaiRemote); inline int Connect(const char * pHostAddress, u_short nPort); inline int Send(const char * pData, int nLen, int nFlags = 0); inline int Receive(char * pBuf, int nLen, int nFlags = 0); inline int SendTo(const char * pData, int nLen, int flags, struct sockaddr_in * pSaiRemote); inline int ReceiveFrom(char * pBuf, int nLen, int nFlags = 0, struct sockaddr_in * pSaiRemote = NULL, socklen_t * pnSaiLen = NULL); inline int GetLocalAddress(struct sockaddr_in * psai); inline int GetLocalAddress(char * pBuf, u_short * pnPort); inline int GetPeerAddress(struct sockaddr_in * psai); inline int GetPeerAddress(char * pBuf, u_short * pnPort); inline int SetSockOpt(int nLevel, int nOptname, const char * pOptval, int nOptlen); inline int GetSockOpt(int nLevel, int nOptname, char * pOptval, int * pnOptlen); inline int GetSockOptError(); inline int SetNonBlockMode(bool bNonBlock); // inline bool TimoutConnect(struct sockaddr_in * psaiRemote, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError); inline bool TimoutConnect(const char * pHostAddress, u_short nPort, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError); inline bool WaitForSending(unsigned long nTimeout, int * pnError); // for non-block mode, *pnError = errno or WSAGetLastError() inline bool WaitForReceiving(unsigned long nTimeout, int * pnError); // for non-block mode, *pnError = errno or WSAGetLastError() protected: SOCKET m_fdSocket; }; inline SOCKET HSocket::GetSocket() { return m_fdSocket; } inline void HSocket::SetSocket(SOCKET sock) { m_fdSocket = sock; } inline SOCKET HSocket::Create(int nDomain, int nType, int nProtocol) { return (m_fdSocket = socket(nDomain, nType, nProtocol)); } inline int HSocket::Close() { int nResult = closesocket(m_fdSocket); m_fdSocket = INVALID_SOCKET; return nResult; } inline int HSocket::Bind(u_short nPort) { return Bind(NULL, nPort); } inline int HSocket::Bind(struct sockaddr_in * psaiLocal) { return bind(m_fdSocket, (struct sockaddr *)psaiLocal, sizeof(struct sockaddr)); } inline int HSocket::Bind(const char * pAddress, u_short nPort) { struct sockaddr_in sai; memset(&sai, 0, sizeof(struct sockaddr_in)); if (pAddress == NULL || pAddress[0] == '\0') sai.sin_addr.s_addr = htonl(INADDR_ANY); else sai.sin_addr.s_addr = inet_addr(pAddress); sai.sin_family = AF_INET; sai.sin_port = htons(nPort); return bind(m_fdSocket, (struct sockaddr *)&sai, sizeof(struct sockaddr)); } inline int HSocket::Listen(int nBackLog) { return listen(m_fdSocket, nBackLog); } inline SOCKET HSocket::Accept(HSocket & sockClient, char * pszPeerIp, u_short * pnPeerPort) { if (pszPeerIp != NULL || pnPeerPort != NULL) { struct sockaddr_in sai; socklen_t len = sizeof(struct sockaddr); SOCKET sock = (sockClient.m_fdSocket = accept(m_fdSocket, (struct sockaddr *)&sai, &len)); if (pszPeerIp != NULL) strcpy(pszPeerIp, inet_ntoa(sai.sin_addr)); if (pnPeerPort != NULL) *pnPeerPort = ntohs(sai.sin_port); return sock; } return (sockClient.m_fdSocket = accept(m_fdSocket, NULL, NULL)); } inline int HSocket::Connect(struct sockaddr_in * psaiRemote) { return connect(m_fdSocket, (struct sockaddr *)psaiRemote, sizeof(struct sockaddr)); } inline int HSocket::Connect(const char * pHostAddress, u_short nPort) { struct sockaddr_in sai; memset(&sai, 0, sizeof(struct sockaddr_in)); sai.sin_addr.s_addr = inet_addr(pHostAddress); sai.sin_family = AF_INET; sai.sin_port = htons(nPort); return connect(m_fdSocket, (struct sockaddr *)&sai, sizeof(struct sockaddr)); } inline int HSocket::Send(const char * pData, int nLen, int nFlags) { return send(m_fdSocket, pData, nLen, nFlags); } inline int HSocket::Receive(char * pBuf, int nLen, int nFlags) { return recv(m_fdSocket, pBuf, nLen, nFlags); } inline int HSocket::SendTo(const char * pData, int nLen, int flags, struct sockaddr_in * pSaiRemote) { return sendto(m_fdSocket, pData, nLen, flags, (struct sockaddr *)pSaiRemote, sizeof(struct sockaddr)); } inline int HSocket::ReceiveFrom(char * pBuf, int nLen, int nFlags, struct sockaddr_in * pSaiRemote, socklen_t * pnSaiLen) { return recvfrom(m_fdSocket, pBuf, nLen, nFlags, (struct sockaddr *)pSaiRemote, pnSaiLen); } inline int HSocket::GetLocalAddress(struct sockaddr_in * psai) { socklen_t len = sizeof(struct sockaddr); return getsockname(m_fdSocket, (struct sockaddr *)psai, &len); } inline int HSocket::GetLocalAddress(char * pBuf, u_short * pnPort) { struct sockaddr_in sai; socklen_t len = sizeof(struct sockaddr); if (getsockname(m_fdSocket, (struct sockaddr *)&sai, &len) < 0) return SockErrorNo(); if (pBuf) strcpy(pBuf, inet_ntoa(sai.sin_addr)); if (pnPort) *pnPort = ntohs(sai.sin_port); return 0; } inline int HSocket::GetPeerAddress(struct sockaddr_in * psai) { socklen_t len = sizeof(struct sockaddr); return getpeername(m_fdSocket, (struct sockaddr *)psai, &len); } inline int HSocket::GetPeerAddress(char * pBuf, u_short * pnPort) { struct sockaddr_in sai; socklen_t len = sizeof(struct sockaddr); if (getpeername(m_fdSocket, (struct sockaddr *)&sai, &len) < 0) return SockErrorNo(); if (pBuf) strcpy(pBuf, inet_ntoa(sai.sin_addr)); if (pnPort) *pnPort = ntohs(sai.sin_port); return 0; } inline int HSocket::SetSockOpt(int nLevel, int nOptname, const char * pOptval, int nOptlen) { return setsockopt(m_fdSocket, nLevel, nOptname, pOptval, nOptlen); } inline int HSocket::GetSockOpt(int nLevel, int nOptname, char * pOptval, int * pnOptlen) { return getsockopt(m_fdSocket, nLevel, nOptname, pOptval, (socklen_t *)pnOptlen); } inline int HSocket::GetSockOptError() { int nOptVal; int nOptLen = sizeof(int); if (getsockopt(m_fdSocket, SOL_SOCKET, SO_ERROR, (char *)(&nOptVal), (socklen_t *)&nOptLen) < 0) return SockErrorNo(); return nOptVal; } inline int HSocket::SetNonBlockMode(bool bNonBlock) { #ifdef _WIN32 ULONG nFlags = bNonBlock; return ioctlsocket(m_fdSocket, FIONBIO, &nFlags); #else int nFlags = fcntl(m_fdSocket, F_GETFL, 0); return fcntl(m_fdSocket, F_SETFL, (bNonBlock ? nFlags | O_NONBLOCK : nFlags & ~O_NONBLOCK)); #endif } inline bool HSocket::TimoutConnect(struct sockaddr_in * psaiRemote, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError) { #ifdef _WIN32 ULONG nFlags = 1; if (ioctlsocket(m_fdSocket, FIONBIO, &nFlags) < 0) #else int nFlags = fcntl(m_fdSocket, F_GETFL, 0); if (fcntl(m_fdSocket, F_SETFL, nFlags | O_NONBLOCK) < 0) #endif { *pnError = SockErrorNo(); return false; } socklen_t len = sizeof(struct sockaddr); int nResult; if ((nResult = connect(m_fdSocket, (struct sockaddr *)psaiRemote, len)) < 0) { *pnError = SockErrorNo(); #ifdef _WIN32 if (*pnError != WSAEINPROGRESS && *pnError != WSAEWOULDBLOCK) #else if (*pnError != EINPROGRESS) #endif return false; } fd_set fsRead, fsWrite; struct timeval tv; FD_ZERO(&fsRead); FD_SET(m_fdSocket, &fsRead); fsWrite = fsRead; tv.tv_sec = nTimeout / 1000; tv.tv_usec = (nTimeout % 1000) * 1000; if ((nResult = select((int)(m_fdSocket + 1), &fsRead, &fsWrite, NULL, &tv)) == 0) { *pnError = ERR_TIMEOUT; return false; } if (FD_ISSET(m_fdSocket, &fsRead) || FD_ISSET(m_fdSocket, &fsWrite)) { len = sizeof(nResult); if (getsockopt(m_fdSocket, SOL_SOCKET, SO_ERROR, (char *)&nResult, &len) < 0) { *pnError = SOCKET_ERROR; return false; // Solaris pending error } } else { *pnError = SOCKET_ERROR; // select error: m_fdSocket not set return false; } if (bRestoreSyncMode) { #ifdef _WIN32 nFlags = 0; if (ioctlsocket(m_fdSocket, FIONBIO, &nFlags) < 0) #else if (fcntl(m_fdSocket, F_SETFL, nFlags) < 0) #endif { *pnError = SockErrorNo(); return false; } } *pnError = 0; return true; } inline bool HSocket::TimoutConnect(const char * pHostAddress, u_short nPort, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError) { struct sockaddr_in sai; memset(&sai, 0, sizeof(struct sockaddr_in)); sai.sin_addr.s_addr = inet_addr(pHostAddress); sai.sin_family = AF_INET; sai.sin_port = htons(nPort); return TimoutConnect(&sai, nTimeout, bRestoreSyncMode, pnError); } inline bool HSocket::WaitForSending(unsigned long nTimeout, int * pnError) { fd_set fsWrite; struct timeval tv; FD_ZERO(&fsWrite); FD_SET(m_fdSocket, &fsWrite); tv.tv_sec = nTimeout / 1000; tv.tv_usec = (nTimeout % 1000) * 1000; int nResult = select((int)m_fdSocket + 1, NULL, &fsWrite, NULL, nTimeout ? &tv : NULL); if (nResult < 0) { *pnError = SockErrorNo(); return false; } if (nResult == 0 || FD_ISSET(m_fdSocket, &fsWrite) == 0) { *pnError = ERR_TIMEOUT; return false; } *pnError = 0; return true; } inline bool HSocket::WaitForReceiving(unsigned long nTimeout, int * pnError) { fd_set fsRead; struct timeval tv; FD_ZERO(&fsRead); FD_SET(m_fdSocket, &fsRead); tv.tv_sec = nTimeout / 1000; tv.tv_usec = (nTimeout % 1000) * 1000; int nResult = select((int)m_fdSocket + 1, &fsRead, NULL, NULL, nTimeout ? &tv : NULL); if (nResult < 0) { *pnError = SockErrorNo(); return false; } if (nResult == 0 || FD_ISSET(m_fdSocket, &fsRead) == 0) { *pnError = ERR_TIMEOUT; return false; } *pnError = 0; return true; } ////////////////////////////////////////////////////////////////////////////// extern inline int TcpCompleteSend(SOCKET sock, const char * pszPacket, int nPacketSize) { int nSentSize; const char * pszPacketOffset = pszPacket; while (nPacketSize > 0) { nSentSize = send(sock, pszPacketOffset, nPacketSize, 0); if (nSentSize <= 0) { //HLOG(HLOG_ERROR, "[ERROR], EmailSender, Failed to send.\n"); return -1; } nPacketSize -= nSentSize; pszPacketOffset += nSentSize; } return 1; } #endif // SOCKET__H_