- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# socketft.cpp

    00001 // socketft.cpp - written and placed in the public domain by Wei Dai
    00002
    00003 #include "pch.h"
    00004 #include "socketft.h"
    00005
    00006 #ifdef SOCKETS_AVAILABLE
    00007
    00008 #include "wait.h"
    00009
    00010 #ifdef USE_BERKELEY_STYLE_SOCKETS
    00011 #include <errno.h>
    00012 #include <netdb.h>
    00013 #include <unistd.h>
    00014 #include <arpa/inet.h>
    00015 #include <netinet/in.h>
    00016 #include <sys/ioctl.h>
    00017 #endif
    00018
    00019 NAMESPACE_BEGIN(CryptoPP)
    00020
    00021 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00022 const int SOCKET_EINVAL = WSAEINVAL;
    00023 const int SOCKET_EWOULDBLOCK = WSAEWOULDBLOCK;
    00024 typedef int socklen_t;
    00025 #else
    00026 const int SOCKET_EINVAL = EINVAL;
    00027 const int SOCKET_EWOULDBLOCK = EWOULDBLOCK;
    00028 #endif
    00029
    00030 Socket::Err::Err(socket_t s, const std::string& operation, int error)
    00031         : OS_Error(IO_ERROR, "Socket: " + operation + " operation failed with error " + IntToString(error), operation, error)
    00032         , m_s(s)
    00033 {
    00034 }
    00035
    00036 Socket::~Socket()
    00037 {
    00038         if (m_own)
    00039         {
    00040                 try
    00041                 {
    00042                         CloseSocket();
    00043                 }
    00044                 catch (...)
    00045                 {
    00046                 }
    00047         }
    00048 }
    00049
    00050 void Socket::AttachSocket(socket_t s, bool own)
    00051 {
    00052         if (m_own)
    00053                 CloseSocket();
    00054
    00055         m_s = s;
    00056         m_own = own;
    00057         SocketChanged();
    00058 }
    00059
    00060 socket_t Socket::DetachSocket()
    00061 {
    00062         socket_t s = m_s;
    00063         m_s = INVALID_SOCKET;
    00064         SocketChanged();
    00065         return s;
    00066 }
    00067
    00068 void Socket::Create(int nType)
    00069 {
    00070         assert(m_s == INVALID_SOCKET);
    00071         m_s = socket(AF_INET, nType, 0);
    00072         CheckAndHandleError("socket", m_s);
    00073         m_own = true;
    00074         SocketChanged();
    00075 }
    00076
    00077 void Socket::CloseSocket()
    00078 {
    00079         if (m_s != INVALID_SOCKET)
    00080         {
    00081 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00082                 CancelIo((HANDLE) m_s);
    00083                 CheckAndHandleError_int("closesocket", closesocket(m_s));
    00084 #else
    00085                 CheckAndHandleError_int("close", close(m_s));
    00086 #endif
    00087                 m_s = INVALID_SOCKET;
    00088                 SocketChanged();
    00089         }
    00090 }
    00091
    00092 void Socket::Bind(unsigned int port, const char *addr)
    00093 {
    00094         sockaddr_in sa;
    00095         memset(&sa, 0, sizeof(sa));
    00096         sa.sin_family = AF_INET;
    00097
    00098         if (addr == NULL)
    00099                 sa.sin_addr.s_addr = htonl(INADDR_ANY);
    00100         else
    00101         {
    00102                 unsigned long result = inet_addr(addr);
    00103                 if (result == -1)       // Solaris doesn't have INADDR_NONE
    00104                 {
    00105                         SetLastError(SOCKET_EINVAL);
    00106                         CheckAndHandleError_int("inet_addr", SOCKET_ERROR);
    00107                 }
    00108                 sa.sin_addr.s_addr = result;
    00109         }
    00110
    00111         sa.sin_port = htons((u_short)port);
    00112
    00113         Bind((sockaddr *)&sa, sizeof(sa));
    00114 }
    00115
    00116 void Socket::Bind(const sockaddr *psa, socklen_t saLen)
    00117 {
    00118         assert(m_s != INVALID_SOCKET);
    00119         // cygwin workaround: needs const_cast
    00120         CheckAndHandleError_int("bind", bind(m_s, const_cast<sockaddr *>(psa), saLen));
    00121 }
    00122
    00123 void Socket::Listen(int backlog)
    00124 {
    00125         assert(m_s != INVALID_SOCKET);
    00126         CheckAndHandleError_int("listen", listen(m_s, backlog));
    00127 }
    00128
    00129 bool Socket::Connect(const char *addr, unsigned int port)
    00130 {
    00131         assert(addr != NULL);
    00132
    00133         sockaddr_in sa;
    00134         memset(&sa, 0, sizeof(sa));
    00135         sa.sin_family = AF_INET;
    00136         sa.sin_addr.s_addr = inet_addr(addr);
    00137
    00138         if (sa.sin_addr.s_addr == -1)   // Solaris doesn't have INADDR_NONE
    00139         {
    00140                 hostent *lphost = gethostbyname(addr);
    00141                 if (lphost == NULL)
    00142                 {
    00143                         SetLastError(SOCKET_EINVAL);
    00144                         CheckAndHandleError_int("gethostbyname", SOCKET_ERROR);
    00145                 }
    00146
    00147                 sa.sin_addr.s_addr = ((in_addr *)lphost->h_addr)->s_addr;
    00148         }
    00149
    00150         sa.sin_port = htons((u_short)port);
    00151
    00152         return Connect((const sockaddr *)&sa, sizeof(sa));
    00153 }
    00154
    00155 bool Socket::Connect(const sockaddr* psa, socklen_t saLen)
    00156 {
    00157         assert(m_s != INVALID_SOCKET);
    00158         int result = connect(m_s, const_cast<sockaddr*>(psa), saLen);
    00159         if (result == SOCKET_ERROR && GetLastError() == SOCKET_EWOULDBLOCK)
    00160                 return false;
    00161         CheckAndHandleError_int("connect", result);
    00162         return true;
    00163 }
    00164
    00165 bool Socket::Accept(Socket& target, sockaddr *psa, socklen_t *psaLen)
    00166 {
    00167         assert(m_s != INVALID_SOCKET);
    00168         socket_t s = accept(m_s, psa, psaLen);
    00169         if (s == INVALID_SOCKET && GetLastError() == SOCKET_EWOULDBLOCK)
    00170                 return false;
    00171         CheckAndHandleError("accept", s);
    00172         target.AttachSocket(s, true);
    00173         return true;
    00174 }
    00175
    00176 void Socket::GetSockName(sockaddr *psa, socklen_t *psaLen)
    00177 {
    00178         assert(m_s != INVALID_SOCKET);
    00179         CheckAndHandleError_int("getsockname", getsockname(m_s, psa, psaLen));
    00180 }
    00181
    00182 void Socket::GetPeerName(sockaddr *psa, socklen_t *psaLen)
    00183 {
    00184         assert(m_s != INVALID_SOCKET);
    00185         CheckAndHandleError_int("getpeername", getpeername(m_s, psa, psaLen));
    00186 }
    00187
    00188 unsigned int Socket::Send(const byte* buf, size_t bufLen, int flags)
    00189 {
    00190         assert(m_s != INVALID_SOCKET);
    00191         int result = send(m_s, (const char *)buf, UnsignedMin(INT_MAX, bufLen), flags);
    00192         CheckAndHandleError_int("send", result);
    00193         return result;
    00194 }
    00195
    00196 unsigned int Socket::Receive(byte* buf, size_t bufLen, int flags)
    00197 {
    00198         assert(m_s != INVALID_SOCKET);
    00199         int result = recv(m_s, (char *)buf, UnsignedMin(INT_MAX, bufLen), flags);
    00200         CheckAndHandleError_int("recv", result);
    00201         return result;
    00202 }
    00203
    00204 void Socket::ShutDown(int how)
    00205 {
    00206         assert(m_s != INVALID_SOCKET);
    00207         int result = shutdown(m_s, how);
    00208         CheckAndHandleError_int("shutdown", result);
    00209 }
    00210
    00211 void Socket::IOCtl(long cmd, unsigned long *argp)
    00212 {
    00213         assert(m_s != INVALID_SOCKET);
    00214 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00215         CheckAndHandleError_int("ioctlsocket", ioctlsocket(m_s, cmd, argp));
    00216 #else
    00217         CheckAndHandleError_int("ioctl", ioctl(m_s, cmd, argp));
    00218 #endif
    00219 }
    00220
    00221 bool Socket::SendReady(const timeval *timeout)
    00222 {
    00223         fd_set fds;
    00224         FD_ZERO(&fds);
    00225         FD_SET(m_s, &fds);
    00226         int ready;
    00227         if (timeout == NULL)
    00228                 ready = select((int)m_s+1, NULL, &fds, NULL, NULL);
    00229         else
    00230         {
    00231                 timeval timeoutCopy = *timeout; // select() modified timeout on Linux
    00232                 ready = select((int)m_s+1, NULL, &fds, NULL, &timeoutCopy);
    00233         }
    00234         CheckAndHandleError_int("select", ready);
    00235         return ready > 0;
    00236 }
    00237
    00238 bool Socket::ReceiveReady(const timeval *timeout)
    00239 {
    00240         fd_set fds;
    00241         FD_ZERO(&fds);
    00242         FD_SET(m_s, &fds);
    00243         int ready;
    00244         if (timeout == NULL)
    00245                 ready = select((int)m_s+1, &fds, NULL, NULL, NULL);
    00246         else
    00247         {
    00248                 timeval timeoutCopy = *timeout; // select() modified timeout on Linux
    00249                 ready = select((int)m_s+1, &fds, NULL, NULL, &timeoutCopy);
    00250         }
    00251         CheckAndHandleError_int("select", ready);
    00252         return ready > 0;
    00253 }
    00254
    00255 unsigned int Socket::PortNameToNumber(const char *name, const char *protocol)
    00256 {
    00257         int port = atoi(name);
    00258         if (IntToString(port) == name)
    00259                 return port;
    00260
    00261         servent *se = getservbyname(name, protocol);
    00262         if (!se)
    00263                 throw Err(INVALID_SOCKET, "getservbyname", SOCKET_EINVAL);
    00264         return ntohs(se->s_port);
    00265 }
    00266
    00267 void Socket::StartSockets()
    00268 {
    00269 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00270         WSADATA wsd;
    00271         int result = WSAStartup(0x0202, &wsd);
    00272         if (result != 0)
    00273                 throw Err(INVALID_SOCKET, "WSAStartup", result);
    00274 #endif
    00275 }
    00276
    00277 void Socket::ShutdownSockets()
    00278 {
    00279 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00280         int result = WSACleanup();
    00281         if (result != 0)
    00282                 throw Err(INVALID_SOCKET, "WSACleanup", result);
    00283 #endif
    00284 }
    00285
    00286 int Socket::GetLastError()
    00287 {
    00288 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00289         return WSAGetLastError();
    00290 #else
    00291         return errno;
    00292 #endif
    00293 }
    00294
    00295 void Socket::SetLastError(int errorCode)
    00296 {
    00297 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00298         WSASetLastError(errorCode);
    00299 #else
    00300         errno = errorCode;
    00301 #endif
    00302 }
    00303
    00304 void Socket::HandleError(const char *operation) const
    00305 {
    00306         int err = GetLastError();
    00307         throw Err(m_s, operation, err);
    00308 }
    00309
    00310 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00311
    00312 SocketReceiver::SocketReceiver(Socket &s)
    00313         : m_s(s), m_resultPending(false), m_eofReceived(false)
    00314 {
    00315         m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
    00316         m_s.CheckAndHandleError("CreateEvent", m_event.HandleValid());
    00317         memset(&m_overlapped, 0, sizeof(m_overlapped));
    00318         m_overlapped.hEvent = m_event;
    00319 }
    00320
    00321 SocketReceiver::~SocketReceiver()
    00322 {
    00323 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00324         CancelIo((HANDLE) m_s.GetSocket());
    00325 #endif
    00326 }
    00327
    00328 bool SocketReceiver::Receive(byte* buf, size_t bufLen)
    00329 {
    00330         assert(!m_resultPending && !m_eofReceived);
    00331
    00332         DWORD flags = 0;
    00333         // don't queue too much at once, or we might use up non-paged memory
    00334         WSABUF wsabuf = {UnsignedMin((u_long)128*1024, bufLen), (char *)buf};
    00335         if (WSARecv(m_s, &wsabuf, 1, &m_lastResult, &flags, &m_overlapped, NULL) == 0)
    00336         {
    00337                 if (m_lastResult == 0)
    00338                         m_eofReceived = true;
    00339         }
    00340         else
    00341         {
    00342                 switch (WSAGetLastError())
    00343                 {
    00344                 default:
    00345                         m_s.CheckAndHandleError_int("WSARecv", SOCKET_ERROR);
    00346                 case WSAEDISCON:
    00347                         m_lastResult = 0;
    00348                         m_eofReceived = true;
    00349                         break;
    00350                 case WSA_IO_PENDING:
    00351                         m_resultPending = true;
    00352                 }
    00353         }
    00354         return !m_resultPending;
    00355 }
    00356
    00357 void SocketReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
    00358 {
    00359         if (m_resultPending)
    00360                 container.AddHandle(m_event, CallStack("SocketReceiver::GetWaitObjects() - result pending", &callStack));
    00361         else if (!m_eofReceived)
    00362                 container.SetNoWait(CallStack("SocketReceiver::GetWaitObjects() - result ready", &callStack));
    00363 }
    00364
    00365 unsigned int SocketReceiver::GetReceiveResult()
    00366 {
    00367         if (m_resultPending)
    00368         {
    00369                 DWORD flags = 0;
    00370                 if (WSAGetOverlappedResult(m_s, &m_overlapped, &m_lastResult, false, &flags))
    00371                 {
    00372                         if (m_lastResult == 0)
    00373                                 m_eofReceived = true;
    00374                 }
    00375                 else
    00376                 {
    00377                         switch (WSAGetLastError())
    00378                         {
    00379                         default:
    00380                                 m_s.CheckAndHandleError("WSAGetOverlappedResult", FALSE);
    00381                         case WSAEDISCON:
    00382                                 m_lastResult = 0;
    00383                                 m_eofReceived = true;
    00384                         }
    00385                 }
    00386                 m_resultPending = false;
    00387         }
    00388         return m_lastResult;
    00389 }
    00390
    00391 // *************************************************************
    00392
    00393 SocketSender::SocketSender(Socket &s)
    00394         : m_s(s), m_resultPending(false), m_lastResult(0)
    00395 {
    00396         m_event.AttachHandle(CreateEvent(NULL, true, false, NULL), true);
    00397         m_s.CheckAndHandleError("CreateEvent", m_event.HandleValid());
    00398         memset(&m_overlapped, 0, sizeof(m_overlapped));
    00399         m_overlapped.hEvent = m_event;
    00400 }
    00401
    00402
    00403 SocketSender::~SocketSender()
    00404 {
    00405 #ifdef USE_WINDOWS_STYLE_SOCKETS
    00406         CancelIo((HANDLE) m_s.GetSocket());
    00407 #endif
    00408 }
    00409
    00410 void SocketSender::Send(const byte* buf, size_t bufLen)
    00411 {
    00412         assert(!m_resultPending);
    00413         DWORD written = 0;
    00414         // don't queue too much at once, or we might use up non-paged memory
    00415         WSABUF wsabuf = {UnsignedMin((u_long)128*1024, bufLen), (char *)buf};
    00416         if (WSASend(m_s, &wsabuf, 1, &written, 0, &m_overlapped, NULL) == 0)
    00417         {
    00418                 m_resultPending = false;
    00419                 m_lastResult = written;
    00420         }
    00421         else
    00422         {
    00423                 if (WSAGetLastError() != WSA_IO_PENDING)
    00424                         m_s.CheckAndHandleError_int("WSASend", SOCKET_ERROR);
    00425
    00426                 m_resultPending = true;
    00427         }
    00428 }
    00429
    00430 void SocketSender::SendEof()
    00431 {
    00432         assert(!m_resultPending);
    00433         m_s.ShutDown(SD_SEND);
    00434         m_s.CheckAndHandleError("ResetEvent", ResetEvent(m_event));
    00435         m_s.CheckAndHandleError_int("WSAEventSelect", WSAEventSelect(m_s, m_event, FD_CLOSE));
    00436         m_resultPending = true;
    00437 }
    00438
    00439 bool SocketSender::EofSent()
    00440 {
    00441         if (m_resultPending)
    00442         {
    00443                 WSANETWORKEVENTS events;
    00444                 m_s.CheckAndHandleError_int("WSAEnumNetworkEvents", WSAEnumNetworkEvents(m_s, m_event, &events));
    00445                 if ((events.lNetworkEvents & FD_CLOSE) != FD_CLOSE)
    00446                         throw Socket::Err(m_s, "WSAEnumNetworkEvents (FD_CLOSE not present)", E_FAIL);
    00447                 if (events.iErrorCode[FD_CLOSE_BIT] != 0)
    00448                         throw Socket::Err(m_s, "FD_CLOSE (via WSAEnumNetworkEvents)", events.iErrorCode[FD_CLOSE_BIT]);
    00449                 m_resultPending = false;
    00450         }
    00451         return m_lastResult != 0;
    00452 }
    00453
    00454 void SocketSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
    00455 {
    00456         if (m_resultPending)
    00457                 container.AddHandle(m_event, CallStack("SocketSender::GetWaitObjects() - result pending", &callStack));
    00458         else
    00459                 container.SetNoWait(CallStack("SocketSender::GetWaitObjects() - result ready", &callStack));
    00460 }
    00461
    00462 unsigned int SocketSender::GetSendResult()
    00463 {
    00464         if (m_resultPending)
    00465         {
    00466                 DWORD flags = 0;
    00467                 BOOL result = WSAGetOverlappedResult(m_s, &m_overlapped, &m_lastResult, false, &flags);
    00468                 m_s.CheckAndHandleError("WSAGetOverlappedResult", result);
    00469                 m_resultPending = false;
    00470         }
    00471         return m_lastResult;
    00472 }
    00473
    00474 #endif
    00475
    00476 #ifdef USE_BERKELEY_STYLE_SOCKETS
    00477
    00478 SocketReceiver::SocketReceiver(Socket &s)
    00479         : m_s(s), m_lastResult(0), m_eofReceived(false)
    00480 {
    00481 }
    00482
    00483 void SocketReceiver::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
    00484 {
    00485         if (!m_eofReceived)
    00486                 container.AddReadFd(m_s, CallStack("SocketReceiver::GetWaitObjects()", &callStack));
    00487 }
    00488
    00489 bool SocketReceiver::Receive(byte* buf, size_t bufLen)
    00490 {
    00491         m_lastResult = m_s.Receive(buf, bufLen);
    00492         if (bufLen > 0 && m_lastResult == 0)
    00493                 m_eofReceived = true;
    00494         return true;
    00495 }
    00496
    00497 unsigned int SocketReceiver::GetReceiveResult()
    00498 {
    00499         return m_lastResult;
    00500 }
    00501
    00502 SocketSender::SocketSender(Socket &s)
    00503         : m_s(s), m_lastResult(0)
    00504 {
    00505 }
    00506
    00507 void SocketSender::Send(const byte* buf, size_t bufLen)
    00508 {
    00509         m_lastResult = m_s.Send(buf, bufLen);
    00510 }
    00511
    00512 void SocketSender::SendEof()
    00513 {
    00514         m_s.ShutDown(SD_SEND);
    00515 }
    00516
    00517 unsigned int SocketSender::GetSendResult()
    00518 {
    00519         return m_lastResult;
    00520 }
    00521
    00522 void SocketSender::GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack)
    00523 {
    00524         container.AddWriteFd(m_s, CallStack("SocketSender::GetWaitObjects()", &callStack));
    00525 }
    00526
    00527 #endif
    00528
    00529 NAMESPACE_END
    00530
    00531 #endif  // #ifdef SOCKETS_AVAILABLE