"Fossies" - the Fresh Open Source Software Archive

Member "memcached-1.6.15/vendor/mcmc/example.c" (21 Feb 2022, 7604 Bytes) of package /linux/www/memcached-1.6.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <string.h>
    4 #include <assert.h>
    5 #include <stdint.h>
    6 #include <poll.h>
    7 #include <signal.h>
    8 #include <sys/uio.h>
    9 
   10 #include "mcmc.h"
   11 
   12 static void show_response(void *c, char *rbuf, size_t bufsize) {
   13     int status;
   14     // buffer shouldn't change until the read is completed.
   15     mcmc_resp_t resp;
   16     int go = 1;
   17     while (go) {
   18         go = 0;
   19         status = mcmc_read(c, rbuf, bufsize, &resp);
   20         if (status == MCMC_OK) {
   21             // OK means a response of some kind was read.
   22             char *val;
   23             // NOTE: is "it's not a miss, and vlen is 0" enough to indicate that
   24             // a 0 byte value was returned?
   25             if (resp.vlen != 0) {
   26                 if (resp.vlen == resp.vlen_read) {
   27                     val = resp.value;
   28                 } else {
   29                     val = malloc(resp.vlen);
   30                     int read = 0;
   31                     do {
   32                         status = mcmc_read_value(c, val, resp.vlen, &read);
   33                     } while (status == MCMC_WANT_READ);
   34                 }
   35                 if (resp.vlen > 0) {
   36                     val[resp.vlen-1] = '\0';
   37                     printf("Response value: %s\n", val);
   38                 }
   39             }
   40             switch (resp.type) {
   41                 case MCMC_RESP_GET:
   42                     // GET's need to continue until END is seen.
   43                     printf("in GET mode\n");
   44                     go = 1;
   45                     break;
   46                 case MCMC_RESP_END: // ascii done-with-get's
   47                     printf("END seen\n");
   48                     break;
   49                 case MCMC_RESP_META: // any meta command. they all return the same.
   50                     printf("META response seen\n");
   51                     if (resp.rlen > 0) {
   52                         resp.rline[resp.rlen-1] = '\0';
   53                         printf("META response line: %s\n", resp.rline);
   54                     }
   55                     break;
   56                 case MCMC_RESP_STAT:
   57                     // STAT responses. need to call mcmc_read() in loop until
   58                     // we get an end signal.
   59                     go = 1;
   60                     break;
   61                 default:
   62                     // TODO: type -> str func.
   63                     fprintf(stderr, "unknown response type: %d\n", resp.type);
   64                     break;
   65             }
   66         } else {
   67             // some kind of command specific error code (management commands)
   68             // or protocol error status.
   69             char code[MCMC_ERROR_CODE_MAX];
   70             char msg[MCMC_ERROR_MSG_MAX];
   71             mcmc_get_error(c, code, MCMC_ERROR_CODE_MAX, msg, MCMC_ERROR_MSG_MAX);
   72             fprintf(stderr, "Got error from mc: status [%d] code [%s] msg: [%s]\n", status, code, msg);
   73             // some errors don't have a msg. in this case msg[0] will be \0
   74         }
   75 
   76         int remain = 0;
   77         // advance us to the next command in the buffer, or ready for the next
   78         // mc_read().
   79         char *newbuf = mcmc_buffer_consume(c, &remain);
   80         printf("remains in buffer: %d\n", remain);
   81         if (remain == 0) {
   82             assert(newbuf == NULL);
   83             // we're done.
   84         } else {
   85             // there're still some bytes unconsumed by the client.
   86             // ensure the next time we call the client, the buffer has those
   87             // bytes at the front still.
   88             // NOTE: this _could_ be an entirely different buffer if we copied
   89             // the data off. The client is just tracking the # of bytes it
   90             // didn't gobble.
   91             // In this case we shuffle the bytes back to the front of our read
   92             // buffer.
   93             memmove(rbuf, newbuf, remain);
   94         }
   95     }
   96 }
   97 
   98 int main (int argc, char *agv[]) {
   99     // TODO: detect if C is pre-C11?
  100     printf("C version: %ld\n", __STDC_VERSION__);
  101 
  102     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
  103         perror("signal");
  104         exit(1);
  105     }
  106 
  107     void *c = malloc(mcmc_size(MCMC_OPTION_BLANK));
  108     // we only "need" the minimum buf size.
  109     // buffers large enough to fit return values result in fewer syscalls.
  110     size_t bufsize = mcmc_min_buffer_size(MCMC_OPTION_BLANK) * 2;
  111     // buffers are also generally agnostic to clients. The buffer must be
  112     // held and re-used when required by the API. When the buffer is empty,
  113     // it may be released to a pool or reused with other connections.
  114     char *rbuf = malloc(bufsize);
  115 
  116     int status;
  117 
  118     // API is blocking by default.
  119     status = mcmc_connect(c, "127.0.0.1", "11211", MCMC_OPTION_BLANK);
  120 
  121     if (status != MCMC_CONNECTED) {
  122         // TODO: mc_strerr(c);
  123         fprintf(stderr, "Failed to connect to memcached\n");
  124         return -1;
  125     }
  126 
  127     char *requests[5] = {"get foo\r\n",
  128         "get foob\r\n",
  129         "mg foo s t v\r\n",
  130         "mg doof s t v Omoo k\r\n",
  131         ""};
  132 
  133     for (int x = 0; strlen(requests[x]) != 0; x++) {
  134         // provide a buffer, the buffer length, and the number of responses
  135         // expected. ie; if pipelining many requests, or using noreply semantics.
  136         // FIXME: not confident "number of expected responses" is worth tracking
  137         // internally.
  138         status = mcmc_send_request(c, requests[x], strlen(requests[x]), 1);
  139         //printf("sent request: %s\n", requests[x]);
  140 
  141         if (status != MCMC_OK) {
  142             fprintf(stderr, "Failed to send request to memcached\n");
  143             return -1;
  144         }
  145 
  146         // Regardless of what command we sent, this should print out the response.
  147         show_response(c, rbuf, bufsize);
  148 
  149     }
  150 
  151     status = mcmc_disconnect(c);
  152     // The only free'ing needed.
  153     free(c);
  154 
  155     // TODO: stats example.
  156 
  157     // nonblocking example.
  158     c = malloc(mcmc_size(MCMC_OPTION_BLANK));
  159     // reuse bufsize/rbuf.
  160     status = mcmc_connect(c, "127.0.0.1", "11211", MCMC_OPTION_NONBLOCK);
  161     printf("nonblock connecting...\n");
  162     struct pollfd pfds[1];
  163     if (status == MCMC_CONNECTING) {
  164         // need to wait for socket to become writeable.
  165         pfds[0].fd = mcmc_fd(c);
  166         pfds[0].events = POLLOUT;
  167         if (poll(pfds, 1, 1000) != 1) {
  168             fprintf(stderr, "poll on connect timed out or failed\n");
  169             return -1;
  170         }
  171         int err = 0;
  172         if (pfds[0].revents & POLLOUT && mcmc_check_nonblock_connect(c, &err) == MCMC_OK) {
  173             printf("asynchronous connection completed: %d\n", err);
  174         } else {
  175             printf("failed to connect: %s\n", strerror(err));
  176             return -1;
  177         }
  178     } else {
  179         perror("connect");
  180         fprintf(stderr, "bad response to nonblock connection: %d\n", status);
  181         return -1;
  182     }
  183 
  184     // TODO: check socket for errors.
  185 
  186     // TODO: send request
  187     status = mcmc_send_request(c, requests[0], strlen(requests[0]), 1);
  188     //printf("sent request: %s\n", requests[x]);
  189 
  190     if (status != MCMC_OK) {
  191         fprintf(stderr, "Failed to send request to memcached\n");
  192         return -1;
  193     }
  194 
  195     mcmc_resp_t resp;
  196     status = mcmc_read(c, rbuf, bufsize, &resp);
  197     // this could race and fail, depending on the system.
  198     if (status == MCMC_WANT_READ) {
  199         printf("got MCMC_WANT_READ from a too-fast read as expected\n");
  200         pfds[0].fd = mcmc_fd(c);
  201         pfds[0].events = POLLIN;
  202         if (poll(pfds, 1, 1000) != 1) {
  203             fprintf(stderr, "poll on connect timed out or failed\n");
  204             return -1;
  205         }
  206         if (pfds[0].revents & POLLIN) {
  207             printf("asynchronous read ready\n");
  208         }
  209 
  210         show_response(c, rbuf, bufsize);
  211     }
  212 
  213     return 0;
  214 }