From f5d8287cc6745802a48bc0521fe3ef6d2e94124e Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Sun, 16 Mar 2008 00:16:53 +0100 Subject: [PATCH] basic tcp handling (missing files) --- logging.c | 101 +++++++++++++++++++++++++++++++++++++++ logging.h | 19 ++++++++ sockaddr.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ sockaddr.h | 14 ++++++ tcpsocket.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tcpsocket.h | 12 +++++ 6 files changed, 398 insertions(+) create mode 100644 logging.c create mode 100644 logging.h create mode 100644 sockaddr.c create mode 100644 sockaddr.h create mode 100644 tcpsocket.c create mode 100644 tcpsocket.h diff --git a/logging.c b/logging.c new file mode 100644 index 0000000..fd0ab0b --- /dev/null +++ b/logging.c @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 07/2007 by Olaf Rempel * + * razzor@kopf-tisch.de * + * * + * 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; version 2 of the License * + * * + * 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. * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "logging.h" + +#define BUFSIZE 8192 + +static FILE *log_fd = NULL; +static int log_prio = LOG_EVERYTIME; +static char *buffer = NULL; + +int log_print(int prio, const char *fmt, ...) +{ + va_list az; + int len = 0, retval; + + if (prio < log_prio) + return 0; + + if (buffer == NULL) { + buffer = malloc(BUFSIZE); + if (buffer == NULL) { + fprintf(stderr, "log_print(): out of memory\n"); + return -1; + } + } + + if (log_fd != NULL) { + time_t tzgr; + time(&tzgr); + + len += strftime(buffer, BUFSIZE, "%b %d %H:%M:%S :", localtime(&tzgr)); + } + + va_start(az, fmt); + len += vsnprintf(buffer + len, BUFSIZE - len, fmt, az); + va_end(az); + + if (len < 0 || len >= BUFSIZE) { + errno = 0; + return log_print(LOG_ERROR, "log_print: arguments too long"); + } + + if (errno) { + len += snprintf(buffer + len, BUFSIZE - len, ": %s", strerror(errno)); + errno = 0; + } + + retval = fprintf((log_fd ? log_fd : stderr), "%s\n", buffer); + fflush(log_fd); + return retval; +} + +void log_close(void) +{ + if (buffer) + free(buffer); + + if (log_fd) + fclose(log_fd); +} + +int log_init(const char *logfile) +{ + if (log_fd != NULL) + log_close(); + + log_fd = fopen(logfile, "a"); + if (log_fd == NULL) { + fprintf(stderr, "log_init(): can not open logfile"); + return -1; + } + return 0; +} + +void log_setprio(int prio) +{ + log_prio = prio; +} diff --git a/logging.h b/logging.h new file mode 100644 index 0000000..82d028d --- /dev/null +++ b/logging.h @@ -0,0 +1,19 @@ +#ifndef _LOGGING_H_ +#define _LOGGING_H_ + +#define LOG_DEBUG 5 +#define LOG_INFO 4 +#define LOG_NOTICE 3 +#define LOG_WARN 2 +#define LOG_ERROR 1 +#define LOG_CRIT 0 + +#define LOG_EVERYTIME 0 + +int log_init(const char *logfile); +void log_close(void); +void log_setprio(int prio); + +int log_print(int prio, const char *fmt, ... ); + +#endif /* _LOGGING_H_ */ diff --git a/sockaddr.c b/sockaddr.c new file mode 100644 index 0000000..0559097 --- /dev/null +++ b/sockaddr.c @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright (C) 07/2007 by Olaf Rempel * + * razzor@kopf-tisch.de * + * * + * 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; version 2 of the License * + * * + * 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. * + ***************************************************************************/ +#include +#include +#include + +#include +#include +#include +#include + +int parse_sockaddr(const char *addr, struct sockaddr_in *sa) +{ + char *buf = strdup(addr); + if (buf == NULL) + return -1; + + char *tmp; + char *ipstr = strtok_r(buf, ":", &tmp); + if (ipstr == NULL) { + free(buf); + return -2; + } + + sa->sin_family = AF_INET; + if (inet_pton(AF_INET, ipstr, &sa->sin_addr) <= 0) { + free(buf); + return -3; + } + + char *portstr = strtok_r(NULL, " \r\n", &tmp); + if (portstr == NULL) { + free(buf); + return -4; + } + + int port = atoi(portstr); + if (port < 0 || port > 65535) { + free(buf); + return -5; + } + + sa->sin_port = htons(port); + free(buf); + return 0; +} + +int parse_subnet(const char *addr, struct in_addr *net, struct in_addr *mask) +{ + char *buf = strdup(addr); + if (buf == NULL) + return -1; + + char *tmp; + char *netstr = strtok_r(buf, "/", &tmp); + if (netstr == NULL) { + free(buf); + return -2; + } + + if (inet_pton(AF_INET, netstr, net) <= 0) { + free(buf); + return -3; + } + + char *maskstr = strtok_r(NULL, " \r\n", &tmp); + if (maskstr == NULL) { + mask->s_addr = ~0; + + } else if (inet_pton(AF_INET, maskstr, mask) <= 0) { + int maskbits = atoi(maskstr); + if (maskbits < 0 || maskbits > 32) { + free(buf); + return -4; + } + + mask->s_addr = htonl(~0 << (32 - maskbits)); + } + + free(buf); + return 0; +} + +int get_sockaddr(char *buf, int size, struct sockaddr_in *addr) +{ + return snprintf(buf, size, "%s:%d", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)); +} + +char * get_sockaddr_buf(struct sockaddr_in *addr) +{ + static char ret[24]; + get_sockaddr(ret, sizeof(ret), addr); + return ret; +} + +int same_sockaddr(struct sockaddr_in *a, struct sockaddr_in *b) +{ + return !((a->sin_family ^ b->sin_family) | + (a->sin_addr.s_addr ^ b->sin_addr.s_addr) | + (a->sin_port ^ b->sin_port)); +} diff --git a/sockaddr.h b/sockaddr.h new file mode 100644 index 0000000..6d1d936 --- /dev/null +++ b/sockaddr.h @@ -0,0 +1,14 @@ +#ifndef _SOCKADDR_H_ +#define _SOCKADDR_H_ + +#include + +int parse_sockaddr(const char *addr, struct sockaddr_in *sa); +int parse_subnet(const char *addr, struct in_addr *net, struct in_addr *mask); + +int get_sockaddr(char *buf, int size, struct sockaddr_in *addr); +char * get_sockaddr_buf(struct sockaddr_in *addr); + +int same_sockaddr(struct sockaddr_in *a, struct sockaddr_in *b); + +#endif /* _SOCKADDR_H_ */ diff --git a/tcpsocket.c b/tcpsocket.c new file mode 100644 index 0000000..1c55106 --- /dev/null +++ b/tcpsocket.c @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright (C) 07/2007 by Olaf Rempel * + * razzor@kopf-tisch.de * + * * + * 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; version 2 of the License * + * * + * 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. * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logging.h" +#include "sockaddr.h" + +int tcp_listen(struct sockaddr_in *sa) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0 ) { + log_print(LOG_ERROR, "tcp_listen_socket(): socket()"); + return -1; + } + + int i = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) { + log_print(LOG_ERROR, "tcp_listen_socket(): setsockopt(SO_REUSEADDR)"); + close(sock); + return -1; + } + + if (bind(sock, (struct sockaddr *)sa, sizeof(*sa))) { + log_print(LOG_ERROR, "tcp_listen_socket(): bind(%s)", get_sockaddr_buf(sa)); + close(sock); + return -1; + } + + if (listen(sock, 8)) { + log_print(LOG_ERROR, "tcp_listen_socket(): listen()"); + close(sock); + return -1; + } + return sock; +} + +int tcp_connect(struct sockaddr_in *sa) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0 ) { + log_print(LOG_ERROR, "tcp_connect_socket(): socket()"); + return -1; + } + + int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa)); + if (ret != 0) { + log_print(LOG_ERROR, "tcp_connect(): connect(%s)", get_sockaddr_buf(sa)); + close(sock); + return -1; + } + + return sock; +} + +int tcp_connect_nonblock(struct sockaddr_in *sa) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0 ) { + log_print(LOG_ERROR, "tcp_connect_nonblock(): socket()"); + return -1; + } + + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_GETFL)"); + close(sock); + return -1; + } + + /* non-blocking connect() */ + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK)) { + log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_SETFL)"); + close(sock); + return -1; + } + + int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa)); + if (ret && errno != EINPROGRESS) { + log_print(LOG_ERROR, "tcp_connect_nonblock(): connect(%s)", get_sockaddr_buf(sa)); + close(sock); + return -1; + } + + /* reset EINPROGRESS */ + errno = 0; + + /* all further actions are blocking */ + if (fcntl(sock, F_SETFL, flags)) { + log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_SETFL)"); + close(sock); + return -1; + } + + return sock; +} + +int tcp_connect_error(int fd) +{ + int err; + unsigned int err_size = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_size)) { + log_print(LOG_ERROR, "tcp_connect_error(): getsockopt(SO_ERROR)"); + return -1; + } + + if (err) { + errno = err; + return -1; + } + + return 0; +} diff --git a/tcpsocket.h b/tcpsocket.h new file mode 100644 index 0000000..606dbab --- /dev/null +++ b/tcpsocket.h @@ -0,0 +1,12 @@ +#ifndef _TCPSOCKET_H_ +#define _TCPSOCKET_H_ + +#include + +int tcp_listen(struct sockaddr_in *sa); +int tcp_connect(struct sockaddr_in *sa); + +int tcp_connect_nonblock(struct sockaddr_in *sa); +int tcp_connect_error(int fd); + +#endif // _TCPSOCKET_H_