С розетки - заблокированы на выбор - PullRequest
0 голосов
/ 22 октября 2011

Я работаю над программой клиент-сервер, которая использует вызовы select () для прослушивания нескольких сокетов. Но мой вызов select блокируется, хотя у меня есть сообщение в одном из этих сокетов, вызов select () не распознает его и все еще ждет там неопределенно долго.

В программе 2 объекта: мастер и клиент. Мастер знает количество клиентов, с которыми он будет работать, и ожидает подключения клиентов к нему. Как только он получает подтверждение клиента, он сохраняет свою информацию. Как только все клиенты подключены, он отправляет информацию о соседнем клиенте каждому клиенту, чтобы он мог сформировать сеть. Именно здесь я использую select () для мониторинга многих сокетов, мастер имеет розетку, к которой подключен каждый ребенок тат у клиента есть 3 основных розетки с1-поговорить с мастером s2-child прослушивает соединение на этом сокете соседний - сокет, на котором его сосед ожидает подключения. (т.е. S2 в соседнем) p- сокет, который является результатом соединения от его соседа (accept s2 - возвращает ths) Я использую select для прослушивания сервера, его собственный сокет для входящих соединений и один раз.

Первоначально мой сервер отправляет строку "привет" одному из клиентов, который получает это сообщение и передает его соседу, таким образом, когда строка возвращается обратно к первому дочернему элементу, который получил это сообщение от сервера, он передает это своему соседу. Но все, хотя все дочерние элементы находятся в select (), ожидая ввода. Что может вызвать это ??

void main(int argc, char **argv) {

    int s1, s2, n, server_port, sc1, sc2, rv, rc, left_peer_port;
    int peer_port;
    fd_set writefds, readfds;
    struct timeval tv;
    struct hostent *server_info, *child_info, *left_peer_info;
    int start_flag = 0;

    struct sockaddr_in server, peer, incoming;

    char host_child[64];
    char *left_host = malloc(1);
    char *right_host = malloc(1);
    char buf1[256];
    char buf2[256];

    server_port = atoi(argv[2]);

    //speak to peer using this
    s2 = socket(AF_INET, SOCK_STREAM, 0);
    if (s2 < 0) {
        perror("socket:");
        exit(s2);
    }

    peer_port = server_port + 1;

    gethostname(host_child, sizeof host_child);

    child_info = gethostbyname(host_child);

    if (child_info == NULL) {
        fprintf(stderr, "%s: host not found (%s)\n", argv[0], host_child);
        exit(1);
    }


    peer.sin_family = AF_INET;
    memcpy(&peer.sin_addr, child_info->h_addr_list[0], child_info->h_length);
    int changeport = 0;
    do {
        peer.sin_port = htons(peer_port);
        rc = bind(s2, (struct sockaddr *) &peer, sizeof(peer));

        if (rc < 0) {
            //perror("bind:");
            peer_port++;
            changeport = 1;
            //exit(rc);

        } else {
            changeport = 0;
        }

    } while (changeport == 1);

    if (listen(s2, 100) == -1) {
        perror("listen");
        exit(3);
    }



//Now talk to server

    server_info = gethostbyname(argv[1]);

    if (server_info == NULL) {
        fprintf(stderr, "%s: host not found\n", argv[0]);
        exit(1);
    }


// pretend we've connected both to a server at this point
//speak to server using this
    s1 = socket(AF_INET, SOCK_STREAM, 0);
    if (s1 < 0) {
        perror("socket:");
        exit(s1);
    }


    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);
    memcpy(&server.sin_addr, server_info->h_addr_list[0], server_info->h_length);

//To talk to the server

    sc1 = connect(s1, (struct sockaddr *) &server, sizeof(server));
    if (sc1 < 0) {
        perror("connect:");
        exit(sc1);
    }

    int send_len;
    char *str = malloc(1);
    sprintf(str, "%d", peer_port);
    printf("\nport-here=%s\n", str);


    send_len = send(s1, str, strlen(str), 0);
    if (send_len != strlen(str)) {
        perror("send");
        exit(1);
    }

    int recv_len;
    char buf[100];
    int ref = 0;
    int recv_stage = 0;
    int start_id;


    recv_len = recv(s1, buf, 34, 0);
    if (recv_len < 0) {
        perror("recv");
        exit(1);
    }
    buf[recv_len] = '\0';
    char *temp_port;

    if (!strcmp("close", buf))
        printf("%s", buf);
            //break;
    else {
        char *temp_buffer = malloc(1);
        char *id = malloc(100);
        char *pp = malloc(1);
        strcpy(temp_buffer, buf);

        char *search = ":";
        temp_port = strtok(temp_buffer, search);
        strcpy(buf, temp_port);
        printf("temp_name%s", temp_port);

        temp_port = strtok(NULL, search);
        strcpy(pp, temp_port);
        printf("temp_port%s", temp_port);
        temp_port = strtok(NULL, search);
        strcpy(id, temp_port);
        printf("id%s", temp_port);

        strcpy(temp_port, pp);
        printf("\nbuf=%s\n", buf);
        printf("\nport=%s\n", temp_port);
        printf("\nid=%s\n", id);
        start_id = atoi(id);
    }

