Mercurial > code
diff C++/SocketTcp.cpp @ 315:c9356cb38c86
Split sockets into SocketTcp and SocketUdp
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 02 Mar 2015 14:00:48 +0100 |
parents | |
children | 4c0af1143fc4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C++/SocketTcp.cpp Mon Mar 02 14:00:48 2015 +0100 @@ -0,0 +1,140 @@ +/* + * SocketTcp.cpp -- portable C++ socket wrappers + * + * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SocketAddress.h" +#include "SocketTcp.h" + +/* -------------------------------------------------------- + * SocketAbstractTcp + * -------------------------------------------------------- */ + +void SocketAbstractTcp::listen(int max) +{ + if (::listen(m_handle, max) == Error) + throw SocketError("listen", Socket::syserror(), errno); +} + +/* -------------------------------------------------------- + * SocketTcp + * -------------------------------------------------------- */ + +SocketTcp SocketTcp::accept() +{ + SocketAddress dummy; + + return accept(dummy); +} + +SocketTcp SocketTcp::accept(SocketAddress &info) +{ + Socket::Handle handle; + + // Store the information + sockaddr_storage address; + socklen_t addrlen; + + addrlen = sizeof (sockaddr_storage); + handle = ::accept(m_handle, reinterpret_cast<sockaddr *>(&address), &addrlen); + + if (handle == Invalid) { +#if defined(_WIN32) + if (WSAGetLastError() == WSAEWOULDBLOCK) + throw SocketError("accept", Socket::syserror(WSAEWOULDBLOCK), WSAEWOULDBLOCK /* TODO: Read */); + + throw SocketError("accept", Socket::syserror(), WSAGetLastError()); +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw SocketError("accept", Socket::syserror(EWOULDBLOCK), EWOULDBLOCK /* TODO: Read */); + + throw SocketError("accept", Socket::syserror(), errno); +#endif + } + + // Usually accept works only with SOCK_STREAM + info = SocketAddress(address, addrlen); + + return SocketTcp(handle); +} + +void SocketTcp::connect(const SocketAddress &address) +{ + auto &sa = address.address(); + auto addrlen = address.length(); + + if (::connect(m_handle, reinterpret_cast<const sockaddr *>(&sa), addrlen) == Error) { + /* + * Determine if the error comes from a non-blocking connect that cannot be + * accomplished yet. + */ +#if defined(_WIN32) + if (WSAGetLastError() == WSAEWOULDBLOCK) + throw SocketError("connect", Socket::syserror(WSAEWOULDBLOCK), WSAEWOULDBLOCK /*, Write */); + + throw SocketError("connect", Socket::syserror(WSAEWOULDBLOCK), WSAGetLastError()); +#else + if (errno == EINPROGRESS) + throw SocketError("connect", Socket::syserror(EINPROGRESS), EINPROGRESS /*, Write */); + + throw SocketError("connect", Socket::syserror(), errno); +#endif + } +} + +unsigned SocketTcp::recv(void *data, unsigned dataLen) +{ + int nbread; + + nbread = ::recv(m_handle, (Socket::Arg)data, dataLen, 0); + if (nbread == Error) { +#if defined(_WIN32) + if (WSAGetLastError() == WSAEWOULDBLOCK) + throw SocketError("recv", Socket::syserror(), WSAEWOULDBLOCK /* TODO: Read */); + + throw SocketError("recv", Socket::syserror(), WSAGetLastError()); +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw SocketError("recv", Socket::syserror(), errno /* TODO: Read */); + + throw SocketError("recv", Socket::syserror(), errno); +#endif + } + + return (unsigned)nbread; +} + +unsigned SocketTcp::send(const void *data, unsigned length) +{ + int nbsent; + + nbsent = ::send(m_handle, (Socket::ConstArg)data, length, 0); + if (nbsent == Error) { +#if defined(_WIN32) + if (WSAGetLastError() == WSAEWOULDBLOCK) + throw SocketError("send", Socket::syserror(), WSAEWOULDBLOCK /* Write */); + + throw SocketError("send", Socket::syserror(), WSAGetLastError()); +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) + throw SocketError("send", Socket::syserror(), errno /*, Write */); + + throw SocketError("send", Socket::syserror(), errno); +#endif + } + + return (unsigned)nbsent; +}