X-Git-Url: http://git.tdb.fi/?p=libs%2Fnet.git;a=blobdiff_plain;f=source%2Fnet%2Fsocket.cpp;fp=source%2Fnet%2Fsocket.cpp;h=5af2b4f507e34de1a3527e1c9b99b5693441eae7;hp=0000000000000000000000000000000000000000;hb=50e9f9ea7f7385a2c5931fca2b8fb1103078e67c;hpb=21c596567e3b6fd794ed6af73d304ce2bc70e58f diff --git a/source/net/socket.cpp b/source/net/socket.cpp new file mode 100644 index 0000000..5af2b4f --- /dev/null +++ b/source/net/socket.cpp @@ -0,0 +1,159 @@ +#ifndef WIN32 +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include "sockaddr_private.h" +#include "socket.h" +#include "socket_private.h" + +namespace { + +#ifdef WIN32 +class WinSockHelper +{ +public: + WinSockHelper() + { + WSADATA wsa_data; + int err = WSAStartup(0x0002, &wsa_data); + if(err) + std::cerr<<"Failed to initialize WinSock: "<handle = p.handle; + + SockAddr::SysAddr sa; + getsockname(priv->handle, reinterpret_cast(&sa.addr), &sa.size); + local_addr = SockAddr::new_from_sys(sa); + +#ifdef WIN32 + *priv->event = CreateEvent(0, false, false, 0); +#else + *priv->event = priv->handle; +#endif +} + +Socket::Socket(Family af, int type, int proto): + priv(new Private), + local_addr(0) +{ + priv->handle = socket(family_to_sys(af), type, proto); + +#ifdef WIN32 + *priv->event = CreateEvent(0, false, false, 0); +#else + *priv->event = priv->handle; +#endif +} + +Socket::~Socket() +{ +#ifdef WIN32 + closesocket(priv->handle); + CloseHandle(*priv->event); +#else + ::close(priv->handle); +#endif + + delete local_addr; + delete priv; +} + +void Socket::set_block(bool b) +{ + mode = (mode&~IO::M_NONBLOCK); + if(b) + mode = (mode|IO::M_NONBLOCK); + +#ifdef WIN32 + u_long flag = !b; + ioctlsocket(priv->handle, FIONBIO, &flag); +#else + int flags = fcntl(priv->handle, F_GETFL); + fcntl(priv->handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); +#endif +} + +const IO::Handle &Socket::get_event_handle() +{ + return priv->event; +} + + +void Socket::bind(const SockAddr &addr) +{ + SockAddr::SysAddr sa = addr.to_sys(); + + int err = ::bind(priv->handle, reinterpret_cast(&sa.addr), sa.size); + if(err==-1) + throw system_error("bind"); + + delete local_addr; + local_addr = addr.copy(); +} + +const SockAddr &Socket::get_local_address() const +{ + if(local_addr==0) + throw bad_socket_state("not bound"); + return *local_addr; +} + +void Socket::set_timeout(const Time::TimeDelta &timeout) +{ +#ifndef WIN32 + timeval tv = Time::rawtime_to_timeval(timeout.raw()); + set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval)); + set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval)); +#else + DWORD msecs = static_cast(timeout/Time::msec); + set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD)); + set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD)); +#endif +} + +int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen) +{ +#ifdef WIN32 + return setsockopt(priv->handle, level, optname, reinterpret_cast(optval), optlen); +#else + return setsockopt(priv->handle, level, optname, optval, optlen); +#endif +} + +int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) const +{ +#ifdef WIN32 + return getsockopt(priv->handle, level, optname, reinterpret_cast(optval), optlen); +#else + return getsockopt(priv->handle, level, optname, optval, optlen); +#endif +} + +} // namespace Net +} // namespace Msp