//To send packet to its neighbour
    left_peer_info = gethostbyname(buf);
    printf("\nleft host=%s\n", buf);
    if (left_peer_info == NULL) {
        fprintf(stderr, "%s: host not found\n", left_host);
        exit(1);
    }
    left_peer_port = atoi(temp_port);


    int neighbour_socket;
    struct hostent *neighbour_info;
    struct sockaddr_in neighbour;
    neighbour_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (neighbour_socket < 0) {
        perror("socket:");
        exit(neighbour_socket);
    }

    neighbour_info = left_peer_info;


    neighbour.sin_family = AF_INET;
    neighbour.sin_port = htons(left_peer_port);
    memcpy(&neighbour.sin_addr, neighbour_info->h_addr_list[0], neighbour_info->h_length);

    printf("\nconnected to port %d\n", left_peer_port);
    //To talk to the neighbour
    printf("\ncomes here\n");


//Listen on this socket connection for potato

    int send_peer_len;
    int nfds;

    nfds = MAX(MAX(neighbour_socket, s2), s1);

// clear the set ahead of time
    FD_ZERO(&writefds);

// add our descriptors to the set
    FD_SET(neighbour_socket, &writefds);
    FD_SET(s1, &writefds);
    FD_SET(s2, &writefds);

//FD_SET(s2, &writefds);


    FD_ZERO(&readfds);
    FD_SET(neighbour_socket, &readfds);
    FD_SET(s1, &readfds);
    FD_SET(s2, &readfds);

//select()

// since we got s2 second, it's the "greater", so we use that for
// the n param in select()
//n = s1 + 1;

// wait until either socket has data ready to be recv()d (timeout 10.5 secs)
    tv.tv_sec = 10;
    tv.tv_usec = 500000;

    int fds[3];
    fds[0] = s1;
    fds[1] = s2;
    fds[2] = neighbour_socket;
    int p = 0;
    int p_flag = 0;

    while (1) {
        printf("\n nfds = %d , p = %d \n", nfds, p);
        char buf_msg[64];


        //This is where the error occurs  //

        rv = select(nfds, &readfds, NULL, NULL, 0);

        //This is where the error occurs  //

        if (rv == -1) {
            perror("select"); // error occurred in select()
        } else if (rv == 0) {
            printf("Timeout occurred!  No data after 10.5 seconds.\n");
        } else {
            // one or both of the descriptors have data
            //reading message from server
            int select_fd;
            for (select_fd = 0; select_fd <= nfds; select_fd++) {

                if (FD_ISSET(select_fd, &readfds) != 0) {
                    if (select_fd == s1) {

                        recv_len = 0;
                        recv_len = recv(s1, buf_msg, 34, 0);
                        if (recv_len < 0) {
                            perror("recv");
                            exit(1);
                        }
                        buf_msg[recv_len] = '\0';
                        printf("\nreceived from server = %s\n", buf_msg);
                        //send to neighbour

                        int sc3;
                        sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
                        if (sc3 < 0) {
                            perror("connect:");
                            exit(sc3);

                        }

                        str = malloc(1);
                        strcpy(str, buf_msg);
                        send_len = send(neighbour_socket, str, strlen(str), 0);
                        printf("\n send - len - s1  - %d\n", send_len);
                        if (send_len != strlen(str)) {
                            perror("send");
                            exit(1);
                        }
                        start_flag = 1;
                        //FD_CLR(s1, &readfds);

                        printf("\ncrossed server\n");

                    } else if (select_fd == s2) {

                        int list_len = sizeof incoming;
                        printf("\ninside client\n");
                        printf("\nWaiting for accept in S2\n");
                        if (p_flag == 0) {
                            p_flag = 1;
                            p = accept(s2, (struct sockaddr *) &incoming, &list_len);
                            printf("\nConnection accepted in S2\n");
                            if (p < 0) {
                                perror("bind:");
                                exit(rc);
                            }
                        }
                        nfds = MAX(nfds, p);
                        recv_len = 0;
                        buf_msg[recv_len] = '\0';
                        recv_len = recv(p, buf_msg, 34, 0);
                        if (recv_len < 0) {
                            perror("recv");
                            exit(1);
                        }
                        buf_msg[recv_len] = '\0';
                        printf("\nreceived from client = %s\n", buf_msg);
                        //send to neighbour

                        //if(start_id!=1){
                        int sc3;
                        sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
                        if (sc3 < 0) {
                            perror("connect:");
                            //exit(sc3);
                        }
                        //}

                        str = malloc(1);
                        strcpy(str, buf_msg);
                        send_len = send(neighbour_socket, str, strlen(str), 0);
                        printf("\n send - len - s2  - %d\n", send_len);
                        if (send_len != strlen(str)) {
                            perror("send");
                            exit(1);
                        }

                    } else if (select_fd == neighbour_socket) {

                        printf("\ncomes in\n");

                    } else if (select_fd == p && p != 0) {

                        int list_len = sizeof incoming;
                        printf("\ninside p\n");
                        recv_len = 0;
                        buf_msg[recv_len] = '\0';
                        printf("\nwaiting at recv in P\n");

                        recv_len = recv(p, buf_msg, 34, 0);

                        printf("\ncrossed at recv in P\n");
                        if (recv_len < 0) {
                            perror("recv");
                            exit(1);
                        }
                        buf_msg[recv_len] = '\0';
                        printf("\nreceived from client = %s\n", buf_msg);
                        //send to neighbour
                        str = malloc(1);
                        strcpy(str, buf_msg);
                        send_len = send(neighbour_socket, str, strlen(str), 0);
                        printf("\n send - len - neighbour - %d\n", send_len);
                        if (send_len != strlen(str)) {
                            perror("send");
                            exit(1);
                        }
                    }
                }
            }

            FD_ZERO(&readfds);
            //FD_SET(neighbour_socket,&readfds);
            FD_SET(s1, &readfds);
            FD_SET(neighbour_socket, &readfds);

            if (p_flag == 1) {
                printf("\nsetting P\n");
                FD_SET(p, &readfds);
                FD_SET(s2, &readfds);

                p_flag = 0;
            } else {
                printf("\nNot setting P\n");
                FD_SET(s2, &readfds);
            }
        }
    }
    close(s1);
    close(s2);
} 

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 22 октября 2011

