0

I added a printf statement under the xbuf_xcat, in stream3.c, as below:

xbuf_xcat(reply, "%x\r\n%s\r\n", len, readbuf);
char *client_arg_time=0;
get_arg("time=", & client_arg_time, argc, argv);
printf("%s\n", client_arg_time);

It is expected to print the time from http argument.
But it prints (null) instead, except the first one.

What's wrong with my code?
I am using ubuntu 12.04, G-WAN 4.3.14.
edit=======================
http with uri ?time=1223456, so the get_arg("time=",...)function gets the "1223456" and print to screen. It is ok, but print once only. When the script is waked up by the wake_up(),it should print another "1223456", but it prints "(null)". If you check the example stream3.c from gwan, you can find the line of "xbuf_xcat(reply, "%x\r\n%s\r\n", len, readbuf);" as below near the bottom. (quoted from gwan example, stream3.c):

    #include "gwan.h"

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    #define NBR_CHUNKS "10"

    // ----------------------------------------------------------------------------
    // popen replacement (GLIBC's popen() does not want to work without buffers)
    // ----------------------------------------------------------------------------
    int run_cmd(char *cmd_to_run)
    {
       const u32 cmd_len = strlen(cmd_to_run) + 1;
       char cmd[cmd_len + 8];
       snprintf(cmd, sizeof(cmd), "%s 2>&1", cmd_to_run);

       // create a one-way communication channel (a pipe)
       // (bytes written on fd[1] can be read from fd[0])
       int fd[2]; if(pipe(fd)) return 0;
       const int f = fd[0];

       const pid_t pid = fork(); // fork is needed to hook the process stdout I/O
       switch(pid)
       {
          case -1: // error
                   close(fd[0]);
                   close(fd[1]);
                   return 0;

          case 0:  // new child process, make child's stdout use our fd
                   dup2(fd[1], 1); // close(fd2) && fd2 = fd
                   close(fd[0]);
                   close(fd[1]);

                   // replace the current process image with a new process image
                   char c1[] = "/bin/sh", c2[] = "sh", c3[] = "-c";
                   char *args[] = { c2, c3, cmd, 0 };
                   execvp(c1, args);
                   exit(127);
       }

       // this is the parent process
       close(fd[1]);
       return f;
    }
    // ----------------------------------------------------------------------------
    // our (minimalist) per-request context
    // ----------------------------------------------------------------------------
    typedef struct { int f; } data_t;

    int main(int argc, char *argv[])
    {
       char readbuf[1024] = {0};

       // get the server 'reply' buffer where to write our answer to the client
       xbuf_t *reply = get_reply(argv);

       // -------------------------------------------------------------------------
       // step 1: setup a per-request context
       // -------------------------------------------------------------------------
       data_t **data = (void*)get_env(argv, US_REQUEST_DATA);
       if(!*data) // we did not setup our per-request structure yet
       {
          // create a per-request memory pool
          if(!gc_init(argv, 4070)) // we can call gc_alloc() to consume 4070 bytes
             return 503; // could not allocate memory!

          *data = gc_malloc(argv, sizeof(data_t)); // allocate our context
          if(!*data) return 503; // not possible here, but better safe than sorry

          // ----------------------------------------------------------------------
          // step 2: run an asynchrone (or incremental) job
          // ----------------------------------------------------------------------
          // run the "ping -c 10 127.0.0.1" command
          (*data)->f = run_cmd("ping -c " NBR_CHUNKS " 127.0.0.1");
          if((*data)->f == 0) // error
          {
             int ret = strerror_r(errno, readbuf, sizeof(readbuf));
             xbuf_cat(reply, ret ? "unknown error" : readbuf);
             return 200;
          }

          // ----------------------------------------------------------------------
          // tell G-WAN when to run this script again (for the same request)
          // ----------------------------------------------------------------------
          wake_up(argv, (*data)->f, WK_FD); // when fd buffer has data

          // ----------------------------------------------------------------------
          // send chunked encoding HTTP header and HTTP status code
          // ----------------------------------------------------------------------
          char head[] = "HTTP/1.1 200 OK\r\n"
                        "Connection: close\r\n"
                        "Content-type: text/html; charset=utf-8\r\n"
                        "Transfer-Encoding: chunked\r\n\r\n"
                        "5\r\n<pre>\r\n";
          xbuf_ncat(reply, head, sizeof(head) - 1);
       }

       // -------------------------------------------------------------------------
       // step 3: repeatedly read (and send to client) ping's incremental reply
       // -------------------------------------------------------------------------
       // fetch the command output and store it in the 'reply' buffer
       const int len = read((*data)->f, readbuf, sizeof(readbuf));
       if(len <= 0) // done
       {
          close((*data)->f);

          // note that malloc() would have to free the 'data' context here
          // (gc_malloc() is automatically freed, along with its memory pool
          //  so there's no need for an explicit free)

          // end the on-going chunked encoding
          char end[] = "6\r\n</pre>\r\n0\r\n\r\n";
          xbuf_ncat(reply, end, sizeof(end) - 1);

          wake_up(argv, 0, WK_FD); // 0:no more wake-up please

          return RC_NOHEADERS; // RC_NOHEADERS: do not generate HTTP headers
       }

       // -------------------------------------------------------------------------
       // format reply to use chunked encoding
       // -------------------------------------------------------------------------
       // anatomy of a chunked response:
       // 
       //  HTTP/1.1 200 OK [CRLF]                          <-+
       //  Content-Type: text/html [CRLF]                    | HTTP headers
       //  Transfer-Encoding: chunked [CRLF]               <-+
       //  [CRLF]
       //  1a; optional-stuff-here [CRLF]                  // hexadecimal length
       //  abcdefghijklmnopqrstuvwxyz [CRLF]               // data (ASCII/binary)
       //  10 [CRLF]                                       // hexadecimal length
       //  1234567890abcdef [CRLF]                         // data (ASCII/binary)
       //  0 [CRLF]                                        // 0: end of chunks
       //  optional-footer: some-value [CRLF]              // can be HTTP headers
       //  optional-another-footer: another-value [CRLF]   // can be HTTP headers
       //  [CRLF]

       xbuf_xcat(reply, "%x\r\n%s\r\n", len, readbuf);
// HERE! added code.
       char *client_arg_time=0;
       get_arg("time=", & client_arg_time, argc, argv);
       printf("%s\n", client_arg_time);
// End of my added code.    
       // -------------------------------------------------------------------------
       // return code
       // -------------------------------------------------------------------------
       // RC_NOHEADERS: do not generate HTTP headers
       // RC_STREAMING: call me again after send() is done
       return RC_NOHEADERS + RC_STREAMING; 
    }
    // ============================================================================
    // End of Source Code
    // ============================================================================
