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