Created
June 20, 2014 16:00
-
-
Save lnicola/e80b69022115218f4e91 to your computer and use it in GitHub Desktop.
datapipe.c version that saves the data to a file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Datapipe - Create a listen socket to pipe connections to another | |
* machine/port. 'localport' accepts connections on the machine running | |
* datapipe, which will connect to 'remoteport' on 'remotehost'. | |
* It will fork itself into the background on non-Windows machines. | |
* | |
* This implementation of the traditional "datapipe" does not depend on | |
* forking to handle multiple simultaneous clients, and instead is able | |
* to do all processing from within a single process, making it ideal | |
* for low-memory environments. The elimination of the fork also | |
* allows it to be used in environments without fork, such as Win32. | |
* | |
* This implementation also differs from most others in that it allows | |
* the specific IP address of the interface to listen on to be specified. | |
* This is useful for machines that have multiple IP addresses. The | |
* specified listening address will also be used for making the outgoing | |
* connections on. | |
* | |
* Note that select() is not used to perform writability testing on the | |
* outgoing sockets, so conceivably other connections might have delayed | |
* responses if any of the connected clients or the connection to the | |
* target machine is slow enough to allow its outgoing buffer to fill | |
* to capacity. | |
* | |
* Compile with: | |
* cc -O -o datapipe datapipe.c | |
* On Solaris/SunOS, compile with: | |
* gcc -Wall datapipe.c -lsocket -lnsl -o datapipe | |
* On Windows compile with: | |
* bcc32 /w datapipe.c (Borland C++) | |
* cl /W3 datapipe.c wsock32.lib (Microsoft Visual C++) | |
* | |
* Run as: | |
* datapipe localhost localport remoteport remotehost | |
* | |
* | |
* written by Jeff Lawson <jlawson@bovine.net> | |
* inspired by code originally by Todd Vierling, 1995. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <time.h> | |
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) | |
#include <winsock.h> | |
#define bzero(p, l) memset(p, 0, l) | |
#define bcopy(s, t, l) memmove(t, s, l) | |
#else | |
#include <sys/time.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/wait.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> | |
#include <netdb.h> | |
#include <strings.h> | |
#define recv(x,y,z,a) read(x,y,z) | |
#define send(x,y,z,a) write(x,y,z) | |
#define closesocket(s) close(s) | |
typedef int SOCKET; | |
#endif | |
#ifndef INADDR_NONE | |
#define INADDR_NONE 0xffffffff | |
#endif | |
struct client_t { | |
int inuse; | |
SOCKET csock, osock; | |
time_t activity; | |
}; | |
#define MAXCLIENTS 20 | |
#define IDLETIMEOUT 300 | |
int main(int argc, char *argv[]) | |
{ | |
SOCKET lsock; | |
char buf[4096]; | |
struct sockaddr_in laddr, oaddr; | |
int i; | |
FILE *flog = fopen("datapipe.log", "a"); | |
struct client_t clients[MAXCLIENTS]; | |
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) | |
/* Winsock needs additional startup activities */ | |
WSADATA wsadata; | |
WSAStartup(MAKEWORD(1, 1), &wsadata); | |
#endif | |
/* check number of command line arguments */ | |
if (argc != 5) { | |
fprintf(stderr, | |
"Usage: %s localhost localport remotehost remoteport\n", | |
argv[0]); | |
return 30; | |
} | |
/* reset all of the client structures */ | |
for (i = 0; i < MAXCLIENTS; i++) | |
clients[i].inuse = 0; | |
/* determine the listener address and port */ | |
bzero(&laddr, sizeof(struct sockaddr_in)); | |
laddr.sin_family = AF_INET; | |
laddr.sin_port = htons((unsigned short) atol(argv[2])); | |
laddr.sin_addr.s_addr = inet_addr(argv[1]); | |
if (!laddr.sin_port) { | |
fprintf(stderr, "invalid listener port\n"); | |
return 20; | |
} | |
if (laddr.sin_addr.s_addr == INADDR_NONE) { | |
struct hostent *n; | |
if ((n = gethostbyname(argv[1])) == NULL) { | |
perror("gethostbyname"); | |
return 20; | |
} | |
bcopy(n->h_addr, (char *) &laddr.sin_addr, n->h_length); | |
} | |
/* determine the outgoing address and port */ | |
bzero(&oaddr, sizeof(struct sockaddr_in)); | |
oaddr.sin_family = AF_INET; | |
oaddr.sin_port = htons((unsigned short) atol(argv[4])); | |
if (!oaddr.sin_port) { | |
fprintf(stderr, "invalid target port\n"); | |
return 25; | |
} | |
oaddr.sin_addr.s_addr = inet_addr(argv[3]); | |
if (oaddr.sin_addr.s_addr == INADDR_NONE) { | |
struct hostent *n; | |
if ((n = gethostbyname(argv[3])) == NULL) { | |
perror("gethostbyname"); | |
return 25; | |
} | |
bcopy(n->h_addr, (char *) &oaddr.sin_addr, n->h_length); | |
} | |
/* create the listener socket */ | |
if ((lsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |
perror("socket"); | |
return 20; | |
} | |
if (bind(lsock, (struct sockaddr *) &laddr, sizeof(laddr))) { | |
perror("bind"); | |
return 20; | |
} | |
if (listen(lsock, 5)) { | |
perror("listen"); | |
return 20; | |
} | |
/* change the port in the listener struct to zero, since we will | |
* use it for binding to outgoing local sockets in the future. */ | |
laddr.sin_port = htons(0); | |
/* fork off into the background. */ | |
#if !defined(__WIN32__) && !defined(WIN32) && !defined(_WIN32) | |
if ((i = fork()) == -1) { | |
perror("fork"); | |
return 20; | |
} | |
if (i > 0) | |
return 0; | |
setsid(); | |
#endif | |
/* main polling loop. */ | |
while (1) { | |
fd_set fdsr; | |
int maxsock; | |
struct timeval tv = { 1, 0 }; | |
time_t now = time(NULL); | |
/* build the list of sockets to check. */ | |
FD_ZERO(&fdsr); | |
FD_SET(lsock, &fdsr); | |
maxsock = (int) lsock; | |
for (i = 0; i < MAXCLIENTS; i++) | |
if (clients[i].inuse) { | |
FD_SET(clients[i].csock, &fdsr); | |
if ((int) clients[i].csock > maxsock) | |
maxsock = (int) clients[i].csock; | |
FD_SET(clients[i].osock, &fdsr); | |
if ((int) clients[i].osock > maxsock) | |
maxsock = (int) clients[i].osock; | |
} | |
if (select(maxsock + 1, &fdsr, NULL, NULL, &tv) < 0) { | |
return 30; | |
} | |
/* check if there are new connections to accept. */ | |
if (FD_ISSET(lsock, &fdsr)) { | |
SOCKET csock = accept(lsock, NULL, 0); | |
for (i = 0; i < MAXCLIENTS; i++) | |
if (!clients[i].inuse) | |
break; | |
if (i < MAXCLIENTS) { | |
/* connect a socket to the outgoing host/port */ | |
SOCKET osock; | |
if ((osock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |
perror("socket"); | |
closesocket(csock); | |
} else | |
if (bind | |
(osock, (struct sockaddr *) &laddr, | |
sizeof(laddr))) { | |
perror("bind"); | |
closesocket(csock); | |
closesocket(osock); | |
} else | |
if (connect | |
(osock, (struct sockaddr *) &oaddr, | |
sizeof(oaddr))) { | |
perror("connect"); | |
closesocket(csock); | |
closesocket(osock); | |
} else { | |
clients[i].osock = osock; | |
clients[i].csock = csock; | |
clients[i].activity = now; | |
clients[i].inuse = 1; | |
} | |
} else { | |
fprintf(stderr, "too many clients\n"); | |
closesocket(csock); | |
} | |
} | |
/* service any client connections that have waiting data. */ | |
for (i = 0; i < MAXCLIENTS; i++) { | |
int nbyt, closeneeded = 0; | |
if (!clients[i].inuse) { | |
continue; | |
} else if (FD_ISSET(clients[i].csock, &fdsr)) { | |
if ((nbyt = | |
recv(clients[i].csock, buf, sizeof(buf), 0)) <= 0 | |
|| send(clients[i].osock, buf, nbyt, 0) <= 0) | |
closeneeded = 1; | |
else { | |
clients[i].activity = now; | |
fprintf(flog, "%s", buf); | |
fflush(flog); | |
bzero(buf, sizeof(buf)); | |
} | |
} else if (FD_ISSET(clients[i].osock, &fdsr)) { | |
if ((nbyt = | |
recv(clients[i].osock, buf, sizeof(buf), 0)) <= 0 | |
|| send(clients[i].csock, buf, nbyt, 0) <= 0) | |
closeneeded = 1; | |
else { | |
clients[i].activity = now; | |
fprintf(flog, "%s", buf); | |
fflush(flog); | |
bzero(buf, sizeof(buf)); | |
} | |
} else if (now - clients[i].activity > IDLETIMEOUT) { | |
closeneeded = 1; | |
} | |
if (closeneeded) { | |
closesocket(clients[i].csock); | |
closesocket(clients[i].osock); | |
clients[i].inuse = 0; | |
} | |
} | |
} | |
fclose(flog); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment