I have a dummy multiplexed server (which echoes requests) working under Linux just fine. I'm testing it on FreeBSD 8.0 and I have a strange behavior. When I use
Code:
int client_fd = accept(server_fd, NULL, NULL);
to accept new clients it works as expected - it handles multiple connections and echoes the requests back. But, if I use
Code:
int client_fd = accept(server_fd, (struct sockaddr *)&client_address, &client_address_len);
then the server can handle only the first client, and all subsequent clients are not accepted. I see no reason for getting client address to affect accepting clients!? In the manual, I see no essential differences between select() under Linux and FreeBSD, and Google does not find such issues. Does any have idea what is the problem?

Here is the code of the entire server. In the problematic scenario (piece of code that is commented out), after the call to accept() the set of readable sockets read_fds does not contain server_fd anymore, no matter that read_fds does not clear server_fd anywhere in the code!? That is caused by calling accept() with client address parameters?
Code:
/*

server_mplex.c
--------------

Single threaded TCP server which uses demultiplexing via 'select' function.

Compile with
	gcc -oserver_mplex server_mplex.c

*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

#ifdef __FreeBSD__
	#include <netinet/in.h>
	#include <sys/select.h>
#endif


int main()
{
	struct addrinfo* server_address;
	struct addrinfo hint;
	int server_fd = 0;
	const char* PORT = "7000";
	const unsigned int MAX_CLIENTS = 5;
	int yes = 1;
	fd_set read_fds;
	int fd_last;
	
	FD_ZERO(&read_fds);

	hint.ai_family = 0;
	hint.ai_socktype = SOCK_STREAM;
	hint.ai_flags = AI_PASSIVE;
	hint.ai_protocol = 0;
	hint.ai_addrlen = 0;
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;

	if (getaddrinfo("localhost", PORT, &hint, &server_address) != 0)
	{
		fprintf(stderr, "main():cannot locate host,exiting program...\n");
		exit(EXIT_FAILURE);
	}

	server_fd = socket(server_address->ai_family, server_address->ai_socktype, server_address->ai_protocol);
	if (server_fd == -1)
	{
		fprintf(stderr, "main():cannot create socket,exiting program...\n");
		exit(EXIT_FAILURE);
	}

	setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
	if (bind(server_fd, server_address->ai_addr, server_address->ai_addrlen) == -1)
	{
		fprintf(stderr, "main():cannot bind,exiting program...\n");
		exit(EXIT_FAILURE);
	}

	freeaddrinfo(server_address);

	if (listen(server_fd, MAX_CLIENTS) == -1)
	{
		fprintf(stderr, "main():cannot listen,exiting program...\n");
		exit(EXIT_FAILURE);
	}
	FD_SET(server_fd, &read_fds);
	fd_last = server_fd;
	
	while (1)
	{
		struct sockaddr_in client_address;
		socklen_t client_address_len = sizeof(struct sockaddr_storage);
		char addr_buf[INET_ADDRSTRLEN];
		int fd;
		fd_set read_fds_copy;
		
		FD_ZERO(&read_fds_copy);
		read_fds_copy = read_fds;		
		if (select(fd_last + 1, &read_fds_copy, NULL, NULL, NULL) == -1)
		{
			fprintf(stderr, "main():error calling 'select()',exiting program...\n");
			exit(EXIT_FAILURE);
		}
		
		for (fd = 0; fd <= fd_last; fd++)
		{
			if (FD_ISSET(fd, &read_fds_copy))
			{
				if (fd == server_fd)
				{
					// new client accepted

					/* code that makes trouble
					int client_fd = accept(server_fd, (struct sockaddr *)&client_address, &client_address_len);
					// the call above removes server_fd from read_fds!?
					if (FD_ISSET(server_fd, &read_fds))
						printf("main():server_fd is in read_fds...\n");
					*/

					int client_fd = accept(server_fd, NULL, NULL);
					if (client_fd == -1)
					{
						printf("main():cannot accept client,sleeping...\n");
						sleep(1);
						continue;
					}
					FD_SET(client_fd, &read_fds);
					if (client_fd > fd_last)
						fd_last = client_fd;
				}
				else
				{
					// client request
				
					const int REQUEST_LEN = 1000;
					char request[REQUEST_LEN];
					int result;

					memset(request, '\0', REQUEST_LEN);
					result = recv(fd, request, REQUEST_LEN, 0);
					if (result <= 0)
					{
						// no request from client
					
						if (result == -1)
							fprintf(stderr, "main():cannot receive request\n");
						else if (result == 0)
							printf("main():client with file descriptor %d closed connection\n", fd);
						close(fd);
						FD_CLR(fd, &read_fds);
						continue;
					}
					else
					{
						// echo client's request
						
						printf("main():request=%s\n", request);
						if (FD_ISSET(fd, &read_fds))
						{
							result = send(fd, request, strlen(request), 0);
							if (result == -1)
							{
								fprintf(stderr, "main():cannot send response\n");
								close(fd);
								continue;
							}
							printf("main():echo sent...\n");
						}
					}
				}
			}
		}
	}
	
	return EXIT_SUCCESS;
}