aboutsummaryrefslogtreecommitdiffstats
path: root/src/platforms/posix/posixSocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/platforms/posix/posixSocket.cpp')
-rw-r--r--src/platforms/posix/posixSocket.cpp680
1 files changed, 0 insertions, 680 deletions
diff --git a/src/platforms/posix/posixSocket.cpp b/src/platforms/posix/posixSocket.cpp
deleted file mode 100644
index ab434116..00000000
--- a/src/platforms/posix/posixSocket.cpp
+++ /dev/null
@@ -1,680 +0,0 @@
-//
-// VMime library (http://www.vmime.org)
-// Copyright (C) 2002-2013 Vincent Richard <[email protected]>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 3 of
-// the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-//
-// Linking this library statically or dynamically with other modules is making
-// a combined work based on this library. Thus, the terms and conditions of
-// the GNU General Public License cover the whole combination.
-//
-
-#include "vmime/config.hpp"
-
-
-#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES
-
-
-#include "vmime/platforms/posix/posixSocket.hpp"
-#include "vmime/platforms/posix/posixHandler.hpp"
-
-#include <unistd.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-
-#include "vmime/utility/stringUtils.hpp"
-
-#include "vmime/exception.hpp"
-
-
-#if defined(EWOULDBLOCK)
-# define IS_EAGAIN(x) ((x) == EAGAIN || (x) == EWOULDBLOCK || (x) == EINTR || (x) == EINPROGRESS)
-#else
-# define IS_EAGAIN(x) ((x) == EAGAIN || (x) == EINTR || (x) == EINPROGRESS)
-#endif
-
-
-namespace vmime {
-namespace platforms {
-namespace posix {
-
-
-//
-// posixSocket
-//
-
-posixSocket::posixSocket(shared_ptr <vmime::net::timeoutHandler> th)
- : m_timeoutHandler(th), m_desc(-1), m_status(0)
-{
-}
-
-
-posixSocket::~posixSocket()
-{
- if (m_desc != -1)
- ::close(m_desc);
-}
-
-
-void posixSocket::connect(const vmime::string& address, const vmime::port_t port)
-{
- // Close current connection, if any
- if (m_desc != -1)
- {
- ::close(m_desc);
- m_desc = -1;
- }
-
-#if VMIME_HAVE_GETADDRINFO // use thread-safe and IPv6-aware getaddrinfo() if available
-
- // Resolve address, if needed
- struct ::addrinfo hints;
- memset(&hints, 0, sizeof(hints));
-
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- std::ostringstream portStr;
- portStr.imbue(std::locale::classic());
-
- portStr << port;
-
- struct ::addrinfo* res0;
-
- if (::getaddrinfo(address.c_str(), portStr.str().c_str(), &hints, &res0) != 0)
- {
- // Error: cannot resolve address
- throw vmime::exceptions::connection_error("Cannot resolve address.");
- }
-
- m_serverAddress = address;
-
- // Connect to host
- int sock = -1;
- struct ::addrinfo* res = res0;
-
- for ( ; sock == -1 && res != NULL ; res = res->ai_next)
- {
- sock = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
-
- if (sock < 0)
- continue; // try next
-
- if (m_timeoutHandler != NULL)
- {
- ::fcntl(sock, F_SETFL, ::fcntl(sock, F_GETFL) | O_NONBLOCK);
-
- if (::connect(sock, res->ai_addr, res->ai_addrlen) < 0)
- {
- switch (errno)
- {
- case 0:
- case EINPROGRESS:
- case EINTR:
-#if defined(EAGAIN)
- case EAGAIN:
-#endif // EAGAIN
-#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
- case EWOULDBLOCK:
-#endif // EWOULDBLOCK
-
- // Connection in progress
- break;
-
- default:
-
- ::close(sock);
- sock = -1;
- continue; // try next
- }
-
- // Wait for socket to be connected.
- // We will check for time out every second.
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
-
- fd_set fdsError;
- FD_ZERO(&fdsError);
- FD_SET(sock, &fdsError);
-
- struct timeval tm;
- tm.tv_sec = 1;
- tm.tv_usec = 0;
-
- m_timeoutHandler->resetTimeOut();
-
- bool connected = false;
-
- do
- {
- const int ret = select(sock + 1, NULL, &fds, &fdsError, &tm);
-
- // Success
- if (ret > 0)
- {
- connected = true;
- break;
- }
- // Error
- else if (ret < -1)
- {
- if (errno != EINTR)
- {
- // Cancel connection
- break;
- }
- }
- // 1-second timeout
- else if (ret == 0)
- {
- if (m_timeoutHandler->isTimeOut())
- {
- if (!m_timeoutHandler->handleTimeOut())
- {
- // Cancel connection
- break;
- }
- else
- {
- // Reset timeout and keep waiting for connection
- m_timeoutHandler->resetTimeOut();
- }
- }
- else
- {
- // Keep waiting for connection
- }
- }
-
- ::sched_yield();
-
- } while (true);
-
- if (!connected)
- {
- ::close(sock);
- sock = -1;
- continue; // try next
- }
-
- break;
- }
- }
- else
- {
- if (::connect(sock, res->ai_addr, res->ai_addrlen) < 0)
- {
- ::close(sock);
- sock = -1;
- continue; // try next
- }
- }
- }
-
- ::freeaddrinfo(res0);
-
- if (sock == -1)
- {
- try
- {
- throwSocketError(errno);
- }
- catch (exceptions::socket_exception& e)
- {
- throw vmime::exceptions::connection_error
- ("Error while connecting socket.", e);
- }
- }
-
- m_desc = sock;
-
-#else // !VMIME_HAVE_GETADDRINFO
-
- // Resolve address
- ::sockaddr_in addr;
-
- memset(&addr, 0, sizeof(addr));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(static_cast <unsigned short>(port));
- addr.sin_addr.s_addr = ::inet_addr(address.c_str());
-
- if (addr.sin_addr.s_addr == static_cast <in_addr_t>(-1))
- {
- ::hostent* hostInfo = ::gethostbyname(address.c_str());
-
- if (hostInfo == NULL)
- {
- // Error: cannot resolve address
- throw vmime::exceptions::connection_error("Cannot resolve address.");
- }
-
- ::memcpy(reinterpret_cast <char*>(&addr.sin_addr), hostInfo->h_addr, hostInfo->h_length);
- }
-
- m_serverAddress = address;
-
- // Get a new socket
- m_desc = ::socket(AF_INET, SOCK_STREAM, 0);
-
- if (m_desc == -1)
- {
- try
- {
- throwSocketError(errno);
- }
- catch (exceptions::socket_exception& e)
- {
- throw vmime::exceptions::connection_error
- ("Error while creating socket.", e);
- }
- }
-
- // Start connection
- if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1)
- {
- try
- {
- throwSocketError(errno);
- }
- catch (exceptions::socket_exception& e)
- {
- ::close(m_desc);
- m_desc = -1;
-
- // Error
- throw vmime::exceptions::connection_error
- ("Error while connecting socket.", e);
- }
- }
-
-#endif // VMIME_HAVE_GETADDRINFO
-
- ::fcntl(m_desc, F_SETFL, ::fcntl(m_desc, F_GETFL) | O_NONBLOCK);
-}
-
-
-bool posixSocket::isConnected() const
-{
- if (m_desc == -1)
- return false;
-
- char buff;
-
- return ::recv(m_desc, &buff, 1, MSG_PEEK) != 0;
-}
-
-
-void posixSocket::disconnect()
-{
- if (m_desc != -1)
- {
- ::shutdown(m_desc, SHUT_RDWR);
- ::close(m_desc);
-
- m_desc = -1;
- }
-}
-
-
-static bool isNumericAddress(const char* address)
-{
-
-#if VMIME_HAVE_GETADDRINFO
-
- struct addrinfo hint, *info = NULL;
- memset(&hint, 0, sizeof(hint));
-
- hint.ai_family = AF_UNSPEC;
- hint.ai_flags = AI_NUMERICHOST;
-
- if (getaddrinfo(address, 0, &hint, &info) == 0)
- {
- freeaddrinfo(info);
- return true;
- }
- else
- {
- return false;
- }
-
-#else
-
- return inet_addr(address) != INADDR_NONE;
-
-#endif
-
-}
-
-
-const string posixSocket::getPeerAddress() const
-{
- // Get address of connected peer
- sockaddr peer;
- socklen_t peerLen = sizeof(peer);
-
- getpeername(m_desc, reinterpret_cast <sockaddr*>(&peer), &peerLen);
-
- // Convert to numerical presentation format
- char numericAddress[1024];
-
- if (inet_ntop(peer.sa_family, &peer, numericAddress, sizeof(numericAddress)) != NULL)
- return string(numericAddress);
-
- return ""; // should not happen
-}
-
-
-const string posixSocket::getPeerName() const
-{
- // Get address of connected peer
- sockaddr peer;
- socklen_t peerLen = sizeof(peer);
-
- getpeername(m_desc, reinterpret_cast <sockaddr*>(&peer), &peerLen);
-
- // If server address as specified when connecting is a numeric
- // address, try to get a host name for it
- if (isNumericAddress(m_serverAddress.c_str()))
- {
-
-#if VMIME_HAVE_GETNAMEINFO
-
- char host[NI_MAXHOST + 1];
- char service[NI_MAXSERV + 1];
-
- if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen,
- host, sizeof(host), service, sizeof(service),
- /* flags */ NI_NAMEREQD) == 0)
- {
- return string(host);
- }
-
-#else
-
- struct hostent *hp;
-
- if ((hp = gethostbyaddr(reinterpret_cast <const void *>(&peer),
- sizeof(peer), peer.sa_family)) != NULL)
- {
- return string(hp->h_name);
- }
-
-#endif
-
- }
-
- return m_serverAddress;
-}
-
-
-size_t posixSocket::getBlockSize() const
-{
- return 16384; // 16 KB
-}
-
-
-void posixSocket::receive(vmime::string& buffer)
-{
- const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
- buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
-}
-
-
-size_t posixSocket::receiveRaw(byte_t* buffer, const size_t count)
-{
- m_status &= ~STATUS_WOULDBLOCK;
-
- // Check whether data is available
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(m_desc, &fds);
-
- struct timeval tv;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- ssize_t ret = ::select(m_desc + 1, &fds, NULL, NULL, &tv);
-
- if (ret < 0)
- {
- if (!IS_EAGAIN(errno))
- throwSocketError(errno);
-
- // No data available at this time
- // Check if we are timed out
- if (m_timeoutHandler &&
- m_timeoutHandler->isTimeOut())
- {
- if (!m_timeoutHandler->handleTimeOut())
- {
- // Server did not react within timeout delay
- throwSocketError(errno);
- }
- else
- {
- // Reset timeout
- m_timeoutHandler->resetTimeOut();
- }
- }
-
- m_status |= STATUS_WOULDBLOCK;
-
- // Continue waiting for data
- return 0;
- }
-
- // Read available data
- ret = ::recv(m_desc, buffer, count, 0);
-
- if (ret < 0)
- {
- if (!IS_EAGAIN(errno))
- throwSocketError(errno);
-
- // Check if we are timed out
- if (m_timeoutHandler &&
- m_timeoutHandler->isTimeOut())
- {
- if (!m_timeoutHandler->handleTimeOut())
- {
- // Server did not react within timeout delay
- throwSocketError(errno);
- }
- else
- {
- // Reset timeout
- m_timeoutHandler->resetTimeOut();
- }
- }
-
- m_status |= STATUS_WOULDBLOCK;
-
- // No data available at this time
- return 0;
- }
- else if (ret == 0)
- {
- // Host shutdown
- throwSocketError(ENOTCONN);
- }
- else
- {
- // Data received, reset timeout
- if (m_timeoutHandler)
- m_timeoutHandler->resetTimeOut();
- }
-
- return ret;
-}
-
-
-void posixSocket::send(const vmime::string& buffer)
-{
- sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
-}
-
-
-void posixSocket::send(const char* str)
-{
- sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str));
-}
-
-
-void posixSocket::sendRaw(const byte_t* buffer, const size_t count)
-{
- m_status &= ~STATUS_WOULDBLOCK;
-
- size_t size = count;
-
- while (size > 0)
- {
- const ssize_t ret = ::send(m_desc, buffer, size, 0);
-
- if (ret <= 0)
- {
- if (ret < 0 && !IS_EAGAIN(errno))
- throwSocketError(errno);
-
- platform::getHandler()->wait();
- }
- else
- {
- buffer += ret;
- size -= ret;
- }
- }
-
- // Reset timeout
- if (m_timeoutHandler)
- m_timeoutHandler->resetTimeOut();
-}
-
-
-size_t posixSocket::sendRawNonBlocking(const byte_t* buffer, const size_t count)
-{
- m_status &= ~STATUS_WOULDBLOCK;
-
- const ssize_t ret = ::send(m_desc, buffer, count, 0);
-
- if (ret <= 0)
- {
- if (ret < 0 && !IS_EAGAIN(errno))
- throwSocketError(errno);
-
- // Check if we are timed out
- if (m_timeoutHandler &&
- m_timeoutHandler->isTimeOut())
- {
- if (!m_timeoutHandler->handleTimeOut())
- {
- // Could not send data within timeout delay
- throwSocketError(errno);
- }
- else
- {
- // Reset timeout
- m_timeoutHandler->resetTimeOut();
- }
- }
-
- m_status |= STATUS_WOULDBLOCK;
-
- // No data can be written at this time
- return 0;
- }
-
- // Reset timeout
- if (m_timeoutHandler)
- m_timeoutHandler->resetTimeOut();
-
- return ret;
-}
-
-
-void posixSocket::throwSocketError(const int err)
-{
- string msg;
-
- switch (err)
- {
- case EACCES: msg = "EACCES: permission denied"; break;
- case EAFNOSUPPORT: msg = "EAFNOSUPPORT: address family not supported"; break;
- case EMFILE: msg = "EMFILE: process file table overflow"; break;
- case ENFILE: msg = "ENFILE: system limit reached"; break;
- case EPROTONOSUPPORT: msg = "EPROTONOSUPPORT: protocol not supported"; break;
- case EAGAIN: msg = "EGAIN: blocking operation"; break;
- case EBADF: msg = "EBADF: invalid descriptor"; break;
- case ECONNRESET: msg = "ECONNRESET: connection reset by peer"; break;
- case EFAULT: msg = "EFAULT: bad user space address"; break;
- case EINTR: msg = "EINTR: signal occured before transmission"; break;
- case EINVAL: msg = "EINVAL: invalid argument"; break;
- case EMSGSIZE: msg = "EMSGSIZE: message cannot be sent atomically"; break;
- case ENOBUFS: msg = "ENOBUFS: output queue is full"; break;
- case ENOMEM: msg = "ENOMEM: out of memory"; break;
- case EPIPE:
- case ENOTCONN: msg = "ENOTCONN: not connected"; break;
- case ECONNREFUSED: msg = "ECONNREFUSED: connection refused"; break;
- default:
-
- std::ostringstream oss;
- oss << ::strerror(err);
-
- msg = oss.str();
- break;
- }
-
- throw exceptions::socket_exception(msg);
-}
-
-
-unsigned int posixSocket::getStatus() const
-{
- return m_status;
-}
-
-
-
-//
-// posixSocketFactory
-//
-
-shared_ptr <vmime::net::socket> posixSocketFactory::create()
-{
- shared_ptr <vmime::net::timeoutHandler> th;
- return make_shared <posixSocket>(th);
-}
-
-
-shared_ptr <vmime::net::socket> posixSocketFactory::create(shared_ptr <vmime::net::timeoutHandler> th)
-{
- return make_shared <posixSocket>(th);
-}
-
-
-} // posix
-} // platforms
-} // vmime
-
-
-#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES