Mercurial > code
view C++/Socket.cpp @ 319:cba77da58496
* Finalize SocketSsl
* Add documentation
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 08 Mar 2015 11:04:01 +0100 |
parents | 890729b8cb60 |
children |
line wrap: on
line source
/* * Socket.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 <cstring> #include "Socket.h" #include "SocketAddress.h" /* -------------------------------------------------------- * System dependent code * -------------------------------------------------------- */ #if defined(_WIN32) std::string Socket::syserror(int errn) { LPSTR str = nullptr; std::string errmsg = "Unknown error"; FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errn, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&str, 0, NULL); if (str) { errmsg = std::string(str); LocalFree(str); } return errmsg; } #else #include <cerrno> std::string Socket::syserror(int errn) { return strerror(errn); } #endif std::string Socket::syserror() { #if defined(_WIN32) return syserror(WSAGetLastError()); #else return syserror(errno); #endif } /* -------------------------------------------------------- * SocketError class * -------------------------------------------------------- */ SocketError::SocketError(Code code, std::string function) : m_code(code) , m_function(std::move(function)) , m_error(Socket::syserror()) { } SocketError::SocketError(Code code, std::string function, int error) : m_code(code) , m_function(std::move(function)) , m_error(Socket::syserror(error)) { } SocketError::SocketError(Code code, std::string function, std::string error) : m_code(code) , m_function(std::move(function)) , m_error(std::move(error)) { } /* -------------------------------------------------------- * Socket class * -------------------------------------------------------- */ #if defined(_WIN32) std::mutex Socket::s_mutex; std::atomic<bool> Socket::s_initialized{false}; #endif Socket::Socket(int domain, int type, int protocol) { #if defined(_WIN32) && !defined(SOCKET_NO_WSA_INIT) if (!s_initialized) initialize(); #endif m_handle = ::socket(domain, type, protocol); if (m_handle == Invalid) throw SocketError(SocketError::System, "socket"); m_state = SocketState::Opened; } void Socket::bind(const SocketAddress &address) { const auto &sa = address.address(); const auto addrlen = address.length(); if (::bind(m_handle, reinterpret_cast<const sockaddr *>(&sa), addrlen) == Error) throw SocketError(SocketError::System, "bind"); m_state = SocketState::Bound; } void Socket::close() { #if defined(_WIN32) ::closesocket(m_handle); #else ::close(m_handle); #endif SocketState::Closed; } void Socket::setBlockMode(bool block) { #if defined(O_NONBLOCK) && !defined(_WIN32) int flags; if ((flags = fcntl(m_handle, F_GETFL, 0)) == -1) flags = 0; if (block) flags &= ~(O_NONBLOCK); else flags |= O_NONBLOCK; if (fcntl(m_handle, F_SETFL, flags) == Error) throw SocketError(SocketError::System, "setBlockMode"); #else unsigned long flags = (block) ? 0 : 1; if (ioctlsocket(m_handle, FIONBIO, &flags) == Error) throw SocketError(SocketError::System, "setBlockMode"); #endif } bool operator==(const Socket &s1, const Socket &s2) { return s1.handle() == s2.handle(); } bool operator<(const Socket &s1, const Socket &s2) { return s1.handle() < s2.handle(); }