k.k. lou
  • 1,805
  • 2
  • 13
  • 16
  • This is missing some context. Is that the source code of G-WAN? What is your modification supposed to do? Why do you assume that `client_arg_time` should not be null at this point? What does “the first one” refer to? – Gilles 'SO- stop being evil' Jul 19 '14 at 09:05
  • the uri is ?time=1223456, so the get_arg("time=",...) gets the "1223456" and print to screen. It is ok, but for the first round only. Later, when the script is called by the wake_up(), it prints "(null)" not 1223456. If you check the example stream3.c from gwan, you can find the line of "xbuf_xcat(reply, "%x\r\n%s\r\n", len, readbuf);" – k.k. lou Jul 19 '14 at 12:44

1 Answers1

0

I'm not shure if wake_up would run the request with all the same configuration.

I would save all that i need on the data_t structure that is gc_alloc because it is an area of memory we know that is saved and used by the wake_up call. So start by extending the data_t structure to accommodate your info. Set it up just before step 2 and read it where you are currently using it.

typedef struct {int f;u32 time;} data_t;
...
char *client_arg_time=0;
get_arg("time=", &client_arg_time, argc, argv);
(*data)->time = atol(client_arg_time);
...
// HERE! added code.
printf("%u\n", (*data)->time);
// End of my added code.    
Paulo Melo
  • 176
  • 1
  • 1
  • i know the way to store the data in kv-store with a persistent pointer. But it doesn't fit my need. i need an uniqe information of each execution of the same servlet. So, the (*data)->time doesn't fit my need, since it is not an uniqe information. Every execution of the servlet goes to this pointer pointing to the same data. – k.k. lou Jul 20 '14 at 13:14
  • For example, every time the servlet is called, a fd is created for the wake_up function, and will get data from this fd when servlet is waken up. Every execution should have its own uniqe fd. i tried to get this uniqe information from get_agrv() or from get_env(). Until now, i can get file_fd and serve_time whenever the servlet is waken up by wake_up(). But these two information still cannot be an uniqe info of each execution. So, i tried get_arg() to get uniqr info from client, but face the above problem, i.e. (null) returns from get_agr(). – k.k. lou Jul 20 '14 at 13:15
  • the uniqe info is used to create an uniqe key for storing the fd in a kv-store. Then, i can get back the store fd pointer whenever the servlet is waken up. – k.k. lou Jul 20 '14 at 13:18
  • i found another info, i.e. get_env(argv, SESSION_ID). Is it useful to make up an uniqe key in a kv-store? – k.k. lou Jul 20 '14 at 13:29
  • Yes whenever you create an http connection you will get a session_id which is unique for the duration of the http handshake. But it will not keep though other connections... For that you will need to send it back as a cookie. – Paulo Melo Jul 20 '14 at 14:26
  • Pls advise the differences between connection file_fd and session_id. – k.k. lou Jul 20 '14 at 14:28
  • Are they one-to-one mapped, i.e. every connection has only one session_id? – k.k. lou Jul 20 '14 at 14:29
  • Yes. Only one session_id per handshake. If you need persistence, then consider creating a session cookie – Paulo Melo Jul 20 '14 at 14:31
  • Within one connection and it is keep-alive, would it accept several requests from the cilent? If yes, the connection file_fd will not be uniqe for my keyName. How about the session_id? Does G-WAN assign the same session_id to the requests within a keep-alived connection? – k.k. lou Jul 20 '14 at 14:38
  • My experiments say that each connection has it's own session_id, even if you use keep-alive. – Paulo Melo Jul 20 '14 at 14:43