Due to the complexity of this situation I have to reproduce this is the
smallest program I could write that produces "connect: cannot assign
requested address". The first run on my machine, it counts to ~220 and then
fails with errno 99 on all of the client processes. It then fails
immediately if I run it again, but if you wait you'll have to run it again.
Sometimes it fails with "bind: Address already in use" followed by
"connect: Connection refused" from all of the clients; this happens
non-deterministically. Please don't judge this program too harshly because
it serves only to get connect to give that errno. It requires netstat,
which is in package net-tools. The program is below as well as attached.

#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
const int PORTNUM = 2423;
const int BACKLOG = 128;

int in_socketfd;
void handle(int interrupt) {
    sched_yield();
    close(in_socketfd);
    exit(0);
}
void server() {
    // on SIGINT, exit cleanly
    struct sigaction term_act;
    term_act.sa_handler = handle;
    sigemptyset(&term_act.sa_mask);
    term_act.sa_flags = 0;
    if (sigaction(SIGINT, &term_act, NULL)) {
        perror("sigaction");
        exit(errno);
    }
    in_socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (in_socketfd == -1) {
        perror("socket");
        exit(errno);
    }
    struct sockaddr_in in_addr;
    memset(&in_addr,0,sizeof(in_addr));
    in_addr.sin_family = AF_INET;
    in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    in_addr.sin_port = htons(PORTNUM);
    if (bind(in_socketfd, (struct sockaddr*)&in_addr,
        sizeof(struct sockaddr_in))) {
        perror("bind");
        exit(errno);
    };
    if (listen(in_socketfd,BACKLOG)) {
        perror("listen");
        exit(errno);
    }
    while (1) {
        struct sockaddr_in dest;
        socklen_t dest_size = sizeof(struct sockaddr_in);
        int socketfd = accept(in_socketfd, (struct sockaddr*) &dest,
            &dest_size);
        if (socketfd == -1) {
            perror("accept");
            exit(errno);
        }
        char placeholder[15];
        assert(recv(socketfd, placeholder, 15, 0) == 0);
        // close(socketfd);
    }
}

int client() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        return errno;
    }
    struct sockaddr_in dest;
    memset(&dest,0,sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    dest.sin_port = htons(PORTNUM);
    if (connect(sockfd,(struct sockaddr*)&dest,
        sizeof(struct sockaddr_in)) == -1) {
        perror("connect");
        return errno;
    }
    close(sockfd);
    return EXIT_SUCCESS;
}
#define fork_split() \
    do { \
        pid_t pid = fork();

#define fork_join() \
        if (pid) { \
            int child_ret; \
            waitpid(pid, &child_ret, 0); \
            ret = ret || child_ret; \
        } else { \
            exit(ret); \
        } \
    } while (0);
int test() {
    int ret = EXIT_SUCCESS;
    int spid = fork();
    if (spid) {
        // parent : clients

        // wait for server to be listening
        while (WEXITSTATUS(system("netstat -tapen 2>/dev/null | grep
':2423' >/dev/null")) == 1) {
            sched_yield();
        }
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        ret = client();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        kill(spid, SIGINT);
        int s_ret;
        waitpid(spid, &s_ret,0);
        return s_ret || ret;
    } else {
        // child : server
        server();
    }
    return ret;
}
int main() {
    int i = 0;
    while (test() == EXIT_SUCCESS) {
        printf("%i\n",i++);
    }
}


On Fri, Apr 25, 2014 at 8:43 AM, Michael Kerrisk (man-pages) <
mtk.manpa...@gmail.com> wrote:

> William, this report is a little vague... Do you have a *minimal*
> program that demonstrates the problem?
>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
const int PORTNUM = 2423;
const int BACKLOG = 128;

int in_socketfd;
void handle(int interrupt) {
    sched_yield();
    close(in_socketfd);
    exit(0);
}
void server() {
    // on SIGINT, exit cleanly
    struct sigaction term_act;
    term_act.sa_handler = handle;
    sigemptyset(&term_act.sa_mask);
    term_act.sa_flags = 0;
    if (sigaction(SIGINT, &term_act, NULL)) {
        perror("sigaction");
        exit(errno);
    }
    in_socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (in_socketfd == -1) {
        perror("socket");
        exit(errno);
    }
    struct sockaddr_in in_addr;
    memset(&in_addr,0,sizeof(in_addr));
    in_addr.sin_family = AF_INET;
    in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    in_addr.sin_port = htons(PORTNUM);
    if (bind(in_socketfd, (struct sockaddr*)&in_addr,
        sizeof(struct sockaddr_in))) {
        perror("bind");   
        exit(errno);
    };
    if (listen(in_socketfd,BACKLOG)) {
        perror("listen");
        exit(errno);
    }
    while (1) {
        struct sockaddr_in dest;
        socklen_t dest_size = sizeof(struct sockaddr_in);
        int socketfd = accept(in_socketfd, (struct sockaddr*) &dest,
            &dest_size);
        if (socketfd == -1) {
            perror("accept");
            exit(errno);
        }
        char placeholder[15];
        assert(recv(socketfd, placeholder, 15, 0) == 0);
        // close(socketfd);
    }
}

int client() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        return errno;
    }
    struct sockaddr_in dest;
    memset(&dest,0,sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    dest.sin_port = htons(PORTNUM);
    if (connect(sockfd,(struct sockaddr*)&dest,
        sizeof(struct sockaddr_in)) == -1) {
        perror("connect");
        return errno;
    }
    close(sockfd);
    return EXIT_SUCCESS;
}
#define fork_split() \
    do { \
        pid_t pid = fork();

#define fork_join() \
        if (pid) { \
            int child_ret; \
            waitpid(pid, &child_ret, 0); \
            ret = ret || child_ret; \
        } else { \
            exit(ret); \
        } \
    } while (0);
int test() {
    int ret = EXIT_SUCCESS;
    int spid = fork();
    if (spid) {
        // parent : clients

        // wait for server to be listening
        while (WEXITSTATUS(system("netstat -tapen 2>/dev/null | grep ':2423' >/dev/null")) == 1) {
            sched_yield();
        }
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        fork_split();
        ret = client();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        fork_join();
        kill(spid, SIGINT);
        int s_ret;
        waitpid(spid, &s_ret,0);
        return s_ret || ret;
    } else {
        // child : server
        server();
    }
    return ret;
}
int main() {
    int i = 0;
    while (test() == EXIT_SUCCESS) {
        printf("%i\n",i++);
    }
}

Reply via email to