/* * Copyright (C) 2010-2016 Free Software Foundation, Inc. * Copyright (C) 2015-2016 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ #include #include #include "gnutls_int.h" #include "errors.h" #include #include #include #include #ifdef _WIN32 # include #else /* !_WIN32 */ # include #endif /* System specific socket function wrappers. */ #ifdef _WIN32 /* Do not use the gnulib functions for sending and receiving data. * Using them makes gnutls only working with gnulib applications. */ #undef send #undef recv #undef select int system_errno(gnutls_transport_ptr p) { int tmperr = WSAGetLastError(); int ret = 0; switch (tmperr) { case WSAEWOULDBLOCK: ret = EAGAIN; break; case NO_ERROR: ret = 0; break; case WSAEINTR: ret = EINTR; break; case WSAEMSGSIZE: ret = EMSGSIZE; break; default: ret = EIO; break; } WSASetLastError(tmperr); return ret; } ssize_t system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size) { return send(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0); } #else /* POSIX */ int system_errno(gnutls_transport_ptr_t ptr) { #if defined(_AIX) || defined(AIX) if (errno == 0) errno = EAGAIN; #endif return errno; } static ssize_t _system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, int iovec_cnt, int flags) { struct msghdr hdr; memset(&hdr, 0, sizeof(hdr)); hdr.msg_iov = (struct iovec *)iovec; hdr.msg_iovlen = iovec_cnt; return sendmsg(GNUTLS_POINTER_TO_INT(ptr), &hdr, flags); } #ifdef MSG_NOSIGNAL ssize_t system_writev_nosignal(gnutls_transport_ptr_t ptr, const giovec_t * iovec, int iovec_cnt) { return _system_writev(ptr, iovec, iovec_cnt, MSG_NOSIGNAL); } #endif ssize_t system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, int iovec_cnt) { return _system_writev(ptr, iovec, iovec_cnt, 0); } #endif ssize_t system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size) { return recv(GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0); } /** * gnutls_system_recv_timeout: * @ptr: A file descriptor (wrapped in a gnutls_transport_ptr_t pointer) * @ms: The number of milliseconds to wait. * * Wait for data to be received from the provided socket (@ptr) within a * timeout period in milliseconds, using select() on the provided @ptr. * * This function is provided as a helper for constructing custom * callbacks for gnutls_transport_set_pull_timeout_function(), * which can be used if you rely on socket file descriptors. * * Returns -1 on error, 0 on timeout, positive value if data are available for reading. * * Since: 3.4.0 **/ int gnutls_system_recv_timeout(gnutls_transport_ptr_t ptr, unsigned int ms) { int ret; int fd = GNUTLS_POINTER_TO_INT(ptr); #ifndef _WIN32 int timeo; struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; pfd.revents = 0; if (ms == GNUTLS_INDEFINITE_TIMEOUT) timeo = -1; else timeo = ms; do { ret = poll(&pfd, 1, timeo); } while(ret == -1 && errno == EINTR); #else fd_set rfds; struct timeval _tv, *tv = NULL; FD_ZERO(&rfds); FD_SET(fd, &rfds); if (ms != GNUTLS_INDEFINITE_TIMEOUT) { _tv.tv_sec = ms/1000; _tv.tv_usec = (ms % 1000) * 1000; tv = &_tv; } ret = select(fd + 1, &rfds, NULL, NULL, tv); #endif if (ret <= 0) return ret; return ret; }