|
ru.unix.bsd- RU.UNIX.BSD ------------------------------------------------------------------ From : Vadim Goncharov 2:5020/400 17 Oct 2005 23:49:28 To : Valentin Davydov Subject : Re: discard server -------------------------------------------------------------------------------- Hi Valentin Davydov! On Mon, 17 Oct 2005 15:53:58 +0000 (UTC); Valentin Davydov wrote about 'discard server': VD> Посоветуйте сабж, пожалуйста. Задача - принимать tcp соединения по некоему VD> порту (например, 9), все приходящие данные дропать, в ответ кроме ackов VD> ничего не посылать, по стандартному таймауту штатно закрывать соединения. VD> При этом чтобы жрало как можно меньше ресурсов, в идеале - только таблицы VD> ядерного tcp/ip стека. Пробовал inetd с его встроенным сервисом, так он VD> нафоркал несколько сотен потомков и скис. Можно, конечно, thttpd взять, VD> но нет ли чего попроще, специально для этой цели? Вот сейчас наваял, жрать должен минимум (естественно, я его проверил толко на маленьких нагрзках). Таймауты - только SO_KEEPALIVE, нормальные лень было делать. >=== begin discard.c === /* Simple discard server (c) Vadim Goncharov, 2005. * Covered by BSD license, no warranty, etc. */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <errno.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <sys/time.h> #include <time.h> #include <sys/stat.h> #include <strings.h> #define DISCARDPORTNUM 9 #define BUFSIZE 4096 #define BYTE unsigned char /* Global vars */ unsigned int listening_port; /* Port on which we listen for connections */ int listening_socket; /* Socket for incoming connections from clients */ BYTE debug; /* 1 for debug mode, else 0 */ int max_sockets; /* max number of clients we can serve */ BYTE quit; /* 1 if time to break endless loop and quit */ fd_set mainset; /* Clients are remebered here */ BYTE buf[BUFSIZE]; /* Dummy input buffer data */ void term_signal(int z) { quit = 1; } void quit_program(void) { int i; close(listening_socket); for (i=0; i < max_sockets; i++) if (FD_ISSET(i, &mainset)) shutdown(i, SHUT_RDWR); } void init_sig(void) { struct sigaction sv; memset(&sv, 0, sizeof(struct sigaction)); sv.sa_flags = 0; sigemptyset(&sv.sa_mask); #ifdef SA_NOCLDWAIT sv.sa_flags |= SA_NOCLDWAIT; #endif #ifdef SA_NOCLDSTOP sv.sa_flags |= SA_NOCLDSTOP; #endif sv.sa_handler = SIG_IGN; /* Don't want broken pipes to kill the server. */ sigaction(SIGPIPE, &sv, NULL); /* ...or any defunct child processes. */ sigaction(SIGCHLD, &sv, NULL); if (debug == 0) /* For daemon safety SIGHUP shouldn't kill us. */ sigaction(SIGHUP, &sv, NULL); sv.sa_handler = term_signal; /* Also, shut down properly. */ sigaction(SIGTERM, &sv, NULL); sigaction(SIGINT, &sv, NULL); } int sock_nonblock(int sock) { int flags; if ((flags = fcntl(sock, F_GETFL, 0)) < 0) { return -1; } /* Non blocking mode */ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { return -1; } return 0; } int get_listening_socket(int port, int set_to_localhost) { int sock; int yes = 1; struct sockaddr_in serv_addr; if(port == 0) return -1; memset (&serv_addr, 0, sizeof(struct sockaddr_in)); /* Create socket */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return -1; } /* Fix the address already in use error */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { return -1; } memset(&serv_addr, 0, sizeof(struct sockaddr_in)); serv_addr.sin_family = AF_INET; if (set_to_localhost) { inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr); } else { serv_addr.sin_addr.s_addr = INADDR_ANY; } serv_addr.sin_port = htons(port); /* Bind socket to port */ if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { return -1; } /* Listen on socket */ if (listen(sock, 100) == -1) { return -1; } /* Put socket into non-blocking mode */ if (sock_nonblock(sock) == -1) { return -1; } return(sock); } void do_read(int fd) { int n, looping; time_t curtime; looping = 1; curtime = time(NULL); /* read from one client for no more than 1 sec */ while ((looping) && (time(NULL) <= curtime)) { /* function central read */ n = read(fd, buf, BUFSIZE); if (n > 0) { continue; } if (n == -1) { /* an error has occured */ if (errno == EINTR) { if (time(NULL) > curtime) { looping = 0; } continue; } looping = 0; if (errno != EAGAIN) { if (debug) printf("Error - In do_read()/read() for fd=%d: %s\n", fd, strerror(errno)); } } if (n == 0) { /* connection closed */ if (debug) printf("Client with fd=%d closed connection\n", fd); looping = 0; /* close client and forget about it */ FD_CLR(fd, &mainset); shutdown(fd, SHUT_RDWR); } } } void get_socket_action(void) { struct sockaddr_in client; int clilen; int yes = 1; fd_set fds; struct timeval tv; int i, nfds, maxfd; time_t curtime; tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&fds); maxfd = listening_socket; /* Add our listening tcp socket to the set... */ if (listening_socket != -1) FD_SET(listening_socket, &fds); /* ... and the established client connections */ for (i=0; i < max_sockets; i++) if (FD_ISSET(i, &mainset)) { /* check in loop for setting maxfd */ FD_SET(i, &fds); if (i > maxfd) maxfd = i; } /* The very central select, where the program should spend most of its time */ nfds = select(maxfd+1, &fds, NULL, NULL, &tv); if (nfds <= 0) { if ((nfds < 0) && (errno != EINTR)) { if (debug) { printf("Error - In get_socket_action()/select(read): %s\n", strerror(errno)); } } return; } /* Check if it's a new connection */ if (FD_ISSET(listening_socket, &fds) && (nfds > 0)) { nfds--; curtime = time(NULL); clilen = sizeof(client); do { i = accept(listening_socket, (struct sockaddr *)&client, &clilen); if (i > 0) break; else if ((errno == EAGAIN) || (errno == ECONNABORTED)) goto check_input; } while ((time(NULL) > curtime) && (errno == EINTR)); if (i < 0) { if (debug) { printf("accept() error: %s\n", strerror(errno)); } goto check_input; } /* Put socket into non-blocking mode */ if (sock_nonblock(i) == -1) { /* can't make socket nonblocking */ close(i); goto check_input; } /* Avoid dead peers */ if (setsockopt(i, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) == -1) { close(i); goto check_input; } /* new user accepted */ FD_SET(i, &mainset); if (debug) printf("New client connected, fd=%d\n", i); } check_input: /* Do input from all clients */ i = 0; while ((i < max_sockets) && (nfds > 0)) { if (FD_ISSET(i, &fds)) { nfds--; do_read(i); } i++; } } int main(int argc, char *argv[]) { int fd; int erret; int x; int pid; /* init vars */ listening_port = DISCARDPORTNUM; max_sockets = getdtablesize(); if(max_sockets > FD_SETSIZE) max_sockets = FD_SETSIZE; listening_socket = -1; debug = 0; quit = 0; FD_ZERO(&mainset); /* prepare server */ if ((listening_socket = get_listening_socket(listening_port, 0)) == -1) { printf("Bind failed.\nRemember, to use a listening port below 1024, you need to be root.\nAlso, make sure that you don't have another instance of the program\nalready running.\n"); return 1; } if ((argc > 1) && ((strcmp(argv[1], "-d")) == 0)) debug = 1; init_sig(); if (debug == 0) { /* Make program a daemon */ pid = fork(); if (pid < 0) { perror("fork"); exit(EXIT_FAILURE); } if (pid > 0) exit(EXIT_SUCCESS); if (setsid() < 0) { perror("setsid"); exit(EXIT_FAILURE); } pid = fork(); if (pid > 0) /* ensure we can't regain control tty */ exit(EXIT_SUCCESS); else if (pid < 0) exit(EXIT_FAILURE);; chdir("/"); umask(0); for (x = 0; x <= 2; x++) { if (close(x) != 0) { printf("Error - When closing fd=%d while daemonizing, exiting\n", x); exit(EXIT_FAILURE); } } fd = open("/dev/null", O_RDWR); if (fd >= 0) { erret = dup2(fd, 1); erret = dup2(fd, 2); } } if (debug) { printf("Discrad server is up and running in debug mode\n"); } /* Main server I/O loop. */ while (quit == 0) { get_socket_action(); } quit_program(); return 0; } >=== end discard.c === -- WBR, Vadim Goncharov. ICQ#166852181 mailto:vadim_nuclight@mail.ru [Moderator of RU.ANTI-ECOLOGY][FreeBSD][http://antigreen.org][LJ:/nuclight] --- slrn/0.9.8.1 on FreeBSD 4.11/i386 * Origin: Nuclear Lightning @ Tomsk, TPU AVTF Hostel (2:5020/400@fidonet) Вернуться к списку тем, сортированных по: возрастание даты уменьшение даты тема автор
Архивное /ru.unix.bsd/10359c2126c7b.html, оценка из 5, голосов 10
|