blob: c6a3622430c6aeb7abd01fed56327b0ffae8ec90 [file] [log] [blame]
/*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "Config.h"
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <stdarg.h>
#include <sys/uio.h>
#include <sys/stat.h>
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h>
#endif
#include "system/Net.h"
/**
* Implementation of the Net Facade for Unix Systems.
*
* @see http://www.mmonit.com/
* @file
*/
/* ---------------------------------------------------------------- Public */
int Net_setNonBlocking(int socket) {
int on = 1;
return (ioctl(socket, FIONBIO, &on) != -1);
}
int Net_setBlocking(int socket) {
int off = 0;
return (ioctl(socket, FIONBIO, &off) != -1);
}
int Net_canRead(int socket, time_t milliseconds) {
int r = 0;
struct pollfd fds[1];
fds[0].fd = socket;
fds[0].events = POLLIN;
do {
r = poll(fds, 1, (int)milliseconds);
} while (r == -1 && errno == EINTR);
return (r > 0);
}
int Net_canWrite(int socket, time_t milliseconds) {
int r = 0;
struct pollfd fds[1];
fds[0].fd = socket;
fds[0].events = POLLOUT;
do {
r = poll(fds, 1, (int)milliseconds);
} while (r == -1 && errno == EINTR);
return (r > 0);
}
size_t Net_read(int socket, void *buffer, size_t size, time_t timeout) {
ssize_t n = 0;
if (size > 0) {
do {
n = read(socket, buffer, size);
} while (n == -1 && errno == EINTR);
if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
if ((timeout == 0) || (Net_canRead(socket, timeout) == false))
return 0;
do {
n = read(socket, buffer, size);
} while (n == -1 && errno == EINTR);
}
}
return n;
}
size_t Net_write(int socket, const void *buffer, size_t size, time_t timeout) {
ssize_t n = 0;
if (size > 0) {
do {
n = write(socket, buffer, size);
} while (n == -1 && errno == EINTR);
if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
if ((timeout == 0) || (Net_canWrite(socket, timeout) == false))
return 0;
do {
n = write(socket, buffer, size);
} while (n == -1 && errno == EINTR);
}
}
return n;
}
int Net_isSocket(int fd) {
struct stat buf;
return (fstat(fd, &buf) == 0 && S_ISSOCK(buf.st_mode));
}