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