📄 unix2tcp.c
字号:
/* * Copyright (C) 2002,2003 Mihai RUSU (dizzy@roedu.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/un.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#include <string.h>#include "list.h"#include "unix2tcp.h"/* Global Variable Definitions */static int listensock;static struct sockaddr_in raddr;static char *unixpath;static fd_set trfds, twfds;static int maxsocket = 0, findmax;static t_list *connlist = NULL;volatile static int quitasap = 0;static void dostop(int);static void usage(void);static void packet_destroy(t_packet *);/* Connection handling routines */static int connection_new(int);static int connection_establish(t_connection *);static void connection_destroy(t_connection *);static int socket_nonblock(int);static int init_socket(char *, char *, char *);static void close_socket(void);static int server_read(t_mysocket *, t_mysocket *);static int server_write(t_mysocket *);static void mainloop(void);int main(int argc, char **argv){ if (argc != 4) usage(); signal(SIGINT, dostop); signal(SIGTERM, dostop); fprintf(stderr, "STARTUP\n"); if (init_socket(argv[1], argv[2], argv[3]) < 0) { printf("Error in init_socket()!\n"); return -1; } mainloop(); close_socket(); fprintf(stderr, "SHUTDOWN\n"); return 0;}static int init_socket(char *upath, char *remoteip, char *remoteport){ struct sockaddr_un unixaddr; if (upath == NULL || remoteip == NULL || remoteport == NULL) return -1; if (inet_aton(remoteip, &raddr.sin_addr) == 0) return -1; raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(remoteport)); unixpath = upath; listensock = socket(PF_UNIX, SOCK_STREAM, 0); if (listensock < 0) { fprintf(stderr, "Error doing socket()\n"); return -1; } if (socket_nonblock(listensock) < 0) { fprintf(stderr, "Error trying to set O_NONBLOCK\n"); close(listensock); return -1; } unixaddr.sun_family = AF_UNIX; strcpy(unixaddr.sun_path, unixpath); if (bind(listensock, (struct sockaddr *)&unixaddr, sizeof(unixaddr))) { fprintf(stderr, "Error doing bind()\n"); close(listensock); return -1; } if (chmod(unixpath, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH) < 0) { fprintf(stderr, "Error chmod() (%s)\n", strerror(errno)); close(listensock); return -1; } if (listen(listensock, 5)) { printf("Eroare doing listen()\n"); close(listensock); unlink(unixpath); return -1; } FD_ZERO(&trfds); FD_ZERO(&twfds); FD_SET(listensock, &trfds); if (maxsocket < listensock) maxsocket = listensock; findmax = 100; return 0;}static void close_socket(void){ t_list_elem *elem; /* FIXME: close all incoming/outgoing connections */ if (listensock) close(listensock); unlink(unixpath); if (connlist) { for(elem = LIST_FIRST(connlist); elem ; elem = LIST_NEXT(elem)) { t_connection *c = elem_get_data(elem); if (c) connection_destroy(c); else fprintf(stderr, "close_socket : found NULL entry in conn list\n"); } list_free(connlist); connlist = NULL; } FD_ZERO(&trfds); FD_ZERO(&twfds);}static void mainloop(void){ fd_set rfds, wfds; int res; t_list_elem *elem, *next; if (connlist == NULL && (connlist = list_init()) == NULL) return; while(!quitasap) { memmove(&rfds, &trfds, sizeof(fd_set)); memmove(&wfds, &twfds, sizeof(fd_set)); res = select(maxsocket + 1, &rfds, &wfds, NULL, NULL); if (res == 0) fprintf(stderr, "mainloop() : select returned with 0 fds!\n"); else if (res < 0) switch(errno) { case EINTR: /* got signal */ break; default: fprintf(stderr, "mainloop() : got error in select()(%s)\n", strerror(errno)); } else { if (FD_ISSET(listensock, &rfds)) { int newsock; struct sockaddr addr; socklen_t size; memset(&addr, 0, sizeof(addr)); size = 0; newsock = accept(listensock, &addr, &size); if (newsock < 0) switch(errno) { case EAGAIN: fprintf(stderr, "mainloop() : select returned rdy but accept() would block\n"); break; default: fprintf(stderr, "mainloop() : got error in accept()(%s)\n", strerror(errno)); } else if (connection_new(newsock) < 0) /* could not creat the proxy connection, close the source */ close(newsock); } for(elem = LIST_FIRST(connlist); elem ; elem = next) { t_connection *c = elem_get_data(elem); next = LIST_NEXT(elem); if (c) { res = 0; if (FD_ISSET(c->in.sock, &rfds)) res = server_read(&c->in, &c->out); if (res == 0 && FD_ISSET(c->in.sock, &wfds)) res = server_write(&c->in); if (res == 0 && FD_ISSET(c->out.sock, &rfds)) res = server_read(&c->out, &c->in); if (res == 0 && FD_ISSET(c->out.sock, &wfds)) { if (c->inprogress) res = connection_establish(c); else res = server_write(&c->out); } if (res < 0) quitasap = 1; else if (res > 0) { connection_destroy(c); list_delete_by_elem(connlist, elem); } } else fprintf(stderr, "mainloop() : got NULL entry in in_conn list\n"); } } }}static int server_read(t_mysocket *in, t_mysocket *out){ static char buffer[4096]; t_packet *packet; int res, len; if (in == NULL || out == NULL) { fprintf(stderr, "server_read : Got NULL in/out sockets\n"); return -1; } res = read(in->sock, buffer, sizeof(buffer)); if (res < 0) { switch(errno) { case EAGAIN: /* no data available */ case EINTR: /* call was interupted by a signel before any data was read */ return 0; case ECONNRESET: return 1; default: fprintf(stderr, "server_read : got error in read() (%s)\n", strerror(errno)); return -1; } } if (res == 0) return 1; /* connection closed by peer */ res = write(out->sock, buffer, len = res); if (res == len) return 0; if (res < 0) { switch(errno) { case EPIPE: /* connection closed */ case ECONNRESET: return 1; case EAGAIN: /* would block */ case EINTR: /* interupted in write() */ break; default: fprintf(stderr, "server_read : error in write() (%s)\n", strerror(errno)); return -1; } } else if (res && res < len) { /* sent a part of original data */ len -= res; memmove(buffer, buffer + res, len); } /* could not send read data, so we queue it for later send */ if (out->outqueue == NULL && (out->outqueue = list_init()) == NULL) { fprintf(stderr, "server_read : could not init the outqueue\n"); return -1; } if ((packet = malloc(sizeof(t_packet))) == NULL) { fprintf(stderr, "server_read : could not allocate new packet\n"); return -1; } if ((packet->data = malloc(len)) == NULL) { fprintf(stderr, "server_read : could not allocate for data\n"); free(packet); return -1; } memmove(packet->data, buffer, len); packet->len = len; if (list_append_data(out->outqueue, packet) < 0) { fprintf(stderr, "server_read : could not append packet to out\n"); free(packet->data); free(packet); return -1; } FD_SET(out->sock, &twfds); /* next select() will need to check for writing */ return 0;}static int server_write(t_mysocket *con){ int res; t_list_elem *elem; t_packet *packet; if (con == NULL) { fprintf(stderr, "server_write : got NULL con\n"); return -1; } if (con->outqueue == NULL) { fprintf(stderr, "server_write : got NULL outqueue\n"); return -1; } elem = LIST_FIRST(con->outqueue); if (elem == NULL) { fprintf(stderr, "server_write : outqueue is empty\n"); return -1; } packet = elem_get_data(elem); if (packet == NULL || packet->data == NULL) { fprintf(stderr, "server_write : found NULL packet in outqueue\n"); return -1; } res = write(con->sock, packet->data, packet->len); if (res < 0) { switch(errno) { case EPIPE: /* connection closed */ case ECONNRESET: return 1; case EAGAIN: /* would block */ case EINTR: /* interupted in write() */ return 0; default: fprintf(stderr, "server_write : error in write() (%s)\n", strerror(errno)); return -1; } } if (!res) return 0; /* nothing written */ if (res < packet->len) { /* we wrote fewer bytes than requested */ memmove(packet->data, (char *)packet->data + res, packet->len - res); packet->len -= res; return 0; } packet_destroy(packet); if (list_delete_by_elem(con->outqueue, elem) < 0) { fprintf(stderr, "server_write : could not remove sent packet from outqueue\n"); return -1; } /* outqueue is empty so next select() wont need to check for write */ if (list_get_size(con->outqueue) == 0) FD_CLR(con->sock, &twfds); return 0;}static int connection_new(int newsock){ t_connection *c; int outsock; if (connlist == NULL) return -1; if (newsock < 1) { fprintf(stderr, "connection_new() : got invalid socket\n"); return -1; } c = malloc(sizeof(t_connection)); if (c == NULL) { fprintf(stderr, "connection_new() : could not allocate for new connections\n"); return -1; } outsock = socket(PF_INET, SOCK_STREAM, 0); if (outsock < 1) { fprintf(stderr, "connection_new() : could not create new socket\n"); free(c); return -1; } if (socket_nonblock(outsock) < 0) { fprintf(stderr, "connection_new() : could not set O_NONBLOCK on socket\n"); free(c); close(outsock); return -1; } if (connect(outsock, (struct sockaddr *) &raddr, sizeof(raddr))) { switch(errno) { case EINPROGRESS: /* note a in progress connection */ c->inprogress = 1; break; default: fprintf(stderr, "connection_new() : could not connect()(%s)\n", strerror(errno)); close(outsock); free(c); return -1; } } else c->inprogress = 0; c->in.sock = newsock; c->in.outqueue = NULL; c->out.sock = outsock; c->out.outqueue = NULL; if (list_append_data(connlist, c) < 0) { fprintf(stderr, "connection_new() : could not append new connection to list\n"); close(outsock); free(c); return -1; } if (maxsocket < c->in.sock) maxsocket = c->in.sock; if (maxsocket < c->out.sock) maxsocket = c->out.sock; if (!c->inprogress) { /* connection fully established */ FD_SET(c->in.sock, &trfds); FD_SET(c->out.sock, &trfds); } else FD_SET(c->out.sock, &twfds); /* connection in progress, wait for write */ return 0;}static int connection_establish(t_connection *c){ int error; socklen_t len; if (c == NULL) { fprintf(stderr, "connection_establish() : found NULL connection\n"); return -1; } if (!c->inprogress || c->out.sock <= 0) { fprintf(stderr, "connection_establish() : got invalid connection\n"); return -1; } len = sizeof(error); if (getsockopt(c->out.sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { fprintf(stderr, "connection_establish() : could not getsockopt()\n"); return -1; } if (error) /* could not establish remote connection */ return 1; /* close this connection */ c->inprogress = 0; /* connection established */ FD_CLR(c->out.sock, &twfds); FD_SET(c->in.sock, &trfds); FD_SET(c->out.sock, &trfds); return 0;}static void connection_destroy(t_connection *c){ t_list_elem *elem; t_packet *packet; if (c == NULL) return; close(c->in.sock); close(c->out.sock); FD_CLR(c->in.sock, &trfds); FD_CLR(c->out.sock, &trfds); FD_CLR(c->in.sock, &twfds); FD_CLR(c->out.sock, &twfds); if (--findmax == 0) { t_connection *con; maxsocket = listensock; for(elem = LIST_FIRST(connlist); elem; elem = LIST_NEXT(elem)) { con = elem_get_data(elem); if (con && con != c) { if (con->in.sock > maxsocket) maxsocket = con->in.sock; if (con->out.sock > maxsocket) maxsocket = con->out.sock; } } findmax = 100; } if (c->in.outqueue) { for(elem = LIST_FIRST(c->in.outqueue); elem; elem = LIST_NEXT(elem)) { packet = elem_get_data(elem); if (packet) packet_destroy(packet); else fprintf(stderr, "connection_destroy : found NULL entry in outqueue\n"); } list_free(c->in.outqueue); } if (c->out.outqueue) { for(elem = LIST_FIRST(c->out.outqueue); elem; elem = LIST_NEXT(elem)) { packet = elem_get_data(elem); if (packet) packet_destroy(packet); else fprintf(stderr, "connection_destroy : found NULL entry in outqueue\n"); } list_free(c->out.outqueue); } free(c);}static void packet_destroy(t_packet *packet){ if (packet == NULL) return; if (packet->data) free(packet->data); free(packet);}static int socket_nonblock(int fd){ int flags; flags = fcntl(fd, F_GETFL); if (flags < 0) return -1; flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) return -1; return 0;}static void usage(void){ printf("Usage: unix2tcp <unix-socket> <remote-ip> <remote-port>\n"); exit(-1);}static void dostop(int n){ quitasap = 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -