/* -*- C -*- * Лаборатория Сетевых Колыбельных: hub (сервер) * * Copyright (C) 2001 zhaoway * * $Id: hub.c,v 1.6 2001/12/14 01:34:41 zw Exp $ * * Компиляция: gcc -Wall -g -o hub hub.c * * Pri perevode ispol'zovalas' kodirovka KOI8-R */ #include #include #include #include #include #include #include #include #include #include #include void banner(void) { printf("Лаборатория Сетевых Колыбельных: hub (сервер) $Revision: 1.6 $\n" "Copyright(C) 2001 zhaoway \n\n"); } void usage(void) { banner(); printf("Использование: hub [размер буфера] [номер порта tcp] [число портов в хабе]\n\n" "o размер буфера указывается в байтах. например 10240.\n" "o номер порта tcp должен быть не меньше 1024 для того, чтобы не требовались права root\'а.\n" "o в хабе должно быть не менее двух портов. будьте счасливы.\n"); } /* При неудаче возвращает -1. */ int make_socket(short int port) { int listenfd, val; struct sockaddr_in servaddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(port); if ((bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) == -1) { perror("bind err"); return -1; } listen(listenfd, 1); /* Установим сокет неблокирующим. */ val = fcntl(listenfd, F_GETFL); fcntl(listenfd, F_SETFL, val | O_NONBLOCK); return listenfd; } int main(int argc, char *argv[]) { int listenfd, *connfd, maxline, size, port, ports, i, j; fd_set rset, rset_memo, wset, wset_memo; char *buff; struct timeval nowait = { 0, 0 }; if (argc != 4 || (maxline = strtol(argv[1], NULL, 10)) == 0 || (port = strtol(argv[2], NULL, 10)) == 0 || (ports = strtol(argv[3], NULL, 10)) < 2) { usage(); return(0); } banner(); buff = (char *) malloc(maxline * sizeof(char)); if (buff == NULL) { fprintf(stderr, "не хватило памяти!\n"); return 1; } if ((listenfd = make_socket(port)) == -1) { usage(); return -1; } printf("Hub слушает на порте TCP %i\n", port); connfd = malloc(ports * sizeof(int)); if (connfd == NULL) { fprintf(stderr, "не хватило памяти!\n"); return 1; } for (i = 0; i < ports; i++) { connfd[i] = -1; } FD_ZERO(&rset_memo); FD_ZERO(&wset_memo); /* Игнорируем получение EPIPE. */ signal(SIGPIPE, SIG_IGN); /* Главный цикл. */ for ( ; ; ) { for (i = 0; i < ports; i++) { if (connfd[i] == -1) { connfd[i] = accept(listenfd, NULL, NULL); if (connfd[i] != -1) { FD_SET(connfd[i], &rset_memo); FD_SET(connfd[i], &wset_memo); } } } /* Подготовка к чтению. */ rset = rset_memo; /* Нечего читать? */ if ((select(FD_SETSIZE, &rset, NULL, NULL, &nowait)) <= 0) continue; /* Ищем порт, из которого можно что-нибудь прочесть. */ for (i = 0; i < ports; i++) { /* Порт подсоединен и из него можно читать? */ if (connfd[i] == -1 || ! FD_ISSET(connfd[i], &rset)) continue; /* Проблемы с чтением? */ if ((size = recv(connfd[i], buff, maxline, 0)) == -1) { perror("recv err"); return errno; } /* На самом деле ничего не прочитано? */ if (size == 0) continue; /* Готовимся писать. */ wset = wset_memo; /* Нет порта, открытого на запись? */ if ((select(FD_SETSIZE, NULL, &wset, NULL, &nowait)) <= 0) continue; /* В цикле ищем любой пригодный для записи порт. */ for (j = 0; j < ports; j++) { /* Не пишите в порт, если из него читается. */ if (j == i || connfd[j] == -1 || ! FD_ISSET(connfd[j], &wset)) continue; if ((send(connfd[j], buff, size, 0)) == -1) { if (errno == EPIPE) { FD_CLR(connfd[j], &wset); FD_CLR(connfd[j], &rset); close(connfd[j]); connfd[j] = -1; } else { perror("send err"); return errno; } } } } } /* Главный цикл. */ }