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: */