Download | Plain Text | No Line Numbers


  1. /*
  2.  * Name: gluefile (server(
  3.  * Author: Manuel Mausz, 0728348
  4.  * Description: Server writes data read from client via IPC message queue to
  5.  * file. If filesize is reached server quits automatically. Client
  6.  * sends data read from file via IPC message queue to server
  7.  * Offset specifies file offset to start writing for server.
  8.  * Created: 12.03.2009
  9.  * Exercise: 1h B
  10.  */
  11.  
  12. #include <unistd.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <errno.h>
  16. #include <limits.h>
  17. #include "global.h"
  18.  
  19. /*
  20.  * NAME: sighandler
  21.  * PURPOSE:
  22.  * signal handler sets global error flag to 1
  23.  *
  24.  * PARAMETERS:
  25.  * int signum ... signal number
  26.  *
  27.  * RETURN VALUE:
  28.  * void
  29.  *
  30.  * GLOBAL VARS:
  31.  * error
  32.  */
  33. static void sighandler(int signum)
  34. {
  35. #ifdef DEBUG
  36. (void) printf("signal %d received\n", signum);
  37. #endif
  38. error = 1;
  39. }
  40.  
  41. /*
  42.  * NAME: usage
  43.  * PURPOSE:
  44.  * prints program usage to stderr and terminates with EXIT_FAILURE
  45.  *
  46.  * PARAMETERS:
  47.  * void
  48.  *
  49.  * RETURN VALUE:
  50.  * void
  51.  *
  52.  * GLOBAL VARS:
  53.  * me
  54.  */
  55. static void usage(void)
  56. {
  57. (void) fprintf(stderr, "Usage: %s -s size file\n", me);
  58. (void) exit(EXIT_FAILURE);
  59. }
  60.  
  61. /*
  62.  * NAME: recv_write
  63.  * PURPOSE:
  64.  * writes data read from client via IPC msg queue to stream pointed to by fp.
  65.  * maxsize specifies maximum filesize (data to write). function returns after
  66.  * maxsize is reached or on error.
  67.  *
  68.  * PARAMETERS:
  69.  * int msgqid ... msg queue id to read from
  70.  * FILE *fp ... pointer to stream to write to
  71.  * long maxsize ... maximum file size
  72.  *
  73.  * RETURN VALUE:
  74.  * void
  75.  *
  76.  * GLOBAL VARS:
  77.  * error
  78.  */
  79. static void recv_write(int msgqid, FILE *fp, long maxsize)
  80. {
  81. long pos = 0, maxpos = 0;
  82. msg_t msg;
  83.  
  84. while(!error)
  85. {
  86. /* receive message */
  87. msg.mtype = (maxpos + 1) * -1;
  88. #ifdef DEBUG
  89. (void) printf("messages receiving with offset range [0 - %ld]\n", msg.mtype * -1 - 1);
  90. #endif
  91. if (!error && msgrcv(msgqid, &msg, MSGSIZE, msg.mtype, 0) == -1)
  92. {
  93. (void) printferr("Couldn't receive message");
  94. break;
  95. }
  96.  
  97. #ifdef DEBUG
  98. (void) printf("received [%ld]+%d bytes from msg queue\n", msg.mtype - 1, msg.len);
  99. #endif
  100. msg.mtype--;
  101.  
  102. /* ignore messages to big */
  103. if (!error && msg.mtype + msg.len > maxsize)
  104. {
  105. #ifdef DEBUG
  106. (void) printf("message to big. ignoring...\n");
  107. #endif
  108. continue;
  109. }
  110.  
  111. /* seek to requested position */
  112. if (!error && pos != msg.mtype)
  113. {
  114. #ifdef DEBUG
  115. (void) printf("seeking to %ld\n", msg.mtype);
  116. #endif
  117. if (fseek(fp, msg.mtype, SEEK_SET) == -1)
  118. {
  119. (void) printferr("Unable to seek to requested position");
  120. break;
  121. }
  122. pos = msg.mtype;
  123. }
  124.  
  125. /* write to file */
  126. if (!error && fwrite(msg.data, sizeof(msg.data[0]), msg.len, fp) < msg.len)
  127. {
  128. (void) printferr("Unable to write data to file");
  129. break;
  130. }
  131.  
  132. /* update file current position */
  133. pos += msg.len;
  134. if (pos > maxpos)
  135. maxpos = pos;
  136.  
  137. /* filesize reached */
  138. if (!error && pos == maxsize)
  139. break;
  140. }
  141. }
  142.  
  143. /*
  144.  * NAME: main
  145.  * PURPOSE:
  146.  * install signal handler, parse commandline options,
  147.  * create msg queue and call recv_write
  148.  *
  149.  * PARAMETERS:
  150.  * standard parameters of main
  151.  *
  152.  * RETURN VALUE:
  153.  * int ... 0 on success, 1 on error
  154.  *
  155.  * GLOBAL VARS:
  156.  * me, error
  157.  */
  158. int main(int argc, char *argv[])
  159. {
  160. int opt, msgqid = -1;
  161. long size = 0;
  162. char *endptr;
  163. char *filename = NULL;
  164. FILE *fp = NULL;
  165. struct sigaction new_action, old_action;
  166.  
  167. /* save me */
  168. me = argv[0];
  169.  
  170. /* install signal handler */
  171. new_action.sa_handler = sighandler;
  172. sigemptyset(&new_action.sa_mask);
  173. new_action.sa_flags = 0; /* to avoid restart of blocking syscalls */
  174. INSTALL_SIGNAL(SIGINT, new_action, old_action)
  175. INSTALL_SIGNAL(SIGQUIT, new_action, old_action)
  176. INSTALL_SIGNAL(SIGTERM, new_action, old_action)
  177.  
  178. /* parse cmdline options */
  179. while ((opt = getopt(argc, argv, "s:")) != -1)
  180. {
  181. switch(opt)
  182. {
  183. case 's':
  184. size = strtol(optarg, &endptr, 0);
  185.  
  186. if ((errno == ERANGE && (size == LONG_MAX || size == LONG_MIN))
  187. || (errno != 0 && size == 0))
  188. (void) bailout("Invalid size value");
  189.  
  190. if (*endptr != '\0' || size <= 0)
  191. (void) bailout("Invalid size value. Only positive numbers allowed.");
  192.  
  193. break;
  194. default:
  195. (void) usage();
  196. break;
  197. }
  198. }
  199. argv += optind;
  200.  
  201. /* parse next commandline option */
  202. if (argv)
  203. filename = *argv;
  204.  
  205. /* check required option value */
  206. if (size <= 0 || filename == NULL)
  207. (void) usage();
  208.  
  209. #ifdef DEBUG
  210. (void) printf("size=%ld filename=%s\n", size, filename);
  211. #endif
  212.  
  213. /* open file to write to */
  214. if (!error && (fp = fopen(filename, "w")) == NULL)
  215. (void) bailout("%s", filename);
  216.  
  217. /* get message queue id */
  218. if (!error && (msgqid = msgget(IPC_KEY, IPC_PERMS|IPC_CREAT)) == -1)
  219. (void) printferr("Couldn't create message queue");
  220. #ifdef DEBUG
  221. if (msgqid != -1)
  222. (void) printf("msgqid=%d\n", msgqid);
  223. #endif
  224.  
  225. /* receive and write data */
  226. if (!error)
  227. (void) recv_write(msgqid, fp, size);
  228.  
  229. /* cleanup stuff */
  230. #ifdef DEBUG
  231. (void) printf("doing cleanup...\n");
  232. #endif
  233.  
  234. /* remove message queue */
  235. if (msgqid != -1 && msgctl(msgqid, IPC_RMID, NULL) == -1)
  236. (void) printferr("Unable to remove message queue");
  237.  
  238. /* close open fds */
  239. if (fp != NULL)
  240. (void) fclose(fp);
  241.  
  242. return (error) ? 1 : 0;
  243. }
  244.  
  245. /* vim: set et sw=2 ts=2: */
  246.