Я считаю, Мат нашел основную проблему . Но я думаю, что здесь есть гораздо большая проблема:

int send_len;
char *str=malloc(1);
sprintf(str,"%d",peer_port);
printf("\nport-here=%s\n",str);

Вы испортили свою кучу с помощью sprintf(3) вызова. Возможно, это не важные данные, которые вы перезаписали, и, возможно, malloc(3) никогда не выделит один байт , но это неверное предположение. Вы должны выделить как минимум шесть байтов для номера порта: пять для цифр в 65535 и один для конечного ASCII NUL \0 байта.

  buf[recv_len] = '\0';
  char *temp_port;
  //printf("\n-%s\n",buf);
  if ( !strcmp("close", buf) )
        printf("%s",buf);
    //break;
  else{
    char *temp_buffer=malloc(1);
    char *id=malloc(100);
    char *pp=malloc(1);
    strcpy(temp_buffer,buf);

В предыдущем выделении вы сохранили \0 в конце buf, так что вы, вероятно, работаете со строкой некоторого вида. Но в нескольких строках вы выделяете один байт и затем копируете содержимое buf в этот единственный байт. ASCII NUL будет использовать этот байт полностью, не оставляя места для строки, которую вы получили. Но strcpy(3) не работает таким образом - он скопирует содержимое buf до этого символа '\0' в память, начиная с вашего единственного байта. Вы снова уничтожили свою кучу. Но на этот раз он может перезаписать значительно больше пяти байтов - и все под контролем удаленного узла.

Переполнение кучи чрезвычайно опасно . Я обнаружил более 350 ссылок на уязвимости, которые можно использовать в программах, которые напрямую связаны с переполнением кучи в старом архиве, который у меня есть в проекте Common Vulnerabilities and Exposures .

Не развертывайте эту программу на общедоступных компьютерах, пока не устраните эти проблемы. Это существенный недостаток безопасности. Найдите каждый экземпляр malloc(1) и замените его на правильный объем памяти, который должен быть выделен. Как только вы это сделаете, пожалуйста, запустите вашу программу с MALLOC_CHECK_=1 или под управлением valgrind(1), чтобы помочь вам найти дальнейшие проблемы с выделением памяти.

3 голосов
/ 22 октября 2011

Первым параметром select должен быть максимальный дескриптор файла плюс один .Насколько я могу судить по тому огромному куску кода, который вы разместили, вы забыли это "плюс один".

1 голос
/ 22 октября 2011

Рассматривали ли вы использование poll () вместо select ()? Его легче отлаживать и элегантно масштабировать до любого количества, которое вам нужно.

...