head 1.11; access; symbols; locks; strict; comment @ * @; 1.11 date 2006.08.03.20.30.48; author wessels; state Exp; branches; next 1.10; 1.10 date 2005.04.07.23.38.00; author wessels; state Exp; branches; next 1.9; 1.9 date 2005.04.07.23.35.42; author wessels; state Exp; branches; next 1.8; 1.8 date 2005.04.06.22.37.09; author wessels; state Exp; branches; next 1.7; 1.7 date 2005.01.19.23.26.05; author wessels; state Exp; branches; next 1.6; 1.6 date 2002.11.27.00.40.31; author wessels; state Exp; branches; next 1.5; 1.5 date 2002.10.22.18.59.37; author wessels; state Exp; branches; next 1.4; 1.4 date 2002.10.22.18.49.15; author wessels; state Exp; branches; next 1.3; 1.3 date 2002.03.26.05.38.35; author wessels; state Exp; branches; next 1.2; 1.2 date 2002.03.26.05.36.38; author wessels; state Exp; branches; next 1.1; 1.1 date 2002.03.26.05.33.51; author wessels; state Exp; branches; next ; desc @@ 1.11 log @fix FD leak @ text @/* * $Id: simple-tcp-proxy.c,v 1.10 2005/04/07 23:38:00 wessels Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUF_SIZE 4096 char client_hostname[64]; void cleanup(int sig) { syslog(LOG_NOTICE, "Cleaning up..."); exit(0); } void sigreap(int sig) { int status; pid_t p; signal(SIGCHLD, sigreap); while ((p = waitpid(-1, &status, WNOHANG)) > 0); /* no debugging in signal handler! */ } void set_nonblock(int fd) { int fl; int x; fl = fcntl(fd, F_GETFL, 0); if (fl < 0) { syslog(LOG_ERR, "fcntl F_GETFL: FD %d: %s", fd, strerror(errno)); exit(1); } x = fcntl(fd, F_SETFL, fl | O_NONBLOCK); if (x < 0) { syslog(LOG_ERR, "fcntl F_SETFL: FD %d: %s", fd, strerror(errno)); exit(1); } } int create_server_sock(char *addr, int port) { int addrlen, s, on = 1, x; static struct sockaddr_in client_addr; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) err(1, "socket"); addrlen = sizeof(client_addr); memset(&client_addr, '\0', addrlen); client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = inet_addr(addr); client_addr.sin_port = htons(port); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 4); x = bind(s, (struct sockaddr *) &client_addr, addrlen); if (x < 0) err(1, "bind %s:%d", addr, port); x = listen(s, 5); if (x < 0) err(1, "listen %s:%d", addr, port); syslog(LOG_NOTICE, "listening on %s port %d", addr, port); return s; } int open_remote_host(char *host, int port) { struct sockaddr_in rem_addr; int len, s, x; struct hostent *H; int on = 1; H = gethostbyname(host); if (!H) return (-2); len = sizeof(rem_addr); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return s; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 4); len = sizeof(rem_addr); memset(&rem_addr, '\0', len); rem_addr.sin_family = AF_INET; memcpy(&rem_addr.sin_addr, H->h_addr, H->h_length); rem_addr.sin_port = htons(port); x = connect(s, (struct sockaddr *) &rem_addr, len); if (x < 0) { close(s); return x; } set_nonblock(s); return s; } int get_hinfo_from_sockaddr(struct sockaddr_in addr, int len, char *fqdn) { struct hostent *hostinfo; hostinfo = gethostbyaddr((char *) &addr.sin_addr.s_addr, len, AF_INET); if (!hostinfo) { sprintf(fqdn, "%s", inet_ntoa(addr.sin_addr)); return 0; } if (hostinfo && fqdn) sprintf(fqdn, "%s [%s]", hostinfo->h_name, inet_ntoa(addr.sin_addr)); return 0; } int wait_for_connection(int s) { static int newsock, len; static struct sockaddr_in peer; len = sizeof(struct sockaddr); syslog(LOG_INFO, "calling accept FD %d", s); newsock = accept(s, (struct sockaddr *) &peer, &len); /* dump_sockaddr (peer, len); */ if (newsock < 0) { if (errno != EINTR) { syslog(LOG_NOTICE, "accept FD %d: %s", s, strerror(errno)); return -1; } } get_hinfo_from_sockaddr(peer, len, client_hostname); set_nonblock(newsock); return (newsock); } int mywrite(int fd, char *buf, int *len) { int x = write(fd, buf, *len); if (x < 0) return x; if (x == 0) return x; if (x != *len) memmove(buf, buf+x, (*len)-x); *len -= x; return x; } void service_client(int cfd, int sfd) { int maxfd; char *sbuf; char *cbuf; int x, n; int cbo = 0; int sbo = 0; fd_set R; sbuf = malloc(BUF_SIZE); cbuf = malloc(BUF_SIZE); maxfd = cfd > sfd ? cfd : sfd; maxfd++; while (1) { struct timeval to; if (cbo) { if (mywrite(sfd, cbuf, &cbo) < 0 && errno != EWOULDBLOCK) { syslog(LOG_ERR, "write %d: %s", sfd, strerror(errno)); exit(1); } } if (sbo) { if (mywrite(cfd, sbuf, &sbo) < 0 && errno != EWOULDBLOCK) { syslog(LOG_ERR, "write %d: %s", cfd, strerror(errno)); exit(1); } } FD_ZERO(&R); if (cbo < BUF_SIZE) FD_SET(cfd, &R); if (sbo < BUF_SIZE) FD_SET(sfd, &R); to.tv_sec = 0; to.tv_usec = 1000; x = select(maxfd+1, &R, 0, 0, &to); if (x > 0) { if (FD_ISSET(cfd, &R)) { n = read(cfd, cbuf+cbo, BUF_SIZE-cbo); syslog(LOG_INFO, "read %d bytes from CLIENT (%d)", n, cfd); if (n > 0) { cbo += n; } else { close(cfd); close(sfd); syslog(LOG_INFO, "exiting"); _exit(0); } } if (FD_ISSET(sfd, &R)) { n = read(sfd, sbuf+sbo, BUF_SIZE-sbo); syslog(LOG_INFO, "read %d bytes from SERVER (%d)", n, sfd); if (n > 0) { sbo += n; } else { close(sfd); close(cfd); syslog(LOG_INFO, "exiting"); _exit(0); } } } else if (x < 0 && errno != EINTR) { syslog(LOG_NOTICE, "select: %s", strerror(errno)); close(sfd); close(cfd); syslog(LOG_NOTICE, "exiting"); _exit(0); } } } int main(int argc, char *argv[]) { char *localaddr = NULL; int localport = -1; char *remoteaddr = NULL; int remoteport = -1; int client = -1; int server = -1; int master_sock = -1; if (5 != argc) { fprintf(stderr, "usage: %s laddr lport rhost rport\n", argv[0]); exit(1); } localaddr = strdup(argv[1]); localport = atoi(argv[2]); remoteaddr = strdup(argv[3]); remoteport = atoi(argv[4]); assert(localaddr); assert(localport > 0); assert(remoteaddr); assert(remoteport > 0); openlog(argv[0], LOG_PID, LOG_LOCAL4); signal(SIGINT, cleanup); signal(SIGCHLD, sigreap); master_sock = create_server_sock(localaddr, localport); for (;;) { if ((client = wait_for_connection(master_sock)) < 0) continue; if ((server = open_remote_host(remoteaddr, remoteport)) < 0) { close(client); client = -1; continue; } if (0 == fork()) { /* child */ syslog(LOG_NOTICE, "connection from %s fd=%d", client_hostname, client); syslog(LOG_INFO, "connected to %s:%d fd=%d", remoteaddr, remoteport, server); close(master_sock); service_client(client, server); abort(); } close(client); client = -1; close(server); server = -1; } } @ 1.10 log @no debugging (i.e. syslog) in signal handler. It seemed to cause a hang on suse linux add more syslog debugging @ text @d2 1 a2 1 * $Id: simple-tcp-proxy.c,v 1.8 2005/04/06 22:37:09 wessels Exp wessels $ a33 2 extern int sys_nerr, errno; d39 1 a39 1 syslog(LOG_INFO, "Cleaning up..."); d94 1 a94 1 syslog(LOG_INFO, "listening on %s port %d", addr, port); d160 4 a163 2 if (errno != EINTR) perror("accept"); d248 1 a248 1 syslog(LOG_INFO, "select: %s", strerror(errno)); d251 1 a251 1 syslog(LOG_INFO, "exiting"); d293 3 a295 1 if ((server = open_remote_host(remoteaddr, remoteport)) < 0) d297 3 a299 1 if (!fork()) { d302 1 d304 1 d307 1 d309 1 @ 1.9 log @incorrect use of fcntl() to set non-blocking @ text @a49 4 while ((p = waitpid(-1, &status, WNOHANG)) > 0) { syslog(LOG_INFO, "sigreap: pid=%d, status=%d\n", (int) p, status); } /* doh! */ d51 2 d96 1 d158 1 d231 1 d237 1 a237 1 syslog(LOG_INFO, "read %d bytes from SERVER (%d)\n", n, sfd); d243 1 d248 1 d251 1 d296 2 a297 2 syslog(LOG_NOTICE, "connection from %s fd=%d\n", client_hostname, client); syslog(LOG_INFO, "connected to %s:%d fd=%d\n", remoteaddr, remoteport, server); @ 1.8 log @replace perror(), exit() with err() @ text @d2 1 a2 1 * $Id: simple-tcp-proxy.c,v 1.7 2005/01/19 23:26:05 wessels Exp wessels $ d62 2 a63 2 x = fcntl(fd, F_GETFL, &fl); if (x < 0) { d67 1 a67 2 fl |= O_NONBLOCK; x = fcntl(fd, F_SETFL, &fl); @ 1.7 log @check argc before accesing argv[]! reported by Gregor Bruhin @ text @d2 1 a2 1 * $Id: simple-tcp-proxy.c,v 1.6 2002/11/27 00:40:31 wessels Exp $ d13 1 d84 1 a84 1 perror("socket"), exit(1); d94 1 a94 1 perror("bind"), exit(1); d98 1 a98 1 perror("listen"), exit(1); @ 1.6 log @*** empty log message *** @ text @d2 1 a2 1 * $Id$ d257 7 a263 6 char *localaddr = strdup(argv[1]); int localport = atoi(argv[2]); char *remoteaddr = strdup(argv[3]); int remoteport = atoi(argv[4]); int client, server; int master_sock; d269 6 @ 1.5 log @smaller buf size keeps both sides more balanced and gives better throughput @ text @d1 3 @ 1.4 log @numerous bug fixes @ text @d28 1 a28 1 #define BUF_SIZE (1<<18) @ 1.3 log @use set_nonblock() @ text @d28 1 a28 1 #define BUF_SIZE 4096 a33 1 d167 13 d185 2 a186 1 static char buf[BUF_SIZE]; d188 2 d192 2 d198 13 d212 7 a218 3 FD_SET(cfd, &R); FD_SET(sfd, &R); x = select(maxfd, &R, 0, 0, 0); d221 1 a221 1 n = read(cfd, buf, BUF_SIZE); d224 1 a224 1 write(sfd, buf, n); d232 1 a232 1 n = read(sfd, buf, BUF_SIZE); d235 1 a235 1 write(cfd, buf, n); @ 1.2 log @add set_nonblock() @ text @a6 1 #include a13 1 #include d130 1 d164 1 @ 1.1 log @Initial revision @ text @d56 2 a57 3 int read_sock(int fd, char *ptr, int nbytes) d59 12 a70 10 static int nleft, nread; nleft = nbytes; while (nleft > 0) { nread = read(fd, ptr, nleft); if (nread < 0) return (nread); else if (nread == 0) break; nleft -= nread; ptr += nread; a71 1 return (nbytes - nleft); a73 17 int write_sock(int fd, char *ptr, int nbytes) { static int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = write(fd, ptr, nleft > 8192 ? 8192 : nleft); if (nwritten <= 0) { perror("write"); return (nwritten); } nleft -= nwritten; ptr += nwritten; } return (nbytes - nleft); } @