/xp/net/Socket.cpp
C++ | 446 lines | 343 code | 62 blank | 41 comment | 91 complexity | ad09d63cc4f59a211723e896b1c098e8 MD5 | raw file
Possible License(s): Apache-2.0
- /*
- * $Id: Socket.cpp 50 2009-02-10 05:48:05Z hyunghwan.chung $
- *
- Copyright 2005-2009 Chung, Hyung-Hwan.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- #include <xp/net/Socket.hpp>
- #include <xp/net/InetAddress.hpp>
- #include <xp/bas/string.h>
- #include <xp/bas/memory.h>
- #include <xp/bas/locale.h>
- #include <xp/bas/errno.h>
- #include <xp/bas/assert.h>
- #ifndef _WIN32
- #include <netinet/in.h>
- #include <net/if.h>
- #endif
- namespace xp
- {
- namespace net
- {
- int Socket::v6_supported = 0;
- Socket::Socket (int type)
- {
- // NOTICE:
- // The socket can't be created in the constructor
- // as the implementaion is intended to support both
- // ipv4 and ipv6 seamlessly. The new name resolution
- // API's don't effectively allow the creation of socket
- // before the successful name lookup. So the lazy creation
- // of sockets is empolyed.
-
- this->socket_type = type;
- this->sckhnd = INVALID_HANDLE;
- this->error_code = ERR_NONE;
- disableTimeout ();
- }
- Socket::~Socket ()
- {
- close ();
- }
- int Socket::startup (bool try_v6)
- {
- xp_sck_t sck;
-
- if (::xp_sckstartup() == -1) return -1;
- if (try_v6) {
- if (::xp_sck_open (&sck,
- InetAddress::V6, Socket::DATAGRAM, 0) == XP_NULL) {
- #ifdef _WIN32
- if (XP_NET_SOCKET_ERRNO == WSAEAFNOSUPPORT) {
- #else
- if (XP_NET_SOCKET_ERRNO == EAFNOSUPPORT ||
- XP_NET_SOCKET_ERRNO == ENOSYS) {
- #endif
- v6_supported = -1;
- }
- }
- else {
- ::xp_sck_close (&sck);
- v6_supported = 1;
- }
- }
- else v6_supported = -1;
- return 0;
- }
- int Socket::cleanup ()
- {
- return ::xp_sckcleanup ();
- }
- int Socket::open (Handle handle)
- {
- XP_NET_SOCKET_CHECK_OPEN_HANDLE(this->sckhnd);
- int tmp;
- len_t len = sizeof(tmp);
- if (xp_sck_openhnd(this, handle) == XP_NULL) return -1;
- if (xp_sck_getopt (this,
- SOL_SOCKET, SO_TYPE, (char*)&tmp, &len) == -1) {
- this->error_code = ERR_TYPE_RETRIEVAL;
- xp_sck_forfeit (this);
- this->sckhnd = INVALID_HANDLE;
- return -1;
- }
- if (this->socket_type != 0 &&
- this->socket_type != tmp) {
- xp_sck_forfeit (this);
- this->error_code = ERR_TYPE_MISMATCH;
- return -1;
- }
- this->socket_type = tmp;
- return 0;
- }
- int Socket::close ()
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
-
- int n = ::xp_sck_close (this);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- else this->sckhnd = INVALID_HANDLE;
- return n;
- }
- int Socket::shutdown (int how)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_shtdwn (this, how);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- xp_ssize_t Socket::send (
- const void* data, xp_size_t size, int flags)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_send (this, data, size, flags);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- xp_ssize_t Socket::sendAll (const void* data, xp_size_t size, int flags)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_sendall (this, data, size, flags);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- xp_ssize_t Socket::receive (void* buf, xp_size_t size, int flags)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_recv (this, buf, size, flags);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- xp_ssize_t Socket::receiveAll (void* buf, xp_size_t size, int flags)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_recvall (this, buf, size, flags);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- int Socket::getOption (
- int level, int optname, void* optval, len_t* optlen)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_getopt (
- this, level, optname, (char*)optval, optlen);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_SOCKOPT);
- }
- return n;
- }
- int Socket::setOption (
- int level, int optname, const void* optval, len_t optlen)
- {
- XP_NET_SOCKET_CHECK_CLOSED_HANDLE(this->sckhnd);
- int n = ::xp_sck_setopt (
- this, level, optname, (const char*)optval, optlen);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_SOCKOPT);
- }
- return n;
- }
- int Socket::setDebug (int n)
- {
- return setOption (
- SOL_SOCKET, SO_DEBUG, (char*)&n, xp_sizeof(n));
- };
- int Socket::setReuseAddr (int n)
- {
- return setOption (
- SOL_SOCKET, SO_REUSEADDR, (char*)&n, xp_sizeof(n));
- }
- int Socket::setKeepAlive (int n)
- {
- return setOption (
- SOL_SOCKET, SO_KEEPALIVE, (char*)&n, xp_sizeof(n));
- }
- int Socket::setBroadcast (int n)
- {
- return setOption (
- SOL_SOCKET, SO_BROADCAST, (char*)&n, xp_sizeof(n));
- }
-
- int Socket::setSendBuf (unsigned int size)
- {
- return setOption (
- SOL_SOCKET, SO_SNDBUF, (char*)&size, xp_sizeof(size));
- }
- int Socket::setRecvBuf (unsigned int size)
- {
- return setOption (
- SOL_SOCKET, SO_RCVBUF, (char*)&size, xp_sizeof(size));
- }
-
- int Socket::setLingerOn (int sec)
- {
- struct linger lng;
- lng.l_onoff = 1;
- lng.l_linger = sec;
- return setOption (
- SOL_SOCKET, SO_LINGER, (char*)&lng, xp_sizeof(lng));
- }
- int Socket::setLingerOff ()
- {
- struct linger lng;
- lng.l_onoff = 0;
- lng.l_linger = 0;
- return setOption (SOL_SOCKET,
- SO_LINGER, (char*)&lng, xp_sizeof(lng));
- }
-
- int Socket::setTcpNodelay (int n)
- {
- #ifdef TCP_NODELAY
- return setOption (IPPROTO_TCP,
- TCP_NODELAY, (char*)&n, xp_sizeof(n));
- #else
- this->error_code = ERR_NOSUPPORT;
- return -1;
- #endif
- }
- int Socket::setOobInline (int n)
- {
- #ifdef SO_OOBINLINE
- return setOption (SOL_SOCKET,
- SO_OOBINLINE, (char*)&n, xp_sizeof(n));
- #else
- this->error_code = ERR_NOSUPPORT;
- return -1;
- #endif
- }
- int Socket::setIpv6Only (int n)
- {
- #ifdef IPV6_V6ONLY
- return setOption (IPPROTO_IPV6,
- IPV6_V6ONLY, (char*)&n, xp_sizeof(n));
- #else
- this->error_code = ERR_NOSUPPORT;
- return -1;
- #endif
- }
- int Socket::bindToDevice (const xp_char_t* device)
- {
- #ifdef SO_BINDTODEVICE
- if (device == XP_NULL) {
- return setOption (SOL_SOCKET,
- SO_BINDTODEVICE, XP_NULL, 0);
- }
- else {
- struct ifreq iface;
- xp_memset (&iface, 0, xp_sizeof(iface));
- #ifdef XP_CHAR_IS_MCHAR
- xp_strxcpy (iface.ifr_name, xp_countof(iface.ifr_name), device);
- #else
- if (xp_wcstomcs(device, iface.ifr_name,
- xp_countof(iface.ifr_name)) < xp_strlen(device)) {
- this->error_code = ERR_INVALID;
- return -1;
- };
- #endif
- return setOption (SOL_SOCKET,
- SO_BINDTODEVICE, (char*)&iface, xp_sizeof(iface));
- }
- #else
- this->error_code = ERR_NOSUPPORT;
- return -1;
- #endif
- }
- int Socket::unbindToDevice ()
- {
- return bindToDevice (XP_NULL);
- }
- int Socket::create_socket (int domain, int type, int proto)
- {
- xp_assert (this->sckhnd == INVALID_HANDLE);
- // domain adjustment
- if (domain == InetAddress::V0 &&
- v6_supported == -1) domain = InetAddress::V4;
- if (::xp_sck_open(this, domain, type, proto) == XP_NULL) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_CREATE);
- return -1;
- }
- return 0;
- }
- int Socket::bind_socket (addr_t* addr, len_t len)
- {
- xp_assert (this->sckhnd != INVALID_HANDLE);
- int n = ::xp_sck_bind (this, addr, len);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- int Socket::connect_socket (addr_t* addr, len_t len)
- {
- xp_assert (this->sckhnd != INVALID_HANDLE);
- xp_sck_setcancel (this, XP_SCK_CONN, NULL, NULL);
- int n = ::xp_sck_conn (this, addr, len);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- int Socket::connect_socket (addr_t* addr, len_t len, xp_bool_t (*cancel) (void*))
- {
- xp_assert (this->sckhnd != INVALID_HANDLE);
- xp_sck_setcancel (this, XP_SCK_CONN, cancel, this);
- int n = ::xp_sck_conn (this, addr, len);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- int Socket::listen_socket (int backlog)
- {
- xp_assert (this->sckhnd != INVALID_HANDLE);
- int n = ::xp_sck_lstn (this, backlog);
- if (n == -1) {
- this->error_code = translate_errno (
- XP_NET_SOCKET_ERRNO, ERR_GENERAL);
- }
- return n;
- }
- int Socket::translate_errno (int num, int def_err)
- {
- /*#ifdef _WIN32
- if (num == WSAETIMEDOUT) return ERR_TIMEDOUT;
- if (num == WSAECANCELED) return ERR_CANCELED;
- if (num == WSAEINVAL || num == WSAENOTSOCK)
- return ERR_INVALID;
- if (num == WSAEAFNOSUPPORT || num == WSAEPROTONOSUPPORT)
- return ERR_NOSUPPORT;
- if (num == WSAENOBUFS || num == WSAEMFILE)
- return ERR_NORESOURCE;
- if (num == WSAEACCES) return ERR_ACCESS;
- if (num == WSAEADDRINUSE) return ERR_ADDRINUSE;
- if (num == WSAECONNREFUSED) return ERR_REFUSED;
- if (num == WSAENOTCONN) return ERR_NOTCONNECTED;
- if (num == WSAENETUNREACH) return ERR_UNREACHABLE;
- #else*/
- if (num == XP_ETIMEDOUT) return ERR_TIMEDOUT;
- if (num == XP_ECANCELED) return ERR_CANCELED;
- if (num == XP_EBADF || num == XP_EINVAL || num == XP_ENOTSOCK)
- return ERR_INVALID;
- if (num == XP_EAFNOSUPPORT || num == XP_EPROTONOSUPPORT)
- return ERR_NOSUPPORT;
- if (num == XP_ENOMEM || num == XP_EMFILE || num == XP_EAGAIN)
- return ERR_NORESOURCE;
- if (num == XP_EACCES) return ERR_ACCESS;
- if (num == XP_EADDRINUSE) return ERR_ADDRINUSE;
- if (num == XP_ECONNREFUSED) return ERR_REFUSED;
- if (num == XP_ENOTCONN) return ERR_NOTCONNECTED;
- if (num == XP_ENETUNREACH) return ERR_UNREACHABLE;
- /*#endif*/
- return def_err;
- }
- }
- }