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