home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1997 March / PCWK0397.iso / novell / webserv3 / nws30.exe / DISK1 / WEB / SAMPLES / CGIAPP / RCGI.C < prev    next >
C/C++ Source or Header  |  1996-06-14  |  13KB  |  596 lines

  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <sys/stat.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <ctype.h>
  9. #include <errno.h>
  10. #include <time.h>
  11. #include <nwdir.h>
  12. #include <conio.h>
  13. #include <io.h>
  14. #include <netdb.h>
  15. #include <netinet/in.h>
  16. #include <arpa/inet.h>
  17.  
  18. NETDB_DEFINE_CONTEXT
  19.  
  20. #define MAX_FNAME    1024
  21. #define MAX_LINE_LEN    1025
  22. #define MAX_ENV 1024
  23.  
  24. void set_local_log();
  25. int rcgi_main(char *, int (*fptr)());
  26.  
  27. static int sockfd;
  28. extern int server_port ;
  29. static int server_socket;
  30. static int reply_socket=0; /** Use this to send data to web server **/
  31. static int server_alive;
  32. char *cmd_line = 0;
  33. int env_count;
  34. static int in_port = 0;
  35. static char *cmds[] = {
  36.     "env",
  37.     "cmd",
  38.     "input",
  39.     "port",
  40.     "end",
  41.     "vers",
  42.     0
  43. };
  44. char *env[MAX_ENV];
  45. char *input;
  46.  
  47. /************************************************************************/
  48. /************ THE RCGI INTERFACE FUNCTION *******************************/
  49. /************************************************************************/
  50.  
  51.  
  52.  
  53. /****** Use this function to send data to the web server *****/
  54. rcgi_sendreply(char *buf)
  55. {
  56.     if (!buf)
  57.         return -1;
  58.  
  59.     rcgi_send(reply_socket, buf, strlen(buf));
  60. }
  61.  
  62. /****** Use this function to send the generic header to the web server *****/
  63. rcgi_sendheader()
  64. {
  65.     char tmpbuf[200];
  66.  
  67.     /**** BUILD AND SEND THE HEADER ***/
  68.  
  69.     memset(tmpbuf, 0, 200);
  70.     sprintf(tmpbuf, "Content-type: text/plain");
  71.     strcat(tmpbuf, "\r\n");
  72.     strcat(tmpbuf, "\r\n");
  73.  
  74.     rcgi_send(reply_socket, tmpbuf, strlen(tmpbuf));
  75. }
  76.  
  77. /********** Use this function before exiting to cleanup stuff allocated **/
  78. /********** by RCGI *****/
  79. rcgi_cleanup()
  80. {
  81.     free_env();
  82.     if (input)
  83.         free(input);
  84.     input = 0;
  85.     if(cmd_line)
  86.         free(cmd_line);
  87.     cmd_line = 0;
  88.     close(sockfd);
  89.     close(server_socket);
  90.     close(reply_socket);
  91. }
  92.  
  93. /*** The main RCGI server function. Waits for a request, does the RCGI ***/
  94. /*** processing, calls the process_request() function and loops        ***/
  95.  
  96. int
  97. rcgi_main(char *srvr_port, int (*process_request)())
  98. {
  99.     int client_socket, clen, one=1;
  100.     struct sockaddr_in sa_client;
  101.     struct sockaddr_in sa_server;
  102.  
  103.     if (srvr_port)
  104.         set_server_port(srvr_port);
  105.  
  106.     /* open tcp socket */
  107.     if ((server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  108.         ConsolePrintf("rcgid: could not get tcp socket\n");
  109.         perror("socket");
  110.             return -1;
  111.     }
  112.  
  113.     if ((setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
  114.             (char *)&one, sizeof(one))) == -1)
  115.     {
  116.         ConsolePrintf( "rcgid: could not set tcp socket option\n");
  117.         perror("setsockopt");
  118.             return -1;
  119.     }
  120.  
  121.     /* bind it to an addres, port */
  122.     memset((char *)&sa_server, 0, sizeof(sa_server));
  123.     sa_server.sin_family = AF_INET;
  124.     sa_server.sin_addr.s_addr = htonl(INADDR_ANY);
  125.     sa_server.sin_port = htons((short)server_port);
  126.  
  127.     if (bind(server_socket, (struct sockaddr *)&sa_server,
  128.          sizeof(sa_server)) == -1)
  129.     {
  130.         ConsolePrintf( "rcgid: could not bind tcp socket to port %d\n", 
  131.         server_port);
  132.         perror("bind");
  133.             return -1;
  134.     }
  135.  
  136.     listen(server_socket, 5);
  137.  
  138.     server_alive = 1;
  139.  
  140.     while (server_alive) {
  141.       retry:
  142.         clen = sizeof(sa_client);
  143.         client_socket = accept(server_socket, 
  144.                    (struct sockaddr *)&sa_client, &clen);
  145.  
  146.         if (client_socket == -1) {
  147.             if (errno == ETIMEDOUT && server_alive) {
  148.                 goto retry;
  149.             }
  150.  
  151.             ConsolePrintf("accept failed, errno %d, server_alive %d\n", 
  152.                errno, server_alive);
  153.  
  154.             /* if we're not being shut down, schedule death */
  155.             if (server_alive)
  156.                 graceful_death();
  157.         } else {
  158.             reply_socket = rcgi(client_socket, &sa_client);
  159.             correct_env();
  160.             (*process_request)();
  161.             if (input){
  162.                 free(input);
  163.                 input = 0;
  164.             }
  165.             free_env();
  166.             if (cmd_line) {
  167.                 free(cmd_line);
  168.                 cmd_line = 0;
  169.             }
  170.             close(reply_socket);
  171.         }
  172.  
  173.         /* */
  174.     }
  175.  
  176. }
  177.  
  178.  
  179.  
  180.  
  181. /************************************************************************/
  182. /* -------------- MAIN RCGI PROCESSING ------------------------------ */
  183. /************************************************************************/
  184.  
  185.  
  186.  
  187. int
  188. rcgi(skt, sa_client)
  189. int skt;
  190. struct sockaddr_in *sa_client;
  191. {
  192.     int more, i;
  193.     char buf[MAX_LINE_LEN], *p;
  194.     int rcgi_state = 0;
  195.     char scratchbuf[MAX_LINE_LEN];
  196.     int ret = skt;
  197.  
  198.  
  199.     rcgi_state = 0;
  200.     more = 1;
  201.  
  202.     while (more) {
  203.         int len;
  204.         for (i=0;i<MAX_LINE_LEN;i++) buf[i] = 0;
  205.  
  206.         if (!rcgi_recv(skt, buf, sizeof(buf)-1))
  207.             break;
  208.  
  209.         len = strlen(buf);
  210.  
  211.         if (len >= 2 && buf[len-2] == '\r' && buf[len-1] == '\n') {
  212.             buf[len-2] = 0;
  213.             len -= 2;
  214.         } else
  215.             if (len >=1 && buf[len-1] == '\n') {
  216.                 buf[len-1] = 0;
  217.                 len--;
  218.             }
  219.  
  220.         switch(rcgi_state) {
  221.           case 0:
  222.             for (p = buf; *p && *p != ' '; p++)
  223.             ;
  224.             if (*p)
  225.                 *p++ = 0;
  226.             for (i = 0; cmds[i]; i++) {
  227.                 if (strcmpi(cmds[i], buf) == 0)
  228.                     break;
  229.             }
  230.             switch (i+1) {
  231.               case 1: /* env */
  232.                 rcgi_state = 1;
  233.                 sprintf(scratchbuf, "100 Enter env.  End with single '.' on a line\r\n");
  234.                 rcgi_send(skt, scratchbuf, strlen(scratchbuf));
  235.                 break;
  236.  
  237.               case 2: /* cmd */
  238.                 if (*p)
  239.                     cmd_line = strdup(p);
  240.                 printf("Command is %s\n", p);
  241.  
  242.                 if (cmd_line) {
  243.                     sprintf(scratchbuf, "101 Cmd accepted '%s'\r\n", cmd_line);
  244.                     rcgi_send(skt, scratchbuf, strlen(scratchbuf));
  245.                 }
  246.                 break;
  247.  
  248.               case 3: /* input */
  249.                 rcgi_state = 2;
  250.                 break;
  251.  
  252.                  case 4: /* port */
  253.                 rcgi_state = 3;
  254.                 break;
  255.  
  256.                 case 5: /* end */
  257.                     more = 0;
  258.                 break;
  259.               case 6: /* vers */
  260.                     break;
  261.  
  262.                 default:
  263.                 sprintf(scratchbuf, "500 Bad command '%s'\r\n", buf);
  264.                 rcgi_send(skt, scratchbuf, strlen(scratchbuf));
  265.                 more = 0;
  266.             }
  267.         break;
  268.  
  269.       case 1: /* env */
  270.         if (len == 1 && buf[0] == '.') {
  271.             sprintf(scratchbuf, "100 Env accepted\r\n");
  272.             rcgi_send(skt, scratchbuf, strlen(scratchbuf));
  273.             rcgi_state = 0;
  274.             break;
  275.         }
  276.  
  277.         if (buf[0] == 0)
  278.             break;
  279.  
  280.         if (add_env(buf)) {
  281.             sprintf(scratchbuf, "501 Environment full '%s'\r\n", buf);
  282.             rcgi_send(skt, scratchbuf, strlen(scratchbuf));
  283.             more = 0;
  284.         }
  285.         break;
  286.  
  287.       case 2: /* input */
  288.  
  289.         if (len > 1 && buf[0] == '.' && buf[1] == '.')
  290.             ;
  291.         else
  292.             if (len == 1 && buf[0] == '.') 
  293.                 rcgi_state = 0;
  294.  
  295.         add_input(buf);
  296.         break;
  297.       case 3: /* port */
  298.         in_port = atoi(p);
  299.         break;
  300.     } /*switch */
  301.     } /*while */
  302.  
  303.     printf("end of loop\n");
  304.     if (in_port) {
  305.         int one=1;
  306.  
  307.         /* open tcp socket */
  308.         if ((skt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  309.             fprintf(stderr,"rcgid: could not get tcp socket\n");
  310.                 perror("socket");
  311.                 return(-1);
  312.             }
  313.  
  314.         if ((setsockopt(skt, SOL_SOCKET, SO_REUSEADDR,
  315.                 (char *)&one, sizeof(one))) == -1)
  316.             {
  317.                 fprintf(stderr, "rcgid: could not set tcp socket option\n");
  318.                 perror("setsockopt");
  319.                 return(-1);
  320.             }
  321.  
  322.             sa_client->sin_port = htons((short)in_port);
  323.  
  324.         if (connect(skt, (struct sockaddr *) sa_client, 
  325.                     sizeof(struct sockaddr_in)) == -1) {
  326.                 fprintf(stderr, "rcgid: could not connect\n");
  327.                 perror("connect");
  328.                 return(-1);
  329.         }
  330.         ret = skt;
  331.     }
  332.     
  333.     if (cmd_line) {
  334.         sprintf(scratchbuf, "200 Cmd started '%s'\r\n", cmd_line);
  335.         rcgi_send(skt, scratchbuf, strlen(scratchbuf));
  336.     }
  337.  
  338.     /* Now that we have all the info that we need, let main process execute */
  339.  
  340.     return ret;
  341. }
  342.  
  343. /************************************************************************/
  344. /************ SUPPORT FUNCTIONS FOR RCGI()*******************************/
  345. /************************************************************************/
  346.  
  347. /**** This function is used to extract and set the server port from ***/
  348. /**** string passed on the command line ***/
  349.  
  350. void
  351. set_server_port(arg)
  352. char *arg;
  353. {
  354.     server_port = atoi(arg);
  355. }
  356.  
  357. /********* This function is used to get store input from the web server **/
  358. /********* in the "input" variable ***/
  359. int 
  360. add_input(buf)
  361. char *buf;
  362. {
  363.     char *newinput = NULL;
  364.     if (!input) {
  365.         input = (char *) malloc(strlen(buf)+1);
  366.         if (!input) return -1;
  367.         strcpy(input, buf);
  368.     }
  369.     else {
  370.         newinput = realloc(input, strlen(input) + strlen(buf) +1 );
  371.         if (!newinput)
  372.             return (-1);
  373.         memset(newinput + strlen(input), 0, strlen(buf) + 1);
  374.         input = newinput;
  375.         strcat(input, buf);
  376.     }
  377.     return(0);
  378.     
  379. }
  380.  
  381. /********* This function is used to store environment data from the web ***/
  382. /********* server in the "env" variable ***/
  383. int
  384. add_env(buf)
  385. char *buf;
  386. {
  387.  
  388.     if (env_count >= MAX_ENV)
  389.         return -1;
  390.  
  391.     env[env_count++] = strdup(buf);
  392.     env[env_count] = 0;
  393.  
  394.     return 0;
  395. }
  396.  
  397. /********* This function is used to free the "env" array ******/
  398. void
  399. free_env(void)
  400. {
  401.     int i;
  402.  
  403.     for (i = 0; i < env_count; i++) 
  404.         if ( env && env[i])
  405.             free(env[i]);
  406.  
  407.     env_count = 0;
  408. }
  409.  
  410. char *
  411. get_env(name)
  412. char *name;
  413. {
  414.     char *tmp = NULL;
  415.     int i=0;
  416.  
  417.     for (i=0;i<env_count;i++)  {
  418.         tmp = strchr(env[i], '=');
  419.         if (tmp)
  420.             *tmp = '\0';
  421.         if (!strcmp(env[i], name) ) {
  422.             *tmp = '=';
  423.             tmp++;
  424.             return(strdup(tmp));
  425.         }
  426.         else 
  427.         if (tmp)
  428.             *tmp = '=';
  429.     }
  430.     return NULL;
  431. }
  432.  
  433. set_env(name, val)
  434. char *name;
  435. char *val;
  436. {
  437.     char *tmp = NULL;
  438.     int i=0, namelen=0, vallen=0;
  439.     char *newenv = NULL;
  440.  
  441.     for (i=0;i<env_count;i++)  {
  442.         tmp = strchr(env[i], '=');
  443.         if (tmp)
  444.             *tmp = '\0';
  445.         if (!strcmp(env[i], name) ) {
  446.             namelen = strlen(env[i]);
  447.             vallen = strlen(val);
  448.             newenv = (char *) malloc(namelen+vallen+2);
  449.             if (!newenv) {
  450.                 tmp--;
  451.                 *tmp = '=';
  452.                 return(1);
  453.             }
  454.             memset(newenv, 0, namelen+vallen+2);
  455.             strcat(newenv, env[i]);
  456.             strcat(newenv, "=");
  457.             strcat(newenv, val);
  458.             free(env[i]);
  459.             env[i] = newenv;
  460.             return 0;
  461.         }
  462.         else {
  463.             if (tmp)
  464.                 *tmp = '=';
  465.         }
  466.     }
  467.     /* if it gets here then its a new env var */
  468.     newenv = (char *) malloc(strlen(name)+strlen(val)+2);
  469.     if (!newenv) 
  470.         return(1);
  471.     strcat(newenv, name);
  472.     strcat(newenv, "=");
  473.     strcat(newenv, val);
  474.     add_env(newenv);
  475.     if (newenv)
  476.         free(newenv);
  477. }
  478.  
  479. correct_env(void)
  480. {
  481.     char *path_info_val = NULL, *script_name_val = NULL;
  482.  
  483.     script_name_val = get_env("SCRIPT_NAME");
  484.     path_info_val = get_env("PATH_INFO");
  485.  
  486.     munge_env(script_name_val, path_info_val);
  487.  
  488.     if (script_name_val)
  489.         free(script_name_val);
  490.     if (path_info_val)
  491.         free(path_info_val);
  492. }
  493.  
  494. munge_env(script_name_val, path_info_val)
  495. char *script_name_val, *path_info_val;
  496. {
  497.     char path_info[256];
  498.     char script_name[256];
  499.     char *tmp1 = NULL, *tmp2 = NULL;
  500.     int i=0;
  501.  
  502.     for (i=0;i<256;i++) path_info[i] = '\0';
  503.     for (i=0;i<256;i++) script_name[i] = '\0';
  504.  
  505.     if (!script_name_val || !path_info_val)
  506.         return;
  507.  
  508.     tmp1 = script_name_val;
  509.     if (*tmp1 == '/') tmp1++;
  510.  
  511.     tmp2 = strchr(tmp1, '/'); /* Search for first '/' */
  512.  
  513.     if (tmp2) 
  514.         *tmp2 = '\0';
  515.  
  516.     strcat(script_name, tmp1);
  517.  
  518.     if (tmp2) {
  519.         *tmp2 = '/';
  520.         strcat(path_info, tmp2);
  521.     }
  522.     tmp1 = path_info + strlen(path_info)  ;
  523.     if (*(tmp1-1) != '/') *tmp1 = '/'; /* Append a slash if missing */
  524.  
  525.     tmp1 = path_info_val;
  526.     if (*tmp1 == '/') tmp1++; /* skip past leading slash */
  527.     if (tmp1 && *tmp1 != '\0')
  528.         strcat(path_info, tmp1);
  529.     set_env("PATH_INFO", path_info);
  530.     set_env("SCRIPT_NAME", script_name);
  531. }
  532.  
  533. /************************************************************************/
  534. /*********** ROUTINES TO SEND AND GET STUFF FROM THE RCGI CLIENT ******/
  535. /************************************************************************/
  536.  
  537. int
  538. rcgi_send(int skt, char *buf, int len)
  539. {
  540.     char *ptr = buf;
  541.     int num_left = len;
  542.     int num_sent = 0;
  543.  
  544.     if (!buf)
  545.         return -1;
  546.     printf("\nSending %s. \nNo. of bytes = %d\n", buf, len);
  547.     while(num_left) {
  548.         num_sent = send(skt, ptr, num_left, 0);
  549.         if (num_sent == -1){
  550.             ConsolePrintf("Couldn;t send data. Errno = %d!\n", errno);
  551.             return(-1);
  552.         }
  553.         num_left -= num_sent;
  554.         ptr += num_sent;
  555.     }
  556. }
  557. int
  558. rcgi_recv(int skt, char *buf, int len)
  559. {
  560.     int num_recd = 0;
  561.     int num_left = len;
  562.     char *ptr = buf;
  563.  
  564.     if (!buf)
  565.         return -1;
  566.  
  567.     while (num_left) {
  568.         if ((num_recd = recv(skt, ptr, 1, 0)) == -1) {
  569.             ConsolePrintf("Error in receiving. Errno = %d\n", errno);
  570.             return -1;
  571.         }
  572.         num_left --;
  573.         if (*ptr == '\n') {
  574.             ptr++;
  575.             *ptr = '\0';
  576.             return ptr-buf;
  577.         }
  578.         ptr ++;
  579.     }
  580.     ConsolePrintf("Received %s\n", buf);
  581.     return len;
  582. }
  583.  
  584. /* ------------------------------------------------------------------ */
  585. /* -------------- UTIL FUNCTIONS ------------------------------------ */
  586.  
  587.  
  588.  
  589. void
  590. graceful_death()
  591. {
  592.     printf("graceful_death()\n");
  593. }
  594.  
  595.  
  596.