"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 }