diff options
Diffstat (limited to 'src/libs/network/socket/socket_bsd.c')
-rw-r--r-- | src/libs/network/socket/socket_bsd.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/libs/network/socket/socket_bsd.c b/src/libs/network/socket/socket_bsd.c new file mode 100644 index 0000000..2bf25b8 --- /dev/null +++ b/src/libs/network/socket/socket_bsd.c @@ -0,0 +1,283 @@ +/* + * Copyright 2006 Serge van den Boom <svdb@stack.nl> + * + * 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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// Socket functions for BSD sockets. + +#define SOCKET_INTERNAL +#include "socket.h" + +#include "libs/log.h" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +# include <netinet/in_systm.h> +# include <netinet/in.h> +#endif +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <unistd.h> +#include <fcntl.h> + + +static Socket * +Socket_alloc(void) { + return malloc(sizeof (Socket)); +} + +static void +Socket_free(Socket *sock) { + free(sock); +} + +Socket * +Socket_openNative(int domain, int type, int protocol) { + Socket *result; + int fd; + + fd = socket(domain, type, protocol); + if (fd == -1) { + // errno is set + return Socket_noSocket; + } + + result = Socket_alloc(); + result->fd = fd; + return result; +} + +int +Socket_close(Socket *sock) { + int closeResult; + + do { + closeResult = close(sock->fd); + if (closeResult == 0) { + Socket_free(sock); + return 0; + } + } while (errno == EINTR); + + return -1; +} + +int +Socket_connect(Socket *sock, const struct sockaddr *addr, + socklen_t addrLen) { + int connectResult; + + do { + connectResult = connect(sock->fd, addr, addrLen); + } while (connectResult == -1 && errno == EINTR); + + return connectResult; +} + +int +Socket_bind(Socket *sock, const struct sockaddr *addr, socklen_t addrLen) { + return bind(sock->fd, addr, addrLen); +} + +int +Socket_listen(Socket *sock, int backlog) { + return listen(sock->fd, backlog); +} + +Socket * +Socket_accept(Socket *sock, struct sockaddr *addr, socklen_t *addrLen) { + int acceptResult; + socklen_t tempAddrLen; + + do { + tempAddrLen = *addrLen; + acceptResult = accept(sock->fd, addr, &tempAddrLen); + if (acceptResult != -1) { + Socket *result = Socket_alloc(); + result->fd = acceptResult; + *addrLen = tempAddrLen; + return result; + } + + } while (errno == EINTR); + + // errno is set + return Socket_noSocket; +} + +ssize_t +Socket_send(Socket *sock, const void *buf, size_t len, int flags) { + return send(sock->fd, buf, len, flags); +} + +ssize_t +Socket_sendto(Socket *sock, const void *buf, size_t len, int flags, + const struct sockaddr *addr, socklen_t addrLen) { + return sendto(sock->fd, buf, len, flags, addr, addrLen); +} + +ssize_t +Socket_recv(Socket *sock, void *buf, size_t len, int flags) { + return recv(sock->fd, buf, len, flags); +} + +ssize_t +Socket_recvfrom(Socket *sock, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromLen) { + return recvfrom(sock->fd, buf, len, flags, from, fromLen); +} + +int +Socket_setNonBlocking(Socket *sock) { + int flags; + + flags = fcntl(sock->fd, F_GETFL); + if (flags == -1) { + int savedErrno = errno; + log_add(log_Error, "Getting file descriptor flags of socket failed: " + "%s.", strerror(errno)); + errno = savedErrno; + return -1; + } + + if (fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK) == -1) { + int savedErrno = errno; + log_add(log_Error, "Setting non-blocking mode on socket failed: " + "%s.", strerror(errno)); + errno = savedErrno; + return -1; + } + + return 0; +} + +int +Socket_setReuseAddr(Socket *sock) { + int flag = 1; + + if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof flag) + == -1) { + int savedErrno = errno; + log_add(log_Error, "Setting socket reuse failed: %s.", + strerror(errno)); + errno = savedErrno; + return -1; + } + return 0; +} + +// Send data as soon as it is available. Do not collect data to send at +// once. +int +Socket_setNodelay(Socket *sock) { + int flag = 1; + + if (setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag) + == -1) { +#ifdef DEBUG + int savedErrno = errno; + log_add(log_Warning, "Disabling Nagle algorithm failed: %s.", + strerror(errno)); + errno = savedErrno; +#endif + return -1; + } + return 0; +} + +// 'tos' should be IPTOS_LOWDELAY, IPTOS_THROUGHPUT, IPTOS_THROUGHPUT, +// IPTOS_RELIABILITY, or IPTOS_MINCOST. +int +Socket_setTOS(Socket *sock, int tos) { + if (setsockopt(sock->fd, IPPROTO_IP, IP_TOS, &tos, sizeof tos) == -1) { +#ifdef DEBUG + int savedErrno = errno; + log_add(log_Warning, "Setting socket type-of-service failed: %s.", + strerror(errno)); + errno = savedErrno; +#endif + return -1; + } + return 0; +} + +// This function setups the socket for optimal configuration for an +// interactive connection. +int +Socket_setInteractive(Socket *sock) { + if (Socket_setNodelay(sock) == -1) { + // errno is set + return -1; + } + + if (Socket_setTOS(sock, IPTOS_LOWDELAY) == -1) { + // errno is set + return -1; + } + return 0; +} + +int +Socket_setInlineOOB(Socket *sock) { + int flag = 1; + + if (setsockopt(sock->fd, SOL_SOCKET, SO_OOBINLINE, &flag, sizeof flag) + == -1) { + int savedErrno = errno; + log_add(log_Error, "Setting inline OOB on socket failed: %s", + strerror(errno)); + errno = savedErrno; + return -1; + } + return 0; +} + +int +Socket_setKeepAlive(Socket *sock) { + int flag = 1; + + if (setsockopt(sock->fd, IPPROTO_TCP, SO_KEEPALIVE, &flag, sizeof flag) + == -1) { + int savedErrno = errno; + log_add(log_Error, "Setting keep-alive on socket failed: %s", + strerror(errno)); + errno = savedErrno; + return -1; + } + return 0; +} + +int +Socket_getError(Socket *sock, int *err) { + socklen_t errLen = sizeof(*err); + + if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, err, &errLen) == -1) { + // errno is set + return -1; + } + + assert(errLen == sizeof(*err)); + // err is set + return 0; +} + + |