basic tcp handling (missing files)

This commit is contained in:
Olaf Rempel 2008-03-16 00:16:53 +01:00
parent be0608c451
commit f5d8287cc6
6 changed files with 398 additions and 0 deletions

101
logging.c Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#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;
}

19
logging.h Normal file
View File

@ -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_ */

117
sockaddr.c Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
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));
}

14
sockaddr.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _SOCKADDR_H_
#define _SOCKADDR_H_
#include <netinet/in.h>
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_ */

135
tcpsocket.c Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#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;
}

12
tcpsocket.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _TCPSOCKET_H_
#define _TCPSOCKET_H_
#include <netinet/ip.h>
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_