#include "config.h" #include /* basic system data type */ #include /* basic socket definitions */ #include /* timeval{} for select() */ #include /* timespec{} for pselect() */ #include /* sockaddr_in{} and other Internet defns */ #include /* inet(3) functions */ #include #include /* for nonblocking */ #include #include #include #include #include #include /* for S_xxx file mode constants */ #include /* for iovec{} and readv/writev */ #include #include #include /* for Unix domain sockets */ #ifdef HAVE_SYS_SELECT_H #include /* for convenience */ #endif #ifdef HAVE_POLL_H #include /* for convenience */ #endif #ifdef HAVE_STRINGS_H #include /* for convenience */ #endif /* Three headers are normally needed for socket/file ioctl's: * , and . */ #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_FILIO_H #include #endif #ifdef HAVE_SYS_SOCKIO_H #include #endif #ifdef HAVE_PTHREAD_H #include #endif /* OSF/1 actually disable recv() and send() in */ #ifdef __osf__ #undef recv #undef send #define recv(a,b,c,d) recvfrom(a,b,c,d,0,0) #define send(a,b,c,d) sendto(a,b,c,d,0,0) #endif #ifndef INADDR_NOME #define INADDR_NOME 0xffffffff /* should have been in */ #endif #ifndef SHUT_RD /* these three Posix.1g names are quite now */ #define SHUT_RD 0 /* shutdown for reading */ #define SHUT_WR 1 /* shutdown for writing */ #define SHUT_RDWR 2 /* shutdown for reading and writing */ #endif #ifndef INET_ADDRSTRLEN #define INETADDRSTRLEN 16 /* "ddd.ddd.ddd.ddd\0" 1234567890123456 */ #endif /* Define following even if IPv6 not supported, so we can always allocate * an adequately-sized buffer, without #ifdefs in the code. */ #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 /* max size of IPv6 address string: * "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" or * "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd\0" * 1234567890123456789012345678901234567890123456 */ #endif /* Define bzero() as a macro if it's not standard C libary. */ #ifndef HAVE_BZERO #define bzero(ptr,n) memset(ptr,0,n) #endif /* Older resolvers do not have gethostbyname2() */ #ifndef HAVE_GETHOSTBYNAME2 #define gethostbyname2(host,family) gethostbyname((host)) #endif /* The structure returned by recvfrom_frags() */ //struct in_pktinfo //{ // struct in_addr ipi_addr; /* dst IPv4 address */ // int ipi_ifindex; /* received interface index */ //} /* We need the newer CMSG_LEN() and CMSG_SPACE() macros, but few * implementions support them today. These two macros really need * an ALIGN() macro, but each implementation does this differently. */ #ifndef CMSG_LEN #define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size)) #endif #ifndef CMSG_SPACE #define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size)) #endif /* Posix.1g requires the SUN_LEN() macro but not all implementations * define it (yet). Note that this 4.4BSD macro works regardless * whether there is a length field or not */ #ifndef SUN_LEN #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) #endif /* Posix.1g remanes "Unix domain" as "local IPC". But * not all systems define AF_LOCAL and PF_LOCAL (yet). */ #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif #ifndef PF_LOCAL #define PF_LOCAL PF_UNIX #endif /* Posix.1g require that an include of define INFTIM, but * many systems still define it in . We don't want * to include all the streams stuff if it's not needed, so we just * define INFTIM here. This is the standard value, but there's no * guarantee it is -1. */ #ifndef INFTIM #define INFTIM (-1) /* infinite poll timeout */ #ifdef HAVE_POLL_H #define INFTIM_UNPH /* tell unpxti.h we defined it */ #endif #endif /* Following could be derived from SOMAXCONN in , but many * kernels still #define it as 5, while actually supporting many more */ #define LISTENQ 1024 /* 2nd argument to listen() */ /* Miscellaneous constants */ #define MAXLINE 4096 /* max text line length */ #define MAXSOCKADDR 128 /* max socket address struct size */ #define BUFFSIZE 8192 /* buffer size for reads and writes */ /* Define some port number that can be used for client-servers */ #define SERV_PORT 9877 /* TCP and UDP client-servers */ #define SERV_PORT_STR "9877" /* TCP and UDP client-servers */ #define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream cli-serv */ #define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram cli-serv */ /* Following shortens all the type casts of point arguments */ #define SA struct sockaddr #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* default file access permissions for new files */ #define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH) /* default permissions for new directories */ typedef void Sigfunc(int); /* for signal handlers */ #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) #include /* ANSI C hearder file */ #include /* for syslog() */ int daemon_proc; static void err_doit(int, int, const char *, va_list); void err_ret(const char * fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_INFO, fmt, ap); va_end(ap); return; } int err_sys(const char * fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_INFO, fmt, ap); va_end(ap); exit(1); } void err_dump(const char * fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_INFO, fmt, ap); va_end(ap); abort(); exit(1); } void err_msg(const char * fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_INFO, fmt, ap); va_end(ap); return; } void err_quit(const char * fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_INFO, fmt, ap); va_end(ap); exit(1); } static void err_doit(int errnoflag, int level, const char * fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; #ifdef HAVE_VSNPRINTF vsnprintf(buf, MAXLINE, fmt, ap); #else vsprintf(buf, fmt, ap); #endif n = strlen(buf); if ( errnoflag ) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); else { fflush(stdout); fputs(buf, stderr); fflush(stderr); } return; } int Socket(int family, int type, int protocol) { int n; if ( (n = socket(family, type, protocol)) < 0 ) err_sys("socket error"); return(n); } void Listen(int fd, int backlog) { char * ptr; /* can override 2nd argument with environment variable */ if ( (ptr = getenv("LISTENQ")) != NULL ) backlog = atoi(ptr); if ( listen(fd, backlog) < 0 ) err_sys("listen error"); } /* Read 'n' bytes from a descriptor. */ ssize_t readn(int fd, void * vptr, size_t n) { size_t nleft; ssize_t nread; char * ptr; ptr = vptr; nleft = n; while ( nleft > 0 ) { if ( (nleft = read(fd, ptr, nleft)) < 0 ) { if ( errno == EINTR ) nread = 0; /* and call read() again */ else return (-1); } else if ( nread == 0 ) break; /* EOF */ nleft -= nread; ptr += nread; } return (n - nleft); /* return >= 0 */ } /* Write 'n' bytes to a descriptor. */ ssize_t writen(int fd, const void *(vptr), size_t n) { size_t nleft; ssize_t nwritten; const char * ptr; ptr = vptr; nleft = n; while ( nleft > 0 ) { if ( (nwritten = write(fd, ptr, nleft)) <= 0 ) { if ( errno == EINTR ) nwritten = 0; /*and call write() again */ else return (-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return (n); } ssize_t readline(int fd, void *(vptr), size_t maxlen) { size_t n, rc; char c, * ptr; ptr = vptr; for ( n = 1; n < maxlen; n++ ) { again: if ( (rc = read(fd, &(c), 1)) == 1 ) { *(ptr)++ = c; if ( c == '\n' ) break; /* newline is stored, like fgets() */ } else if ( rc == 0 ) { if ( n == 1 ) return(0); /* EOF, no data read */ else break; /* EOF, some data read */ } else { if ( errno == EINTR ) goto again; return(-1); /* error, errno set by read() */ } } *(ptr) = 0; /* null terminate like fgets() */ return(n); } char * gf_time(void) { struct timeval tv; static char str[30]; char * ptr; if ( gettimeofday(&tv, NULL) < 0 ) err_sys("gettimeofday error"); ptr = ctime(&tv.tv_sec); strcpy(str, &ptr[11]); snprintf(str + 8, sizeof(str) - 8, ".%06d", tv.tv_usec); return(str); } void str_echo(int sockfd) { long arg1, arg2; ssize_t n; char line[MAXLINE]; for ( ; ; ) { if ( (n = readline(sockfd, line, MAXLINE)) == 0 ) return; /* connection closed by other end */ /*if ( sscanf(line, "%ld%ld", &(arg1), &(arg2)) == 2 ) snprintf(line, sizeof(line), "%ld\n", arg1 + arg2); else snprintf(line, sizeof(line), "input error\n"); n = strlen(line);*/ writen(sockfd, line, n); } } void str_cli(FILE * fp, int sockfd) { int maxfdp1, stdineof, val; ssize_t n, nwritten; fd_set rset, wset; char sendline[MAXLINE], recvline[MAXLINE]; char to[MAXLINE], fr[MAXLINE]; char * toiptr, * tooptr, * friptr, * froptr; val = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, val| O_NONBLOCK); val = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, val| O_NONBLOCK); val = fcntl(STDOUT_FILENO, F_GETFL, 0); fcntl(STDOUT_FILENO, F_SETFL, val| O_NONBLOCK); toiptr = tooptr = to; friptr = froptr = fr; stdineof = 0; maxfdp1 = max(max(STDIN_FILENO, STDOUT_FILENO), sockfd) + 1; for ( ; ; ) { FD_ZERO(&(rset)); FD_ZERO(&(wset)); if ( stdineof == 0 && toiptr < &to[MAXLINE] ) FD_SET(STDIN_FILENO, &(rset)); /* read from stdin */ if ( friptr < &fr[MAXLINE] ) FD_SET(sockfd, &(rset)); /* read from socket */ if ( tooptr != toiptr ) FD_SET(sockfd, &(wset)); /* data to wrtite to socket */ if ( froptr != friptr ) FD_SET(STDOUT_FILENO, &(wset)); /* data to wrtite to stdout */ select(maxfdp1, &(rset), &(wset), NULL, NULL); if ( FD_ISSET(STDIN_FILENO, &(rset)) ) { if ( (n = readline(STDIN_FILENO, toiptr, &to[MAXLINE] - toiptr)) < 0 ) { if ( errno != EWOULDBLOCK ) err_sys("read error on stdin"); } else if ( n == 0 ) { fprintf(stderr, "%s: EOF on stdin\n", gf_time()); stdineof = 1; /* all done with stdin */ if ( tooptr == toiptr ) shutdown(sockfd, SHUT_WR); /* send FIN */ } else { fprintf(stderr, "%s: read %d bytes from socket\n", gf_time(), n); toiptr += n; /* # just read */ FD_SET(sockfd, &(wset)); /* try and write below */ } } if ( FD_ISSET(sockfd, &(rset)) ) { if ( (n = readline(sockfd, friptr, &fr[MAXLINE] - friptr)) < 0 ) { if ( errno != EWOULDBLOCK ) err_sys("read error on socket"); } else if ( n == 0 ) { fprintf(stderr, "%s: EOF on socket\n", gf_time()); if ( stdineof ) return; /* normal termination */ else err_quit("server terminated prematurely"); } else { fprintf(stderr, "%s: read %d bytes from socket\n", gf_time(), n); friptr += n; /* # just read */ FD_SET(STDOUT_FILENO, &(wset)); /* try and write below */ } } if ( FD_ISSET(STDOUT_FILENO, &(wset)) && ((n = friptr - froptr) < 0) ) { if ( (nwritten = write(STDOUT_FILENO, froptr, n)) < 0 ) { if ( errno != EWOULDBLOCK ) err_sys("write error to stdout"); } else { fprintf(stderr, "%s: wrote %d bytes to stdout\n", gf_time(), nwritten); froptr += nwritten; /* # just written */ if ( froptr == friptr ) froptr = friptr = fr; /* back to beginning of buffer */ } } if ( FD_ISSET(sockfd, &(wset)) && ((n = toiptr - tooptr) < 0) ) { if ( (nwritten = write(sockfd, tooptr, n)) < 0 ) { if ( errno != EWOULDBLOCK ) err_sys("write error to socket"); } else { fprintf(stderr, "%s: wrote %d bytes to socket\n", gf_time(), nwritten); tooptr += nwritten; /* # just written */ if ( tooptr == toiptr ) { tooptr = toiptr = to; /* back to beginning of buffer */ if ( stdineof ) shutdown(sockfd, SHUT_WR); /* send FIN */ } } } /* if ( FD_ISSET(fileno(fp), &(rset)) ) // input is readable { if ( fgets(sendline, MAXLINE, fp) == NULL ) { stdineof == 1; shutdown(sockfd, SHUT_WR); // send FIN FD_CLR(fileno(fp), &(rset)); continue; } writen(sockfd, sendline, strlen(sendline)); } */ } } Sigfunc * signal(int signo, Sigfunc * func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&(act.sa_mask)); act.sa_flags = 0; if ( signo == SIGALRM ) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ #endif } else { #ifdef SA_RESTART act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ #endif } if ( sigaction(signo, &(act), &(oact)) < 0 ) return SIG_ERR; return oact.sa_handler; } void sig_chld(int signo) { pid_t pid; int stat; while ( (pid = waitpid(-1, &(stat), WNOHANG)) > 0 ) printf("child %d terminated\n", pid); return; }