Download | Plain Text | Line Numbers
/*
* Name: gluefile (server(
* Author: Manuel Mausz, 0728348
* Description: Server writes data read from client via IPC message queue to
* file. If filesize is reached server quits automatically. Client
* sends data read from file via IPC message queue to server
* Offset specifies file offset to start writing for server.
* Created: 12.03.2009
* Exercise: 1h B
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include "global.h"
/*
* NAME: sighandler
* PURPOSE:
* signal handler sets global error flag to 1
*
* PARAMETERS:
* int signum ... signal number
*
* RETURN VALUE:
* void
*
* GLOBAL VARS:
* error
*/
static void sighandler(int signum)
{
#ifdef DEBUG
(void) printf("signal %d received\n", signum);
#endif
error = 1;
}
/*
* NAME: usage
* PURPOSE:
* prints program usage to stderr and terminates with EXIT_FAILURE
*
* PARAMETERS:
* void
*
* RETURN VALUE:
* void
*
* GLOBAL VARS:
* me
*/
static void usage(void)
{
(void) fprintf(stderr, "Usage: %s -s size file\n", me);
(void) exit(EXIT_FAILURE);
}
/*
* NAME: recv_write
* PURPOSE:
* writes data read from client via IPC msg queue to stream pointed to by fp.
* maxsize specifies maximum filesize (data to write). function returns after
* maxsize is reached or on error.
*
* PARAMETERS:
* int msgqid ... msg queue id to read from
* FILE *fp ... pointer to stream to write to
* long maxsize ... maximum file size
*
* RETURN VALUE:
* void
*
* GLOBAL VARS:
* error
*/
static void recv_write(int msgqid, FILE *fp, long maxsize)
{
long pos = 0, maxpos = 0;
msg_t msg;
while(!error)
{
/* receive message */
msg.mtype = (maxpos + 1) * -1;
#ifdef DEBUG
(void) printf("messages receiving with offset range [0 - %ld]\n", msg.mtype * -1 - 1);
#endif
if (!error && msgrcv(msgqid, &msg, MSGSIZE, msg.mtype, 0) == -1)
{
(void) printferr("Couldn't receive message");
break;
}
#ifdef DEBUG
(void) printf("received [%ld]+%d bytes from msg queue\n", msg.mtype - 1, msg.len);
#endif
msg.mtype--;
/* ignore messages to big */
if (!error && msg.mtype + msg.len > maxsize)
{
#ifdef DEBUG
(void) printf("message to big. ignoring...\n");
#endif
continue;
}
/* seek to requested position */
if (!error && pos != msg.mtype)
{
#ifdef DEBUG
(void) printf("seeking to %ld\n", msg.mtype);
#endif
if (fseek(fp, msg.mtype, SEEK_SET) == -1)
{
(void) printferr("Unable to seek to requested position");
break;
}
pos = msg.mtype;
}
/* write to file */
if (!error && fwrite(msg.data, sizeof(msg.data[0]), msg.len, fp) < msg.len)
{
(void) printferr("Unable to write data to file");
break;
}
/* update file current position */
pos += msg.len;
if (pos > maxpos)
maxpos = pos;
/* filesize reached */
if (!error && pos == maxsize)
break;
}
}
/*
* NAME: main
* PURPOSE:
* install signal handler, parse commandline options,
* create msg queue and call recv_write
*
* PARAMETERS:
* standard parameters of main
*
* RETURN VALUE:
* int ... 0 on success, 1 on error
*
* GLOBAL VARS:
* me, error
*/
int main(int argc, char *argv[])
{
int opt, msgqid = -1;
long size = 0;
char *endptr;
char *filename = NULL;
FILE *fp = NULL;
struct sigaction new_action, old_action;
/* save me */
me = argv[0];
/* install signal handler */
new_action.sa_handler = sighandler;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0; /* to avoid restart of blocking syscalls */
INSTALL_SIGNAL(SIGINT, new_action, old_action)
INSTALL_SIGNAL(SIGQUIT, new_action, old_action)
INSTALL_SIGNAL(SIGTERM, new_action, old_action)
/* parse cmdline options */
while ((opt = getopt(argc, argv, "s:")) != -1)
{
switch(opt)
{
case 's':
size = strtol(optarg, &endptr, 0);
if ((errno == ERANGE && (size == LONG_MAX || size == LONG_MIN))
|| (errno != 0 && size == 0))
(void) bailout("Invalid size value");
if (*endptr != '\0' || size <= 0)
(void) bailout("Invalid size value. Only positive numbers allowed.");
break;
default:
(void) usage();
break;
}
}
argv += optind;
/* parse next commandline option */
if (argv)
filename = *argv;
/* check required option value */
if (size <= 0 || filename == NULL)
(void) usage();
#ifdef DEBUG
(void) printf("size=%ld filename=%s\n", size, filename);
#endif
/* open file to write to */
if (!error && (fp = fopen(filename, "w")) == NULL)
(void) bailout("%s", filename);
/* get message queue id */
if (!error && (msgqid = msgget(IPC_KEY, IPC_PERMS|IPC_CREAT)) == -1)
(void) printferr("Couldn't create message queue");
#ifdef DEBUG
if (msgqid != -1)
(void) printf("msgqid=%d\n", msgqid);
#endif
/* receive and write data */
if (!error)
(void) recv_write(msgqid, fp, size);
/* cleanup stuff */
#ifdef DEBUG
(void) printf("doing cleanup...\n");
#endif
/* remove message queue */
if (msgqid != -1 && msgctl(msgqid, IPC_RMID, NULL) == -1)
(void) printferr("Unable to remove message queue");
/* close open fds */
if (fp != NULL)
(void) fclose(fp);
return (error) ? 1 : 0;
}
/* vim: set et sw=2 ts=2: */