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++); } }