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

Generated on Sat Dec 23 02:07:10 2006 for Crypto++ by  doxygen 1.5.1-p1