1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 #include <sys/types.h>
25 #include <netinet/in.h>
26 #include "tscore/ink_defs.h"
27
28 #include "TxnSM.h"
29
30 extern TSTextLogObject protocol_plugin_log;
31
32 /* Fix me: currently, tunnelling server_response from OS to both cache and
33 client doesn't work for client_vc. So write data first to cache and then
34 write cached data to client. */
35
36 /* static functions */
37 int main_handler(TSCont contp, TSEvent event, void *data);
38
39 /* functions for clients */
40 int state_start(TSCont contp, TSEvent event, void *data);
41 int state_interface_with_client(TSCont contp, TSEvent event, TSVIO vio);
42 int state_read_request_from_client(TSCont contp, TSEvent event, TSVIO vio);
43 int state_send_response_to_client(TSCont contp, TSEvent event, TSVIO vio);
44
45 /* functions for cache operation */
46 int state_handle_cache_lookup(TSCont contp, TSEvent event, TSVConn vc);
47 int state_handle_cache_read_response(TSCont contp, TSEvent event, TSVIO vio);
48 int state_handle_cache_prepare_for_write(TSCont contp, TSEvent event, TSVConn vc);
49 int state_write_to_cache(TSCont contp, TSEvent event, TSVIO vio);
50
51 /* functions for servers */
52 int state_build_and_send_request(TSCont contp, TSEvent event, void *data);
53 int state_dns_lookup(TSCont contp, TSEvent event, TSHostLookupResult host_info);
54 int state_connect_to_server(TSCont contp, TSEvent event, TSVConn vc);
55 int state_interface_with_server(TSCont contp, TSEvent event, TSVIO vio);
56 int state_send_request_to_server(TSCont contp, TSEvent event, TSVIO vio);
57 int state_read_response_from_server(TSCont contp, TSEvent event, TSVIO vio);
58
59 /* misc functions */
60 int state_done(TSCont contp, TSEvent event, TSVIO vio);
61
62 int send_response_to_client(TSCont contp);
63 int prepare_to_die(TSCont contp);
64
65 char *get_info_from_buffer(TSIOBufferReader the_reader);
66 int is_request_end(char *buf);
67 int parse_request(char *request, char *server_name, char *file_name);
68 TSCacheKey CacheKeyCreate(char *file_name);
69
70 /* Continuation handler is a function pointer, this function
71 is to assign the continuation handler to a specific function. */
72 int
main_handler(TSCont contp,TSEvent event,void * data)73 main_handler(TSCont contp, TSEvent event, void *data)
74 {
75 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
76 TxnSMHandler q_current_handler = txn_sm->q_current_handler;
77
78 TSDebug(PLUGIN_NAME, "main_handler (contp %p event %d)", contp, event);
79
80 /* handle common cases errors */
81 if (event == TS_EVENT_ERROR) {
82 return prepare_to_die(contp);
83 }
84
85 if (q_current_handler != (TxnSMHandler)&state_interface_with_server) {
86 if (event == TS_EVENT_VCONN_EOS) {
87 return prepare_to_die(contp);
88 }
89 }
90
91 TSDebug(PLUGIN_NAME, "current_handler (%p)", q_current_handler);
92
93 return (*q_current_handler)(contp, event, data);
94 }
95
96 /* Create the Txn data structure and the continuation for the Txn. */
97 TSCont
TxnSMCreate(TSMutex pmutex,TSVConn client_vc,int server_port)98 TxnSMCreate(TSMutex pmutex, TSVConn client_vc, int server_port)
99 {
100 TSCont contp;
101 TxnSM *txn_sm;
102
103 txn_sm = (TxnSM *)TSmalloc(sizeof(TxnSM));
104
105 txn_sm->q_mutex = pmutex;
106 txn_sm->q_pending_action = NULL;
107
108 /* Txn will use this server port to connect to the origin server. */
109 txn_sm->q_server_port = server_port;
110 /* The client_vc is returned by TSNetAccept, refer to Protocol.c. */
111 txn_sm->q_client_vc = client_vc;
112 /* The server_vc will be created if Txn connects to the origin server. */
113 txn_sm->q_server_vc = NULL;
114
115 txn_sm->q_client_read_vio = NULL;
116 txn_sm->q_client_write_vio = NULL;
117 txn_sm->q_client_request_buffer = NULL;
118 txn_sm->q_client_response_buffer = NULL;
119 txn_sm->q_client_request_buffer_reader = NULL;
120 txn_sm->q_client_response_buffer_reader = NULL;
121
122 txn_sm->q_server_read_vio = NULL;
123 txn_sm->q_server_write_vio = NULL;
124 txn_sm->q_server_request_buffer = NULL;
125 txn_sm->q_server_response_buffer = NULL;
126 txn_sm->q_server_request_buffer_reader = NULL;
127
128 /* Char buffers to store client request and server response. */
129 txn_sm->q_client_request = (char *)TSmalloc(sizeof(char) * (MAX_REQUEST_LENGTH + 1));
130 memset(txn_sm->q_client_request, '\0', (sizeof(char) * (MAX_REQUEST_LENGTH + 1)));
131 txn_sm->q_server_response = NULL;
132 txn_sm->q_server_response_length = 0;
133 txn_sm->q_block_bytes_read = 0;
134 txn_sm->q_cache_vc = NULL;
135 txn_sm->q_cache_response_length = 0;
136 txn_sm->q_cache_read_buffer = NULL;
137 txn_sm->q_cache_read_buffer_reader = NULL;
138
139 txn_sm->q_server_name = (char *)TSmalloc(sizeof(char) * (MAX_SERVER_NAME_LENGTH + 1));
140 txn_sm->q_file_name = (char *)TSmalloc(sizeof(char) * (MAX_FILE_NAME_LENGTH + 1));
141
142 txn_sm->q_key = NULL;
143 txn_sm->q_magic = TXN_SM_ALIVE;
144
145 /* Set the current handler to be state_start. */
146 set_handler(txn_sm->q_current_handler, &state_start);
147
148 contp = TSContCreate(main_handler, txn_sm->q_mutex);
149 TSContDataSet(contp, txn_sm);
150 return contp;
151 }
152
153 /* This function starts to read incoming client request data from client_vc */
154 int
state_start(TSCont contp,TSEvent event ATS_UNUSED,void * data ATS_UNUSED)155 state_start(TSCont contp, TSEvent event ATS_UNUSED, void *data ATS_UNUSED)
156 {
157 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
158
159 if (!txn_sm->q_client_vc) {
160 return prepare_to_die(contp);
161 }
162
163 txn_sm->q_client_request_buffer = TSIOBufferCreate();
164 if (!txn_sm->q_client_request_buffer) {
165 return prepare_to_die(contp);
166 }
167 txn_sm->q_client_request_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_client_request_buffer);
168 if (!txn_sm->q_client_request_buffer_reader) {
169 return prepare_to_die(contp);
170 }
171
172 /* Now the IOBuffer and IOBufferReader is ready, the data from
173 client_vc can be read into the IOBuffer. Since we don't know
174 the size of the client request, set the expecting size to be
175 INT64_MAX, so that we will always get TS_EVENT_VCONN_READ_READY
176 event, but never TS_EVENT_VCONN_READ_COMPLETE event. */
177 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_interface_with_client);
178 txn_sm->q_client_read_vio = TSVConnRead(txn_sm->q_client_vc, contp, txn_sm->q_client_request_buffer, INT64_MAX);
179
180 return TS_SUCCESS;
181 }
182
183 /* This function is to call proper functions according to the
184 VIO argument. If it's read_vio, which means reading request from
185 client_vc, call state_read_request_from_client. If it's write_vio,
186 which means sending response to client_vc, call
187 state_send_response_to_client. If the event is TS_EVENT_VCONN_EOS,
188 which means the client closed socket and thus implies the client
189 drop all jobs between TxnSM and the client, so go to die. */
190 int
state_interface_with_client(TSCont contp,TSEvent event,TSVIO vio)191 state_interface_with_client(TSCont contp, TSEvent event, TSVIO vio)
192 {
193 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
194
195 TSDebug(PLUGIN_NAME, "enter state_interface_with_client");
196
197 txn_sm->q_pending_action = NULL;
198
199 if (vio == txn_sm->q_client_read_vio) {
200 return state_read_request_from_client(contp, event, vio);
201 }
202
203 /* vio == txn_sm->q_client_write_vio */
204 return state_send_response_to_client(contp, event, vio);
205 }
206
207 /* Data is read from client_vc, if all data for the request is in,
208 parse it and do cache lookup. */
209 int
state_read_request_from_client(TSCont contp,TSEvent event,TSVIO vio ATS_UNUSED)210 state_read_request_from_client(TSCont contp, TSEvent event, TSVIO vio ATS_UNUSED)
211 {
212 int bytes_read;
213
214 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
215
216 TSDebug(PLUGIN_NAME, "enter state_read_request_from_client");
217
218 switch (event) {
219 case TS_EVENT_VCONN_READ_READY:
220 bytes_read = TSIOBufferReaderAvail(txn_sm->q_client_request_buffer_reader);
221
222 if (bytes_read > 0) {
223 char *temp_buf = get_info_from_buffer(txn_sm->q_client_request_buffer_reader);
224 TSstrlcat(txn_sm->q_client_request, temp_buf, MAX_REQUEST_LENGTH + 1);
225 TSfree(temp_buf);
226
227 /* Check if the request is fully read, if so, do cache lookup. */
228 if (strstr(txn_sm->q_client_request, "\r\n\r\n") != NULL) {
229 temp_buf = (char *)TSmalloc(sizeof(char) * (strlen(txn_sm->q_client_request) + 1));
230 memcpy(temp_buf, txn_sm->q_client_request, strlen(txn_sm->q_client_request));
231 temp_buf[strlen(txn_sm->q_client_request)] = '\0';
232
233 int parse_result = parse_request(temp_buf, txn_sm->q_server_name, txn_sm->q_file_name);
234 TSfree(temp_buf);
235
236 if (parse_result != 1) {
237 return prepare_to_die(contp);
238 }
239
240 /* Start to do cache lookup */
241 TSDebug(PLUGIN_NAME, "Key material: file name is %s*****", txn_sm->q_file_name);
242 txn_sm->q_key = CacheKeyCreate(txn_sm->q_file_name);
243
244 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_lookup);
245 txn_sm->q_pending_action = TSCacheRead(contp, txn_sm->q_key);
246
247 return TS_SUCCESS;
248 }
249 }
250
251 /* The request is not fully read, reenable the read_vio. */
252 TSVIOReenable(txn_sm->q_client_read_vio);
253 break;
254
255 default: /* Shouldn't get here, prepare to die. */
256 return prepare_to_die(contp);
257 }
258 return TS_SUCCESS;
259 }
260
261 /* This function handle the cache lookup result. If MISS, try to
262 open cache write_vc for writing. Otherwise, use the vc returned
263 by the cache to read the data from the cache. */
264 int
state_handle_cache_lookup(TSCont contp,TSEvent event,TSVConn vc)265 state_handle_cache_lookup(TSCont contp, TSEvent event, TSVConn vc)
266 {
267 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
268 int64_t response_size;
269 int ret_val;
270
271 TSDebug(PLUGIN_NAME, "enter state_handle_cache_lookup");
272
273 switch (event) {
274 case TS_EVENT_CACHE_OPEN_READ:
275 TSDebug(PLUGIN_NAME, "cache hit!!!");
276 /* Cache hit. */
277
278 /* Write log */
279 ret_val = TSTextLogObjectWrite(protocol_plugin_log, "%s %s %d \n", txn_sm->q_file_name, txn_sm->q_server_name, 1);
280 if (ret_val != TS_SUCCESS) {
281 TSError("[%s] Fail to write into log", PLUGIN_NAME);
282 }
283
284 txn_sm->q_cache_vc = vc;
285 txn_sm->q_pending_action = NULL;
286
287 /* Get the size of the cached doc. */
288 response_size = TSVConnCacheObjectSizeGet(txn_sm->q_cache_vc);
289
290 /* Allocate IOBuffer to store data from the cache. */
291 txn_sm->q_client_response_buffer = TSIOBufferCreate();
292 if (!txn_sm->q_client_response_buffer) {
293 return prepare_to_die(contp);
294 }
295 txn_sm->q_client_response_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_client_response_buffer);
296 if (!txn_sm->q_client_response_buffer_reader) {
297 return prepare_to_die(contp);
298 }
299 txn_sm->q_cache_read_buffer = TSIOBufferCreate();
300 if (!txn_sm->q_cache_read_buffer) {
301 return prepare_to_die(contp);
302 }
303 txn_sm->q_cache_read_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_cache_read_buffer);
304 if (!txn_sm->q_cache_read_buffer_reader) {
305 return prepare_to_die(contp);
306 }
307
308 /* Read doc from the cache. */
309 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_read_response);
310 txn_sm->q_cache_read_vio = TSVConnRead(txn_sm->q_cache_vc, contp, txn_sm->q_cache_read_buffer, response_size);
311
312 break;
313
314 case TS_EVENT_CACHE_OPEN_READ_FAILED:
315 /* Cache miss or error, open cache write_vc. */
316 TSDebug(PLUGIN_NAME, "cache miss or error!!!");
317 /* Write log */
318 ret_val = TSTextLogObjectWrite(protocol_plugin_log, "%s %s %d \n", txn_sm->q_file_name, txn_sm->q_server_name, 0);
319
320 if (ret_val != TS_SUCCESS) {
321 TSError("[%s] Fail to write into log", PLUGIN_NAME);
322 }
323
324 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_prepare_for_write);
325 txn_sm->q_pending_action = TSCacheWrite(contp, txn_sm->q_key);
326 break;
327
328 default:
329 /* unknown event, abort transaction */
330 return prepare_to_die(contp);
331 }
332
333 return TS_SUCCESS;
334 }
335
336 static void
load_buffer_cache_data(TxnSM * txn_sm)337 load_buffer_cache_data(TxnSM *txn_sm)
338 {
339 /* transfer the data from the cache buffer (which must
340 fully be consumed on a VCONN_READY event, to the
341 server response buffer */
342 int rdr_avail = TSIOBufferReaderAvail(txn_sm->q_cache_read_buffer_reader);
343
344 TSDebug(PLUGIN_NAME, "entering buffer_cache_data");
345 TSDebug(PLUGIN_NAME, "loading %d bytes to buffer reader", rdr_avail);
346
347 TSAssert(rdr_avail > 0);
348
349 TSIOBufferCopy(txn_sm->q_client_response_buffer, /* (cache response buffer) */
350 txn_sm->q_cache_read_buffer_reader, /* (transient buffer) */
351 rdr_avail, 0);
352
353 TSIOBufferReaderConsume(txn_sm->q_cache_read_buffer_reader, rdr_avail);
354 }
355
356 /* If the document is fully read out of the cache, close the
357 cache read_vc, send the document to the client. Otherwise,
358 reenable the read_vio to read more data out. If some error
359 occurs, close the read_vc, open write_vc for writing the doc
360 into the cache.*/
361 int
state_handle_cache_read_response(TSCont contp,TSEvent event,TSVIO vio ATS_UNUSED)362 state_handle_cache_read_response(TSCont contp, TSEvent event, TSVIO vio ATS_UNUSED)
363 {
364 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
365
366 TSDebug(PLUGIN_NAME, "enter state_handle_cache_read_response");
367
368 txn_sm->q_pending_action = NULL;
369
370 switch (event) {
371 case TS_EVENT_VCONN_READ_COMPLETE:
372 load_buffer_cache_data(txn_sm);
373 TSVConnClose(txn_sm->q_cache_vc);
374 txn_sm->q_cache_vc = NULL;
375 txn_sm->q_cache_read_vio = NULL;
376 txn_sm->q_cache_write_vio = NULL;
377 TSIOBufferReaderFree(txn_sm->q_cache_read_buffer_reader);
378 TSIOBufferDestroy(txn_sm->q_cache_read_buffer);
379 txn_sm->q_cache_read_buffer_reader = NULL;
380 txn_sm->q_cache_read_buffer = NULL;
381 return send_response_to_client(contp);
382
383 case TS_EVENT_VCONN_READ_READY:
384 load_buffer_cache_data(txn_sm);
385
386 TSVIOReenable(txn_sm->q_cache_read_vio);
387 break;
388
389 default:
390 /* Error */
391 if (txn_sm->q_cache_vc) {
392 TSVConnClose(txn_sm->q_cache_vc);
393 txn_sm->q_cache_vc = NULL;
394 txn_sm->q_cache_read_vio = NULL;
395 txn_sm->q_cache_write_vio = NULL;
396 }
397
398 /* Open the write_vc, after getting doc from the origin server,
399 write the doc into the cache. */
400 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_prepare_for_write);
401 TSAssert(txn_sm->q_pending_action == NULL);
402 txn_sm->q_pending_action = TSCacheWrite(contp, txn_sm->q_key);
403 break;
404 }
405 return TS_SUCCESS;
406 }
407
408 /* The cache processor call us back with the vc to use for writing
409 data into the cache.
410 In case of error, abort txn. */
411 int
state_handle_cache_prepare_for_write(TSCont contp,TSEvent event,TSVConn vc)412 state_handle_cache_prepare_for_write(TSCont contp, TSEvent event, TSVConn vc)
413 {
414 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
415
416 TSDebug(PLUGIN_NAME, "enter state_handle_cache_prepare_for_write");
417
418 txn_sm->q_pending_action = NULL;
419
420 switch (event) {
421 case TS_EVENT_CACHE_OPEN_WRITE:
422 txn_sm->q_cache_vc = vc;
423 break;
424 default:
425 TSError("[%s] Can't open cache write_vc, aborting txn", PLUGIN_NAME);
426 txn_sm->q_cache_vc = NULL;
427 return prepare_to_die(contp);
428 break;
429 }
430 return state_build_and_send_request(contp, 0, NULL);
431 }
432
433 /* Cache miss or error case. Start the process to send the request
434 the origin server. */
435 int
state_build_and_send_request(TSCont contp,TSEvent event ATS_UNUSED,void * data ATS_UNUSED)436 state_build_and_send_request(TSCont contp, TSEvent event ATS_UNUSED, void *data ATS_UNUSED)
437 {
438 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
439
440 TSDebug(PLUGIN_NAME, "enter state_build_and_send_request");
441
442 txn_sm->q_pending_action = NULL;
443
444 txn_sm->q_server_request_buffer = TSIOBufferCreate();
445 if (!txn_sm->q_server_request_buffer) {
446 return prepare_to_die(contp);
447 }
448 txn_sm->q_server_request_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_server_request_buffer);
449 if (!txn_sm->q_server_request_buffer_reader) {
450 return prepare_to_die(contp);
451 }
452 txn_sm->q_server_response_buffer = TSIOBufferCreate();
453 if (!txn_sm->q_server_response_buffer) {
454 return prepare_to_die(contp);
455 }
456 txn_sm->q_cache_response_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_server_response_buffer);
457 if (!txn_sm->q_cache_response_buffer_reader) {
458 return prepare_to_die(contp);
459 }
460
461 /* Marshal request */
462 TSIOBufferWrite(txn_sm->q_server_request_buffer, txn_sm->q_client_request, strlen(txn_sm->q_client_request));
463
464 /* First thing to do is to get the server IP from the server host name. */
465 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_dns_lookup);
466 TSAssert(txn_sm->q_pending_action == NULL);
467 txn_sm->q_pending_action = TSHostLookup(contp, txn_sm->q_server_name, strlen(txn_sm->q_server_name));
468
469 TSAssert(txn_sm->q_pending_action);
470 TSDebug(PLUGIN_NAME, "initiating host lookup");
471
472 return TS_SUCCESS;
473 }
474
475 /* If Host lookup is successfully, connect to that IP. */
476 int
state_dns_lookup(TSCont contp,TSEvent event,TSHostLookupResult host_info)477 state_dns_lookup(TSCont contp, TSEvent event, TSHostLookupResult host_info)
478 {
479 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
480 struct sockaddr const *q_server_addr;
481 struct sockaddr_in ip_addr;
482
483 TSDebug(PLUGIN_NAME, "enter state_dns_lookup");
484
485 /* Can't find the server IP. */
486 if (event != TS_EVENT_HOST_LOOKUP || !host_info) {
487 return prepare_to_die(contp);
488 }
489 txn_sm->q_pending_action = NULL;
490
491 /* Get the server IP from data structure TSHostLookupResult. */
492 q_server_addr = TSHostLookupResultAddrGet(host_info);
493
494 /* Connect to the server using its IP. */
495 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_connect_to_server);
496 TSAssert(txn_sm->q_pending_action == NULL);
497 TSAssert(q_server_addr->sa_family == AF_INET); /* NO IPv6 in this plugin */
498
499 memcpy(&ip_addr, q_server_addr, sizeof(ip_addr));
500 ip_addr.sin_port = txn_sm->q_server_port;
501 txn_sm->q_pending_action = TSNetConnect(contp, (struct sockaddr const *)&ip_addr);
502
503 return TS_SUCCESS;
504 }
505
506 /* Net Processor calls back, if succeeded, the net_vc is returned.
507 Note here, even if the event is TS_EVENT_NET_CONNECT, it doesn't
508 mean the net connection is set up because TSNetConnect is non-blocking.
509 Do VConnWrite to the net_vc, if fails, that means there is no net
510 connection. */
511 int
state_connect_to_server(TSCont contp,TSEvent event,TSVConn vc)512 state_connect_to_server(TSCont contp, TSEvent event, TSVConn vc)
513 {
514 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
515
516 TSDebug(PLUGIN_NAME, "enter state_connect_to_server");
517
518 /* TSNetConnect failed. */
519 if (event != TS_EVENT_NET_CONNECT) {
520 return prepare_to_die(contp);
521 }
522 txn_sm->q_pending_action = NULL;
523
524 txn_sm->q_server_vc = vc;
525
526 /* server_vc will be used to write request and read response. */
527 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_send_request_to_server);
528
529 /* Actively write the request to the net_vc. */
530 txn_sm->q_server_write_vio =
531 TSVConnWrite(txn_sm->q_server_vc, contp, txn_sm->q_server_request_buffer_reader, strlen(txn_sm->q_client_request));
532 return TS_SUCCESS;
533 }
534
535 /* Net Processor calls back, if write complete, wait for the response
536 coming in, otherwise, reenable the write_vio. */
537 int
state_send_request_to_server(TSCont contp,TSEvent event,TSVIO vio)538 state_send_request_to_server(TSCont contp, TSEvent event, TSVIO vio)
539 {
540 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
541
542 TSDebug(PLUGIN_NAME, "enter state_send_request_to_server");
543
544 switch (event) {
545 case TS_EVENT_VCONN_WRITE_READY:
546 TSVIOReenable(vio);
547 break;
548 case TS_EVENT_VCONN_WRITE_COMPLETE:
549 /* Waiting for the incoming response. */
550 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_interface_with_server);
551 txn_sm->q_server_read_vio = TSVConnRead(txn_sm->q_server_vc, contp, txn_sm->q_server_response_buffer, INT64_MAX);
552 break;
553
554 /* it could be failure of TSNetConnect */
555 default:
556 return prepare_to_die(contp);
557 }
558 return TS_SUCCESS;
559 }
560
561 /* Call correct handler according to the vio type. */
562 int
state_interface_with_server(TSCont contp,TSEvent event,TSVIO vio)563 state_interface_with_server(TSCont contp, TSEvent event, TSVIO vio)
564 {
565 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
566
567 TSDebug(PLUGIN_NAME, "enter state_interface_with_server");
568
569 txn_sm->q_pending_action = NULL;
570
571 switch (event) {
572 /* This is returned from cache_vc. */
573 case TS_EVENT_VCONN_WRITE_READY:
574 case TS_EVENT_VCONN_WRITE_COMPLETE:
575 return state_write_to_cache(contp, event, vio);
576 /* Otherwise, handle events from server. */
577 case TS_EVENT_VCONN_READ_READY:
578 /* Actually, we shouldn't get READ_COMPLETE because we set bytes
579 count to be INT64_MAX. */
580 case TS_EVENT_VCONN_READ_COMPLETE:
581 return state_read_response_from_server(contp, event, vio);
582
583 /* all data of the response come in. */
584 case TS_EVENT_VCONN_EOS:
585 TSDebug(PLUGIN_NAME, "get server eos");
586 /* There is no more use of server_vc, close it. */
587 if (txn_sm->q_server_vc) {
588 TSVConnClose(txn_sm->q_server_vc);
589 txn_sm->q_server_vc = NULL;
590 }
591 txn_sm->q_server_read_vio = NULL;
592 txn_sm->q_server_write_vio = NULL;
593
594 /* Check if the response is good */
595 if (txn_sm->q_server_response_length == 0) {
596 /* This is the bad response. Close client_vc. */
597 if (txn_sm->q_client_vc) {
598 TSVConnClose(txn_sm->q_client_vc);
599 txn_sm->q_client_vc = NULL;
600 }
601 txn_sm->q_client_read_vio = NULL;
602 txn_sm->q_client_write_vio = NULL;
603
604 /* Close cache_vc as well. */
605 if (txn_sm->q_cache_vc) {
606 TSVConnClose(txn_sm->q_cache_vc);
607 txn_sm->q_cache_vc = NULL;
608 }
609 txn_sm->q_cache_write_vio = NULL;
610 return state_done(contp, 0, NULL);
611 }
612
613 if (txn_sm->q_cache_response_length >= txn_sm->q_server_response_length) {
614 /* Write is complete, close the cache_vc. */
615 TSVConnClose(txn_sm->q_cache_vc);
616 txn_sm->q_cache_vc = NULL;
617 txn_sm->q_cache_write_vio = NULL;
618 TSIOBufferReaderFree(txn_sm->q_cache_response_buffer_reader);
619
620 /* Open cache_vc to read data and send to client. */
621 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_lookup);
622 txn_sm->q_pending_action = TSCacheRead(contp, txn_sm->q_key);
623 } else { /* not done with writing into cache */
624
625 TSDebug(PLUGIN_NAME, "cache_response_length is %d, server response length is %d", txn_sm->q_cache_response_length,
626 txn_sm->q_server_response_length);
627 TSVIOReenable(txn_sm->q_cache_write_vio);
628 }
629
630 default:
631 break;
632 }
633
634 return TS_SUCCESS;
635 }
636
637 /* The response comes in. If the origin server finishes writing, it
638 will close the socket, so the event returned from the net_vc is
639 TS_EVENT_VCONN_EOS. By this event, TxnSM knows all data of the
640 response arrives and so parse it, save a copy in the cache and
641 send the doc to the client. If reading is not done, reenable the
642 read_vio. */
643 int
state_read_response_from_server(TSCont contp,TSEvent event ATS_UNUSED,TSVIO vio ATS_UNUSED)644 state_read_response_from_server(TSCont contp, TSEvent event ATS_UNUSED, TSVIO vio ATS_UNUSED)
645 {
646 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
647 int bytes_read = 0;
648
649 TSDebug(PLUGIN_NAME, "enter state_read_response_from_server");
650
651 bytes_read = TSIOBufferReaderAvail(txn_sm->q_cache_response_buffer_reader);
652
653 if ((bytes_read > 0) && (txn_sm->q_cache_vc)) {
654 /* If this is the first write, do TSVConnWrite, otherwise, simply
655 reenable q_cache_write_vio. */
656 if (txn_sm->q_server_response_length == 0) {
657 txn_sm->q_cache_write_vio = TSVConnWrite(txn_sm->q_cache_vc, contp, txn_sm->q_cache_response_buffer_reader, bytes_read);
658 } else {
659 TSAssert(txn_sm->q_server_response_length > 0);
660 TSVIOReenable(txn_sm->q_cache_write_vio);
661 txn_sm->q_block_bytes_read = bytes_read;
662 /*
663 txn_sm->q_cache_write_vio = TSVConnWrite (txn_sm->q_cache_vc,
664 contp,
665 txn_sm->q_cache_response_buffer_reader,
666 bytes_read);
667 */
668 }
669 }
670
671 txn_sm->q_server_response_length += bytes_read;
672 TSDebug(PLUGIN_NAME, "bytes read is %d, total response length is %d", bytes_read, txn_sm->q_server_response_length);
673
674 return TS_SUCCESS;
675 }
676
677 /* If the whole doc has been written into the cache, send the response
678 to the client, otherwise, reenable the read_vio. */
679 int
state_write_to_cache(TSCont contp,TSEvent event,TSVIO vio)680 state_write_to_cache(TSCont contp, TSEvent event, TSVIO vio)
681 {
682 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
683
684 TSDebug(PLUGIN_NAME, "enter state_write_to_cache");
685
686 switch (event) {
687 case TS_EVENT_VCONN_WRITE_READY:
688 TSVIOReenable(txn_sm->q_cache_write_vio);
689 return TS_SUCCESS;
690
691 case TS_EVENT_VCONN_WRITE_COMPLETE:
692 TSDebug(PLUGIN_NAME, "nbytes %" PRId64 ", ndone %" PRId64, TSVIONBytesGet(vio), TSVIONDoneGet(vio));
693 /* Since the first write is through TSVConnWrite, which already consume
694 the data in cache_buffer_reader, don't consume it again. */
695 if (txn_sm->q_cache_response_length > 0 && txn_sm->q_block_bytes_read > 0) {
696 TSIOBufferReaderConsume(txn_sm->q_cache_response_buffer_reader, txn_sm->q_block_bytes_read);
697 }
698
699 txn_sm->q_cache_response_length += TSVIONBytesGet(vio);
700
701 /* If not all data have been read in, we have to reenable the read_vio */
702 if (txn_sm->q_server_vc != NULL) {
703 TSDebug(PLUGIN_NAME, "re-enable server_read_vio");
704 TSVIOReenable(txn_sm->q_server_read_vio);
705 return TS_SUCCESS;
706 }
707
708 if (txn_sm->q_cache_response_length >= txn_sm->q_server_response_length) {
709 /* Write is complete, close the cache_vc. */
710 TSDebug(PLUGIN_NAME, "close cache_vc, cache_response_length is %d, server_response_length is %d",
711 txn_sm->q_cache_response_length, txn_sm->q_server_response_length);
712 TSVConnClose(txn_sm->q_cache_vc);
713 txn_sm->q_cache_vc = NULL;
714 txn_sm->q_cache_write_vio = NULL;
715 TSIOBufferReaderFree(txn_sm->q_cache_response_buffer_reader);
716
717 /* Open cache_vc to read data and send to client. */
718 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_lookup);
719 txn_sm->q_pending_action = TSCacheRead(contp, txn_sm->q_key);
720 } else { /* not done with writing into cache */
721
722 TSDebug(PLUGIN_NAME, "re-enable cache_write_vio");
723 TSVIOReenable(txn_sm->q_cache_write_vio);
724 }
725 return TS_SUCCESS;
726 default:
727 break;
728 }
729
730 /* Something wrong if getting here. */
731 return prepare_to_die(contp);
732 }
733
734 /* If the response has been fully written into the client_vc,
735 which means this txn is done, close the client_vc. Otherwise,
736 reenable the write_vio. */
737 int
state_send_response_to_client(TSCont contp,TSEvent event,TSVIO vio)738 state_send_response_to_client(TSCont contp, TSEvent event, TSVIO vio)
739 {
740 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
741
742 TSDebug(PLUGIN_NAME, "enter state_send_response_to_client");
743
744 switch (event) {
745 case TS_EVENT_VCONN_WRITE_READY:
746 TSDebug(PLUGIN_NAME, " . wr ready");
747 TSDebug(PLUGIN_NAME, "write_ready: nbytes %" PRId64 ", ndone %" PRId64, TSVIONBytesGet(vio), TSVIONDoneGet(vio));
748 TSVIOReenable(txn_sm->q_client_write_vio);
749 break;
750
751 case TS_EVENT_VCONN_WRITE_COMPLETE:
752 TSDebug(PLUGIN_NAME, " . wr complete");
753 TSDebug(PLUGIN_NAME, "write_complete: nbytes %" PRId64 ", ndone %" PRId64, TSVIONBytesGet(vio), TSVIONDoneGet(vio));
754 /* Finished sending all data to client, close client_vc. */
755 if (txn_sm->q_client_vc) {
756 TSVConnClose(txn_sm->q_client_vc);
757 txn_sm->q_client_vc = NULL;
758 }
759 txn_sm->q_client_read_vio = NULL;
760 txn_sm->q_client_write_vio = NULL;
761
762 return state_done(contp, 0, NULL);
763
764 default:
765 TSDebug(PLUGIN_NAME, " . default handler");
766 return prepare_to_die(contp);
767 }
768
769 TSDebug(PLUGIN_NAME, "leaving send_response_to_client");
770
771 return TS_SUCCESS;
772 }
773
774 /* There is something wrong, abort client, server and cache vc
775 if they exist. */
776 int
prepare_to_die(TSCont contp)777 prepare_to_die(TSCont contp)
778 {
779 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
780
781 TSDebug(PLUGIN_NAME, "enter prepare_to_die");
782 if (txn_sm->q_client_vc) {
783 TSVConnAbort(txn_sm->q_client_vc, 1);
784 txn_sm->q_client_vc = NULL;
785 }
786 txn_sm->q_client_read_vio = NULL;
787 txn_sm->q_client_write_vio = NULL;
788
789 if (txn_sm->q_server_vc) {
790 TSVConnAbort(txn_sm->q_server_vc, 1);
791 txn_sm->q_server_vc = NULL;
792 }
793 txn_sm->q_server_read_vio = NULL;
794 txn_sm->q_server_write_vio = NULL;
795
796 if (txn_sm->q_cache_vc) {
797 TSVConnAbort(txn_sm->q_cache_vc, 1);
798 txn_sm->q_cache_vc = NULL;
799 }
800 txn_sm->q_cache_read_vio = NULL;
801 txn_sm->q_cache_write_vio = NULL;
802
803 return state_done(contp, 0, NULL);
804 }
805
806 int
state_done(TSCont contp,TSEvent event ATS_UNUSED,TSVIO vio ATS_UNUSED)807 state_done(TSCont contp, TSEvent event ATS_UNUSED, TSVIO vio ATS_UNUSED)
808 {
809 TxnSM *txn_sm = (TxnSM *)TSContDataGet(contp);
810
811 TSDebug(PLUGIN_NAME, "enter state_done");
812
813 if (txn_sm->q_pending_action && !TSActionDone(txn_sm->q_pending_action)) {
814 TSDebug(PLUGIN_NAME, "cancelling pending action %p", txn_sm->q_pending_action);
815 TSActionCancel(txn_sm->q_pending_action);
816 } else if (txn_sm->q_pending_action) {
817 TSDebug(PLUGIN_NAME, "action is done %p", txn_sm->q_pending_action);
818 }
819
820 txn_sm->q_pending_action = NULL;
821 txn_sm->q_mutex = NULL;
822
823 if (txn_sm->q_client_request_buffer) {
824 if (txn_sm->q_client_request_buffer_reader) {
825 TSIOBufferReaderFree(txn_sm->q_client_request_buffer_reader);
826 }
827 TSIOBufferDestroy(txn_sm->q_client_request_buffer);
828 txn_sm->q_client_request_buffer = NULL;
829 txn_sm->q_client_request_buffer_reader = NULL;
830 }
831
832 if (txn_sm->q_client_response_buffer) {
833 if (txn_sm->q_client_response_buffer_reader) {
834 TSIOBufferReaderFree(txn_sm->q_client_response_buffer_reader);
835 }
836
837 TSIOBufferDestroy(txn_sm->q_client_response_buffer);
838 txn_sm->q_client_response_buffer = NULL;
839 txn_sm->q_client_response_buffer_reader = NULL;
840 }
841
842 if (txn_sm->q_cache_read_buffer) {
843 if (txn_sm->q_cache_read_buffer_reader) {
844 TSIOBufferReaderFree(txn_sm->q_cache_read_buffer_reader);
845 }
846 TSIOBufferDestroy(txn_sm->q_cache_read_buffer);
847 txn_sm->q_cache_read_buffer = NULL;
848 txn_sm->q_cache_read_buffer_reader = NULL;
849 }
850
851 if (txn_sm->q_server_request_buffer) {
852 if (txn_sm->q_server_request_buffer_reader) {
853 TSIOBufferReaderFree(txn_sm->q_server_request_buffer_reader);
854 }
855 TSIOBufferDestroy(txn_sm->q_server_request_buffer);
856 txn_sm->q_server_request_buffer = NULL;
857 txn_sm->q_server_request_buffer_reader = NULL;
858 }
859
860 if (txn_sm->q_server_response_buffer) {
861 TSIOBufferDestroy(txn_sm->q_server_response_buffer);
862 txn_sm->q_server_response_buffer = NULL;
863 }
864
865 if (txn_sm->q_server_name) {
866 TSfree(txn_sm->q_server_name);
867 txn_sm->q_server_name = NULL;
868 }
869
870 if (txn_sm->q_file_name) {
871 TSfree(txn_sm->q_file_name);
872 txn_sm->q_file_name = NULL;
873 }
874
875 if (txn_sm->q_key) {
876 TSCacheKeyDestroy(txn_sm->q_key);
877 }
878
879 if (txn_sm->q_client_request) {
880 TSfree(txn_sm->q_client_request);
881 txn_sm->q_client_request = NULL;
882 }
883
884 if (txn_sm->q_server_response) {
885 TSfree(txn_sm->q_server_response);
886 txn_sm->q_server_response = NULL;
887 }
888
889 txn_sm->q_magic = TXN_SM_DEAD;
890 TSfree(txn_sm);
891
892 TSContDestroy(contp);
893 return TS_EVENT_NONE;
894 }
895
896 /* Write the data into the client_vc. */
897 int
send_response_to_client(TSCont contp)898 send_response_to_client(TSCont contp)
899 {
900 TxnSM *txn_sm;
901 int response_len;
902
903 TSDebug(PLUGIN_NAME, "enter send_response_to_client");
904
905 txn_sm = (TxnSM *)TSContDataGet(contp);
906 response_len = TSIOBufferReaderAvail(txn_sm->q_client_response_buffer_reader);
907
908 TSDebug(PLUGIN_NAME, " . resp_len is %d", response_len);
909
910 set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_interface_with_client);
911 txn_sm->q_client_write_vio = TSVConnWrite(txn_sm->q_client_vc, contp, txn_sm->q_client_response_buffer_reader, response_len);
912 return TS_SUCCESS;
913 }
914
915 /* Read data out through the_reader and save it in a char buffer. */
916 char *
get_info_from_buffer(TSIOBufferReader the_reader)917 get_info_from_buffer(TSIOBufferReader the_reader)
918 {
919 char *info;
920 char *info_start;
921
922 int64_t read_avail, read_done;
923
924 if (!the_reader) {
925 return NULL;
926 }
927
928 read_avail = TSIOBufferReaderAvail(the_reader);
929
930 info = (char *)TSmalloc(sizeof(char) * read_avail);
931 if (info == NULL) {
932 return NULL;
933 }
934 info_start = info;
935
936 /* Read the data out of the reader */
937 while (read_avail > 0) {
938 TSIOBufferBlock blk = TSIOBufferReaderStart(the_reader);
939 char *buf = (char *)TSIOBufferBlockReadStart(blk, the_reader, &read_done);
940 memcpy(info, buf, read_done);
941 if (read_done > 0) {
942 TSIOBufferReaderConsume(the_reader, read_done);
943 read_avail -= read_done;
944 info += read_done;
945 }
946 }
947
948 return info_start;
949 }
950
951 /* Check if the end token is in the char buffer. */
952 int
is_request_end(char * buf)953 is_request_end(char *buf)
954 {
955 char *temp = strstr(buf, " \n\n");
956 if (!temp) {
957 return 0;
958 }
959 return 1;
960 }
961
962 /* Parse the server_name and file name from the request. */
963 int
parse_request(char * request,char * server_name,char * file_name)964 parse_request(char *request, char *server_name, char *file_name)
965 {
966 char *saveptr = NULL;
967 char *temp = strtok_r(request, " ", &saveptr);
968
969 if (temp != NULL) {
970 TSstrlcpy(server_name, temp, MAX_SERVER_NAME_LENGTH + 1);
971 } else {
972 return 0;
973 }
974
975 temp = strtok_r(NULL, " ", &saveptr);
976 if (temp != NULL) {
977 TSstrlcpy(file_name, temp, MAX_FILE_NAME_LENGTH + 1);
978 } else {
979 return 0;
980 }
981
982 return 1;
983 }
984
985 /* Create 128-bit cache key based on the input string, in this case,
986 the file_name of the requested doc. */
987 TSCacheKey
CacheKeyCreate(char * file_name)988 CacheKeyCreate(char *file_name)
989 {
990 TSCacheKey key;
991
992 /* TSCacheKeyCreate is to allocate memory space for the key */
993 key = TSCacheKeyCreate();
994
995 /* TSCacheKeyDigestSet is to compute TSCackeKey from the input string */
996 TSCacheKeyDigestSet(key, file_name, strlen(file_name));
997 return key;
998 }
999