/* -*- C -*- * Лаборатория Сетевых Колыбельных: cable (клиент) * * Copyright (C) 2001 zhaoway * * $Id: cable.c,v 1.15 2001/12/14 01:33:55 zw Exp $ * * Комприляция: gcc -Wall -g -o cable cable.c * * Pri perevode ispol'zovalas' kodirovka KOI8-R */ #include #include #include #include #include #include #include #include #include void banner(void) { printf("Лаборатория Сетевых Колыбельных: cable (клиент) $Revision: 1.14 $\n" "Copyright (C) 2001 zhaoway \n\n"); } void usage(void) { banner(); printf("Использование: cable [размер буфера] [1-й ip] [1-й порт] [2-й ip] [2-й порт] ..\n\n" "o размер буфера указывается в байтах. например 10240.\n" "o порты должны прослушиваться, иначе попытка соединения закончится неудачей.\n" "o должно быть указано по меньшей мере два набора ip:port.\n"); } /* При неудаче возвращает -1. */ int make_socket(struct sockaddr_in *servaddr) { int sockfd; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (connect(sockfd, (struct sockaddr *) servaddr, sizeof(struct sockaddr_in)) == -1) { perror("connect"); return -1; } return sockfd; } /* Возвращает число открытых портов, в случае неудачи оно < 2. */ int cmdline(int argc, char *argv[], int *sockfd[], int *maxline) { struct sockaddr_in *servaddr, tmpaddr; int ports = 2, i; /* У нас должно быть по меньшей мере два соединения. */ servaddr = malloc(ports * sizeof(struct sockaddr_in)); if (servaddr == NULL) { fprintf(stderr, "не хватило памяти!\n"); return 1; } memset(servaddr, 0, sizeof(servaddr)); for (i = 0; i < ports; i++) servaddr[i].sin_family = AF_INET; if (argc < 6 || (*maxline = strtol(argv[1], NULL, 10)) == 0 || (inet_pton(AF_INET, argv[2], &servaddr[0].sin_addr)) <= 0 || (servaddr[0].sin_port = htons(strtol(argv[3], NULL, 10))) == 0 || (inet_pton(AF_INET, argv[4], &servaddr[1].sin_addr)) <= 0 || (servaddr[1].sin_port = htons(strtol(argv[5], NULL, 10))) == 0) { usage(); return 0; } banner(); for ( ; ; ) { if ((argc -= 2) < 6) break; memset(&tmpaddr, 0, sizeof(struct sockaddr_in)); if ((inet_pton(AF_INET, argv[ports * 2 + 2], &tmpaddr.sin_addr)) <= 0) break; if ((tmpaddr.sin_port = htons(strtol(argv[ports * 2 + 3], NULL, 10))) == 0) break; servaddr = realloc(servaddr, (ports + 1) * sizeof(struct sockaddr_in)); servaddr[ports].sin_addr = tmpaddr.sin_addr; servaddr[ports].sin_port = tmpaddr.sin_port; ports++; } *sockfd = malloc(ports * sizeof(int)); if (*sockfd == NULL) { fprintf(stderr, "не хватило памяти!\n"); return 1; } for (i = 0; i < ports; i++) { if (((*sockfd)[i] = make_socket(&servaddr[i])) == -1) { if (i >= --ports) break; servaddr[i] = servaddr[ports]; i--; /* retry */ } } return ports; } int main(int argc, char *argv[]) { int *sockfd, ports, size, maxline, i, j; char *buff; fd_set rset, rset_memo, wset, wset_memo; struct timeval nowait = { 0, 0 }; if ((ports = cmdline(argc, argv, &sockfd, &maxline)) < 2) return 1; buff = (char *) malloc(maxline * sizeof(char)); if (buff == NULL) { fprintf(stderr, "не хватило памяти!\n"); return 1; } FD_ZERO(&rset_memo); FD_ZERO(&wset_memo); for (i = 0; i < ports; i++) { FD_SET(sockfd[i], &rset_memo); FD_SET(sockfd[i], &wset_memo); } /* Ignore this to receive EPIPE. */ signal(SIGPIPE, SIG_IGN); /* Main loop. */ for ( ; ; ) { if (ports < 2) { fprintf(stderr, "кабель поврежден и только %i соединение(я) по прежнему отркрыто(ы)\n", ports); return 1; } /* Готовимся читать. */ rset = rset_memo; /* С какого-нибудь порта посылаются данные? */ if ((select(FD_SETSIZE, &rset, NULL, NULL, &nowait)) <= 0) continue; /* Ищем порт, из которого можно читать. */ for (i = 0; i < ports; i++) { /* Можно ли что-нибудь прочесть из этого порта? */ if (! FD_ISSET(sockfd[i], &rset)) continue; /* А если не получится, то... */ else if ((size = recv(sockfd[i], buff, maxline, 0)) == -1) { perror("recv err"); return errno; } /* А если мы прочли в точности ничего? */ else if (size == 0) continue; /* Что-то прочли, приготовимся к записи. */ wset = wset_memo; /* А если писать мы не можем? */ if ((select(FD_SETSIZE, NULL, &wset, NULL, &nowait)) <= 0) { fprintf(stderr, "Кабель \"поломатый\", с записью ничего не вышло!\n"); return 2; } /* Write. */ for (j = 0; j < ports; j++) { /* Не пишите ответов в порт, посылающий данные. */ if (j != i && FD_ISSET(sockfd[j], &wset)) { /* Проверим возможность записи. */ if ((send(sockfd[j], buff, size, 0)) == -1) { if (errno == EPIPE) { FD_CLR(sockfd[j], &wset); FD_CLR(sockfd[j], &rset); close(sockfd[j]); sockfd[j] = sockfd[--ports]; } else { perror("send err"); return errno; } } } } } /* Цикл, ищущий порт, из которого можно читать. */ } /* Главный цикл. */ }