On 04/25/2014 11:02 PM, William Morriss wrote: > Okay I was able to do it without fork. This one been tested on Arch > Linux and Ubuntu. It's simpler I think and also won't give the bind > error. It's below and attached.
William, Thanks for that. I've got it now, I think. The point is I think that you are running out of ephemeral ports on the system. An ephemeral port is a random port number that an Internet domain socket is assigned during any of the following operations: * bind(), specifying a port number of 0 * listen() on an unbound socket * connect() on an unbound socket * sendto() on an unbound socket The point is that port numbers are 16 bits long, and the ephemeral port numbers that are used by unprivileged processes is restricted to the range given in /proc/sys/net/ipv4/ip_local_port_range (see the ip(7) man page). I've appended an even simpler program below that I think produces the error for the same reason as your program. (You may need to run as root and up your open files limit ("ulimit -n") when testing this.) You might want to confirm that it's doing something equivalent your program, in terms of triggering the error. Funnily enough, someone asked me the other day what happens if you run out of ephemeral ports, and I replied that the relevant system call would get an error. The next question was: what error? I said I didn't know (was a way from a machine, so could not check the man page). And now we see that the error is not in a man page. However, things are sadly a little worse than I expected. The various cases above give different errors if the ephemeral port range is exhausted: * listen() and bind() give EADDRINUSE * connect() gives EADDRNOTAVAIL * sendto() gives EAGAIN I will add this text to connect() EADDRNOTAVAIL (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers in the ephemeral port range are currently in use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7). and similar text to the other pages. And I've updated the text in ip(7) to say ip_local_port_range (since Linux 2.2) This file contains two integers that define the default local port range allocated to sockets that are not explicitly bound to a port number—that is, the range used for ephemeral ports. An ephemeral port is allo‐ cated to a socket in the following circumstances: * the port number in a socket address is specified as 0 when calling bind(2); * listen(2) is called on a stream socket that was not previously bound; * connect(2) was called on a socket that was not not previously bound; * sendto(2) is called on a datagram socket that was not not previously bound. Allocation of ephemeral ports starts with the first num‐ ber in ip_local_port_range and ends with the second num‐ ber. If the range of ephemeral ports is exhausted, then the relevant system call returns an error (but see BUGS) Note that the port range in ip_local_port_range should not conflict with the ports used by masquerading (although the case is handled). Also, arbitrary choices may cause problems with some firewall packet filters that make assumptions about the local ports in use. The first number should be at least greater than 1024, or better, greater than 4096, to avoid clashes with well known ports and to minimize firewall problems. Thanks for the report. Cheers, Michael /*#* consume_ephemeral_ports_connect.c Determine what error is generated when connect() is unable to obtain an ephemeral port. Usage: ./consume_ephemeral_ports_connect [num-loops [sleep-secs]] */ /*#** Change history Apr 14 Initial creation */ #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <limits.h> #define errMsg(msg) do { perror(msg); } while (0) #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) int main(int argc, char *argv[]) { struct sockaddr_in svaddr, claddr; int sfd, cfd, afd, limit, j; socklen_t len; limit = (argc > 1) ? atoi(argv[1]) : INT_MAX; sfd = socket(AF_INET, SOCK_STREAM, 0); if (sfd == -1) errExit("socket"); memset(&svaddr, 0, sizeof(struct sockaddr_in)); svaddr.sin_family = AF_INET; svaddr.sin_addr.s_addr = htonl(INADDR_ANY); svaddr.sin_port = 0; if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_in)) == -1) errExit("bind"); len = sizeof(struct sockaddr_in); if (getsockname(sfd, (struct sockaddr *) &svaddr, &len) == -1) errExit("getsockname"); printf("Server port: %d\n", svaddr.sin_port); if (listen(sfd, 50) == -1) errExit("listen"); for (j = 0; j < limit; j++) { cfd = socket(AF_INET, SOCK_STREAM, 0); if (cfd == -1) errExit("socket"); if (connect(cfd, (struct sockaddr *) &svaddr, len) == -1) { errMsg("connect"); if (argc > 2) sleep(atoi(argv[1])); exit(EXIT_FAILURE); } afd = accept(sfd, NULL, 0); if (afd ==-1) errExit("accept"); len = sizeof(struct sockaddr_in); if (getsockname(cfd, (struct sockaddr *) &claddr, &len) == -1) errExit("getsockname"); printf("Client port [%d]: %d\n", j, ntohs(claddr.sin_port)); } if (argc > 2) sleep(atoi(argv[2])); exit(EXIT_SUCCESS); } -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org