summaryrefslogtreecommitdiff
path: root/proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'proxy.c')
-rw-r--r--proxy.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/proxy.c b/proxy.c
new file mode 100644
index 0000000..32ae0e2
--- /dev/null
+++ b/proxy.c
@@ -0,0 +1,206 @@
+#include <pthread.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <unistd.h>
+
+#include <poll.h>
+
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+static const char *name;
+
+typedef struct
+{
+ int sock_fd;
+ const char *remote_host;
+ const char *remote_port;
+} ThreadArg;
+
+static void Error(const char *call)
+{
+ fprintf(stderr, "%s:", name);
+ perror(call);
+ exit(EXIT_FAILURE);
+}
+
+static int Connect(const char *n, const char *p)
+{
+ struct addrinfo *addr, *addr_p;
+ struct addrinfo hints = {0};
+ int status;
+ int sock = -1;
+
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ status = getaddrinfo(n, p, &hints, &addr);
+
+ if (status)
+ {
+ fprintf(stderr, "%s: %s\n", name, gai_strerror(status));
+ exit(EXIT_FAILURE);
+ }
+
+ for(addr_p = addr; addr_p && sock == -1; addr_p = addr_p->ai_next)
+ {
+ sock = socket(addr_p->ai_family,
+ addr_p->ai_socktype,
+ addr_p->ai_protocol);
+
+ if (sock != -1)
+ {
+ if (connect(sock, addr_p->ai_addr, addr_p->ai_addrlen) == -1)
+ {
+ close(sock);
+ sock = -1;
+ }
+ }
+ }
+
+ if (sock == -1)
+ {
+ fprintf(stderr, "%s: Failed to connect to %s:%s\n", name, n, p);
+ exit(EXIT_FAILURE);
+ }
+
+ return sock;
+}
+
+static int Server(int p)
+{
+ struct sockaddr_in addr;
+ int sock_fd;
+
+ if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ Error("socket");
+ }
+
+ /* Bind port to address
+ */
+ addr.sin_family=AF_INET;
+ addr.sin_addr.s_addr=INADDR_ANY;
+ addr.sin_port=htons(p);
+
+ if (bind(sock_fd,(void*)&addr,sizeof(addr))==-1)
+ {
+ Error("bind");
+ }
+
+ if (listen(sock_fd,5)==-1)
+ {
+ Error("listen");
+ }
+
+ return sock_fd;
+}
+
+static void *ThreadCode(void *arg)
+{
+ int fd;
+ ThreadArg *ta = arg;
+ struct pollfd fds[2] = {0};
+ int done = 0;
+
+ fd = Connect(ta->remote_host, ta->remote_port);
+
+ fds[0].fd = ta->sock_fd;
+ fds[0].events = POLLRDNORM;
+ fds[1].fd = fd;
+ fds[1].events = POLLRDNORM;
+
+ while(!done)
+ {
+ int f;
+
+ if (poll(fds, 2, -1) == -1)
+ {
+ Error("poll");
+ }
+
+ for(int f = 0; f < 2; f++)
+ {
+ if (fds[f].revents & POLLRDNORM)
+ {
+ char buff[1024];
+ int rd;
+
+ if ((rd = read(fds[f].fd, buff, sizeof buff)) < 1)
+ {
+ done = 1;
+ }
+ else
+ {
+ write(fds[f ^ 1].fd, buff, rd);
+ }
+ }
+ }
+ }
+
+ close(ta->sock_fd);
+ close(fd);
+
+ free(ta);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in addr;
+ char buff[1025];
+ int len;
+ socklen_t addrlen;
+ int sock_fd;
+ int connect_fd;
+
+ name=argv[0];
+
+ if (argc != 4)
+ {
+ fprintf(stderr,"%s: usage %s local_port remote_address remote_port\n",
+ name, name);
+ exit(1);
+ }
+
+ sock_fd = Server((short)atoi(argv[1]));
+
+ printf("%s: socket bound\n",name);
+
+ while(1)
+ {
+ pthread_t thread;
+ ThreadArg *arg;
+
+ printf("%s: accepting\n",name);
+
+ if ((connect_fd=accept(sock_fd,NULL,0))==-1)
+ {
+ Error("accept");
+ }
+
+ if (!(arg = malloc(sizeof *arg)))
+ {
+ Error("malloc");
+ }
+
+ arg->sock_fd = connect_fd;
+ arg->remote_host = argv[2];
+ arg->remote_port = argv[3];
+
+ pthread_create(&thread, NULL, ThreadCode, arg);
+ pthread_detach(thread);
+ }
+
+ return EXIT_SUCCESS;
+}