diff options
Diffstat (limited to 'proxy.c')
-rw-r--r-- | proxy.c | 206 |
1 files changed, 206 insertions, 0 deletions
@@ -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; +} |