I'm trying to make a server that takes incoming requests and sends the file
descriptor to one of multiple awaiting forked processes that works on them.
I've simplified the procedure in server_sample.c , where it just sends them
to one receiver. Is there something not being reinitialized after line 104 ?
#include <err.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>

int portno = 8000;


/* called to send a socket connection request to port "portno" */
int client()
{
    int pid;
	switch (pid = fork()) {
	case -1:
		err(1, "cannot fork");
		break;
	case 0:
		break;
	default:
		return (pid);
	}
    
	setvbuf(stdout, NULL, _IOLBF, 0);
	setvbuf(stderr, NULL, _IOLBF, 0);

	int sockfd;
	struct sockaddr_in serv_addr;
	struct hostent *server;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        err(1, "ERROR opening socket");
    server = gethostbyname("localhost");
    if (server == NULL)
        err(1, "ERROR, no such host\n");
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
        (char *)&serv_addr.sin_addr.s_addr,
        server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        err(1,"ERROR connecting to %d\n", portno);
    sleep(1);
    _exit(0);
}


/* sends socket file descriptors generated by client() requests from main */
/* to here twice over socket "s"*/
int receive(int s[2])
{
    int pid;
	switch (pid = fork()) {
	case -1:
		err(1, "cannot fork");
		break;
	case 0:
		break;
	default:
		return (pid);
	}
        
	setvbuf(stdout, NULL, _IOLBF, 0);
	setvbuf(stderr, NULL, _IOLBF, 0);

    int fd = -1;
    
    close(s[1]);
        
    struct msghdr    msg;
    struct cmsghdr  *cmsg;
    union {
	   struct cmsghdr hdr;
	   unsigned char    buf[CMSG_SPACE(sizeof(int))];
    } cmsgbuf;

    memset(&msg, 0, sizeof(msg));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);

    if (recvmsg(s[0], &msg, 0) == -1)
	   err(1, "recvmsg");
    if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
	   errx(1, "control message truncated");
    cmsg = CMSG_FIRSTHDR(&msg);
    if (cmsg != NULL)
    {
        if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
           cmsg->cmsg_level == SOL_SOCKET &&
           cmsg->cmsg_type == SCM_RIGHTS) {
           fd = *(int *)CMSG_DATA(cmsg);
        }
    
        printf("fd == %d\n", fd);
    }
    else
        printf("cmsg == NULL\n");



    /* do it again */



    fd = -1;

    memset(&msg, 0, sizeof(msg));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);

    if (recvmsg(s[0], &msg, 0) == -1)
	   err(1, "recvmsg");
    if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
	   errx(1, "control message truncated");
    cmsg = CMSG_FIRSTHDR(&msg);
    if (cmsg != NULL)
    {
        if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
           cmsg->cmsg_level == SOL_SOCKET &&
           cmsg->cmsg_type == SCM_RIGHTS) {
           fd = *(int *)CMSG_DATA(cmsg);
        }
       
        printf("fd == %d\n", fd);
    }
    else
        printf("cmsg == NULL\n");
   
    sleep(1);
    _exit(0);
}

int main()
{
	setvbuf(stdout, NULL, _IOLBF, 0);
	setvbuf(stderr, NULL, _IOLBF, 0);
    int s[2];
	int sockfd, newsockfd;
	socklen_t clilen;
	struct sockaddr_in serv_addr, cli_addr;


	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
		err(1, "ERROR opening socket");

	bzero(&serv_addr, sizeof(serv_addr));
 	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(portno);
	if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
		err(1, "ERROR on binding on %d", portno);

	if (listen(sockfd,100000) == -1)
		err(1, "listen failed");
	clilen = sizeof(cli_addr);

    if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1)
        err(1, "socketpair"); 
        
    receive(s);
    close(s[0]);
    
    client();
    
    newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);

    struct msghdr    msg;
    struct cmsghdr  *cmsg;
    union {
            struct cmsghdr hdr;
            unsigned char    buf[CMSG_SPACE(sizeof(int))];
    } cmsgbuf;

    memset(&msg, 0, sizeof(msg));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    *(int *)CMSG_DATA(cmsg) = newsockfd;

    if (sendmsg(s[1], &msg, 0) == -1)
	   err(1, "sendmsg");

    close(newsockfd);
    
    client();
    
    newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);

    memset(&msg, 0, sizeof(msg));
    msg.msg_control = &cmsgbuf.buf;
    msg.msg_controllen = sizeof(cmsgbuf.buf);

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    *(int *)CMSG_DATA(cmsg) = newsockfd;

    if (sendmsg(s[1], &msg, 0) == -1)
	   err(1, "sendmsg");

    wait(NULL);
    wait(NULL);
    wait(NULL);

    printf("done\n");
    close(sockfd);
    return 0;
}

Reply via email to