svmsg_file.h
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stddef.h>
#include <limits.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include "tlpi_hdr.h"
#define SERVER_KEY 0x1aaaaaa1
struct requestMsg{
long mtype;
int clientId;
char pathname[PATH_MAX];
};
#define REQ_MSG_SIZE (offsetof(struct requestMsg, pathname) - \
offsetof(struct requestMsg, clientId) + PATH_MAX)
#define RESP_MSG_SIZE 8192
struct responseMsg{
long mtype;
char data[RESP_MSG_SIZE];
};
#define RESP_MT_FAILURE 1
#define RESP_MT_DATA 2
#define RESP_MT_END 3
svmsg_file_server.c
#include "svmsg_file.h"
static void grimReaper(int sig)
{
int savedErrno;
savedErrno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0)
continue;
errno = savedErrno;
}
static void serveRequest(const struct requestMsg *req)
{
int fd;
ssize_t numRead;
struct responseMsg resp;
fd = open(req->pathname, O_RDONLY);
if(fd == -1)
{
resp.mtype = RESP_MT_FAILURE;
snprintf(resp.data, sizeof(resp.data), "%s", "Couldn't open");
msgsnd(req->clientId, &req, strlen(resp.data) + 1, 0);
exit(EXIT_FAILURE);
}
resp.mtype = RESP_MT_DATA;
while((numRead = read(fd, resp.data, RESP_MSG_SIZE)) > 0)
{
if(msgsnd(req->clientId, &resp, numRead, 0) == -1)
break;
}
resp.mtype = RESP_MT_END;
msgsnd(req->clientId, &resp, 0, 0);
}
int main(int argc, char *argv[])
{
struct requestMsg req;
pid_t pid;
ssize_t msgLen;
int serverId;
struct sigaction sa;
serverId = msgget(SERVER_KEY, IPC_CREAT | IPC_EXCL |
S_IRUSR | S_IWUSR | S_IWGRP);
if(serverId == -1)
{
printf("msgget\n");
exit(EXIT_FAILURE);
}
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = grimReaper;
if(sigaction(SIGCHLD, &sa, NULL) == -1)
{
errMsg("sigaction\n");
}
for(;;)
{
msgLen = msgrcv(serverId, &req, REQ_MSG_SIZE, 0, 0);
if(msgLen == -1)
{
if(errno == EINTR)
continue;
errMsg("msgrcv");
break;
}
pid = fork();
if(pid == -1)
{
errMsg("fork");
break;
}
if(pid == 0)
{
serveRequest(&req);
_exit(EXIT_SUCCESS);
}
}
if(msgctl(serverId, IPC_RMID, NULL) == -1)
errExit("msgctl");
exit(EXIT_SUCCESS);
}
svmsg_file_client.c
#include "svmsg_file.h"
static int clientId;
static void removeQueue( )
{
if(msgctl(clientId, IPC_RMID, NULL) == -1)
{
errExit("msgctl");
}
}
int main(int argc, char *argv[])
{
struct requestMsg req;
struct responseMsg resp;
int serverId, numMsgs;
ssize_t msgLen, totBytes;
if(argc != 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s pathname\n", argv[0]);
serverId = msgget(SERVER_KEY, S_IWUSR);
if(serverId == -1)
errExit("msgget - server message queue");
clientId = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR | S_IWGRP);
if(clientId == -1)
errExit("msgget - client message queue");
if(atexit(removeQueue) != 0)
errExit("atexit");
req.mtype = 1;
req.clientId = clientId;
strncpy(req.pathname, argv[1], sizeof(req.pathname));
req.pathname[sizeof(req.pathname) - 1] = '\0';
if(msgsnd(clientId, &req, REQ_MSG_SIZE, 0) == -1)
errExit("msgsnd");
msgLen = msgrcv(clientId, &req, RESP_MSG_SIZE, 0, 0);
if(msgLen == -1)
errExit("msgrcv");
if(resp.mtype == RESP_MT_FAILURE)
{
printf("%s\n", resp.data);
if(msgctl(clientId, IPC_RMID, NULL) == -1)
errExit("msgctl");
exit(EXIT_FAILURE);
}
totBytes = msgLen;
for(numMsgs = 1; resp.mtype == RESP_MT_DATA; numMsgs++)
{
msgLen = msgrcv(clientId, &resp, RESP_MSG_SIZE, 0, 0);
if(msgLen == -1)
errExit("msgrcv");
totBytes += msgLen;
}
printf("Receivd %ld bytes (%d message)\n", (long)totBytes, numMsgs);
exit(EXIT_SUCCESS);
}