/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* soio -- usefull routines to simplify sockets handling in manner of regular filedescriptors. void sosetline(int) -- set line termination style time_t sotimeout(sec) -- set timeout in seconds for socket operations, returns old timeout set by sotimeout(). int soread(fdes, buf, siz) -- read socket using select(), returns number of bytes read. int sogets(fdes, buf, siz) -- read line \n terminated. returns number of bytes read. int sosayn(fdes, str, siz) -- put line to socket, terminate with \r\n; returns 0 when ok, other when write fails. int sosay(fdes, str) -- simplified version of sosayn(), do not uses string length. $Id: soio.c,v 1.15 2007/09/10 02:49:13 arkenoi Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "firewall.h" /* this is to be moved into specific .h */ #define SO_LNONE 0 #define SO_LCRLF 1 #define SO_LCR 2 #define SO_LLF 3 static char* moduleId ATTR_UNUSED = "$Id: soio.c,v 1.15 2007/09/10 02:49:13 arkenoi Exp $"; extern int proxy_timeout; extern size_t strlcat(char*,const char*,size_t); extern size_t strlcpy(char*,const char*,size_t); static struct timeval sotimo = { 0L, 0L }; static char crlf[3] = "\r\n"; int proxy_linestyle = SO_LCRLF; void sosetline(t) int t; { bzero(crlf, sizeof(crlf)); switch(t) { case SO_LNONE: break; case SO_LCRLF: (void)strlcpy(crlf, "\r\n", 3); break; case SO_LCR: (void)strlcpy(crlf, "\r", 3); break; case SO_LLF: (void)strlcpy(crlf, "\n", 3); break; } proxy_linestyle = t; return; } time_t sotimeout(sec) int sec; { time_t oldtim = sotimo.tv_sec; if(sec) { sotimo.tv_sec = (sec == -1) ? 0L : (time_t)sec; sotimo.tv_usec = 0L; } return oldtim; } int soread(fd, buf, siz) int fd, siz; char *buf; { fd_set r; struct timeval timo; int x; if (!sotimo.tv_sec) sotimeout(proxy_timeout); timo = sotimo; while (1) { FD_ZERO(&r); FD_SET(fd, &r); x = select(fd + 1, &r, (fd_set *)0, (fd_set *)0, &timo); if (x == 0) { syslog(LLEV, "Network timeout signal after %lu seconds", sotimo.tv_sec); return(-1); } if (x < 0) { if (errno == EINTR) continue; return -1; } break; } x = read(fd, buf, siz); return((x == 0) ? -1 : x); } int sowrite(fd,s,n) int fd, n; char *s; { char *buffer; int x, nleft; fd_set w; struct timeval timo; buffer = s; nleft = n; if (!sotimo.tv_sec) sotimeout(proxy_timeout); timo = sotimo; while ( nleft > 0 ) { if ((x = write(fd, buffer, nleft)) <= 0 ) { if ( errno == EINTR ) x = 0; else if (errno == EAGAIN) { FD_ZERO(&w); FD_SET(fd, &w); switch(select(fd+1,NULL,&w,NULL,&timo)) { case -1: return(-1); case 0: syslog(LLEV, "Network timeout signal after %lu seconds", sotimo.tv_sec); return(-1); } } else return(-1); } nleft -= x; buffer += x; } return n; } int sogets(fd, buf, siz) int fd, siz; char *buf; { int x = 0; while(1) { if(soread(fd, (char *)&buf[x], 1) != 1) return(-1); /* some telnets send NULL-terminated lines in NOECHO :( */ if(buf[x] == '\0') continue; if(buf[x] == '\n') { buf[++x] = '\0'; return(x); } if(++x >= siz) { syslog(LLEV, "fwtksyserr: sogets(): buffer overrun"); return(-1); } } } int sosayn(fd, s, n) int fd, n; char *s; { int tl = strlen(crlf); if(sowrite(fd, s, n) != n) return(1); return(tl ? sowrite(fd, crlf, tl) != tl : 0); } int sosay(fd, s) int fd; char *s; { return(sosayn(fd, s, strlen(s))); }