Mercurial > code
diff C++/Socket.cpp @ 170:fd138f2a9773
Add C++ portable sockets
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 10 Sep 2013 15:17:56 +0200 |
parents | |
children | 9f22bd478f21 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C++/Socket.cpp Tue Sep 10 15:17:56 2013 +0200 @@ -0,0 +1,266 @@ +/* + * Socket.cpp -- portable C++ socket wrappers + * + * Copyright (c) 2013, 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 <cerrno> + +#include "Socket.h" +#include "SocketAddress.h" + +/* -------------------------------------------------------- + * SocketError implementation + * -------------------------------------------------------- */ + +SocketError::SocketError(const std::string &error) +{ + m_error = error; +} + +const char *SocketError::what() const throw() +{ + return m_error.c_str(); +} + +/* -------------------------------------------------------- + * Socket implementation + * -------------------------------------------------------- */ + +void Socket::init() +{ +#if defined(_WIN32) + WSADATA wsa; + WSAStartup(MAKEWORD(2, 2), &wsa); +#endif +} + +/* -------------------------------------------------------- + * System dependent code + * -------------------------------------------------------- */ + +#if defined(_WIN32) + +string Socket::getLastSysError() +{ + LPSTR str = nullptr; + string errmsg = "Unknown error"; + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&str, 0, NULL); + + + if (str) + { + errmsg = string(str); + LocalFree(str); + } + + return errmsg; +} + +#else + +std::string Socket::getLastSysError() +{ + return strerror(errno); +} + +#endif + +void Socket::finish() +{ +#if defined(_WIN32) + WSACleanup(); +#endif +} + +Socket::Socket() +{ +} + +Socket::Socket(int domain, int type, int protocol) +{ + m_socket = socket(domain, type, protocol); + + if (m_socket == INVALID_SOCKET) + throw SocketError(getLastSysError()); +} + +Socket::Socket(Socket::Type sock) + : m_socket(sock) +{ +} + +Socket::~Socket() +{ +} + +Socket::Type Socket::getSocket() const +{ + return m_socket; +} + +void Socket::set(int level, int name, const void *arg, unsigned argLen) +{ + if (setsockopt(m_socket, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR) + throw SocketError(getLastSysError()); +} + +void Socket::blockMode(bool block) +{ +#if defined(O_NONBLOCK) && !defined(_WIN32) + int flags; + + if ((flags = fcntl(m_socket, F_GETFL, 0)) == -1) + flags = 0; + + if (!block) + flags &= ~(O_NONBLOCK); + else + flags |= O_NONBLOCK; + + if (fcntl(m_socket, F_SETFL, flags) == -1) + throw SocketError(getLastSysError()); +#else + unsigned long flags = (block) ? 0 : 1; + + if (ioctlsocket(m_socket, FIONBIO, &flags) == SOCKET_ERROR) + throw SocketError(getLastSysError()); +#endif +} + +void Socket::bind(const SocketAddress &addr) +{ + const sockaddr_storage &sa = addr.address(); + size_t addrlen = addr.length(); + + if (::bind(m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR) + throw SocketError(getLastSysError()); +} + +void Socket::connect(const SocketAddress &addr) +{ + const sockaddr_storage &sa = addr.address(); + size_t addrlen = addr.length(); + + if (::connect(m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR) + throw SocketError(getLastSysError()); +} + +Socket Socket::accept() +{ + SocketAddress dummy; + + return accept(dummy); +} + +Socket Socket::accept(SocketAddress &info) +{ + Socket::Type sock; + + info.m_addrlen = sizeof (sockaddr_storage); + sock = ::accept(m_socket, (sockaddr *)&info.m_addr, &info.m_addrlen); + + if (sock == INVALID_SOCKET) + throw SocketError(getLastSysError()); + + return Socket(sock); +} + +void Socket::listen(int max) +{ + if (::listen(m_socket, max) == SOCKET_ERROR) + throw SocketError(getLastSysError()); +} + +unsigned Socket::recv(void *data, unsigned dataLen) +{ + int nbread; + + nbread = ::recv(m_socket, (Socket::Arg)data, dataLen, 0); + if (nbread == SOCKET_ERROR) + throw SocketError(getLastSysError()); + + return (unsigned)nbread; +} + +unsigned Socket::send(const void *data, unsigned dataLen) +{ + int nbsent; + + nbsent = ::send(m_socket, (Socket::ConstArg)data, dataLen, 0); + if (nbsent == SOCKET_ERROR) + throw SocketError(getLastSysError()); + + return (unsigned)nbsent; +} + +unsigned Socket::send(const std::string &message) +{ + return Socket::send(message.c_str(), message.length()); +} + +unsigned Socket::recvfrom(void *data, unsigned dataLen) +{ + SocketAddress dummy; + + return recvfrom(data, dataLen, dummy); +} + +unsigned Socket::recvfrom(void *data, unsigned dataLen, SocketAddress &info) +{ + int nbread; + + info.m_addrlen = sizeof (struct sockaddr_storage); + nbread = ::recvfrom(m_socket, (Socket::Arg)data, dataLen, 0, + (sockaddr *)&info.m_addr, &info.m_addrlen); + + if (nbread == SOCKET_ERROR) + throw SocketError(getLastSysError()); + + return (unsigned)nbread; +} + +unsigned Socket::sendto(const void *data, unsigned dataLen, const SocketAddress &info) +{ + int nbsent; + + nbsent = ::sendto(m_socket, (Socket::ConstArg)data, dataLen, 0, + (const sockaddr *)&info.m_addr, info.m_addrlen); + if (nbsent == SOCKET_ERROR) + throw SocketError(getLastSysError()); + + return (unsigned)nbsent; +} + +unsigned Socket::sendto(const std::string &message, const SocketAddress &info) +{ + return sendto(message.c_str(), message.length(), info); +} + +void Socket::close() +{ + (void)closesocket(m_socket); +} + +bool operator==(const Socket &s1, const Socket &s2) +{ + return s1.getSocket() == s2.getSocket(); +}