From aa4d426b4d3527d7e166df1a05058c9a4a0f6683 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 30 Apr 2021 00:33:56 +0200 Subject: initial/final commit --- .../vmime/platforms/posix/posixChildProcess.cpp | 410 +++++++++ .../vmime/platforms/posix/posixChildProcess.hpp | 92 ++ .../vmime/platforms/posix/posixCriticalSection.cpp | 67 ++ .../vmime/platforms/posix/posixCriticalSection.hpp | 69 ++ .../src/vmime/platforms/posix/posixFile.cpp | 715 +++++++++++++++ .../src/vmime/platforms/posix/posixFile.hpp | 224 +++++ .../src/vmime/platforms/posix/posixHandler.cpp | 292 +++++++ .../src/vmime/platforms/posix/posixHandler.hpp | 103 +++ .../src/vmime/platforms/posix/posixSocket.cpp | 969 +++++++++++++++++++++ .../src/vmime/platforms/posix/posixSocket.hpp | 118 +++ 10 files changed, 3059 insertions(+) create mode 100644 vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixFile.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixFile.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixHandler.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixHandler.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixSocket.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixSocket.hpp (limited to 'vmime-master/src/vmime/platforms/posix') diff --git a/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp b/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp new file mode 100644 index 0000000..4a9fef3 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp @@ -0,0 +1,410 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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_FILESYSTEM_FEATURES + + +#include "vmime/platforms/posix/posixChildProcess.hpp" +#include "vmime/platforms/posix/posixFile.hpp" + +#include "vmime/exception.hpp" + +#include +#include +#include +#include +#include +#include + + +namespace vmime { +namespace platforms { +namespace posix { + + +// posixChildProcessFactory + +shared_ptr posixChildProcessFactory::create(const utility::file::path& path) const { + + return make_shared (path); +} + + + +#ifndef VMIME_BUILDING_DOC + + +// getPosixSignalMessage +// Returns the name of a POSIX signal. + +static const string getPosixSignalMessage(const int num) { + + switch (num) { + case SIGHUP: return "SIGHUP"; + case SIGINT: return "SIGINT"; + case SIGQUIT: return "SIGQUIT"; + case SIGILL: return "SIGILL"; + case SIGABRT: return "SIGABRT"; + case SIGFPE: return "SIGFPE"; + case SIGKILL: return "SIGKILL"; + case SIGSEGV: return "SIGSEGV"; + case SIGPIPE: return "SIGPIPE"; + case SIGALRM: return "SIGALRM"; + case SIGTERM: return "SIGTERM"; + case SIGUSR1: return "SIGUSR1"; + case SIGUSR2: return "SIGUSR2"; + case SIGCHLD: return "SIGCHLD"; + case SIGCONT: return "SIGCONT"; + case SIGSTOP: return "SIGSTOP"; + case SIGTSTP: return "SIGTSTP"; + case SIGTTIN: return "SIGTTIN"; + case SIGTTOU: return "SIGTTOU"; + } + + return "(unknown)"; +} + + +// getPosixErrorMessage +// Returns a message corresponding to an error code. + +static const string getPosixErrorMessage(const int num) { + +#ifdef strerror_r + char res[256]; + res[0] = '\0'; + + strerror_r(num, res, sizeof(res)); + + return string(res); +#else + return string(strerror(num)); +#endif + +} + + +// Output stream adapter for POSIX pipe + +class outputStreamPosixPipeAdapter : public utility::outputStream { + +public: + + outputStreamPosixPipeAdapter(const int desc) + : m_desc(desc) { + + } + + void flush() { + + ::fsync(m_desc); + } + +protected: + + void writeImpl(const byte_t* const data, const size_t count) { + + if (::write(m_desc, data, count) == -1) { + const string errorMsg = getPosixErrorMessage(errno); + throw exceptions::system_error(errorMsg); + } + } + +private: + + const int m_desc; +}; + + +// Input stream adapter for POSIX pipe + +class inputStreamPosixPipeAdapter : public utility::inputStream { + +public: + + inputStreamPosixPipeAdapter(const int desc) + : m_desc(desc) { + } + + bool eof() const { + + return m_eof; + } + + void reset() { + + // Do nothing: unsupported + } + + size_t skip(const size_t count) { + + // TODO: not tested + byte_t buffer[4096]; + + ssize_t bytesSkipped = 0; + ssize_t bytesRead = 0; + + while ((bytesRead = ::read(m_desc, buffer, + std::min(sizeof(buffer), count - bytesSkipped))) != 0) { + + if (bytesRead == -1) { + const string errorMsg = getPosixErrorMessage(errno); + throw exceptions::system_error(errorMsg); + } + + bytesSkipped += bytesRead; + } + + return static_cast (bytesSkipped); + } + + size_t read(byte_t* const data, const size_t count) { + + ssize_t bytesRead = 0; + + if ((bytesRead = ::read(m_desc, data, count)) == -1) { + const string errorMsg = getPosixErrorMessage(errno); + throw exceptions::system_error(errorMsg); + } + + m_eof = (bytesRead == 0); + + return static_cast (bytesRead); + } + +private: + + const int m_desc; + + bool m_eof; +}; + + +#endif // VMIME_BUILDING_DOC + + + +// posixChildProcess + +posixChildProcess::posixChildProcess(const utility::file::path& path) + : m_processPath(path), + m_started(false), + m_stdIn(null), + m_stdOut(null), + m_pid(0), + m_argArray(NULL) { + + m_pipe[0] = 0; + m_pipe[1] = 0; + + sigemptyset(&m_oldProcMask); +} + + +posixChildProcess::~posixChildProcess() { + + if (m_started) { + sigprocmask(SIG_SETMASK, &m_oldProcMask, NULL); + } + + if (m_pipe[0] != 0) { + close(m_pipe[0]); + } + + if (m_pipe[1] != 0) { + close(m_pipe[1]); + } + + delete [] m_argArray; +} + + +// The following code is highly inspired and adapted from the 'sendmail' +// provider module in Evolution data server code. +// +// Original authors: Dan Winship +// Copyright 2000 Ximian, Inc. (www.ximian.com) + +void posixChildProcess::start(const std::vector & args, const int flags) { + + if (m_started) { + return; + } + + // Construct C-style argument array + const char** argv = new const char*[args.size() + 2]; + + m_argVector = args; // for c_str() pointer to remain valid + m_argArray = argv; // to free later + + argv[0] = m_processPath.getLastComponent().getBuffer().c_str(); + argv[args.size() + 1] = NULL; + + for (unsigned int i = 0 ; i < m_argVector.size() ; ++i) { + argv[i + 1] = m_argVector[i].c_str(); + } + + // Create a pipe to communicate with the child process + int fd[2]; + + if (pipe(fd) == -1) { + throw exceptions::system_error(getPosixErrorMessage(errno)); + } + + m_pipe[0] = fd[0]; + m_pipe[1] = fd[1]; + + // Block SIGCHLD so the calling application doesn't notice + // process exiting before we do + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, &m_oldProcMask); + + // Spawn process + const pid_t pid = fork(); + + if (pid == -1) { // error + + const string errorMsg = getPosixErrorMessage(errno); + + sigprocmask(SIG_SETMASK, &m_oldProcMask, NULL); + + close(fd[0]); + close(fd[1]); + + throw exceptions::system_error(errorMsg); + + } else if (pid == 0) { // child process + + if (flags & FLAG_REDIRECT_STDIN) { + dup2(fd[0], STDIN_FILENO); + } else { + close(fd[0]); + } + + if (flags & FLAG_REDIRECT_STDOUT) { + dup2(fd[1], STDOUT_FILENO); + } else { + close(fd[1]); + } + + posixFileSystemFactory* pfsf = new posixFileSystemFactory(); + + const string path = pfsf->pathToString(m_processPath); + + delete pfsf; + + execv(path.c_str(), const_cast (argv)); + _exit(255); + } + + if (flags & FLAG_REDIRECT_STDIN) { + + m_stdIn = make_shared (m_pipe[1]); + + } else { + + close(m_pipe[1]); + m_pipe[1] = 0; + } + + if (flags & FLAG_REDIRECT_STDOUT) { + + m_stdOut = make_shared (m_pipe[0]); + + } else { + + close(m_pipe[0]); + m_pipe[0] = 0; + } + + m_pid = pid; + m_started = true; +} + + +shared_ptr posixChildProcess::getStdIn() { + + return m_stdIn; +} + + +shared_ptr posixChildProcess::getStdOut() { + + return m_stdOut; +} + + +void posixChildProcess::waitForFinish() { + + // Close stdin pipe + if (m_pipe[1] != 0) { + close(m_pipe[1]); + m_pipe[1] = 0; + } + + int wstat; + + while (waitpid(m_pid, &wstat, 0) == -1 && errno == EINTR) { + ; + } + + if (!WIFEXITED(wstat)) { + + throw exceptions::system_error("Process exited with signal " + + getPosixSignalMessage(WTERMSIG(wstat))); + + } else if (WEXITSTATUS(wstat) != 0) { + + if (WEXITSTATUS(wstat) == 255) { + + scoped_ptr pfsf(new posixFileSystemFactory()); + + throw exceptions::system_error("Could not execute '" + + pfsf->pathToString(m_processPath) + "'"); + + } else { + + std::ostringstream oss; + oss.imbue(std::locale::classic()); + + oss << "Process exited with status " << WEXITSTATUS(wstat); + + throw exceptions::system_error(oss.str()); + } + } +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + diff --git a/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp b/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp new file mode 100644 index 0000000..b831e8b --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp @@ -0,0 +1,92 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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. +// + +#ifndef VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/utility/childProcess.hpp" + +#include +#include + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixChildProcess : public utility::childProcess { + +public: + + posixChildProcess(const utility::file::path& path); + ~posixChildProcess(); + + void start(const std::vector & args, const int flags = 0); + + shared_ptr getStdIn(); + shared_ptr getStdOut(); + + void waitForFinish(); + +private: + + utility::file::path m_processPath; + bool m_started; + + shared_ptr m_stdIn; + shared_ptr m_stdOut; + + sigset_t m_oldProcMask; + pid_t m_pid; + int m_pipe[2]; + + std::vector m_argVector; + const char** m_argArray; +}; + + +class posixChildProcessFactory : public utility::childProcessFactory { + +public: + + shared_ptr create(const utility::file::path& path) const; +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + +#endif // VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp new file mode 100644 index 0000000..2f25cfa --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp @@ -0,0 +1,67 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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 + + +#include "vmime/platforms/posix/posixCriticalSection.hpp" + + +namespace vmime { +namespace platforms { +namespace posix { + + +posixCriticalSection::posixCriticalSection() { + + pthread_mutex_init(&m_cs, NULL); +} + + +posixCriticalSection::~posixCriticalSection() { + + pthread_mutex_destroy(&m_cs); +} + + +void posixCriticalSection::lock() { + + pthread_mutex_lock(&m_cs); +} + + +void posixCriticalSection::unlock() { + + pthread_mutex_unlock(&m_cs); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX diff --git a/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp new file mode 100644 index 0000000..9a4bed5 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp @@ -0,0 +1,69 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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. +// + +#ifndef VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX + + +#include "vmime/utility/sync/criticalSection.hpp" + + +#include +#include + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixCriticalSection : public utility::sync::criticalSection { + +public: + + posixCriticalSection(); + ~posixCriticalSection(); + + void lock(); + void unlock(); + +private: + + pthread_mutex_t m_cs; +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX + +#endif // VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/posix/posixFile.cpp b/vmime-master/src/vmime/platforms/posix/posixFile.cpp new file mode 100644 index 0000000..9773b3a --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixFile.cpp @@ -0,0 +1,715 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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_FILESYSTEM_FEATURES + + +#include "vmime/platforms/posix/posixFile.hpp" + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "vmime/exception.hpp" + + +namespace vmime { +namespace platforms { +namespace posix { + + +// +// posixFileIterator +// + +posixFileIterator::posixFileIterator( + const vmime::utility::file::path& path, + const vmime::string& nativePath +) + : m_path(path), + m_nativePath(nativePath), + m_dir(NULL), + m_dirEntry(NULL) { + + if ((m_dir = ::opendir(m_nativePath.c_str())) == NULL) { + posixFileSystemFactory::reportError(path, errno); + } + + getNextElement(); +} + + +posixFileIterator::~posixFileIterator() { + + if (m_dir) { + + if (::closedir(m_dir) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + } +} + + +bool posixFileIterator::hasMoreElements() const { + + return (m_dirEntry != NULL); +} + + +shared_ptr posixFileIterator::nextElement() { + + shared_ptr file = make_shared ( + m_path / vmime::utility::file::path::component(m_dirEntry->d_name) + ); + + getNextElement(); + + return file; +} + + +void posixFileIterator::getNextElement() { + + errno = 0; + + while ((m_dirEntry = ::readdir(m_dir)) != NULL) { + + const char* name = m_dirEntry->d_name; + const size_t len = ::strlen(name); + + if (!(len == 1 && name[0] == '.') && + !(len == 2 && name[0] == '.' && name[1] == '.')) { + + break; + } + } + + if (errno) { + posixFileSystemFactory::reportError(m_path, errno); + } +} + + + +// +// posixFileWriterOutputStream +// + +posixFileWriterOutputStream::posixFileWriterOutputStream( + const vmime::utility::file::path& path, + const int fd +) + : m_path(path), + m_fd(fd) { + +} + + +posixFileWriterOutputStream::~posixFileWriterOutputStream() { + + ::close(m_fd); +} + + +void posixFileWriterOutputStream::writeImpl( + const byte_t* const data, + const size_t count +) { + + const byte_t* array = data; + size_t size = count; + + while (1) { + + ssize_t ret = ::write(m_fd, array, size); + + if (ret == -1) { + + if (errno == EINTR) { + continue; + } + + posixFileSystemFactory::reportError(m_path, errno); + break; + + } else if (size_t(ret) < size) { + + array += ret; + size -= ret; + } + + break; + } +} + + +void posixFileWriterOutputStream::flush() { + + if (::fsync(m_fd) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } +} + + + +// +// posixFileReaderInputStream +// + +posixFileReaderInputStream::posixFileReaderInputStream( + const vmime::utility::file::path& path, + const int fd +) + : m_path(path), + m_fd(fd), + m_eof(false) { + +} + + +posixFileReaderInputStream::~posixFileReaderInputStream() { + + if (::close(m_fd) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } +} + + +bool posixFileReaderInputStream::eof() const { + + return m_eof; +} + + +void posixFileReaderInputStream::reset() { + + if (::lseek(m_fd, 0, SEEK_SET) == off_t(-1)) { + posixFileSystemFactory::reportError(m_path, errno); + } + + m_eof = false; +} + + +size_t posixFileReaderInputStream::read( + byte_t* const data, + const size_t count +) { + + ssize_t c = 0; + + if ((c = ::read(m_fd, data, count)) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + if (c == 0 && count != 0) { + m_eof = true; + } + + return static_cast (c); +} + + +size_t posixFileReaderInputStream::skip(const size_t count) { + + const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR); + + if (curPos == off_t(-1)) { + posixFileSystemFactory::reportError(m_path, errno); + } + + const off_t newPos = ::lseek(m_fd, count, SEEK_CUR); + + if (newPos == off_t(-1)) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return static_cast (newPos - curPos); +} + + +size_t posixFileReaderInputStream::getPosition() const { + + const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR); + + if (curPos == off_t(-1)) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return static_cast (curPos); +} + + +void posixFileReaderInputStream::seek(const size_t pos) { + + const off_t newPos = ::lseek(m_fd, pos, SEEK_SET); + + if (newPos == off_t(-1)) { + posixFileSystemFactory::reportError(m_path, errno); + } +} + + + +// +// posixFileWriter +// + +posixFileWriter::posixFileWriter( + const vmime::utility::file::path& path, + const vmime::string& nativePath +) + : m_path(path), + m_nativePath(nativePath) { + +} + + +shared_ptr posixFileWriter::getOutputStream() { + + int fd = 0; + + if ((fd = ::open(m_nativePath.c_str(), O_WRONLY, 0660)) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return make_shared (m_path, fd); +} + + + +// +// posixFileReader +// + +posixFileReader::posixFileReader( + const vmime::utility::file::path& path, + const vmime::string& nativePath +) + : m_path(path), + m_nativePath(nativePath) { + +} + + +shared_ptr posixFileReader::getInputStream() { + + int fd = 0; + + if ((fd = ::open(m_nativePath.c_str(), O_RDONLY, 0640)) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return make_shared (m_path, fd); +} + + + +// +// posixFile +// + +posixFile::posixFile(const vmime::utility::file::path& path) + : m_path(path), + m_nativePath(posixFileSystemFactory::pathToStringImpl(path)) { + +} + + +void posixFile::createFile() { + + int fd = 0; + + if ((fd = ::open(m_nativePath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660)) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + if (::fsync(fd) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + if (::close(fd) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } +} + + +void posixFile::createDirectory(const bool createAll) { + + createDirectoryImpl(m_path, m_path, createAll); +} + + +bool posixFile::isFile() const { + + struct stat buf; + + if (::stat(m_nativePath.c_str(), &buf) == -1) { + + if (errno == ENOENT) { + return false; + } + + posixFileSystemFactory::reportError(m_path, errno); + return false; + } + + return S_ISREG(buf.st_mode); +} + + +bool posixFile::isDirectory() const { + + struct stat buf; + + if (::stat(m_nativePath.c_str(), &buf) == -1) { + + if (errno == ENOENT) { + return false; + } + + posixFileSystemFactory::reportError(m_path, errno); + return false; + } + + return S_ISDIR(buf.st_mode); +} + + +bool posixFile::canRead() const { + + struct stat buf; + + if (::stat(m_nativePath.c_str(), &buf) == -1) { + + if (errno == ENOENT) { + return false; + } + + posixFileSystemFactory::reportError(m_path, errno); + return false; + } + + return S_ISREG(buf.st_mode) + && ::access(m_nativePath.c_str(), R_OK | F_OK) == 0; +} + + +bool posixFile::canWrite() const { + + struct stat buf; + + if (::stat(m_nativePath.c_str(), &buf) == -1) { + + if (errno == ENOENT) { + return false; + } + + posixFileSystemFactory::reportError(m_path, errno); + return false; + } + + return S_ISREG(buf.st_mode) + && ::access(m_nativePath.c_str(), W_OK | F_OK) == 0; +} + + +posixFile::length_type posixFile::getLength() { + + struct stat buf; + + if (::stat(m_nativePath.c_str(), &buf) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return static_cast (buf.st_size); +} + + +const posixFile::path& posixFile::getFullPath() const { + + return m_path; +} + + +bool posixFile::exists() const { + + struct stat buf; + return ::stat(m_nativePath.c_str(), &buf) == 0; +} + + +shared_ptr posixFile::getParent() const { + + if (m_path.isEmpty()) { + return null; + } else { + return make_shared (m_path.getParent()); + } +} + + +void posixFile::rename(const path& newName) { + + const vmime::string newNativePath = posixFileSystemFactory::pathToStringImpl(newName); + + posixFile dest(newName); + + if (isDirectory()) { + dest.createDirectory(); + } else { + dest.createFile(); + } + + if (::rename(m_nativePath.c_str(), newNativePath.c_str()) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + m_path = newName; + m_nativePath = newNativePath; +} + + +void posixFile::remove() { + + struct stat buf; + + if (::stat(m_nativePath.c_str(), &buf) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + if (S_ISDIR(buf.st_mode)) { + + if (::rmdir(m_nativePath.c_str()) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + } else if (S_ISREG(buf.st_mode)) { + + if (::unlink(m_nativePath.c_str()) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + } +} + + +shared_ptr posixFile::getFileWriter() { + + return make_shared (m_path, m_nativePath); +} + + +shared_ptr posixFile::getFileReader() { + + return make_shared (m_path, m_nativePath); +} + + +shared_ptr posixFile::getFiles() const { + + if (!isDirectory()) { + throw vmime::exceptions::not_a_directory(m_path); + } + + return make_shared (m_path, m_nativePath); +} + + +void posixFile::createDirectoryImpl( + const vmime::utility::file::path& fullPath, + const vmime::utility::file::path& path, + const bool recursive +) { + + const vmime::string nativePath = posixFileSystemFactory::pathToStringImpl(path); + struct stat buf; + + if (::stat(nativePath.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) { + return; + } + + if (!path.isEmpty() && recursive) { + createDirectoryImpl(fullPath, path.getParent(), true); + } + + if (::mkdir(nativePath.c_str(), 0750) == -1) { + posixFileSystemFactory::reportError(fullPath, errno); + } +} + + + +// +// posixFileSystemFactory +// + +shared_ptr posixFileSystemFactory::create( + const vmime::utility::file::path& path +) const { + + return make_shared (path); +} + + +const vmime::utility::file::path posixFileSystemFactory::stringToPath( + const vmime::string& str +) const { + + return stringToPathImpl(str); +} + + +const vmime::string posixFileSystemFactory::pathToString( + const vmime::utility::file::path& path +) const { + + return pathToStringImpl(path); +} + + +const vmime::utility::file::path posixFileSystemFactory::stringToPathImpl( + const vmime::string& str +) { + + vmime::size_t offset = 0; + vmime::size_t prev = 0; + + vmime::utility::file::path path; + + while ((offset = str.find_first_of("/", offset)) != vmime::string::npos) { + + if (offset != prev) { + + path.appendComponent( + vmime::utility::file::path::component( + vmime::string(str.begin() + prev, str.begin() + offset) + ) + ); + } + + prev = offset + 1; + offset++; + } + + if (prev < str.length()) { + + path.appendComponent( + vmime::utility::file::path::component( + vmime::string(str.begin() + prev, str.end()) + ) + ); + } + + return path; +} + + +const vmime::string posixFileSystemFactory::pathToStringImpl(const vmime::utility::file::path& path) { + + vmime::string native = "/"; + + for (size_t i = 0 ; i < path.getSize() ; ++i) { + + if (i > 0) { + native += "/"; + } + + native += path[i].getBuffer(); + } + + return native; +} + + +bool posixFileSystemFactory::isValidPathComponent( + const vmime::utility::file::path::component& comp +) const { + + return comp.getBuffer().find_first_of("/*") == vmime::string::npos; +} + + +bool posixFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const { + + for (size_t i = 0 ; i < path.getSize() ; ++i) { + + if (!isValidPathComponent(path[i])) { + return false; + } + } + + return true; +} + + +void posixFileSystemFactory::reportError(const vmime::utility::path& path, const int err) { + + vmime::string desc; + + switch (err) { + case EEXIST: desc = "EEXIST: file already exists."; break; + case EISDIR: desc = "EISDIR: path refers to a directory."; break; + case EACCES: desc = "EACCES: permission denied"; break; + case ENAMETOOLONG: desc = "ENAMETOOLONG: path too long."; break; + case ENOENT: desc = "ENOENT: a directory in the path does not exist."; break; + case ENOTDIR: desc = "ENOTDIR: path is not a directory."; break; + case EROFS: desc = "EROFS: read-only filesystem."; break; + case ELOOP: desc = "ELOOP: too many symbolic links."; break; + case ENOSPC: desc = "ENOSPC: no space left on device."; break; + case ENOMEM: desc = "ENOMEM: insufficient kernel memory."; break; + case EMFILE: desc = "ENFILE: limit on number of files open by the process has been reached."; break; + case ENFILE: desc = "ENFILE: limit on number of files open on the system has been reached."; break; +#ifndef AIX + case ENOTEMPTY: desc = "ENOTEMPTY: directory is not empty."; break; +#endif + + default: + + std::ostringstream oss; + oss << ::strerror(err) << "."; + + desc = oss.str(); + break; + } + + throw vmime::exceptions::filesystem_exception(desc, path); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES diff --git a/vmime-master/src/vmime/platforms/posix/posixFile.hpp b/vmime-master/src/vmime/platforms/posix/posixFile.hpp new file mode 100644 index 0000000..d1fda9e --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixFile.hpp @@ -0,0 +1,224 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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. +// + +#ifndef VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/utility/file.hpp" +#include "vmime/utility/seekableInputStream.hpp" + + +#include + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixFileWriterOutputStream : public vmime::utility::outputStream { + +public: + + posixFileWriterOutputStream(const vmime::utility::file::path& path, const int fd); + ~posixFileWriterOutputStream(); + + void flush(); + +protected: + + void writeImpl(const byte_t* const data, const size_t count); + +private: + + const vmime::utility::file::path m_path; + const int m_fd; +}; + + + +class posixFileReaderInputStream : public vmime::utility::seekableInputStream { + +public: + + posixFileReaderInputStream(const vmime::utility::file::path& path, const int fd); + ~posixFileReaderInputStream(); + + bool eof() const; + + void reset(); + + size_t read(byte_t* const data, const size_t count); + + size_t skip(const size_t count); + + size_t getPosition() const; + void seek(const size_t pos); + +private: + + const vmime::utility::file::path m_path; + const int m_fd; + + bool m_eof; +}; + + + +class posixFileWriter : public vmime::utility::fileWriter { + +public: + + posixFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath); + + shared_ptr getOutputStream(); + +private: + + vmime::utility::file::path m_path; + vmime::string m_nativePath; +}; + + + +class posixFileReader : public vmime::utility::fileReader { + +public: + + posixFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath); + + shared_ptr getInputStream(); + +private: + + vmime::utility::file::path m_path; + vmime::string m_nativePath; +}; + + + +class posixFileIterator : public vmime::utility::fileIterator { + +public: + + posixFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath); + ~posixFileIterator(); + + bool hasMoreElements() const; + shared_ptr nextElement(); + +private: + + void getNextElement(); + + vmime::utility::file::path m_path; + vmime::string m_nativePath; + + DIR* m_dir; + struct dirent* m_dirEntry; +}; + + + +class posixFile : public vmime::utility::file { + +public: + + posixFile(const vmime::utility::file::path& path); + + void createFile(); + void createDirectory(const bool createAll = false); + + bool isFile() const; + bool isDirectory() const; + + bool canRead() const; + bool canWrite() const; + + length_type getLength(); + + const path& getFullPath() const; + + bool exists() const; + + shared_ptr getParent() const; + + void rename(const path& newName); + + void remove(); + + shared_ptr getFileWriter(); + shared_ptr getFileReader(); + + shared_ptr getFiles() const; + +private: + + static void createDirectoryImpl( + const vmime::utility::file::path& fullPath, + const vmime::utility::file::path& path, + const bool recursive = false + ); + +private: + + vmime::utility::file::path m_path; + vmime::string m_nativePath; +}; + + + +class posixFileSystemFactory : public vmime::utility::fileSystemFactory { + +public: + + shared_ptr create(const vmime::utility::file::path& path) const; + + const vmime::utility::file::path stringToPath(const vmime::string& str) const; + const vmime::string pathToString(const vmime::utility::file::path& path) const; + + static const vmime::utility::file::path stringToPathImpl(const vmime::string& str); + static const vmime::string pathToStringImpl(const vmime::utility::file::path& path); + + bool isValidPathComponent(const vmime::utility::file::path::component& comp) const; + bool isValidPath(const vmime::utility::file::path& path) const; + + static void reportError(const vmime::utility::path& path, const int err); +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + +#endif // VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/posix/posixHandler.cpp b/vmime-master/src/vmime/platforms/posix/posixHandler.cpp new file mode 100644 index 0000000..eecdbea --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixHandler.cpp @@ -0,0 +1,292 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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 + + +#include "vmime/platforms/posix/posixHandler.hpp" + +#include "vmime/platforms/posix/posixCriticalSection.hpp" + +#include "vmime/utility/stringUtils.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if VMIME_HAVE_SYSCALL +# include +#endif + +#include + +#include +#include +#include + + +/* +#ifdef _POSIX_PRIORITY_SCHEDULING + #include +#endif // _POSIX_PRIORITY_SCHEDULING +*/ + + +namespace vmime { +namespace platforms { +namespace posix { + + +posixHandler::posixHandler() { + +#if VMIME_HAVE_MESSAGING_FEATURES + m_socketFactory = make_shared (); +#endif +#if VMIME_HAVE_FILESYSTEM_FEATURES + m_fileSysFactory = make_shared (); + m_childProcFactory = make_shared (); +#endif + +} + + +posixHandler::~posixHandler() { + +} + + +unsigned long posixHandler::getUnixTime() const { + + return static_cast (::time(NULL)); +} + + +const vmime::datetime posixHandler::getCurrentLocalTime() const { + + const time_t t(::time(NULL)); + + // Get the local time +#if VMIME_HAVE_LOCALTIME_R + tm local; + ::localtime_r(&t, &local); +#else + tm local = *::localtime(&t); // WARNING: this is not thread-safe! +#endif + + // Get the UTC time +#if VMIME_HAVE_GMTIME_R + tm gmt; + ::gmtime_r(&t, &gmt); +#else + tm gmt = *::gmtime(&t); // WARNING: this is not thread-safe! +#endif + + // "A negative value for tm_isdst causes mktime() to attempt + // to determine whether Daylight Saving Time is in effect + // for the specified time." + local.tm_isdst = -1; + gmt.tm_isdst = -1; + + // Calculate the difference (in seconds) + const time_t diff = ::mktime(&local) - ::mktime(&gmt); + + // Return the date + return vmime::datetime( + local.tm_year + 1900, local.tm_mon + 1, local.tm_mday, + local.tm_hour, local.tm_min, local.tm_sec, static_cast (diff / 60) + ); +} + + +const vmime::charset posixHandler::getLocalCharset() const { + + // Note: nl_langinfo() might be affected by calls to setlocale() + // in a multithread environment. There is not MT-safe alternative + // to nl_langinfo(). + auto codeset = ::nl_langinfo(CODESET); + + if (codeset) { + return vmime::charset(codeset); + } + + return vmime::charset(); +} + + +static inline bool isAcceptableHostname(const vmime::string& str) { + + // At least, try to find something better than "localhost" + if (utility::stringUtils::isStringEqualNoCase(str, "localhost", 9) || + utility::stringUtils::isStringEqualNoCase(str, "localhost.localdomain", 21)) { + + return false; + } + + // Anything else will be OK, as long as it is a valid hostname + return utility::stringUtils::isValidHostname(str); +} + + +const vmime::string posixHandler::getHostName() const { + char hostname[256]; + + ::gethostname(hostname, sizeof(hostname)); + hostname[sizeof(hostname)-1] = '\0'; + + // Try to get official canonical name of this host + struct addrinfo hints; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // either IPV4 or IPV6 + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + + struct addrinfo* info; + + if (getaddrinfo(hostname, "http", &hints, &info) == 0) { + // First, try to get a Fully-Qualified Domain Name (FQDN) + for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next) { + + if (p->ai_canonname) { + + const string hn(p->ai_canonname); + + if (utility::stringUtils::isValidFQDN(hn)) { + freeaddrinfo(info); + return hn; + } + } + } + + // Then, try to find an acceptable host name + for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next) { + + if (p->ai_canonname) { + + const string hn(p->ai_canonname); + + if (isAcceptableHostname(hn)) { + freeaddrinfo(info); + return hn; + } + } + } + + freeaddrinfo(info); + } + + if (::strlen(hostname) == 0 || !isAcceptableHostname(hostname)) { + ::strcpy(hostname, "localhost.localdomain"); + } + + return hostname; +} + + +unsigned int posixHandler::getProcessId() const { + + return ::getpid(); +} + + +unsigned int posixHandler::getThreadId() const { + +#if VMIME_HAVE_GETTID + return static_cast (::gettid()); +#elif VMIME_HAVE_SYSCALL && VMIME_HAVE_SYSCALL_GETTID + return static_cast (::syscall(SYS_gettid)); +#elif VMIME_HAVE_GETTHRID // OpenBSD + return static_cast (::getthrid()); +#else + #error We have no implementation of getThreadId() for this platform! +#endif + +} + + +#if VMIME_HAVE_MESSAGING_FEATURES + +shared_ptr posixHandler::getSocketFactory() { + + return m_socketFactory; +} + +#endif + + +#if VMIME_HAVE_FILESYSTEM_FEATURES + +shared_ptr posixHandler::getFileSystemFactory() { + + return m_fileSysFactory; +} + + +shared_ptr posixHandler::getChildProcessFactory() { + + return m_childProcFactory; +} + +#endif + + +void posixHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count) { + + int fd = open("/dev/urandom", O_RDONLY); + + if (fd != -1) { + + read(fd, buffer, count); + close(fd); + + } else { // fallback + + for (unsigned int i = 0 ; i < count ; ++i) { + buffer[i] = static_cast (rand() % 255); + } + } +} + + +shared_ptr posixHandler::createCriticalSection() { + + return make_shared (); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX diff --git a/vmime-master/src/vmime/platforms/posix/posixHandler.hpp b/vmime-master/src/vmime/platforms/posix/posixHandler.hpp new file mode 100644 index 0000000..30417f1 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixHandler.hpp @@ -0,0 +1,103 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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. +// + +#ifndef VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX + + +#include "vmime/platform.hpp" + +#if VMIME_HAVE_MESSAGING_FEATURES + #include "vmime/platforms/posix/posixSocket.hpp" +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + #include "vmime/platforms/posix/posixFile.hpp" + #include "vmime/platforms/posix/posixChildProcess.hpp" +#endif + + +namespace vmime { +namespace platforms { +namespace posix { + + +class VMIME_EXPORT posixHandler : public vmime::platform::handler { + +public: + + posixHandler(); + ~posixHandler(); + + unsigned long getUnixTime() const; + + const vmime::datetime getCurrentLocalTime() const; + + const vmime::charset getLocalCharset() const; + + const vmime::string getHostName() const; + + unsigned int getProcessId() const; + unsigned int getThreadId() const; + +#if VMIME_HAVE_MESSAGING_FEATURES + shared_ptr getSocketFactory(); +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + shared_ptr getFileSystemFactory(); + + shared_ptr getChildProcessFactory(); +#endif + + void generateRandomBytes(unsigned char* buffer, const unsigned int count); + + shared_ptr createCriticalSection(); + +private: + +#if VMIME_HAVE_MESSAGING_FEATURES + shared_ptr m_socketFactory; +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + shared_ptr m_fileSysFactory; + shared_ptr m_childProcFactory; +#endif +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX + +#endif // VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/posix/posixSocket.cpp b/vmime-master/src/vmime/platforms/posix/posixSocket.cpp new file mode 100644 index 0000000..aec6a83 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixSocket.cpp @@ -0,0 +1,969 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // for getaddrinfo_a() in +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + + +// Workaround for detection of strerror_r variants +#if VMIME_HAVE_STRERROR_R + +namespace { + +char* vmime_strerror_r_result(int /* res */, char* buf) { + + // XSI-compliant prototype: + // int strerror_r(int errnum, char *buf, size_t buflen); + return buf; +} + +char* vmime_strerror_r_result(char* res, char* /* buf */) { + + // GNU-specific prototype: + // char *strerror_r(int errnum, char *buf, size_t buflen); + return res; +} + +} + +#endif // VMIME_HAVE_STRERROR_R + + + +namespace vmime { +namespace platforms { +namespace posix { + + +// +// posixSocket +// + +posixSocket::posixSocket(shared_ptr 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 (m_tracer) { + + std::ostringstream trace; + trace << "Connecting to " << address << ", port " << port; + + m_tracer->traceSend(trace.str()); + } + +#if VMIME_HAVE_GETADDRINFO // use thread-safe and IPv6-aware getaddrinfo() if available + + // Resolve address, if needed + m_serverAddress = address; + + struct ::addrinfo* addrInfo = NULL; // resolved addresses + resolve(&addrInfo, address, port); + + // Connect to host + int sock = -1; + int connectErrno = 0; + + if (m_timeoutHandler != NULL) { + m_timeoutHandler->resetTimeOut(); + } + + for (struct ::addrinfo* curAddrInfo = addrInfo ; + sock == -1 && curAddrInfo != NULL ; + curAddrInfo = curAddrInfo->ai_next, connectErrno = ETIMEDOUT) { + + if (curAddrInfo->ai_family != AF_INET && curAddrInfo->ai_family != AF_INET6) { + continue; + } + + sock = ::socket(curAddrInfo->ai_family, curAddrInfo->ai_socktype, curAddrInfo->ai_protocol); + + if (sock < 0) { + connectErrno = errno; + continue; // try next + } + +#if VMIME_HAVE_SO_KEEPALIVE + + // Enable TCP Keepalive + int keepAlive_optval = 1; + socklen_t keepAlive_optlen = sizeof(keepAlive_optval); + + ::setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive_optval, keepAlive_optlen); + +#endif // VMIME_HAVE_SO_KEEPALIVE + +#if VMIME_HAVE_SO_NOSIGPIPE + + // Return EPIPE instead of generating SIGPIPE + int nosigpipe_optval = 1; + socklen_t nosigpipe_optlen = sizeof(nosigpipe_optval); + + ::setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe_optval, nosigpipe_optlen); + +#endif // VMIME_HAVE_SO_NOSIGPIPE + + + if (m_timeoutHandler) { + + ::fcntl(sock, F_SETFL, ::fcntl(sock, F_GETFL) | O_NONBLOCK); + + if (::connect(sock, curAddrInfo->ai_addr, curAddrInfo->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: + + connectErrno = errno; + ::close(sock); + sock = -1; + continue; // try next + } + + // Wait for socket to be connected. + bool connected = false; + + const int pollTimeout = 1000; // poll() timeout (ms) + const int tryNextTimeout = 5000; // maximum time before trying next (ms) + + timeval startTime = { 0, 0 }; + gettimeofday(&startTime, /* timezone */ NULL); + + do { + + pollfd fds[1]; + fds[0].fd = sock; + fds[0].events = POLLIN | POLLOUT; + + const int ret = ::poll(fds, sizeof(fds) / sizeof(fds[0]), pollTimeout); + + // Success + if (ret > 0) { + + if (fds[0].revents & (POLLIN | POLLOUT)) { + + int error = 0; + socklen_t len = sizeof(error); + + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + + connectErrno = errno; + + } else { + + if (error != 0) { + connectErrno = error; + } else { + connected = true; + } + } + } + + break; + + // Error + } else if (ret < -1) { + + if (errno != EAGAIN && errno != EINTR) { + + // Cancel connection + connectErrno = errno; + break; + } + } + + // Check for timeout + if (m_timeoutHandler->isTimeOut()) { + + if (!m_timeoutHandler->handleTimeOut()) { + + // Cancel connection + connectErrno = ETIMEDOUT; + break; + + } else { + + // Reset timeout and keep waiting for connection + m_timeoutHandler->resetTimeOut(); + } + + } else { + + // Keep waiting for connection + } + + timeval curTime = { 0, 0 }; + gettimeofday(&curTime, /* timezone */ NULL); + + if (curAddrInfo->ai_next != NULL && + curTime.tv_usec - startTime.tv_usec >= tryNextTimeout * 1000) { + + connectErrno = ETIMEDOUT; + break; + } + + } while (true); + + if (!connected) { + + ::close(sock); + sock = -1; + continue; // try next + } + + break; + + } else { + + // Connection successful + break; + } + + } else { + + if (::connect(sock, curAddrInfo->ai_addr, curAddrInfo->ai_addrlen) < 0) { + + connectErrno = errno; + ::close(sock); + sock = -1; + continue; // try next + } + } + } + + ::freeaddrinfo(addrInfo); + + if (sock == -1) { + + try { + throwSocketError(connectErrno); + } catch (exceptions::socket_exception& e) { // wrap + 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 (port)); + addr.sin_addr.s_addr = ::inet_addr(address.c_str()); + + if (addr.sin_addr.s_addr == static_cast (-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 (&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) { // wrap + throw vmime::exceptions::connection_error("Error while creating socket.", e); + } + } + + // Start connection + if (::connect(m_desc, reinterpret_cast (&addr), sizeof(addr)) == -1) { + + try { + + throwSocketError(errno); + + } catch (exceptions::socket_exception& e) { // wrap + + ::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); +} + + +void posixSocket::resolve( + struct ::addrinfo** addrInfo, + const vmime::string& address, + const vmime::port_t port +) { + + char portStr[16]; + snprintf(portStr, sizeof(portStr), "%u", static_cast (port)); + + + struct ::addrinfo hints; + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_CANONNAME | AI_NUMERICSERV; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + +#if VMIME_HAVE_GETADDRINFO_A + + // If getaddrinfo_a() is available, use asynchronous resolving to allow + // the timeout handler to cancel the operation + + struct ::gaicb gaiRequest; + memset(&gaiRequest, 0, sizeof(gaiRequest)); + + gaiRequest.ar_name = address.c_str(); + gaiRequest.ar_service = portStr; + gaiRequest.ar_request = &hints; + + struct ::gaicb* gaiRequests = &gaiRequest; + int gaiError; + + if ((gaiError = getaddrinfo_a(GAI_NOWAIT, &gaiRequests, 1, NULL)) != 0) { + + throw vmime::exceptions::connection_error( + "getaddrinfo_a() failed: " + std::string(gai_strerror(gaiError)) + ); + } + + if (m_timeoutHandler) { + m_timeoutHandler->resetTimeOut(); + } + + while (true) { + + struct timespec gaiTimeout; + gaiTimeout.tv_sec = 1; // query timeout handler every second + gaiTimeout.tv_nsec = 0; + + gaiError = gai_suspend(&gaiRequests, 1, &gaiTimeout); + + if (gaiError == 0 || gaiError == EAI_ALLDONE) { + + const int ret = gai_error(&gaiRequest); + + if (ret != 0) { + + throw vmime::exceptions::connection_error( + "getaddrinfo_a() request failed: " + std::string(gai_strerror(ret)) + ); + + } else { + + *addrInfo = gaiRequest.ar_result; + break; + } + + } else if (gaiError != EAI_AGAIN) { + + if (gaiError == EAI_SYSTEM) { + + const int ret = gai_error(&gaiRequest); + + if (ret != EAI_INPROGRESS && errno != 0) { + + try { + throwSocketError(errno); + } catch (exceptions::socket_exception& e) { // wrap + throw vmime::exceptions::connection_error("Error while connecting socket.", e); + } + } + + } else { + + throw vmime::exceptions::connection_error( + "gai_suspend() failed: " + std::string(gai_strerror(gaiError)) + ); + } + } + + // Check for timeout + if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) { + + if (!m_timeoutHandler->handleTimeOut()) { + + throw exceptions::operation_timed_out(); + + } else { + + // Reset timeout and keep waiting for connection + m_timeoutHandler->resetTimeOut(); + } + } + } + +#else // !VMIME_HAVE_GETADDRINFO_A + + if (::getaddrinfo(address.c_str(), portStr, &hints, addrInfo) != 0) { + + // Error: cannot resolve address + throw vmime::exceptions::connection_error("Cannot resolve address."); + } + +#endif // VMIME_HAVE_GETADDRINFO_A + +} + + +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) { + + if (m_tracer) { + m_tracer->traceSend("Disconnecting"); + } + + ::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); + + if (getpeername(m_desc, &peer, &peerLen) != 0) { + throwSocketError(errno); + } + + // Convert to numerical presentation format + char buf[INET6_ADDRSTRLEN]; + + if (!inet_ntop(peer.sa_family, &(reinterpret_cast (&peer))->sin_addr, buf, sizeof(buf))) { + throwSocketError(errno); + } + + return string(buf); +} + + +const string posixSocket::getPeerName() const { + + // Get address of connected peer + sockaddr peer; + socklen_t peerLen = sizeof(peer); + + if (getpeername(m_desc, &peer, &peerLen) != 0) { + throwSocketError(errno); + } + + // 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 (&peer), peerLen, + host, sizeof(host), service, sizeof(service), + /* flags */ NI_NAMEREQD) == 0) { + + return string(host); + } + +#else + + struct hostent *hp; + + if ((hp = gethostbyaddr(reinterpret_cast (&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 +} + + +bool posixSocket::waitForData(const bool read, const bool write, const int msecs) { + + for (int i = 0 ; i <= msecs / 10 ; ++i) { + + // Check whether data is available + pollfd fds[1]; + fds[0].fd = m_desc; + fds[0].events = 0; + + if (read) { + fds[0].events |= POLLIN; + } + + if (write) { + fds[0].events |= POLLOUT; + } + + const int ret = ::poll(fds, sizeof(fds) / sizeof(fds[0]), 10 /* ms */); + + if (ret < 0) { + + if (errno != EAGAIN && errno != EINTR) { + throwSocketError(errno); + } + + } else if (ret > 0) { + + if (fds[0].revents & (POLLIN | POLLOUT)) { + return true; + } + } + + // 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 + throw exceptions::operation_timed_out(); + + } else { + + // Reset timeout + m_timeoutHandler->resetTimeOut(); + } + } + } + + return false; // time out +} + + +bool posixSocket::waitForRead(const int msecs) { + + return waitForData(/* read */ true, /* write */ false, msecs); +} + + +bool posixSocket::waitForWrite(const int msecs) { + + return waitForData(/* read */ false, /* write */ true, msecs); +} + + +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 + if (!waitForRead(50 /* msecs */)) { + + m_status |= STATUS_WOULDBLOCK; + + // Continue waiting for data + return 0; + } + + // Read available data + ssize_t 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 (buffer.data()), buffer.length()); +} + + +void posixSocket::send(const char* str) { + + sendRaw(reinterpret_cast (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) { + +#if VMIME_HAVE_MSG_NOSIGNAL + const ssize_t ret = ::send(m_desc, buffer, size, MSG_NOSIGNAL); +#else + const ssize_t ret = ::send(m_desc, buffer, size, 0); +#endif + + if (ret <= 0) { + + if (ret < 0 && !IS_EAGAIN(errno)) { + throwSocketError(errno); + } + + waitForWrite(50 /* msecs */); + + } 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; + +#if VMIME_HAVE_MSG_NOSIGNAL + const ssize_t ret = ::send(m_desc, buffer, count, MSG_NOSIGNAL); +#else + const ssize_t ret = ::send(m_desc, buffer, count, 0); +#endif + + 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 + throw exceptions::operation_timed_out(); + + } 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) { + + const char* msg = NULL; + + 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 occurred 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: msg = "EPIPE: broken pipe"; break; + case ENOTCONN: msg = "ENOTCONN: not connected"; break; + case ECONNREFUSED: msg = "ECONNREFUSED: connection refused"; break; + } + + if (msg) { + + throw exceptions::socket_exception(msg); + + } else { + + // Use strerror() to get string describing error number + +#if VMIME_HAVE_STRERROR_R + + char errbuf[512]; + + throw exceptions::socket_exception( + vmime_strerror_r_result( + strerror_r(err, errbuf, sizeof(errbuf)), + errbuf + ) + ); + +#else // !VMIME_HAVE_STRERROR_R + + const std::string strmsg(strerror(err)); + throw exceptions::socket_exception(strmsg); + +#endif // VMIME_HAVE_STRERROR_R + + } +} + + +unsigned int posixSocket::getStatus() const { + + return m_status; +} + + +shared_ptr posixSocket::getTimeoutHandler() { + + return m_timeoutHandler; +} + + +void posixSocket::setTracer(const shared_ptr & tracer) { + + m_tracer = tracer; +} + + +shared_ptr posixSocket::getTracer() { + + return m_tracer; +} + + + +// +// posixSocketFactory +// + +shared_ptr posixSocketFactory::create() { + + shared_ptr th; + return make_shared (th); +} + + +shared_ptr posixSocketFactory::create(const shared_ptr & th) { + + return make_shared (th); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES diff --git a/vmime-master/src/vmime/platforms/posix/posixSocket.hpp b/vmime-master/src/vmime/platforms/posix/posixSocket.hpp new file mode 100644 index 0000000..7d732b7 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixSocket.hpp @@ -0,0 +1,118 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard +// +// 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. +// + +#ifndef VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES + + +#include "vmime/net/socket.hpp" + + +struct addrinfo; + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixSocket : public vmime::net::socket { + +public: + + posixSocket(shared_ptr th); + ~posixSocket(); + + void connect(const vmime::string& address, const vmime::port_t port); + bool isConnected() const; + void disconnect(); + + bool waitForRead(const int msecs = 30000); + bool waitForWrite(const int msecs = 30000); + + void receive(vmime::string& buffer); + size_t receiveRaw(byte_t* buffer, const size_t count); + + void send(const vmime::string& buffer); + void send(const char* str); + void sendRaw(const byte_t* buffer, const size_t count); + size_t sendRawNonBlocking(const byte_t* buffer, const size_t count); + + size_t getBlockSize() const; + + unsigned int getStatus() const; + + const string getPeerName() const; + const string getPeerAddress() const; + + shared_ptr getTimeoutHandler(); + + void setTracer(const shared_ptr & tracer); + shared_ptr getTracer(); + +protected: + + void resolve(struct ::addrinfo** addrInfo, const vmime::string& address, const vmime::port_t port); + + bool waitForData(const bool read, const bool write, const int msecs); + + static void throwSocketError(const int err); + +private: + + shared_ptr m_timeoutHandler; + shared_ptr m_tracer; + + byte_t m_buffer[65536]; + int m_desc; + + unsigned int m_status; + + string m_serverAddress; +}; + + + +class posixSocketFactory : public vmime::net::socketFactory { + +public: + + shared_ptr create(); + shared_ptr create(const shared_ptr & th); +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES + +#endif // VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED -- cgit v1.2.3