📄 socketft.cpp
字号:
// socketft.cpp - written and placed in the public domain by Wei Dai#include "pch.h"#include "socketft.h"#ifdef SOCKETS_AVAILABLE#include "wait.h"#ifdef USE_BERKELEY_STYLE_SOCKETS#include <errno.h>#include <netdb.h>#include <unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/ioctl.h>#endifNAMESPACE_BEGIN(CryptoPP)#ifdef USE_WINDOWS_STYLE_SOCKETSconst int SOCKET_EINVAL = WSAEINVAL;const int SOCKET_EWOULDBLOCK = WSAEWOULDBLOCK;typedef int socklen_t;#elseconst int SOCKET_EINVAL = EINVAL;const int SOCKET_EWOULDBLOCK = EWOULDBLOCK;#endifSocket::Err::Err(socket_t s, const std::string& operation, int error) : OS_Error(IO_ERROR, "Socket: " + operation + " operation failed with error " + IntToString(error), operation, error) , m_s(s){}Socket::~Socket(){ if (m_own) { try { CloseSocket(); } catch (...) { } }}void Socket::AttachSocket(socket_t s, bool own){ if (m_own) CloseSocket(); m_s = s; m_own = own; SocketChanged();}socket_t Socket::DetachSocket(){ socket_t s = m_s; m_s = INVALID_SOCKET; SocketChanged(); return s;}void Socket::Create(int nType){ assert(m_s == INVALID_SOCKET); m_s = socket(AF_INET, nType, 0); CheckAndHandleError("socket", m_s); m_own = true; SocketChanged();}void Socket::CloseSocket(){ if (m_s != INVALID_SOCKET) {#ifdef USE_WINDOWS_STYLE_SOCKETS CancelIo((HANDLE) m_s); CheckAndHandleError_int("closesocket", closesocket(m_s));#else CheckAndHandleError_int("close", close(m_s));#endif m_s = INVALID_SOCKET; SocketChanged(); }}void Socket::Bind(unsigned int port, const char *addr){ sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; if (addr == NULL) sa.sin_addr.s_addr = htonl(INADDR_ANY); else { unsigned long result = inet_addr(addr); if (result == -1) // Solaris doesn't have INADDR_NONE { SetLastError(SOCKET_EINVAL); CheckAndHandleError_int("inet_addr", SOCKET_ERROR); } sa.sin_addr.s_addr = result; } sa.sin_port = htons((u_short)port); Bind((sockaddr *)&sa, sizeof(sa));}void Socket::Bind(const sockaddr *psa, socklen_t saLen){ assert(m_s != INVALID_SOCKET); // cygwin workaround: needs const_cast CheckAndHandleError_int("bind", bind(m_s, const_cast<sockaddr *>(psa), saLen));}void Socket::Listen(int backlog){ assert(m_s != INVALID_SOCKET); CheckAndHandleError_int("listen", listen(m_s, backlog));}bool Socket::Connect(const char *addr, unsigned int port){ assert(addr != NULL); sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(addr); if (sa.sin_addr.s_addr == -1) // Solaris doesn't have INADDR_NONE { hostent *lphost = gethostbyname(addr); if (lphost == NULL) { SetLastError(SOCKET_EINVAL); CheckAndHandleError_int("gethostbyname", SOCKET_ERROR); } sa.sin_addr.s_addr = ((in_addr *)lphost->h_addr)->s_addr; } sa.sin_port = htons((u_short)port); return Connect((const sockaddr *)&sa, sizeof(sa));}bool Socket::Connect(const sockaddr* psa, socklen_t saLen){ assert(m_s != INVALID_SOCKET); int result = connect(m_s, const_cast<sockaddr*>(psa), saLen); if (result == SOCKET_ERROR && GetLastError() == SOCKET_EWOULDBLOCK) return false; CheckAndHandleError_int("connect", result); return true;}bool Socket::Accept(Socket& target, sockaddr *psa, socklen_t *psaLen){ assert(m_s != INVALID_SOCKET); socket_t s = accept(m_s, psa, psaLen); if (s == INVALID_SOCKET && GetLastError() == SOCKET_EWOULDBLOCK) return false; CheckAndHandleError("accept", s); target.AttachSocket(s, true); return true;}void Socket::GetSockName(sockaddr *psa, socklen_t *psaLen){ assert(m_s != INVALID_SOCKET); CheckAndHandleError_int("getsockname", getsockname(m_s, psa, psaLen));}void Socket::GetPeerName(sockaddr *psa, socklen_t *psaLen){ assert(m_s != INVALID_SOCKET); CheckAndHandleError_int("getpeername", getpeername(m_s, psa, psaLen));}unsigned int Socket::Send(const byte* buf, size_t bufLen, int flags){ assert(m_s != INVALID_SOCKET); int result = send(m_s, (const char *)buf, UnsignedMin(INT_MAX, bufLen), flags); CheckAndHandleError_int("send", result); return result;}unsigned int Socket::Receive(byte* buf, size_t bufLen, int flags){ assert(m_s != INVALID_SOCKET); int result = recv(m_s, (char *)buf, UnsignedMin(INT_MAX, bufLen), flags); CheckAndHandleError_int("recv", result); return result;}void Socket::ShutDown(int how){ assert(m_s != INVALID_SOCKET); int result = shutdown(m_s, how); CheckAndHandleError_int("shutdown", result);}void Socket::IOCtl(long cmd, unsigned long *argp){ assert(m_s != INVALID_SOCKET);#ifdef USE_WINDOWS_STYLE_SOCKETS CheckAndHandleError_int("ioctlsocket", ioctlsocket(m_s, cmd, argp));#else CheckAndHandleError_int("ioctl", ioctl(m_s, cmd, argp));#endif}bool Socket::SendReady(const timeval *timeout){ fd_set fds; FD_ZERO(&fds); FD_SET(m_s, &fds); int ready; if (timeout == NULL) ready = select((int)m_s+1, NULL, &fds, NULL, NULL); else { timeval timeoutCopy = *timeout; // select() modified timeout on Linux ready = select((int)m_s+1, NULL, &fds, NULL, &timeoutCopy); } CheckAndHandleError_int("select", ready); return ready > 0;}bool Socket::ReceiveReady(const timeval *timeout){ fd_set fds; FD_ZERO(&fds); FD_SET(m_s, &fds); int ready; if (timeout == NULL) ready = select((int)m_s+1, &fds, NULL, NULL, NULL); else { timeval timeoutCopy = *timeout; // select() modified timeout on Linux ready = select((int)m_s+1, &fds, NULL, NULL, &timeoutCopy); } CheckAndHandleError_int("select", ready); return ready > 0;}unsigned int Socket::PortNameToNumber(const char *name, const char *protocol){ int port = atoi(name); if (IntToString(port) == name) return port; servent *se = getservbyname(name, protocol); if (!se) throw Err(INVALID_SOCKET, "getservbyname", SOCKET_EINVAL); return ntohs(se->s_port);}void Socket::StartSockets(){#ifdef USE_WINDOWS_STYLE_SOCKETS WSADATA wsd; int result = WSAStartup(0x0202, &wsd); if (result != 0) throw Err(INVALID_SOCKET, "WSAStartup", result);#endif}void Socket::ShutdownSockets(){#ifdef USE_WINDOWS_STYLE_SOCKETS int result = WSACleanup(); if (result != 0) throw Err(INVALID_SOCKET, "WSACleanup", result);#endif}int Socket::GetLastError(){#ifdef USE_WINDOWS_STYLE_SOCKETS return WSAGetLastError();#else return errno;#endif}void Socket::SetLastError(int errorCode){#ifdef USE_WINDOWS_STYLE_SOCKETS WSASetLastError(errorCode);#else errno = errorCode;#endif}void Socket::HandleError(const char *operation) const{ int err = GetLastError(); throw Err(m_s, operation, err);}#ifdef USE_WINDOWS_STYLE_SOCKETSSocketReceiver::SocketReceiver(Socket &s) : m_s(s), m_resultPending(false), m_eofReceived(false){ m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); m_s.CheckAndHandleError("CreateEvent", m_event.HandleValid()); memset(&m_overlapped, 0, sizeof(m_overlapped)); m_overlapped.hEvent = m_event;}SocketReceiver::~SocketReceiver(){#ifdef USE_WINDOWS_STYLE_SOCKETS CancelIo((HANDLE) m_s.GetSocket());#endif}bool SocketReceiver::Receive(byte* buf, size_t bufLen){ assert(!m_resultPending && !m_eofReceived); DWORD flags = 0; // don't queue too much at once, or we might use up non-paged memory WSABUF wsabuf = {UnsignedMin((u_long)128*1024, bufLen), (char *)buf}; if (WSARecv(m_s, &wsabuf, 1, &m_lastResult, &flags, &m_overlapped, NULL) == 0) { if (m_lastResult == 0) m_eofReceived = true; } else { switch (WSAGetLastError()) { default: m_s.CheckAndHandleError_int("WSARecv", SOCKET_ERROR); case WSAEDISCON: m_lastResult = 0; m_eofReceived = true; break; case WSA_IO_PENDING: m_resultPending = true; } } return !m_resultPending;}void SocketReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack){ if (m_resultPending) container.AddHandle(m_event, CallStack("SocketReceiver::GetWaitObjects() - result pending", &callStack)); else if (!m_eofReceived) container.SetNoWait(CallStack("SocketReceiver::GetWaitObjects() - result ready", &callStack));}unsigned int SocketReceiver::GetReceiveResult(){ if (m_resultPending) { DWORD flags = 0; if (WSAGetOverlappedResult(m_s, &m_overlapped, &m_lastResult, false, &flags)) { if (m_lastResult == 0) m_eofReceived = true; } else { switch (WSAGetLastError()) { default: m_s.CheckAndHandleError("WSAGetOverlappedResult", FALSE); case WSAEDISCON: m_lastResult = 0; m_eofReceived = true; } } m_resultPending = false; } return m_lastResult;}// *************************************************************SocketSender::SocketSender(Socket &s) : m_s(s), m_resultPending(false), m_lastResult(0){ m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true); m_s.CheckAndHandleError("CreateEvent", m_event.HandleValid()); memset(&m_overlapped, 0, sizeof(m_overlapped)); m_overlapped.hEvent = m_event;}SocketSender::~SocketSender(){#ifdef USE_WINDOWS_STYLE_SOCKETS CancelIo((HANDLE) m_s.GetSocket());#endif}void SocketSender::Send(const byte* buf, size_t bufLen){ assert(!m_resultPending); DWORD written = 0; // don't queue too much at once, or we might use up non-paged memory WSABUF wsabuf = {UnsignedMin((u_long)128*1024, bufLen), (char *)buf}; if (WSASend(m_s, &wsabuf, 1, &written, 0, &m_overlapped, NULL) == 0) { m_resultPending = false; m_lastResult = written; } else { if (WSAGetLastError() != WSA_IO_PENDING) m_s.CheckAndHandleError_int("WSASend", SOCKET_ERROR); m_resultPending = true; }}void SocketSender::SendEof(){ assert(!m_resultPending); m_s.ShutDown(SD_SEND); m_s.CheckAndHandleError("ResetEvent", ResetEvent(m_event)); m_s.CheckAndHandleError_int("WSAEventSelect", WSAEventSelect(m_s, m_event, FD_CLOSE)); m_resultPending = true;}bool SocketSender::EofSent(){ if (m_resultPending) { WSANETWORKEVENTS events; m_s.CheckAndHandleError_int("WSAEnumNetworkEvents", WSAEnumNetworkEvents(m_s, m_event, &events)); if ((events.lNetworkEvents & FD_CLOSE) != FD_CLOSE) throw Socket::Err(m_s, "WSAEnumNetworkEvents (FD_CLOSE not present)", E_FAIL); if (events.iErrorCode[FD_CLOSE_BIT] != 0) throw Socket::Err(m_s, "FD_CLOSE (via WSAEnumNetworkEvents)", events.iErrorCode[FD_CLOSE_BIT]); m_resultPending = false; } return m_lastResult != 0;}void SocketSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack){ if (m_resultPending) container.AddHandle(m_event, CallStack("SocketSender::GetWaitObjects() - result pending", &callStack)); else container.SetNoWait(CallStack("SocketSender::GetWaitObjects() - result ready", &callStack));}unsigned int SocketSender::GetSendResult(){ if (m_resultPending) { DWORD flags = 0; BOOL result = WSAGetOverlappedResult(m_s, &m_overlapped, &m_lastResult, false, &flags); m_s.CheckAndHandleError("WSAGetOverlappedResult", result); m_resultPending = false; } return m_lastResult;}#endif#ifdef USE_BERKELEY_STYLE_SOCKETSSocketReceiver::SocketReceiver(Socket &s) : m_s(s), m_lastResult(0), m_eofReceived(false){}void SocketReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack){ if (!m_eofReceived) container.AddReadFd(m_s, CallStack("SocketReceiver::GetWaitObjects()", &callStack));}bool SocketReceiver::Receive(byte* buf, size_t bufLen){ m_lastResult = m_s.Receive(buf, bufLen); if (bufLen > 0 && m_lastResult == 0) m_eofReceived = true; return true;}unsigned int SocketReceiver::GetReceiveResult(){ return m_lastResult;}SocketSender::SocketSender(Socket &s) : m_s(s), m_lastResult(0){}void SocketSender::Send(const byte* buf, size_t bufLen){ m_lastResult = m_s.Send(buf, bufLen);}void SocketSender::SendEof(){ m_s.ShutDown(SD_SEND);}unsigned int SocketSender::GetSendResult(){ return m_lastResult;}void SocketSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack){ container.AddWriteFd(m_s, CallStack("SocketSender::GetWaitObjects()", &callStack));}#endifNAMESPACE_END#endif // #ifdef SOCKETS_AVAILABLE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -