Advertisement
Guest User

Programování v UNIXu - 22.1.2013 - Kotal

a guest
Jan 22nd, 2014
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.04 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <strings.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <libgen.h>
  10. #include <err.h>
  11. #include <sys/types.h>
  12. #include <sys/wait.h>
  13. #include <arpa/inet.h>
  14. #include <time.h>
  15. #include <sys/time.h>
  16. #include <netdb.h>
  17. #include <poll.h>
  18.  
  19. #include <signal.h>
  20. #include <pthread.h>
  21. #include <errno.h>
  22. #include <semaphore.h>
  23.  
  24. #define KILL_MSG "killed\n"
  25. #define TO_MSG "timeout\n"
  26.  
  27. #define BUFF_LEN 2048
  28. #define MAX_ARGS 32
  29. #define MAX_CONN 4
  30.  
  31. // @author Petr Bělohlávek
  32.  
  33. // GLOBAL vars =====================================
  34.  
  35. //  semaphor for conn. count
  36. sem_t sem;
  37. int error, server_socket, client_socket;
  38.  
  39.  
  40. // my itoa =====================================
  41. size_t
  42. itoa(int i, char * b)
  43. {
  44.     char const digit[] = "0123456789";
  45.     char * p = b;
  46.  
  47.     if (i < 0) {
  48.         *p++ = '-';
  49.         i *= -1;
  50.     }
  51.  
  52.     int shifter = i;
  53.     do { // Move to where representation ends
  54.         ++p;
  55.         shifter = shifter / 10;
  56.     } while (shifter);
  57.     *p = '\0';
  58.  
  59.     size_t s = p - b;
  60.  
  61.     do { // Move back, inserting digits as u go
  62.         *--p = digit[i % 10];
  63.         i = i / 10;
  64.     } while (i);
  65.  
  66.     return (s);
  67. }
  68.  
  69. // get time in ms =====================================
  70. uint64_t
  71. now()
  72. {
  73.     struct timeval tv;
  74.     gettimeofday(&tv, NULL);
  75.     double time_in_mill =  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
  76.     return ((uint64_t) time_in_mill);
  77. }
  78.  
  79. // parse by '|' into args =====================================
  80. void
  81. parse_args(char * arg_buffer, char ** args)
  82. {
  83.     // never free() args !!!
  84.     char * token;
  85.     char * str;
  86.     char * saveptr;
  87.  
  88.     size_t i = 0;
  89.     for (str = arg_buffer; i < MAX_ARGS; str = NULL) {
  90.         token = strtok_r(str, "|", &saveptr);
  91.         if (token == NULL) {
  92.             break;
  93.         }
  94.  
  95.         args[i++] = token;
  96.     }
  97.     args[i] = NULL;
  98. }
  99.  
  100. // SIGINT handler =====================================
  101. void
  102. killed(int sig)
  103. {
  104.     write(1, KILL_MSG, strlen(KILL_MSG));
  105.     kill(0, SIGKILL);
  106.  
  107.     close(client_socket);
  108.     close(server_socket);
  109.  
  110.     sem_destroy(&sem);
  111.  
  112.     exit(0);
  113. }
  114.  
  115. // fork and fork and meassure time =====================================
  116. int
  117. get_exec_time(char * arg_buffer, int timeout, int client_socket)
  118. {
  119.     char * args[MAX_ARGS];
  120.     parse_args(arg_buffer, args);   // free args
  121.  
  122.     // arg test
  123.     /*
  124.     int j;
  125.     for (j = 0; ; ++j) {
  126.         if (args[j] == NULL) break;
  127.         fprintf(stderr, "%s\n", args[j]);
  128.     }
  129.     */
  130.  
  131.     int t, rc;
  132.     uint64_t start_time;
  133.  
  134.     int p[2];
  135.     if (pipe(p) == -1) {
  136.         err(1, "pipe");
  137.     }
  138.  
  139.     struct pollfd ufds[1];
  140.     ufds[0].fd = p[0];
  141.     ufds[0].events = POLLIN;
  142.  
  143.     int pid1 = -1, pid2 = -1;
  144.  
  145.     //  other possibilities: alarm
  146.  
  147.     // ----------------------------------------------
  148.     //  poll X handle
  149.     switch (pid1 = fork()) {
  150.         case -1:
  151.             close(client_socket);
  152.             err(1, "fork");
  153.  
  154.         // ----------------------------------------------
  155.         case 0: // run command
  156.             switch (pid2 = fork()) {
  157.                 case -1:
  158.                     err(1, "fork");
  159.  
  160.             case 0: // run command
  161.                 close(0); close(1); close(2);
  162.                 close(p[0]); close(p[1]);
  163.                 close(client_socket);
  164.  
  165.                 execv(args[0], args);
  166.                 err(1, "execv failed");
  167.  
  168.             default:    // parent
  169.                 wait(NULL);
  170.                 fprintf(stderr, "waited\n");
  171.                 write(p[1], ".", 1);
  172.                 close(p[0]); close(p[1]);
  173.  
  174.                 close(client_socket);
  175.                 exit(0);
  176.             }
  177.  
  178.             break;
  179.  
  180.         // ----------------------------------------------
  181.         default:    //  meassure time
  182.  
  183.             start_time = now();
  184.             rc = poll(ufds, 1, timeout);
  185.             if (rc == -1) {
  186.                 close(client_socket);
  187.                 err(1, "poll");
  188.             } else if (rc == 0) {
  189.                 fprintf(stderr, "timeout\n");
  190.                 t = -1;
  191.  
  192.             } else {
  193.                 fprintf(stderr, "stopped\n");
  194.                 t = now() - start_time;
  195.             }
  196.  
  197.             // manage zombies
  198.             if (pid1 != -1) {
  199.                 kill(pid1, SIGKILL);
  200.                 waitpid(pid1, NULL, 0);
  201.             }
  202.             if (pid2 != -1) {
  203.                 kill(pid2, SIGKILL);
  204.                 waitpid(pid2, NULL, 0);
  205.             }
  206.             close(p[0]); close(p[1]);
  207.             // while (waitpid(-1, NULL, WNOHANG));
  208.     }
  209.     // ----------------------------------------------
  210.     return (t);
  211. }
  212.  
  213. int
  214. main(int argc, char ** argv) {
  215.  
  216.     // TODO: check close() exitcode
  217.     // let client request be valid
  218.  
  219.     //  sigint
  220.     struct sigaction act;
  221.     bzero(&act, sizeof (act));
  222.     act.sa_handler = killed;
  223.     if (sigaction(SIGINT, &act, NULL) == -1) {
  224.         err(1, "sigaction");
  225.     }
  226.  
  227.     if (argc != 3) {
  228.         err(1, "usage: ./a.out <port> <timeout>");
  229.     }
  230.  
  231.     char * portstr = argv[1];
  232.     int timeout = 1000 * atoi(argv[2]); // in miliseconds for poll
  233.  
  234.     struct sockaddr_storage client;
  235.     struct addrinfo *r, *rorig, hint;
  236.     socklen_t sz;
  237.  
  238.     memset(&hint, 0, sizeof (hint));
  239.     hint.ai_family = AF_UNSPEC;
  240.     hint.ai_socktype = SOCK_STREAM;
  241.     hint.ai_flags = AI_PASSIVE;
  242.  
  243.     //  get possible adresses
  244.     if ((error = getaddrinfo(NULL, portstr, &hint, &r)) != 0) {
  245.         errx(1, "%s", gai_strerror(error));
  246.     }
  247.  
  248.     //  bind to any
  249.     for (rorig = r; r != NULL; r = r->ai_next) {
  250.         server_socket = socket(r->ai_family,
  251.             r->ai_socktype, r->ai_protocol);
  252.  
  253.         if (!bind(server_socket, r->ai_addr, r->ai_addrlen)) {
  254.             break;
  255.         }
  256.         close(server_socket);
  257.     }
  258.  
  259.     //  free
  260.     freeaddrinfo(rorig);
  261.  
  262.     //  if all tried and failed
  263.     if (r == NULL) {
  264.         close(server_socket);
  265.         errx(1, "getaddrinfo");
  266.     }
  267.  
  268.     //  set reuse addresses
  269.     int optval = 1;
  270.     if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
  271.         &optval, sizeof (optval)) == -1) {
  272.  
  273.         close(server_socket);
  274.         err(1, "setsockopt");
  275.     }
  276.  
  277.     //  listen
  278.     if (listen(server_socket, MAX_CONN) == -1) {
  279.         close(server_socket);
  280.         err(1, "listen");
  281.     }
  282.  
  283.     //  init. semaphor
  284.     if (sem_init(&sem, 0, MAX_CONN) == -1) {
  285.         close(server_socket);
  286.         err(1, "sem. init");
  287.     }
  288.  
  289.     //  tmp vars
  290.     char arg_buffer[BUFF_LEN], repl[BUFF_LEN];
  291.     int n, t, s;
  292.  
  293.     //  accept every
  294.     for (;;) {
  295.         fprintf(stderr, "- waiting for free slot\n");
  296.         //  don't care about another client for a while
  297.         sem_wait(&sem);
  298.         fprintf(stderr, "- ready\n");
  299.  
  300.         //  acccept conn.
  301.         sz = sizeof (client);
  302.         if ((client_socket = accept(server_socket,
  303.             (struct sockaddr *) &client, &sz)) == -1) {
  304.  
  305.             close(client_socket);
  306.             close(server_socket);
  307.             err(1, "listen");
  308.         }
  309.  
  310.         // create worker
  311.         switch (fork()) {
  312.             case -1:
  313.                 close(server_socket);
  314.                 err(1, "fork");
  315.                 //  may kill
  316.  
  317.             case 0:  // worker - handle this connection
  318.                 if ((n = read(client_socket,
  319.                     &arg_buffer, BUFF_LEN)) == -1) {
  320.  
  321.                     close(client_socket);
  322.  
  323.                     err(1, "child read");
  324.                 }
  325.                 arg_buffer[n] = 0;
  326.                 fprintf(stderr, "accepted req.: %s\n",
  327.                     arg_buffer);
  328.  
  329.                 t = get_exec_time(arg_buffer,
  330.                     timeout, client_socket);
  331.  
  332.                 if (t == -1) { // timeout
  333.                     if (write(client_socket, TO_MSG,
  334.                         sizeof (TO_MSG)) == -1) {
  335.  
  336.                         close(client_socket);
  337.  
  338.                         err(1, "child write");
  339.                     }
  340.                 } else {
  341.                     s = itoa(t, repl);
  342.                     if (write(client_socket,
  343.                         repl, s) == -1) {
  344.  
  345.                         close(client_socket);
  346.  
  347.                         err(1, "child write");
  348.                     }
  349.                 }
  350.  
  351.                 close(client_socket);
  352.  
  353.                 break;
  354.  
  355.             default:
  356.                 while (waitpid(-1, NULL, WNOHANG)) {
  357.                     sem_post(&sem);
  358.                 }
  359.                 close(client_socket);
  360.                 break;
  361.         }
  362.     }
  363.  
  364.     // actually never reached
  365.     close(server_socket);
  366.     return (0);
  367. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement