1 /** @file
2 
3   Implements unit test for SDK APIs
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 // Turn off -Wdeprecated so that we can still test our own deprecated APIs.
25 #if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
26 #pragma GCC diagnostic ignored "-Wdeprecated"
27 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
28 #endif
29 
30 #include <sys/types.h>
31 #include <arpa/inet.h> /* For htonl */
32 
33 #include <cerrno>
34 #include <pthread.h>
35 #include <unistd.h>
36 #include <cstdio>
37 #include <cstring>
38 
39 #include "tscore/ink_config.h"
40 #include "tscore/ink_sprintf.h"
41 #include "tscore/ink_file.h"
42 #include "tscore/Regression.h"
43 #include "tscore/Filenames.h"
44 #include "ts/ts.h"
45 #include "ts/experimental.h"
46 #include "records/I_RecCore.h"
47 
48 #include "P_Net.h"
49 #include "records/I_RecHttp.h"
50 
51 #include "http/HttpSM.h"
52 #include "tscore/TestBox.h"
53 
54 // This used to be in InkAPITestTool.cc, which we'd just #include here... But that seemed silly.
55 #define SDBG_TAG "SockServer"
56 #define CDBG_TAG "SockClient"
57 
58 #define IP(a, b, c, d) htonl((a) << 24 | (b) << 16 | (c) << 8 | (d))
59 
60 #define SET_TEST_HANDLER(_d, _s) \
61   {                              \
62     _d = _s;                     \
63   }
64 
65 #define MAGIC_ALIVE 0xfeedbaba
66 #define MAGIC_DEAD 0xdeadbeef
67 
68 #define SYNSERVER_LISTEN_PORT 3300
69 #define SYNSERVER_DUMMY_PORT -1
70 
71 #define PROXY_CONFIG_NAME_HTTP_PORT "proxy.config.http.server_port"
72 #define PROXY_HTTP_DEFAULT_PORT 8080
73 
74 #define REQUEST_MAX_SIZE 4095
75 #define RESPONSE_MAX_SIZE 4095
76 
77 #define HTTP_REQUEST_END "\r\n\r\n"
78 
79 // each request/response includes an identifier as a Mime field
80 #define X_REQUEST_ID "X-Request-ID"
81 #define X_RESPONSE_ID "X-Response-ID"
82 
83 #define ERROR_BODY "TESTING ERROR PAGE"
84 #define TRANSFORM_APPEND_STRING "This is a transformed response"
85 
86 //////////////////////////////////////////////////////////////////////////////
87 // STRUCTURES
88 //////////////////////////////////////////////////////////////////////////////
89 
90 using TxnHandler = int (*)(TSCont, TSEvent, void *);
91 
92 /* Server transaction structure */
93 typedef struct {
94   TSVConn vconn;
95 
96   TSVIO read_vio;
97   TSIOBuffer req_buffer;
98   TSIOBufferReader req_reader;
99 
100   TSVIO write_vio;
101   TSIOBuffer resp_buffer;
102   TSIOBufferReader resp_reader;
103 
104   char request[REQUEST_MAX_SIZE + 1];
105   int request_len;
106 
107   TxnHandler current_handler;
108   unsigned int magic;
109 } ServerTxn;
110 
111 /* Server structure */
112 typedef struct {
113   int accept_port;
114   TSAction accept_action;
115   TSCont accept_cont;
116   unsigned int magic;
117 } SocketServer;
118 
119 typedef enum {
120   REQUEST_SUCCESS,
121   REQUEST_INPROGRESS,
122   REQUEST_FAILURE,
123 } RequestStatus;
124 
125 /* Client structure */
126 typedef struct {
127   TSVConn vconn;
128 
129   TSVIO read_vio;
130   TSIOBuffer req_buffer;
131   TSIOBufferReader req_reader;
132 
133   TSVIO write_vio;
134   TSIOBuffer resp_buffer;
135   TSIOBufferReader resp_reader;
136 
137   char *request;
138   char response[RESPONSE_MAX_SIZE + 1];
139   int response_len;
140 
141   RequestStatus status;
142 
143   int connect_port;
144   int local_port;
145   uint64_t connect_ip;
146   TSAction connect_action;
147 
148   TxnHandler current_handler;
149 
150   unsigned int magic;
151 } ClientTxn;
152 
153 //////////////////////////////////////////////////////////////////////////////
154 // DECLARATIONS
155 //////////////////////////////////////////////////////////////////////////////
156 
157 /* utility */
158 static char *get_body_ptr(const char *request);
159 static char *generate_request(int test_case);
160 static char *generate_response(const char *request);
161 static int get_request_id(TSHttpTxn txnp);
162 
163 /* client side */
164 static ClientTxn *synclient_txn_create();
165 static int synclient_txn_delete(ClientTxn *txn);
166 static void synclient_txn_close(ClientTxn *txn);
167 static int synclient_txn_send_request(ClientTxn *txn, char *request);
168 static int synclient_txn_send_request_to_vc(ClientTxn *txn, char *request, TSVConn vc);
169 static int synclient_txn_read_response(TSCont contp);
170 static int synclient_txn_read_response_handler(TSCont contp, TSEvent event, void *data);
171 static int synclient_txn_write_request(TSCont contp);
172 static int synclient_txn_write_request_handler(TSCont contp, TSEvent event, void *data);
173 static int synclient_txn_connect_handler(TSCont contp, TSEvent event, void *data);
174 static int synclient_txn_main_handler(TSCont contp, TSEvent event, void *data);
175 
176 /* Server side */
177 SocketServer *synserver_create(int port);
178 static int synserver_start(SocketServer *s);
179 static int synserver_stop(SocketServer *s);
180 static int synserver_delete(SocketServer *s);
181 static int synserver_vc_accept(TSCont contp, TSEvent event, void *data);
182 static int synserver_vc_refuse(TSCont contp, TSEvent event, void *data);
183 static int synserver_txn_close(TSCont contp);
184 static int synserver_txn_write_response(TSCont contp);
185 static int synserver_txn_write_response_handler(TSCont contp, TSEvent event, void *data);
186 static int synserver_txn_read_request(TSCont contp);
187 static int synserver_txn_read_request_handler(TSCont contp, TSEvent event, void *data);
188 static int synserver_txn_main_handler(TSCont contp, TSEvent event, void *data);
189 
190 //////////////////////////////////////////////////////////////////////////////
191 // REQUESTS/RESPONSES GENERATION
192 //////////////////////////////////////////////////////////////////////////////
193 
194 static char *
get_body_ptr(const char * request)195 get_body_ptr(const char *request)
196 {
197   char *ptr = const_cast<char *>(strstr(request, (const char *)"\r\n\r\n"));
198   return (ptr != nullptr) ? (ptr + 4) : nullptr;
199 }
200 
201 /* Caller must free returned request */
202 static char *
generate_request(int test_case)203 generate_request(int test_case)
204 {
205 // We define request formats.
206 // Each format has an X-Request-ID field that contains the id of the testcase
207 #define HTTP_REQUEST_DEFAULT_FORMAT                   \
208   "GET http://127.0.0.1:%d/default.html HTTP/1.0\r\n" \
209   "X-Request-ID: %d\r\n"                              \
210   "\r\n"
211 
212 #define HTTP_REQUEST_FORMAT1                          \
213   "GET http://127.0.0.1:%d/format1.html HTTP/1.0\r\n" \
214   "X-Request-ID: %d\r\n"                              \
215   "\r\n"
216 
217 #define HTTP_REQUEST_FORMAT2                          \
218   "GET http://127.0.0.1:%d/format2.html HTTP/1.0\r\n" \
219   "X-Request-ID: %d\r\n"                              \
220   "Content-Type: text/html\r\n"                       \
221   "\r\n"
222 #define HTTP_REQUEST_FORMAT3                          \
223   "GET http://127.0.0.1:%d/format3.html HTTP/1.0\r\n" \
224   "X-Request-ID: %d\r\n"                              \
225   "Response: Error\r\n"                               \
226   "\r\n"
227 #define HTTP_REQUEST_FORMAT4                          \
228   "GET http://127.0.0.1:%d/format4.html HTTP/1.0\r\n" \
229   "X-Request-ID: %d\r\n"                              \
230   "Request:%d\r\n"                                    \
231   "\r\n"
232 #define HTTP_REQUEST_FORMAT5                          \
233   "GET http://127.0.0.1:%d/format5.html HTTP/1.0\r\n" \
234   "X-Request-ID: %d\r\n"                              \
235   "Request:%d\r\n"                                    \
236   "\r\n"
237 #define HTTP_REQUEST_FORMAT6                         \
238   "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
239   "X-Request-ID: %d\r\n"                             \
240   "Accept-Language: English\r\n"                     \
241   "\r\n"
242 #define HTTP_REQUEST_FORMAT7                         \
243   "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
244   "X-Request-ID: %d\r\n"                             \
245   "Accept-Language: French\r\n"                      \
246   "\r\n"
247 #define HTTP_REQUEST_FORMAT8                         \
248   "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
249   "X-Request-ID: %d\r\n"                             \
250   "Accept-Language: English,French\r\n"              \
251   "\r\n"
252 #define HTTP_REQUEST_FORMAT9                                      \
253   "GET http://trafficserver.apache.org/format9.html HTTP/1.0\r\n" \
254   "X-Request-ID: %d\r\n"                                          \
255   "\r\n"
256 #define HTTP_REQUEST_FORMAT10                                      \
257   "GET http://trafficserver.apache.org/format10.html HTTP/1.0\r\n" \
258   "X-Request-ID: %d\r\n"                                           \
259   "\r\n"
260 #define HTTP_REQUEST_FORMAT11                                      \
261   "GET http://trafficserver.apache.org/format11.html HTTP/1.0\r\n" \
262   "X-Request-ID: %d\r\n"                                           \
263   "\r\n"
264   char *request = static_cast<char *>(TSmalloc(REQUEST_MAX_SIZE + 1));
265 
266   switch (test_case) {
267   case 1:
268     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT1, SYNSERVER_LISTEN_PORT, test_case);
269     break;
270   case 2:
271     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT2, SYNSERVER_LISTEN_PORT, test_case);
272     break;
273   case 3:
274     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT3, SYNSERVER_LISTEN_PORT, test_case);
275     break;
276   case 4:
277     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT4, SYNSERVER_LISTEN_PORT, test_case, 1);
278     break;
279   case 5:
280     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT5, SYNSERVER_LISTEN_PORT, test_case, 2);
281     break;
282   case 6:
283     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT6, SYNSERVER_LISTEN_PORT, test_case);
284     break;
285   case 7:
286     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT7, SYNSERVER_LISTEN_PORT, test_case - 1);
287     break;
288   case 8:
289     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT8, SYNSERVER_LISTEN_PORT, test_case - 2);
290     break;
291   case 9:
292     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT9, test_case);
293     break;
294   case 10:
295     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT10, test_case);
296     break;
297   case 11:
298     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT11, test_case);
299     break;
300   default:
301     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_DEFAULT_FORMAT, SYNSERVER_LISTEN_PORT, test_case);
302     break;
303   }
304 
305   return request;
306 }
307 
308 /* Caller must free returned response */
309 static char *
generate_response(const char * request)310 generate_response(const char *request)
311 {
312 // define format for response
313 // Each response contains a field X-Response-ID that contains the id of the testcase
314 #define HTTP_REQUEST_TESTCASE_FORMAT \
315   "GET %1024s HTTP/1.%d\r\n"         \
316   "X-Request-ID: %d\r\n"
317 
318 #define HTTP_RESPONSE_DEFAULT_FORMAT \
319   "HTTP/1.0 200 OK\r\n"              \
320   "X-Response-ID: %d\r\n"            \
321   "Cache-Control: max-age=86400\r\n" \
322   "Content-Type: text/html\r\n"      \
323   "\r\n"                             \
324   "Default body"
325 
326 #define HTTP_RESPONSE_FORMAT1   \
327   "HTTP/1.0 200 OK\r\n"         \
328   "X-Response-ID: %d\r\n"       \
329   "Content-Type: text/html\r\n" \
330   "Cache-Control: no-cache\r\n" \
331   "\r\n"                        \
332   "Body for response 1"
333 
334 #define HTTP_RESPONSE_FORMAT2        \
335   "HTTP/1.0 200 OK\r\n"              \
336   "X-Response-ID: %d\r\n"            \
337   "Cache-Control: max-age=86400\r\n" \
338   "Content-Type: text/html\r\n"      \
339   "\r\n"                             \
340   "Body for response 2"
341 #define HTTP_RESPONSE_FORMAT4        \
342   "HTTP/1.0 200 OK\r\n"              \
343   "X-Response-ID: %d\r\n"            \
344   "Cache-Control: max-age=86400\r\n" \
345   "Content-Type: text/html\r\n"      \
346   "\r\n"                             \
347   "Body for response 4"
348 #define HTTP_RESPONSE_FORMAT5   \
349   "HTTP/1.0 200 OK\r\n"         \
350   "X-Response-ID: %d\r\n"       \
351   "Content-Type: text/html\r\n" \
352   "\r\n"                        \
353   "Body for response 5"
354 #define HTTP_RESPONSE_FORMAT6        \
355   "HTTP/1.0 200 OK\r\n"              \
356   "X-Response-ID: %d\r\n"            \
357   "Cache-Control: max-age=86400\r\n" \
358   "Content-Language: English\r\n"    \
359   "\r\n"                             \
360   "Body for response 6"
361 #define HTTP_RESPONSE_FORMAT7        \
362   "HTTP/1.0 200 OK\r\n"              \
363   "X-Response-ID: %d\r\n"            \
364   "Cache-Control: max-age=86400\r\n" \
365   "Content-Language: French\r\n"     \
366   "\r\n"                             \
367   "Body for response 7"
368 
369 #define HTTP_RESPONSE_FORMAT8             \
370   "HTTP/1.0 200 OK\r\n"                   \
371   "X-Response-ID: %d\r\n"                 \
372   "Cache-Control: max-age=86400\r\n"      \
373   "Content-Language: French, English\r\n" \
374   "\r\n"                                  \
375   "Body for response 8"
376 
377 #define HTTP_RESPONSE_FORMAT9        \
378   "HTTP/1.0 200 OK\r\n"              \
379   "Cache-Control: max-age=86400\r\n" \
380   "X-Response-ID: %d\r\n"            \
381   "\r\n"                             \
382   "Body for response 9"
383 
384 #define HTTP_RESPONSE_FORMAT10       \
385   "HTTP/1.0 200 OK\r\n"              \
386   "Cache-Control: max-age=86400\r\n" \
387   "X-Response-ID: %d\r\n"            \
388   "\r\n"                             \
389   "Body for response 10"
390 
391 #define HTTP_RESPONSE_FORMAT11          \
392   "HTTP/1.0 200 OK\r\n"                 \
393   "Cache-Control: private,no-store\r\n" \
394   "X-Response-ID: %d\r\n"               \
395   "\r\n"                                \
396   "Body for response 11"
397 
398   int test_case, match, http_version;
399 
400   char *response = static_cast<char *>(TSmalloc(RESPONSE_MAX_SIZE + 1));
401   char url[1025];
402 
403   // coverity[secure_coding]
404   match = sscanf(request, HTTP_REQUEST_TESTCASE_FORMAT, url, &http_version, &test_case);
405   if (match == 3) {
406     switch (test_case) {
407     case 1:
408       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT1, test_case);
409       break;
410     case 2:
411       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT2, test_case);
412       break;
413     case 4:
414       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT4, test_case);
415       break;
416     case 5:
417       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT5, test_case);
418       break;
419     case 6:
420       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT6, test_case);
421       break;
422     case 7:
423       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT7, test_case);
424       break;
425     case 8:
426       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT8, test_case);
427       break;
428     case 9:
429       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT9, test_case);
430       break;
431     case 10:
432       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT10, test_case);
433       break;
434     case 11:
435       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT11, test_case);
436       break;
437     default:
438       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_DEFAULT_FORMAT, test_case);
439       break;
440     }
441   } else {
442     /* Didn't recognize a testcase request. send the default response */
443     snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_DEFAULT_FORMAT, test_case);
444   }
445 
446   return response;
447 }
448 
449 static int
get_request_id_value(const char * name,TSMBuffer buf,TSMLoc hdr)450 get_request_id_value(const char *name, TSMBuffer buf, TSMLoc hdr)
451 {
452   int id = -1;
453   TSMLoc field;
454 
455   field = TSMimeHdrFieldFind(buf, hdr, name, -1);
456   if (field != TS_NULL_MLOC) {
457     id = TSMimeHdrFieldValueIntGet(buf, hdr, field, 0);
458   }
459 
460   TSHandleMLocRelease(buf, hdr, field);
461   return id;
462 }
463 
464 // This routine can be called by tests, from the READ_REQUEST_HDR_HOOK
465 // to figure out the id of a test message
466 // Returns id/-1 in case of error
467 static int
get_request_id(TSHttpTxn txnp)468 get_request_id(TSHttpTxn txnp)
469 {
470   TSMBuffer bufp;
471   TSMLoc hdr_loc;
472   int id = -1;
473 
474   if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
475     return -1;
476   }
477 
478   id = get_request_id_value(X_REQUEST_ID, bufp, hdr_loc);
479   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
480   return id;
481 }
482 
483 // This routine can be called by tests, from the READ_RESPONSE_HDR_HOOK
484 // to figure out the id of a test message
485 // Returns id/-1 in case of error
486 static int
get_response_id(TSHttpTxn txnp)487 get_response_id(TSHttpTxn txnp)
488 {
489   TSMBuffer bufp;
490   TSMLoc hdr_loc;
491   int id = -1;
492 
493   if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
494     return -1;
495   }
496 
497   id = get_request_id_value(X_RESPONSE_ID, bufp, hdr_loc);
498   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
499   return id;
500 }
501 
502 //////////////////////////////////////////////////////////////////////////////
503 // SOCKET CLIENT
504 //////////////////////////////////////////////////////////////////////////////
505 
506 static ClientTxn *
synclient_txn_create()507 synclient_txn_create()
508 {
509   const HttpProxyPort *proxy_port;
510 
511   ClientTxn *txn = static_cast<ClientTxn *>(TSmalloc(sizeof(ClientTxn)));
512 
513   ink_zero(*txn);
514 
515   if (nullptr == (proxy_port = HttpProxyPort::findHttp(AF_INET))) {
516     txn->connect_port = PROXY_HTTP_DEFAULT_PORT;
517   } else {
518     txn->connect_port = proxy_port->m_port;
519   }
520 
521   txn->connect_ip = IP(127, 0, 0, 1);
522   txn->status     = REQUEST_INPROGRESS;
523   txn->magic      = MAGIC_ALIVE;
524 
525   TSDebug(CDBG_TAG, "Connecting to proxy 127.0.0.1 on port %d", txn->connect_port);
526   return txn;
527 }
528 
529 static int
synclient_txn_delete(ClientTxn * txn)530 synclient_txn_delete(ClientTxn *txn)
531 {
532   TSAssert(txn->magic == MAGIC_ALIVE);
533   if (txn->connect_action && !TSActionDone(txn->connect_action)) {
534     TSActionCancel(txn->connect_action);
535     txn->connect_action = nullptr;
536   }
537 
538   ats_free(txn->request);
539   txn->magic = MAGIC_DEAD;
540   TSfree(txn);
541   return 1;
542 }
543 
544 static void
synclient_txn_close(ClientTxn * txn)545 synclient_txn_close(ClientTxn *txn)
546 {
547   if (txn) {
548     if (txn->vconn != nullptr) {
549       TSVConnClose(txn->vconn);
550       txn->vconn = nullptr;
551     }
552 
553     if (txn->req_buffer != nullptr) {
554       TSIOBufferDestroy(txn->req_buffer);
555       txn->req_buffer = nullptr;
556     }
557 
558     if (txn->resp_buffer != nullptr) {
559       TSIOBufferDestroy(txn->resp_buffer);
560       txn->resp_buffer = nullptr;
561     }
562 
563     TSDebug(CDBG_TAG, "Client Txn destroyed");
564   }
565 }
566 
567 static int
synclient_txn_send_request(ClientTxn * txn,char * request)568 synclient_txn_send_request(ClientTxn *txn, char *request)
569 {
570   TSCont cont;
571   sockaddr_in addr;
572 
573   TSAssert(txn->magic == MAGIC_ALIVE);
574   txn->request = ats_strdup(request);
575   SET_TEST_HANDLER(txn->current_handler, synclient_txn_connect_handler);
576 
577   cont = TSContCreate(synclient_txn_main_handler, TSMutexCreate());
578   TSContDataSet(cont, txn);
579 
580   ats_ip4_set(&addr, txn->connect_ip, htons(txn->connect_port));
581   TSNetConnect(cont, ats_ip_sa_cast(&addr));
582   return 1;
583 }
584 
585 /* This can be used to send a request to a specific VC */
586 static int
synclient_txn_send_request_to_vc(ClientTxn * txn,char * request,TSVConn vc)587 synclient_txn_send_request_to_vc(ClientTxn *txn, char *request, TSVConn vc)
588 {
589   TSCont cont;
590   TSAssert(txn->magic == MAGIC_ALIVE);
591   txn->request = ats_strdup(request);
592   SET_TEST_HANDLER(txn->current_handler, synclient_txn_connect_handler);
593 
594   cont = TSContCreate(synclient_txn_main_handler, TSMutexCreate());
595   TSContDataSet(cont, txn);
596 
597   TSContCall(cont, TS_EVENT_NET_CONNECT, vc);
598   return 1;
599 }
600 
601 static int
synclient_txn_read_response(TSCont contp)602 synclient_txn_read_response(TSCont contp)
603 {
604   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
605   TSAssert(txn->magic == MAGIC_ALIVE);
606 
607   TSIOBufferBlock block = TSIOBufferReaderStart(txn->resp_reader);
608   while (block != nullptr) {
609     int64_t blocklen;
610     const char *blockptr = TSIOBufferBlockReadStart(block, txn->resp_reader, &blocklen);
611 
612     if (txn->response_len + blocklen <= RESPONSE_MAX_SIZE) {
613       memcpy((txn->response + txn->response_len), blockptr, blocklen);
614       txn->response_len += blocklen;
615     } else {
616       TSError("Error: Response length %" PRId64 " > response buffer size %d", txn->response_len + blocklen, RESPONSE_MAX_SIZE);
617     }
618 
619     block = TSIOBufferBlockNext(block);
620   }
621 
622   txn->response[txn->response_len] = '\0';
623   TSDebug(CDBG_TAG, "Response = |%s|, req len = %d", txn->response, txn->response_len);
624 
625   return 1;
626 }
627 
628 static int
synclient_txn_read_response_handler(TSCont contp,TSEvent event,void *)629 synclient_txn_read_response_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
630 {
631   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
632   TSAssert(txn->magic == MAGIC_ALIVE);
633 
634   int64_t avail;
635 
636   switch (event) {
637   case TS_EVENT_VCONN_READ_READY:
638   case TS_EVENT_VCONN_READ_COMPLETE:
639     if (event == TS_EVENT_VCONN_READ_READY) {
640       TSDebug(CDBG_TAG, "READ_READY");
641     } else {
642       TSDebug(CDBG_TAG, "READ_COMPLETE");
643     }
644 
645     avail = TSIOBufferReaderAvail(txn->resp_reader);
646     TSDebug(CDBG_TAG, "%" PRId64 " bytes available in buffer", avail);
647 
648     if (avail > 0) {
649       synclient_txn_read_response(contp);
650       TSIOBufferReaderConsume(txn->resp_reader, avail);
651     }
652 
653     TSVIOReenable(txn->read_vio);
654     break;
655 
656   case TS_EVENT_VCONN_EOS:
657     TSDebug(CDBG_TAG, "READ_EOS");
658     // Connection closed. In HTTP/1.0 it means we're done for this request.
659     txn->status = REQUEST_SUCCESS;
660     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
661     TSContDestroy(contp);
662     return 1;
663 
664   case TS_EVENT_ERROR:
665     TSDebug(CDBG_TAG, "READ_ERROR");
666     txn->status = REQUEST_FAILURE;
667     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
668     TSContDestroy(contp);
669     return 1;
670 
671   default:
672     TSAssert(!"Invalid event");
673     break;
674   }
675   return 1;
676 }
677 
678 static int
synclient_txn_write_request(TSCont contp)679 synclient_txn_write_request(TSCont contp)
680 {
681   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
682   TSAssert(txn->magic == MAGIC_ALIVE);
683 
684   TSIOBufferBlock block;
685   char *ptr_block;
686   int64_t len, ndone, ntodo, towrite, avail;
687 
688   len = strlen(txn->request);
689 
690   ndone = 0;
691   ntodo = len;
692   while (ntodo > 0) {
693     block     = TSIOBufferStart(txn->req_buffer);
694     ptr_block = TSIOBufferBlockWriteStart(block, &avail);
695     towrite   = std::min(ntodo, avail);
696     memcpy(ptr_block, txn->request + ndone, towrite);
697     TSIOBufferProduce(txn->req_buffer, towrite);
698     ntodo -= towrite;
699     ndone += towrite;
700   }
701 
702   /* Start writing the response */
703   TSDebug(CDBG_TAG, "Writing |%s| (%" PRId64 ") bytes", txn->request, len);
704   txn->write_vio = TSVConnWrite(txn->vconn, contp, txn->req_reader, len);
705 
706   return 1;
707 }
708 
709 static int
synclient_txn_write_request_handler(TSCont contp,TSEvent event,void *)710 synclient_txn_write_request_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
711 {
712   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
713   TSAssert(txn->magic == MAGIC_ALIVE);
714 
715   switch (event) {
716   case TS_EVENT_VCONN_WRITE_READY:
717     TSDebug(CDBG_TAG, "WRITE_READY");
718     TSVIOReenable(txn->write_vio);
719     break;
720 
721   case TS_EVENT_VCONN_WRITE_COMPLETE:
722     TSDebug(CDBG_TAG, "WRITE_COMPLETE");
723     // Weird: synclient should not close the write part of vconn.
724     // Otherwise some strangeness...
725 
726     /* Start reading */
727     SET_TEST_HANDLER(txn->current_handler, synclient_txn_read_response_handler);
728     txn->read_vio = TSVConnRead(txn->vconn, contp, txn->resp_buffer, INT64_MAX);
729     break;
730 
731   case TS_EVENT_VCONN_EOS:
732     TSDebug(CDBG_TAG, "WRITE_EOS");
733     txn->status = REQUEST_FAILURE;
734     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
735     TSContDestroy(contp);
736     break;
737 
738   case TS_EVENT_ERROR:
739     TSDebug(CDBG_TAG, "WRITE_ERROR");
740     txn->status = REQUEST_FAILURE;
741     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
742     TSContDestroy(contp);
743     break;
744 
745   default:
746     TSAssert(!"Invalid event");
747     break;
748   }
749   return TS_EVENT_IMMEDIATE;
750 }
751 
752 static int
synclient_txn_connect_handler(TSCont contp,TSEvent event,void * data)753 synclient_txn_connect_handler(TSCont contp, TSEvent event, void *data)
754 {
755   TSAssert((event == TS_EVENT_NET_CONNECT) || (event == TS_EVENT_NET_CONNECT_FAILED));
756 
757   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
758   TSAssert(txn->magic == MAGIC_ALIVE);
759 
760   if (event == TS_EVENT_NET_CONNECT) {
761     TSDebug(CDBG_TAG, "NET_CONNECT");
762 
763     txn->req_buffer  = TSIOBufferCreate();
764     txn->req_reader  = TSIOBufferReaderAlloc(txn->req_buffer);
765     txn->resp_buffer = TSIOBufferCreate();
766     txn->resp_reader = TSIOBufferReaderAlloc(txn->resp_buffer);
767 
768     txn->response[0]  = '\0';
769     txn->response_len = 0;
770 
771     txn->vconn      = static_cast<TSVConn>(data);
772     txn->local_port = (int)((NetVConnection *)data)->get_local_port();
773 
774     txn->write_vio = nullptr;
775     txn->read_vio  = nullptr;
776 
777     /* start writing */
778     SET_TEST_HANDLER(txn->current_handler, synclient_txn_write_request_handler);
779     synclient_txn_write_request(contp);
780 
781     return TS_EVENT_IMMEDIATE;
782   } else {
783     TSDebug(CDBG_TAG, "NET_CONNECT_FAILED");
784     txn->status = REQUEST_FAILURE;
785     synclient_txn_close(static_cast<ClientTxn *>(TSContDataGet(contp)));
786     TSContDestroy(contp);
787   }
788 
789   return TS_EVENT_IMMEDIATE;
790 }
791 
792 static int
synclient_txn_main_handler(TSCont contp,TSEvent event,void * data)793 synclient_txn_main_handler(TSCont contp, TSEvent event, void *data)
794 {
795   ClientTxn *txn = static_cast<ClientTxn *>(TSContDataGet(contp));
796   TSAssert(txn->magic == MAGIC_ALIVE);
797 
798   TxnHandler handler = txn->current_handler;
799   return (*handler)(contp, event, data);
800 }
801 
802 //////////////////////////////////////////////////////////////////////////////
803 // SOCKET SERVER
804 //////////////////////////////////////////////////////////////////////////////
805 
806 SocketServer *
synserver_create(int port,TSCont cont)807 synserver_create(int port, TSCont cont)
808 {
809   if (port != SYNSERVER_DUMMY_PORT) {
810     TSAssert(port > 0);
811     TSAssert(port < INT16_MAX);
812   }
813 
814   SocketServer *s  = static_cast<SocketServer *>(TSmalloc(sizeof(SocketServer)));
815   s->magic         = MAGIC_ALIVE;
816   s->accept_port   = port;
817   s->accept_action = nullptr;
818   s->accept_cont   = cont;
819   TSContDataSet(s->accept_cont, s);
820   return s;
821 }
822 
823 SocketServer *
synserver_create(int port)824 synserver_create(int port)
825 {
826   return synserver_create(port, TSContCreate(synserver_vc_accept, TSMutexCreate()));
827 }
828 
829 static int
synserver_start(SocketServer * s)830 synserver_start(SocketServer *s)
831 {
832   TSAssert(s->magic == MAGIC_ALIVE);
833   TSAssert(s->accept_action == nullptr);
834 
835   if (s->accept_port != SYNSERVER_DUMMY_PORT) {
836     TSAssert(s->accept_port > 0);
837     TSAssert(s->accept_port < INT16_MAX);
838 
839     s->accept_action = TSNetAccept(s->accept_cont, s->accept_port, AF_INET, 0);
840   }
841 
842   return 1;
843 }
844 
845 static int
synserver_stop(SocketServer * s)846 synserver_stop(SocketServer *s)
847 {
848   TSAssert(s->magic == MAGIC_ALIVE);
849   if (s->accept_action && !TSActionDone(s->accept_action)) {
850     TSActionCancel(s->accept_action);
851     s->accept_action = nullptr;
852     TSDebug(SDBG_TAG, "Had to cancel action");
853   }
854   TSDebug(SDBG_TAG, "stopped");
855   return 1;
856 }
857 
858 static int
synserver_delete(SocketServer * s)859 synserver_delete(SocketServer *s)
860 {
861   if (s != nullptr) {
862     TSAssert(s->magic == MAGIC_ALIVE);
863     synserver_stop(s);
864 
865     if (s->accept_cont) {
866       TSContDestroy(s->accept_cont);
867       s->accept_cont = nullptr;
868       TSDebug(SDBG_TAG, "destroyed accept cont");
869     }
870 
871     s->magic = MAGIC_DEAD;
872     TSfree(s);
873     TSDebug(SDBG_TAG, "deleted server");
874   }
875 
876   return 1;
877 }
878 
879 static int
synserver_vc_refuse(TSCont contp,TSEvent event,void * data)880 synserver_vc_refuse(TSCont contp, TSEvent event, void *data)
881 {
882   TSAssert((event == TS_EVENT_NET_ACCEPT) || (event == TS_EVENT_NET_ACCEPT_FAILED));
883 
884   SocketServer *s = static_cast<SocketServer *>(TSContDataGet(contp));
885   TSAssert(s->magic == MAGIC_ALIVE);
886 
887   TSDebug(SDBG_TAG, "%s: NET_ACCEPT", __func__);
888 
889   if (event == TS_EVENT_NET_ACCEPT_FAILED) {
890     Warning("Synserver failed to bind to port %d.", ntohs(s->accept_port));
891     ink_release_assert(!"Synserver must be able to bind to a port, check system netstat");
892     TSDebug(SDBG_TAG, "%s: NET_ACCEPT_FAILED", __func__);
893     return TS_EVENT_IMMEDIATE;
894   }
895 
896   TSVConnClose(static_cast<TSVConn>(data));
897   return TS_EVENT_IMMEDIATE;
898 }
899 
900 static int
synserver_vc_accept(TSCont contp,TSEvent event,void * data)901 synserver_vc_accept(TSCont contp, TSEvent event, void *data)
902 {
903   TSAssert((event == TS_EVENT_NET_ACCEPT) || (event == TS_EVENT_NET_ACCEPT_FAILED));
904 
905   SocketServer *s = static_cast<SocketServer *>(TSContDataGet(contp));
906   TSAssert(s->magic == MAGIC_ALIVE);
907 
908   if (event == TS_EVENT_NET_ACCEPT_FAILED) {
909     Warning("Synserver failed to bind to port %d.", ntohs(s->accept_port));
910     ink_release_assert(!"Synserver must be able to bind to a port, check system netstat");
911     TSDebug(SDBG_TAG, "%s: NET_ACCEPT_FAILED", __func__);
912     return TS_EVENT_IMMEDIATE;
913   }
914 
915   TSDebug(SDBG_TAG, "%s: NET_ACCEPT", __func__);
916 
917   /* Create a new transaction */
918   ServerTxn *txn = static_cast<ServerTxn *>(TSmalloc(sizeof(ServerTxn)));
919   txn->magic     = MAGIC_ALIVE;
920 
921   SET_TEST_HANDLER(txn->current_handler, synserver_txn_read_request_handler);
922 
923   TSCont txn_cont = TSContCreate(synserver_txn_main_handler, TSMutexCreate());
924   TSContDataSet(txn_cont, txn);
925 
926   txn->req_buffer = TSIOBufferCreate();
927   txn->req_reader = TSIOBufferReaderAlloc(txn->req_buffer);
928 
929   txn->resp_buffer = TSIOBufferCreate();
930   txn->resp_reader = TSIOBufferReaderAlloc(txn->resp_buffer);
931 
932   txn->request[0]  = '\0';
933   txn->request_len = 0;
934 
935   txn->vconn = static_cast<TSVConn>(data);
936 
937   txn->write_vio = nullptr;
938 
939   /* start reading */
940   txn->read_vio = TSVConnRead(txn->vconn, txn_cont, txn->req_buffer, INT64_MAX);
941 
942   return TS_EVENT_IMMEDIATE;
943 }
944 
945 static int
synserver_txn_close(TSCont contp)946 synserver_txn_close(TSCont contp)
947 {
948   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
949   TSAssert(txn->magic == MAGIC_ALIVE);
950 
951   if (txn->vconn != nullptr) {
952     TSVConnClose(txn->vconn);
953   }
954   if (txn->req_buffer) {
955     TSIOBufferDestroy(txn->req_buffer);
956   }
957   if (txn->resp_buffer) {
958     TSIOBufferDestroy(txn->resp_buffer);
959   }
960 
961   txn->magic = MAGIC_DEAD;
962   TSfree(txn);
963   TSContDestroy(contp);
964 
965   TSDebug(SDBG_TAG, "Server Txn destroyed");
966   return TS_EVENT_IMMEDIATE;
967 }
968 
969 static int
synserver_txn_write_response(TSCont contp)970 synserver_txn_write_response(TSCont contp)
971 {
972   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
973   TSAssert(txn->magic == MAGIC_ALIVE);
974 
975   SET_TEST_HANDLER(txn->current_handler, synserver_txn_write_response_handler);
976 
977   TSIOBufferBlock block;
978   char *ptr_block;
979   int64_t len, ndone, ntodo, towrite, avail;
980   char *response;
981 
982   response = generate_response(txn->request);
983   len      = strlen(response);
984 
985   ndone = 0;
986   ntodo = len;
987   while (ntodo > 0) {
988     block     = TSIOBufferStart(txn->resp_buffer);
989     ptr_block = TSIOBufferBlockWriteStart(block, &avail);
990     towrite   = std::min(ntodo, avail);
991     memcpy(ptr_block, response + ndone, towrite);
992     TSIOBufferProduce(txn->resp_buffer, towrite);
993     ntodo -= towrite;
994     ndone += towrite;
995   }
996 
997   /* Start writing the response */
998   TSDebug(SDBG_TAG, "Writing response: |%s| (%" PRId64 ") bytes)", response, len);
999   txn->write_vio = TSVConnWrite(txn->vconn, contp, txn->resp_reader, len);
1000 
1001   /* Now that response is in IOBuffer, free up response */
1002   TSfree(response);
1003 
1004   return TS_EVENT_IMMEDIATE;
1005 }
1006 
1007 static int
synserver_txn_write_response_handler(TSCont contp,TSEvent event,void *)1008 synserver_txn_write_response_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
1009 {
1010   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1011   TSAssert(txn->magic == MAGIC_ALIVE);
1012 
1013   switch (event) {
1014   case TS_EVENT_VCONN_WRITE_READY:
1015     TSDebug(SDBG_TAG, "WRITE_READY");
1016     TSVIOReenable(txn->write_vio);
1017     break;
1018 
1019   case TS_EVENT_VCONN_WRITE_COMPLETE:
1020     TSDebug(SDBG_TAG, "WRITE_COMPLETE");
1021     TSVConnShutdown(txn->vconn, 0, 1);
1022     return synserver_txn_close(contp);
1023     break;
1024 
1025   case TS_EVENT_VCONN_EOS:
1026     TSDebug(SDBG_TAG, "WRITE_EOS");
1027     return synserver_txn_close(contp);
1028     break;
1029 
1030   case TS_EVENT_ERROR:
1031     TSDebug(SDBG_TAG, "WRITE_ERROR");
1032     return synserver_txn_close(contp);
1033     break;
1034 
1035   default:
1036     TSAssert(!"Invalid event");
1037     break;
1038   }
1039   return TS_EVENT_IMMEDIATE;
1040 }
1041 
1042 static int
synserver_txn_read_request(TSCont contp)1043 synserver_txn_read_request(TSCont contp)
1044 {
1045   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1046   TSAssert(txn->magic == MAGIC_ALIVE);
1047 
1048   int end;
1049   TSIOBufferBlock block = TSIOBufferReaderStart(txn->req_reader);
1050 
1051   while (block != nullptr) {
1052     int64_t blocklen;
1053     const char *blockptr = TSIOBufferBlockReadStart(block, txn->req_reader, &blocklen);
1054 
1055     if (txn->request_len + blocklen <= REQUEST_MAX_SIZE) {
1056       memcpy((txn->request + txn->request_len), blockptr, blocklen);
1057       txn->request_len += blocklen;
1058     } else {
1059       TSError("Error: Request length %" PRId64 " > request buffer size %d", txn->request_len + blocklen, REQUEST_MAX_SIZE);
1060     }
1061 
1062     block = TSIOBufferBlockNext(block);
1063   }
1064 
1065   txn->request[txn->request_len] = '\0';
1066   TSDebug(SDBG_TAG, "Request = |%s|, req len = %d", txn->request, txn->request_len);
1067 
1068   end = (strstr(txn->request, HTTP_REQUEST_END) != nullptr);
1069   TSDebug(SDBG_TAG, "End of request = %d", end);
1070 
1071   return end;
1072 }
1073 
1074 static int
synserver_txn_read_request_handler(TSCont contp,TSEvent event,void *)1075 synserver_txn_read_request_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
1076 {
1077   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1078   TSAssert(txn->magic == MAGIC_ALIVE);
1079 
1080   int64_t avail;
1081   int end_of_request;
1082 
1083   switch (event) {
1084   case TS_EVENT_VCONN_READ_READY:
1085   case TS_EVENT_VCONN_READ_COMPLETE:
1086     TSDebug(SDBG_TAG, (event == TS_EVENT_VCONN_READ_READY) ? "READ_READY" : "READ_COMPLETE");
1087     avail = TSIOBufferReaderAvail(txn->req_reader);
1088     TSDebug(SDBG_TAG, "%" PRId64 " bytes available in buffer", avail);
1089 
1090     if (avail > 0) {
1091       end_of_request = synserver_txn_read_request(contp);
1092       TSIOBufferReaderConsume(txn->req_reader, avail);
1093 
1094       if (end_of_request) {
1095         TSVConnShutdown(txn->vconn, 1, 0);
1096         return synserver_txn_write_response(contp);
1097       }
1098     }
1099 
1100     TSVIOReenable(txn->read_vio);
1101     break;
1102 
1103   case TS_EVENT_VCONN_EOS:
1104     TSDebug(SDBG_TAG, "READ_EOS");
1105     return synserver_txn_close(contp);
1106     break;
1107 
1108   case TS_EVENT_ERROR:
1109     TSDebug(SDBG_TAG, "READ_ERROR");
1110     return synserver_txn_close(contp);
1111     break;
1112 
1113   default:
1114     TSAssert(!"Invalid event");
1115     break;
1116   }
1117   return TS_EVENT_IMMEDIATE;
1118 }
1119 
1120 static int
synserver_txn_main_handler(TSCont contp,TSEvent event,void * data)1121 synserver_txn_main_handler(TSCont contp, TSEvent event, void *data)
1122 {
1123   ServerTxn *txn = static_cast<ServerTxn *>(TSContDataGet(contp));
1124   TSAssert(txn->magic == MAGIC_ALIVE);
1125 
1126   TxnHandler handler = txn->current_handler;
1127   return (*handler)(contp, event, data);
1128 }
1129 
1130 // End of the previous #include "InkAPITestTool.cc"
1131 
1132 #define TC_PASS 1
1133 #define TC_FAIL 0
1134 
1135 #define UTDBG_TAG "sdk_ut"
1136 
1137 // Since there's no way to unregister global hooks, tests that register a hook
1138 // have to co-operate once they are complete by re-enabling and transactions
1139 // and getting out of the way.
1140 #define CHECK_SPURIOUS_EVENT(cont, event, edata)                     \
1141   if (TSContDataGet(cont) == NULL) {                                 \
1142     switch (event) {                                                 \
1143     case TS_EVENT_IMMEDIATE:                                         \
1144     case TS_EVENT_TIMEOUT:                                           \
1145       return TS_EVENT_NONE;                                          \
1146     case TS_EVENT_HTTP_SELECT_ALT:                                   \
1147       return TS_EVENT_NONE;                                          \
1148     case TS_EVENT_HTTP_READ_REQUEST_HDR:                             \
1149     case TS_EVENT_HTTP_OS_DNS:                                       \
1150     case TS_EVENT_HTTP_SEND_REQUEST_HDR:                             \
1151     case TS_EVENT_HTTP_READ_CACHE_HDR:                               \
1152     case TS_EVENT_HTTP_READ_RESPONSE_HDR:                            \
1153     case TS_EVENT_HTTP_SEND_RESPONSE_HDR:                            \
1154     case TS_EVENT_HTTP_REQUEST_TRANSFORM:                            \
1155     case TS_EVENT_HTTP_RESPONSE_TRANSFORM:                           \
1156     case TS_EVENT_HTTP_TXN_START:                                    \
1157     case TS_EVENT_HTTP_TXN_CLOSE:                                    \
1158     case TS_EVENT_HTTP_SSN_START:                                    \
1159     case TS_EVENT_HTTP_SSN_CLOSE:                                    \
1160     case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:                        \
1161     case TS_EVENT_HTTP_PRE_REMAP:                                    \
1162     case TS_EVENT_HTTP_POST_REMAP:                                   \
1163       TSHttpTxnReenable((TSHttpTxn)(edata), TS_EVENT_HTTP_CONTINUE); \
1164       return TS_EVENT_NONE;                                          \
1165     default:                                                         \
1166       break;                                                         \
1167     }                                                                \
1168   }
1169 
1170 /******************************************************************************/
1171 
1172 /* Use SDK_RPRINT to report failure or success for each test case */
1173 int
SDK_RPRINT(RegressionTest * t,const char * api_name,const char * testcase_name,int status,const char * err_details_format,...)1174 SDK_RPRINT(RegressionTest *t, const char *api_name, const char *testcase_name, int status, const char *err_details_format, ...)
1175 {
1176   int l;
1177   char buffer[8192];
1178   char format2[8192];
1179   snprintf(format2, sizeof(format2), "[%s] %s : [%s] <<%s>> { %s }\n", t->name, api_name, testcase_name,
1180            status == TC_PASS ? "PASS" : "FAIL", err_details_format);
1181   va_list ap;
1182   va_start(ap, err_details_format);
1183   l = ink_bvsprintf(buffer, format2, ap);
1184   va_end(ap);
1185   fputs(buffer, stderr);
1186   return (l);
1187 }
1188 
1189 /*
1190   REGRESSION_TEST(SDK_<test_name>)(RegressionTest *t, int atype, int *pstatus)
1191 
1192   RegressionTest *test is a pointer on object that will run the test.
1193    Do not modify.
1194 
1195   int atype is one of:
1196    REGRESSION_TEST_NONE
1197    REGRESSION_TEST_QUICK
1198    REGRESSION_TEST_NIGHTLY
1199    REGRESSION_TEST_EXTENDED
1200 
1201   int *pstatus should be set to one of:
1202    REGRESSION_TEST_PASSED
1203    REGRESSION_TEST_INPROGRESS
1204    REGRESSION_TEST_FAILED
1205    REGRESSION_TEST_NOT_RUN
1206   Note: pstatus is polled and can be used for asynchronous tests.
1207 
1208 */
1209 
1210 /* Misc */
1211 ////////////////////////////////////////////////
1212 //       SDK_API_TSTrafficServerVersionGet
1213 //
1214 // Unit Test for API: TSTrafficServerVersionGet
1215 ////////////////////////////////////////////////
REGRESSION_TEST(SDK_API_TSTrafficServerVersionGet)1216 REGRESSION_TEST(SDK_API_TSTrafficServerVersionGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1217 {
1218   *pstatus = REGRESSION_TEST_INPROGRESS;
1219 
1220   /* Assume the UT runs on TS5.0 and higher */
1221   const char *ts_version = TSTrafficServerVersionGet();
1222   if (!ts_version) {
1223     SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase1", TC_FAIL, "can't get traffic server version");
1224     *pstatus = REGRESSION_TEST_FAILED;
1225     return;
1226   }
1227 
1228   int major_ts_version = 0;
1229   int minor_ts_version = 0;
1230   int patch_ts_version = 0;
1231   // coverity[secure_coding]
1232   if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
1233     SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase2", TC_FAIL, "traffic server version format is incorrect");
1234     *pstatus = REGRESSION_TEST_FAILED;
1235     return;
1236   }
1237 
1238   if (major_ts_version < 2) {
1239     SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase3", TC_FAIL, "traffic server major version is incorrect");
1240     *pstatus = REGRESSION_TEST_FAILED;
1241     return;
1242   }
1243 
1244   SDK_RPRINT(test, "TSTrafficServerVersionGet", "TestCase1", TC_PASS, "ok");
1245   *pstatus = REGRESSION_TEST_PASSED;
1246   return;
1247 }
1248 
1249 ////////////////////////////////////////////////
1250 //       SDK_API_TSPluginDirGet
1251 //
1252 // Unit Test for API: TSPluginDirGet
1253 //                    TSInstallDirGet
1254 //                    TSRuntimeDirGet
1255 ////////////////////////////////////////////////
REGRESSION_TEST(SDK_API_TSPluginDirGet)1256 REGRESSION_TEST(SDK_API_TSPluginDirGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1257 {
1258   *pstatus = REGRESSION_TEST_INPROGRESS;
1259 
1260   const char *plugin_dir  = TSPluginDirGet();
1261   const char *install_dir = TSInstallDirGet();
1262   const char *runtime_dir = TSRuntimeDirGet();
1263 
1264   if (!plugin_dir) {
1265     SDK_RPRINT(test, "TSPluginDirGet", "TestCase1", TC_FAIL, "can't get plugin dir");
1266     *pstatus = REGRESSION_TEST_FAILED;
1267     return;
1268   }
1269 
1270   if (!install_dir) {
1271     SDK_RPRINT(test, "TSInstallDirGet", "TestCase1", TC_FAIL, "can't get installation dir");
1272     *pstatus = REGRESSION_TEST_FAILED;
1273     return;
1274   }
1275 
1276   if (!runtime_dir) {
1277     SDK_RPRINT(test, "TSRuntimeDirGet", "TestCase1", TC_FAIL, "can't get runtime dir");
1278     *pstatus = REGRESSION_TEST_FAILED;
1279     return;
1280   }
1281 
1282   if (strstr(plugin_dir, TS_BUILD_LIBEXECDIR) == nullptr) {
1283     SDK_RPRINT(test, "TSPluginDirGet", "TestCase2", TC_FAIL, "plugin dir(%s) is incorrect, expected (%s) in path.", plugin_dir,
1284                TS_BUILD_LIBEXECDIR);
1285     *pstatus = REGRESSION_TEST_FAILED;
1286     return;
1287   }
1288 
1289   if (strstr(plugin_dir, install_dir) == nullptr) {
1290     SDK_RPRINT(test, "TSInstallDirGet", "TestCase2", TC_FAIL, "install dir is incorrect");
1291     *pstatus = REGRESSION_TEST_FAILED;
1292     return;
1293   }
1294 
1295   if (strstr(runtime_dir, TS_BUILD_RUNTIMEDIR) == nullptr) {
1296     SDK_RPRINT(test, "TSRuntimeDirGet", "TestCase2", TC_FAIL, "runtime dir is incorrect");
1297     *pstatus = REGRESSION_TEST_FAILED;
1298     return;
1299   }
1300 
1301   SDK_RPRINT(test, "TSPluginDirGet", "TestCase1", TC_PASS, "ok");
1302   SDK_RPRINT(test, "TSInstallDirGet", "TestCase1", TC_PASS, "ok");
1303   SDK_RPRINT(test, "TSRuntimeDirGet", "TestCase1", TC_PASS, "ok");
1304   *pstatus = REGRESSION_TEST_PASSED;
1305   return;
1306 }
1307 
1308 /* TSConfig */
1309 ////////////////////////////////////////////////
1310 //       SDK_API_TSConfig
1311 //
1312 // Unit Test for API: TSConfigSet
1313 //                    TSConfigGet
1314 //                    TSConfigRelease
1315 //                    TSConfigDataGet
1316 ////////////////////////////////////////////////
1317 static int my_config_id = 0;
1318 struct ConfigData {
1319   const char *a;
1320   const char *b;
1321 };
1322 
REGRESSION_TEST(SDK_API_TSConfig)1323 REGRESSION_TEST(SDK_API_TSConfig)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1324 {
1325   *pstatus           = REGRESSION_TEST_INPROGRESS;
1326   ConfigData *config = new ConfigData;
1327   config->a          = "unit";
1328   config->b          = "test";
1329 
1330   my_config_id = TSConfigSet(my_config_id, config, [](void *cfg) { delete static_cast<ConfigData *>(cfg); });
1331 
1332   TSConfig test_config = nullptr;
1333   test_config          = TSConfigGet(my_config_id);
1334 
1335   if (!test_config) {
1336     SDK_RPRINT(test, "TSConfigSet", "TestCase1", TC_FAIL, "can't correctly set global config structure");
1337     SDK_RPRINT(test, "TSConfigGet", "TestCase1", TC_FAIL, "can't correctly get global config structure");
1338     TSConfigRelease(my_config_id, reinterpret_cast<TSConfig>(config));
1339     *pstatus = REGRESSION_TEST_FAILED;
1340     return;
1341   }
1342 
1343   if (TSConfigDataGet(test_config) != config) {
1344     SDK_RPRINT(test, "TSConfigDataGet", "TestCase1", TC_FAIL, "failed to get config data");
1345     TSConfigRelease(my_config_id, reinterpret_cast<TSConfig>(config));
1346     *pstatus = REGRESSION_TEST_FAILED;
1347     return;
1348   }
1349 
1350   SDK_RPRINT(test, "TSConfigGet", "TestCase1", TC_PASS, "ok");
1351   SDK_RPRINT(test, "TSConfigSet", "TestCase1", TC_PASS, "ok");
1352   SDK_RPRINT(test, "TSConfigDataGet", "TestCase1", TC_PASS, "ok");
1353 
1354   TSConfigRelease(my_config_id, reinterpret_cast<TSConfig>(config));
1355   *pstatus = REGRESSION_TEST_PASSED;
1356   return;
1357 }
1358 
1359 /* TSNetVConn */
1360 //////////////////////////////////////////////
1361 //       SDK_API_TSNetVConn
1362 //
1363 // Unit Test for API: TSNetVConnRemoteIPGet
1364 //                    TSNetVConnRemotePortGet
1365 //                    TSNetAccept
1366 //                    TSNetConnect
1367 //////////////////////////////////////////////
1368 
1369 struct SDK_NetVConn_Params {
SDK_NetVConn_ParamsSDK_NetVConn_Params1370   SDK_NetVConn_Params(const char *_a, RegressionTest *_t, int *_p)
1371     : buffer(nullptr), api(_a), port(0), test(_t), pstatus(_p), vc(nullptr)
1372   {
1373     this->status.client = this->status.server = REGRESSION_TEST_INPROGRESS;
1374   }
1375 
~SDK_NetVConn_ParamsSDK_NetVConn_Params1376   ~SDK_NetVConn_Params()
1377   {
1378     if (this->buffer) {
1379       TSIOBufferDestroy(this->buffer);
1380     }
1381     if (this->vc) {
1382       TSVConnClose(this->vc);
1383     }
1384   }
1385 
1386   TSIOBuffer buffer;
1387   const char *api;
1388   unsigned short port;
1389   RegressionTest *test;
1390   int *pstatus;
1391   TSVConn vc;
1392   struct {
1393     int client;
1394     int server;
1395   } status;
1396 };
1397 
1398 int
server_handler(TSCont contp,TSEvent event,void * data)1399 server_handler(TSCont contp, TSEvent event, void *data)
1400 {
1401   SDK_NetVConn_Params *params = static_cast<SDK_NetVConn_Params *>(TSContDataGet(contp));
1402 
1403   if (event == TS_EVENT_NET_ACCEPT) {
1404     // Kick off a read so that we can receive an EOS event.
1405     SDK_RPRINT(params->test, params->api, "ServerEvent NET_ACCEPT", TC_PASS, "ok");
1406     params->buffer = TSIOBufferCreate();
1407     params->vc     = static_cast<TSVConn>(data);
1408     TSVConnRead(static_cast<TSVConn>(data), contp, params->buffer, 100);
1409   } else if (event == TS_EVENT_VCONN_EOS) {
1410     // The server end of the test passes if it receives an EOF event. This means that it must have
1411     // connected to the endpoint. Since this always happens *after* the accept, we know that it is
1412     // safe to delete the params.
1413     TSContDestroy(contp);
1414 
1415     SDK_RPRINT(params->test, params->api, "ServerEvent EOS", TC_PASS, "ok");
1416     *params->pstatus = REGRESSION_TEST_PASSED;
1417     delete params;
1418   } else if (event == TS_EVENT_VCONN_READ_READY) {
1419     SDK_RPRINT(params->test, params->api, "ServerEvent READ_READY", TC_PASS, "ok");
1420   } else {
1421     SDK_RPRINT(params->test, params->api, "ServerEvent", TC_FAIL, "received unexpected event %d", event);
1422     *params->pstatus = REGRESSION_TEST_FAILED;
1423     delete params;
1424   }
1425 
1426   return 1;
1427 }
1428 
1429 int
client_handler(TSCont contp,TSEvent event,void * data)1430 client_handler(TSCont contp, TSEvent event, void *data)
1431 {
1432   SDK_NetVConn_Params *params = static_cast<SDK_NetVConn_Params *>(TSContDataGet(contp));
1433 
1434   if (event == TS_EVENT_NET_CONNECT_FAILED) {
1435     SDK_RPRINT(params->test, params->api, "ClientConnect", TC_FAIL, "can't connect to server");
1436 
1437     *params->pstatus = REGRESSION_TEST_FAILED;
1438 
1439     // no need to continue, return
1440     // Fix me: how to deal with server side cont?
1441     TSContDestroy(contp);
1442     return 1;
1443   } else if (TS_EVENT_NET_CONNECT == event) {
1444     sockaddr const *addr       = TSNetVConnRemoteAddrGet(static_cast<TSVConn>(data));
1445     uint16_t input_server_port = ats_ip_port_host_order(addr);
1446 
1447     // If DEFER_ACCEPT is enabled in the OS then the user space accept() doesn't
1448     // happen until data arrives on the socket. Because we're just testing the accept()
1449     // we write a small amount of ignored data to make sure this gets triggered.
1450     UnixNetVConnection *vc = static_cast<UnixNetVConnection *>(data);
1451     ink_release_assert(::write(vc->con.fd, "Bob's your uncle", 16) != 0);
1452 
1453     sleep(1); // XXX this sleep ensures the server end gets the accept event.
1454 
1455     if (ats_is_ip_loopback(addr)) {
1456       SDK_RPRINT(params->test, params->api, "TSNetVConnRemoteIPGet", TC_PASS, "ok");
1457     } else {
1458       ip_text_buffer s, ipb;
1459       IpEndpoint loopback;
1460       ats_ip4_set(&loopback, htonl(INADDR_LOOPBACK));
1461       SDK_RPRINT(params->test, params->api, "TSNetVConnRemoteIPGet", TC_FAIL, "server ip [%s] is incorrect - expected [%s]",
1462                  ats_ip_ntop(addr, s, sizeof s), ats_ip_ntop(&loopback.sa, ipb, sizeof ipb));
1463 
1464       TSContDestroy(contp);
1465       // Fix me: how to deal with server side cont?
1466       *params->pstatus = REGRESSION_TEST_FAILED;
1467       return 1;
1468     }
1469 
1470     if (input_server_port == params->port) {
1471       SDK_RPRINT(params->test, params->api, "TSNetVConnRemotePortGet", TC_PASS, "ok");
1472     } else {
1473       SDK_RPRINT(params->test, params->api, "TSNetVConnRemotePortGet", TC_FAIL, "server port [%d] is incorrect -- expected [%d]",
1474                  input_server_port, params->port);
1475 
1476       TSContDestroy(contp);
1477       // Fix me: how to deal with server side cont?
1478       *params->pstatus = REGRESSION_TEST_FAILED;
1479       return 1;
1480     }
1481 
1482     SDK_RPRINT(params->test, params->api, "TSNetConnect", TC_PASS, "ok");
1483 
1484     // XXX We really ought to do a write/read exchange with the server. The sleep above works around this.
1485 
1486     // Looks good from the client end. Next we disconnect so that the server end can set the final test status.
1487     TSVConnClose(static_cast<TSVConn>(data));
1488   }
1489 
1490   TSContDestroy(contp);
1491 
1492   return 1;
1493 }
1494 
REGRESSION_TEST(SDK_API_TSNetVConn)1495 REGRESSION_TEST(SDK_API_TSNetVConn)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1496 {
1497   *pstatus = REGRESSION_TEST_INPROGRESS;
1498 
1499   SDK_NetVConn_Params *params = new SDK_NetVConn_Params("TSNetAccept", test, pstatus);
1500 
1501   params->port = 12345;
1502 
1503   TSCont server_cont = TSContCreate(server_handler, TSMutexCreate());
1504   TSCont client_cont = TSContCreate(client_handler, TSMutexCreate());
1505 
1506   TSContDataSet(server_cont, params);
1507   TSContDataSet(client_cont, params);
1508 
1509   TSNetAccept(server_cont, params->port, -1, 0);
1510 
1511   IpEndpoint addr;
1512   ats_ip4_set(&addr, htonl(INADDR_LOOPBACK), htons(params->port));
1513   TSNetConnect(client_cont, &addr.sa);
1514 }
1515 
REGRESSION_TEST(SDK_API_TSPortDescriptor)1516 REGRESSION_TEST(SDK_API_TSPortDescriptor)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1517 {
1518   *pstatus = REGRESSION_TEST_INPROGRESS;
1519 
1520   TSPortDescriptor port;
1521   char desc[64];
1522   SDK_NetVConn_Params *params = new SDK_NetVConn_Params("TSPortDescriptorAccept", test, pstatus);
1523   TSCont server_cont          = TSContCreate(server_handler, TSMutexCreate());
1524   TSCont client_cont          = TSContCreate(client_handler, TSMutexCreate());
1525 
1526   params->port = 54321;
1527 
1528   TSContDataSet(server_cont, params);
1529   TSContDataSet(client_cont, params);
1530 
1531   port = TSPortDescriptorParse(nullptr);
1532   if (port) {
1533     SDK_RPRINT(test, "TSPortDescriptorParse", "NULL port descriptor", TC_FAIL, "TSPortDescriptorParse(NULL) returned %s", port);
1534     *pstatus = REGRESSION_TEST_FAILED;
1535     return;
1536   }
1537 
1538   snprintf(desc, sizeof(desc), "%u", params->port);
1539   port = TSPortDescriptorParse(desc);
1540 
1541   if (TSPortDescriptorAccept(port, server_cont) == TS_ERROR) {
1542     SDK_RPRINT(test, "TSPortDescriptorParse", "Basic port descriptor", TC_FAIL, "TSPortDescriptorParse(%s) returned TS_ERROR",
1543                desc);
1544     *pstatus = REGRESSION_TEST_FAILED;
1545     return;
1546   }
1547 
1548   IpEndpoint addr;
1549   ats_ip4_set(&addr, htonl(INADDR_LOOPBACK), htons(params->port));
1550   TSNetConnect(client_cont, &addr.sa);
1551 }
1552 
1553 /* TSCache, TSVConn, TSVIO */
1554 //////////////////////////////////////////////
1555 //       SDK_API_TSCache
1556 //
1557 // Unit Test for API: TSCacheReady
1558 //                    TSCacheWrite
1559 //                    TSCacheRead
1560 //                    TSCacheKeyCreate
1561 //                    TSCacheKeyDigestSet
1562 //                    TSVConnCacheObjectSizeGet
1563 //                    TSVConnClose
1564 //                    TSVConnClosedGet
1565 //                    TSVConnRead
1566 //                    TSVConnReadVIOGet
1567 //                    TSVConnWrite
1568 //                    TSVConnWriteVIOGet
1569 //                    TSVIOBufferGet
1570 //                    TSVIOContGet
1571 //                    TSVIOMutexGet
1572 //                    TSVIONBytesGet
1573 //                    TSVIONBytesSet
1574 //                    TSVIONDoneGet
1575 //                    TSVIONDoneSet
1576 //                    TSVIONTodoGet
1577 //                    TSVIOReaderGet
1578 //                    TSVIOReenable
1579 //                    TSVIOVConnGet
1580 //////////////////////////////////////////////
1581 
1582 // TSVConnAbort can't be tested
1583 // Fix me: test TSVConnShutdown, TSCacheKeyDataTypeSet,
1584 //         TSCacheKeyHostNameSet, TSCacheKeyPinnedSet
1585 
1586 // Logic of the test:
1587 //  - write OBJECT_SIZE bytes in the cache in 3 shots
1588 //    (OBJECT_SIZE/2, then OBJECT_SIZE-100 and finally OBJECT_SIZE)
1589 //  - read object from the cache
1590 //  - remove it from the cache
1591 //  - try to read it (should fail)
1592 
1593 #define OBJECT_SIZE 100000 // size of the object we'll write/read/remove in cache
1594 
1595 RegressionTest *SDK_Cache_test;
1596 int *SDK_Cache_pstatus;
1597 static char content[OBJECT_SIZE];
1598 static int read_counter = 0;
1599 
1600 typedef struct {
1601   TSIOBuffer bufp;
1602   TSIOBuffer out_bufp;
1603   TSIOBufferReader readerp;
1604   TSIOBufferReader out_readerp;
1605 
1606   TSVConn write_vconnp;
1607   TSVConn read_vconnp;
1608   TSVIO read_vio;
1609   TSVIO write_vio;
1610 
1611   TSCacheKey key;
1612 } CacheVConnStruct;
1613 
1614 int
cache_handler(TSCont contp,TSEvent event,void * data)1615 cache_handler(TSCont contp, TSEvent event, void *data)
1616 {
1617   Debug("sdk_ut_cache_write", "Event %d data %p", event, data);
1618 
1619   CacheVConnStruct *cache_vconn = static_cast<CacheVConnStruct *>(TSContDataGet(contp));
1620 
1621   TSIOBufferBlock blockp;
1622   char *ptr_block;
1623   int64_t ntodo, ndone, nbytes, towrite, avail, content_length;
1624 
1625   switch (event) {
1626   case TS_EVENT_CACHE_OPEN_WRITE:
1627     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_WRITE %d %p", event, data);
1628     SDK_RPRINT(SDK_Cache_test, "TSCacheWrite", "TestCase1", TC_PASS, "ok");
1629 
1630     // data is write_vc
1631     cache_vconn->write_vconnp = static_cast<TSVConn>(data);
1632 
1633     // Create buffers/readers to write and read data into the cache
1634     cache_vconn->bufp        = TSIOBufferCreate();
1635     cache_vconn->readerp     = TSIOBufferReaderAlloc(cache_vconn->bufp);
1636     cache_vconn->out_bufp    = TSIOBufferCreate();
1637     cache_vconn->out_readerp = TSIOBufferReaderAlloc(cache_vconn->out_bufp);
1638 
1639     // Write content into upstream IOBuffer
1640     ntodo = OBJECT_SIZE;
1641     ndone = 0;
1642     while (ntodo > 0) {
1643       blockp    = TSIOBufferStart(cache_vconn->bufp);
1644       ptr_block = TSIOBufferBlockWriteStart(blockp, &avail);
1645       towrite   = ((ntodo < avail) ? ntodo : avail);
1646       memcpy(ptr_block, content + ndone, towrite);
1647       TSIOBufferProduce(cache_vconn->bufp, towrite);
1648       ntodo -= towrite;
1649       ndone += towrite;
1650     }
1651 
1652     // first write half of the data. To test TSVIOReenable
1653     cache_vconn->write_vio = TSVConnWrite(static_cast<TSVConn>(data), contp, cache_vconn->readerp, OBJECT_SIZE / 2);
1654     return 1;
1655 
1656   case TS_EVENT_CACHE_OPEN_WRITE_FAILED:
1657     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_WRITE_FAILED %d %p", event, data);
1658     SDK_RPRINT(SDK_Cache_test, "TSCacheWrite", "TestCase1", TC_FAIL, "can't open cache vc, edtata = %p", data);
1659     TSReleaseAssert(!"cache");
1660 
1661     // no need to continue, return
1662     *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1663     return 1;
1664 
1665   case TS_EVENT_CACHE_OPEN_READ:
1666     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_READ %d %p", event, data);
1667     if (read_counter == 2) {
1668       SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase2", TC_FAIL, "shouldn't open cache vc");
1669 
1670       // no need to continue, return
1671       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1672       return 1;
1673     }
1674 
1675     SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase1", TC_PASS, "ok");
1676 
1677     cache_vconn->read_vconnp = static_cast<TSVConn>(data);
1678     content_length           = TSVConnCacheObjectSizeGet(cache_vconn->read_vconnp);
1679     Debug(UTDBG_TAG "_cache_read", "In cache open read [Content-Length: %" PRId64 "]", content_length);
1680     if (content_length != OBJECT_SIZE) {
1681       SDK_RPRINT(SDK_Cache_test, "TSVConnCacheObjectSizeGet", "TestCase1", TC_FAIL, "cached data size is incorrect");
1682 
1683       // no need to continue, return
1684       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1685       return 1;
1686     } else {
1687       SDK_RPRINT(SDK_Cache_test, "TSVConnCacheObjectSizeGet", "TestCase1", TC_PASS, "ok");
1688       cache_vconn->read_vio = TSVConnRead(static_cast<TSVConn>(data), contp, cache_vconn->out_bufp, content_length);
1689     }
1690     return 1;
1691 
1692   case TS_EVENT_CACHE_OPEN_READ_FAILED:
1693     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_OPEN_READ_FAILED %d %p", event, data);
1694     if (read_counter == 1) {
1695       SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase1", TC_FAIL, "can't open cache vc");
1696 
1697       // no need to continue, return
1698       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1699       return 1;
1700     }
1701     SDK_RPRINT(SDK_Cache_test, "TSCacheRead", "TestCase2", TC_PASS, "ok");
1702 
1703     // ok, all tests passed!
1704     break;
1705 
1706   case TS_EVENT_CACHE_REMOVE:
1707     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_REMOVE %d %p", event, data);
1708     SDK_RPRINT(SDK_Cache_test, "TSCacheRemove", "TestCase1", TC_PASS, "ok");
1709 
1710     // read the data which has been removed
1711     read_counter++;
1712     TSCacheRead(contp, cache_vconn->key);
1713     return 1;
1714 
1715   case TS_EVENT_CACHE_REMOVE_FAILED:
1716     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_CACHE_REMOVE_FAILED %d %p", event, data);
1717     SDK_RPRINT(SDK_Cache_test, "TSCacheRemove", "TestCase1", TC_FAIL, "can't remove cached item");
1718 
1719     // no need to continue, return
1720     *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1721     return 1;
1722 
1723   case TS_EVENT_VCONN_WRITE_COMPLETE:
1724     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_WRITE_COMPLETE %d %p", event, data);
1725 
1726     // VConn/VIO APIs
1727     nbytes = TSVIONBytesGet(cache_vconn->write_vio);
1728     ndone  = TSVIONDoneGet(cache_vconn->write_vio);
1729     ntodo  = TSVIONTodoGet(cache_vconn->write_vio);
1730     Debug(UTDBG_TAG "_cache_write", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1731 
1732     if (ndone == (OBJECT_SIZE / 2)) {
1733       TSVIONBytesSet(cache_vconn->write_vio, (OBJECT_SIZE - 100));
1734       TSVIOReenable(cache_vconn->write_vio);
1735       Debug(UTDBG_TAG "_cache_write", "Increment write_counter in write_complete [a]");
1736       return 1;
1737     } else if (ndone == (OBJECT_SIZE - 100)) {
1738       TSVIONBytesSet(cache_vconn->write_vio, OBJECT_SIZE);
1739       TSVIOReenable(cache_vconn->write_vio);
1740       Debug(UTDBG_TAG "_cache_write", "Increment write_counter in write_complete [b]");
1741       return 1;
1742     } else if (ndone == OBJECT_SIZE) {
1743       Debug(UTDBG_TAG "_cache_write", "finishing up [c]");
1744 
1745       SDK_RPRINT(SDK_Cache_test, "TSVIOReenable", "TestCase2", TC_PASS, "ok");
1746       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesSet", "TestCase1", TC_PASS, "ok");
1747       SDK_RPRINT(SDK_Cache_test, "TSVConnWrite", "TestCase1", TC_PASS, "ok");
1748     } else {
1749       SDK_RPRINT(SDK_Cache_test, "TSCacheWrite", "TestCase1", TC_FAIL, "Did not write expected # of bytes");
1750       // no need to continue, return
1751       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1752       return 1;
1753     }
1754 
1755     if (static_cast<TSVIO>(data) != cache_vconn->write_vio) {
1756       SDK_RPRINT(SDK_Cache_test, "TSVConnWrite", "TestCase1", TC_FAIL, "write_vio corrupted");
1757       // no need to continue, return
1758       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1759       return 1;
1760     }
1761     Debug(UTDBG_TAG "_cache_write", "finishing up [d]");
1762 
1763     if (TSVIOBufferGet(cache_vconn->write_vio) != cache_vconn->bufp) {
1764       SDK_RPRINT(SDK_Cache_test, "TSVIOBufferGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1765       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1766       return 1;
1767     } else {
1768       SDK_RPRINT(SDK_Cache_test, "TSVIOBufferGet", "TestCase1", TC_PASS, "ok");
1769     }
1770 
1771     if (TSVIOContGet(cache_vconn->write_vio) != contp) {
1772       SDK_RPRINT(SDK_Cache_test, "TSVIOContGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1773       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1774       return 1;
1775     } else {
1776       SDK_RPRINT(SDK_Cache_test, "TSVIOContGet", "TestCase1", TC_PASS, "ok");
1777     }
1778 
1779     Debug(UTDBG_TAG "_cache_write", "finishing up [f]");
1780 
1781     if (TSVIOMutexGet(cache_vconn->write_vio) != TSContMutexGet(contp)) {
1782       SDK_RPRINT(SDK_Cache_test, "TSVIOMutexGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1783       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1784       return 1;
1785     } else {
1786       SDK_RPRINT(SDK_Cache_test, "TSVIOMutexGet", "TestCase1", TC_PASS, "ok");
1787     }
1788 
1789     if (TSVIOVConnGet(cache_vconn->write_vio) != cache_vconn->write_vconnp) {
1790       SDK_RPRINT(SDK_Cache_test, "TSVIOVConnGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1791       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1792       return 1;
1793     } else {
1794       SDK_RPRINT(SDK_Cache_test, "TSVIOVConnGet", "TestCase1", TC_PASS, "ok");
1795     }
1796 
1797     Debug(UTDBG_TAG "_cache_write", "finishing up [g]");
1798 
1799     if (TSVIOReaderGet(cache_vconn->write_vio) != cache_vconn->readerp) {
1800       SDK_RPRINT(SDK_Cache_test, "TSVIOReaderGet", "TestCase1", TC_FAIL, "write_vio corrupted");
1801       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1802       return 1;
1803     } else {
1804       SDK_RPRINT(SDK_Cache_test, "TSVIOReaderGet", "TestCase1", TC_PASS, "ok");
1805     }
1806 
1807     // tests for write is done, close write_vconnp
1808     TSVConnClose(cache_vconn->write_vconnp);
1809     cache_vconn->write_vconnp = nullptr;
1810 
1811     Debug(UTDBG_TAG "_cache_write", "finishing up [h]");
1812 
1813     // start to read data out of cache
1814     read_counter++;
1815     TSCacheRead(contp, cache_vconn->key);
1816     Debug(UTDBG_TAG "_cache_read", "starting read [i]");
1817     return 1;
1818 
1819   case TS_EVENT_VCONN_WRITE_READY:
1820     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_WRITE_READY %d %p", event, data);
1821     if (static_cast<TSVIO>(data) != cache_vconn->write_vio) {
1822       SDK_RPRINT(SDK_Cache_test, "TSVConnWrite", "TestCase1", TC_FAIL, "write_vio corrupted");
1823       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1824       return 1;
1825     }
1826 
1827     nbytes = TSVIONBytesGet(cache_vconn->write_vio);
1828     ndone  = TSVIONDoneGet(cache_vconn->write_vio);
1829     ntodo  = TSVIONTodoGet(cache_vconn->write_vio);
1830     Debug(UTDBG_TAG "_cache_write", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1831 
1832     TSVIOReenable(cache_vconn->write_vio);
1833     return 1;
1834 
1835   case TS_EVENT_VCONN_READ_COMPLETE:
1836     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_READ_COMPLETE %d %p", event, data);
1837     if (static_cast<TSVIO>(data) != cache_vconn->read_vio) {
1838       SDK_RPRINT(SDK_Cache_test, "TSVConnRead", "TestCase1", TC_FAIL, "read_vio corrupted");
1839 
1840       // no need to continue, return
1841       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1842       return 1;
1843     }
1844 
1845     nbytes = TSVIONBytesGet(cache_vconn->read_vio);
1846     ntodo  = TSVIONTodoGet(cache_vconn->read_vio);
1847     ndone  = TSVIONDoneGet(cache_vconn->read_vio);
1848     Debug(UTDBG_TAG "_cache_read", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1849 
1850     if (nbytes != (ndone + ntodo)) {
1851       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1852       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1853       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1854 
1855       // no need to continue, return
1856       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1857       return 1;
1858     } else {
1859       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_PASS, "ok");
1860       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_PASS, "ok");
1861       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_PASS, "ok");
1862 
1863       TSVIONDoneSet(cache_vconn->read_vio, 0);
1864       if (TSVIONDoneGet(cache_vconn->read_vio) != 0) {
1865         SDK_RPRINT(SDK_Cache_test, "TSVIONDoneSet", "TestCase1", TC_FAIL, "fail to set");
1866 
1867         // no need to continue, return
1868         *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1869         return 1;
1870       } else {
1871         SDK_RPRINT(SDK_Cache_test, "TSVIONDoneSet", "TestCase1", TC_PASS, "ok");
1872       }
1873 
1874       Debug(UTDBG_TAG "_cache_write", "finishing up [i]");
1875 
1876       // now waiting for 100ms to make sure the key is
1877       // written in directory remove the content
1878       TSContScheduleOnPool(contp, 100, TS_THREAD_POOL_NET);
1879     }
1880 
1881     return 1;
1882 
1883   case TS_EVENT_VCONN_READ_READY:
1884     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_VCONN_READ_READY %d %p", event, data);
1885     if (static_cast<TSVIO>(data) != cache_vconn->read_vio) {
1886       SDK_RPRINT(SDK_Cache_test, "TSVConnRead", "TestCase1", TC_FAIL, "read_vio corrupted");
1887 
1888       // no need to continue, return
1889       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1890       return 1;
1891     }
1892 
1893     nbytes = TSVIONBytesGet(cache_vconn->read_vio);
1894     ntodo  = TSVIONTodoGet(cache_vconn->read_vio);
1895     ndone  = TSVIONDoneGet(cache_vconn->read_vio);
1896     Debug(UTDBG_TAG "_cache_read", "Nbytes=%" PRId64 " Ndone=%" PRId64 " Ntodo=%" PRId64 "", nbytes, ndone, ntodo);
1897 
1898     if (nbytes != (ndone + ntodo)) {
1899       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1900       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1901       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_FAIL, "read_vio corrupted");
1902 
1903       // no need to continue, return
1904       *SDK_Cache_pstatus = REGRESSION_TEST_FAILED;
1905       return 1;
1906     } else {
1907       SDK_RPRINT(SDK_Cache_test, "TSVIONBytesGet", "TestCase1", TC_PASS, "ok");
1908       SDK_RPRINT(SDK_Cache_test, "TSVIONTodoGet", "TestCase1", TC_PASS, "ok");
1909       SDK_RPRINT(SDK_Cache_test, "TSVIONDoneGet", "TestCase1", TC_PASS, "ok");
1910     }
1911 
1912     // Fix for bug INKqa12276: Must consume data from iobuffer
1913     nbytes = TSIOBufferReaderAvail(cache_vconn->out_readerp);
1914     TSIOBufferReaderConsume(cache_vconn->out_readerp, nbytes);
1915     TSDebug(UTDBG_TAG "_cache_read", "Consuming %" PRId64 " bytes from cache read VC", nbytes);
1916 
1917     TSVIOReenable(cache_vconn->read_vio);
1918     Debug(UTDBG_TAG "_cache_read", "finishing up [j]");
1919     return 1;
1920 
1921   case TS_EVENT_TIMEOUT:
1922     Debug(UTDBG_TAG "_cache_event", "TS_EVENT_TIMEOUT %d %p", event, data);
1923     // do remove cached doc
1924     TSCacheRemove(contp, cache_vconn->key);
1925     return 1;
1926 
1927   default:
1928     TSReleaseAssert(!"Test SDK_API_TSCache: unexpected event");
1929   }
1930 
1931   Debug(UTDBG_TAG "_cache_event", "DONE DONE DONE");
1932 
1933   // destroy the data structure
1934   Debug(UTDBG_TAG "_cache_write", "all tests passed [z]");
1935   TSIOBufferDestroy(cache_vconn->bufp);
1936   TSIOBufferDestroy(cache_vconn->out_bufp);
1937   TSCacheKeyDestroy(cache_vconn->key);
1938   TSfree(cache_vconn);
1939   *SDK_Cache_pstatus = REGRESSION_TEST_PASSED;
1940 
1941   return 1;
1942 }
1943 
REGRESSION_TEST(SDK_API_TSCache)1944 REGRESSION_TEST(SDK_API_TSCache)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
1945 {
1946   *pstatus          = REGRESSION_TEST_INPROGRESS;
1947   SDK_Cache_test    = test;
1948   SDK_Cache_pstatus = pstatus;
1949   int is_ready      = 0;
1950 
1951   // Check if Cache is ready
1952   TSCacheReady(&is_ready);
1953   if (!is_ready) {
1954     SDK_RPRINT(test, "TSCacheReady", "TestCase1", TC_FAIL, "cache is not ready");
1955 
1956     // no need to continue, return
1957     *pstatus = REGRESSION_TEST_FAILED;
1958     return;
1959   } else {
1960     SDK_RPRINT(test, "TSCacheReady", "TestCase1", TC_PASS, "ok");
1961   }
1962 
1963   // Create CacheKey
1964   char key_name[]    = "key_for_regression_test";
1965   TSCacheKey key     = TSCacheKeyCreate();
1966   TSCacheKey key_cmp = TSCacheKeyCreate();
1967   SDK_RPRINT(test, "TSCacheKeyCreate", "TestCase1", TC_PASS, "ok");
1968   TSCacheKeyDigestSet(key, key_name, strlen(key_name));
1969   TSCacheKeyDigestSet(key_cmp, key_name, strlen(key_name));
1970 
1971   // prepare caching content
1972   // string, null-terminated.
1973   for (int i = 0; i < (OBJECT_SIZE - 1); i++) {
1974     content[i] = 'a';
1975   }
1976   content[OBJECT_SIZE - 1] = '\0';
1977 
1978   // Write data to cache.
1979   TSCont contp                  = TSContCreate(cache_handler, TSMutexCreate());
1980   CacheVConnStruct *cache_vconn = static_cast<CacheVConnStruct *>(TSmalloc(sizeof(CacheVConnStruct)));
1981   cache_vconn->key              = key;
1982   TSContDataSet(contp, cache_vconn);
1983 
1984   TSCacheWrite(contp, key);
1985 }
1986 
1987 /* TSfopen */
1988 
1989 //////////////////////////////////////////////
1990 //       SDK_API_TSfopen
1991 //
1992 // Unit Test for API: TSfopen
1993 //                    TSclose
1994 //                    TSfflush
1995 //                    TSfgets
1996 //                    TSfread
1997 //                    TSfwrite
1998 //////////////////////////////////////////////
1999 
2000 // Note that for each test, if it fails, we set the error status and return.
REGRESSION_TEST(SDK_API_TSfopen)2001 REGRESSION_TEST(SDK_API_TSfopen)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2002 {
2003   *pstatus = REGRESSION_TEST_INPROGRESS;
2004 
2005   char write_file_name[PATH_NAME_MAX];
2006 
2007   TSFile source_read_file; // existing file
2008   TSFile write_file;       // to be created
2009   TSFile cmp_read_file;    // read & compare
2010 
2011   char input_buffer[BUFSIZ];
2012   char cmp_buffer[BUFSIZ];
2013   struct stat stat_buffer_pre, stat_buffer_post, stat_buffer_input;
2014   char *ret_val;
2015   int read = 0, wrote = 0;
2016   int64_t read_amount = 0;
2017   char input_file_full_path[BUFSIZ];
2018 
2019   // Set full path to file at run time.
2020   // TODO: This can never fail since we are
2021   //       returning the char[]
2022   //       Better check the dir itself.
2023   //
2024   if (TSInstallDirGet() == nullptr) {
2025     *pstatus = REGRESSION_TEST_FAILED;
2026     return;
2027   }
2028   // Add "etc/trafficserver" to point to config directory
2029   ink_filepath_make(input_file_full_path, sizeof(input_file_full_path), TSConfigDirGet(), ts::filename::PLUGIN);
2030 
2031   // open existing file for reading
2032   if (!(source_read_file = TSfopen(input_file_full_path, "r"))) {
2033     SDK_RPRINT(test, "TSfopen", "TestCase1", TC_FAIL, "can't open file for reading");
2034 
2035     // no need to continue, return
2036     *pstatus = REGRESSION_TEST_FAILED;
2037     return;
2038   } else {
2039     SDK_RPRINT(test, "TSfopen", "TestCase1", TC_PASS, "ok");
2040   }
2041 
2042   // Create unique tmp _file_name_, do not use any TS file_name
2043   snprintf(write_file_name, PATH_NAME_MAX, "/tmp/%sXXXXXX", ts::filename::PLUGIN);
2044   int write_file_fd; // this file will be reopened below
2045   if ((write_file_fd = mkstemp(write_file_name)) <= 0) {
2046     SDK_RPRINT(test, "mkstemp", "std func", TC_FAIL, "can't create file for writing");
2047 
2048     // no need to continue, return
2049     *pstatus = REGRESSION_TEST_FAILED;
2050     if (source_read_file != nullptr) {
2051       TSfclose(source_read_file);
2052     }
2053     return;
2054   }
2055   close(write_file_fd);
2056 
2057   // open file for writing, the file doesn't have to exist.
2058   if (!(write_file = TSfopen(write_file_name, "w"))) {
2059     SDK_RPRINT(test, "TSfopen", "TestCase2", TC_FAIL, "can't open file for writing");
2060 
2061     // no need to continue, return
2062     *pstatus = REGRESSION_TEST_FAILED;
2063     if (source_read_file != nullptr) {
2064       TSfclose(source_read_file);
2065     }
2066     return;
2067   }
2068   SDK_RPRINT(test, "TSfopen", "TestCase2", TC_PASS, "ok");
2069 
2070   memset(input_buffer, '\0', BUFSIZ);
2071 
2072   // source_read_file and input_file_full_path are the same file
2073   if (stat(input_file_full_path, &stat_buffer_input) != 0) {
2074     SDK_RPRINT(test, "stat", "std func", TC_FAIL, "source file and input file messed up");
2075 
2076     // no need to continue, return
2077     *pstatus = REGRESSION_TEST_FAILED;
2078     if (source_read_file != nullptr) {
2079       TSfclose(source_read_file);
2080     }
2081     if (write_file != nullptr) {
2082       TSfclose(write_file);
2083     }
2084     return;
2085   }
2086 
2087   read_amount =
2088     (stat_buffer_input.st_size <= static_cast<off_t>(sizeof(input_buffer))) ? (stat_buffer_input.st_size) : (sizeof(input_buffer));
2089 
2090   // TSfgets
2091   if ((ret_val = TSfgets(source_read_file, input_buffer, read_amount)) == nullptr) {
2092     SDK_RPRINT(test, "TSfgets", "TestCase1", TC_FAIL, "can't read from file");
2093 
2094     // no need to continue, return
2095     *pstatus = REGRESSION_TEST_FAILED;
2096     if (source_read_file != nullptr) {
2097       TSfclose(source_read_file);
2098     }
2099     if (write_file != nullptr) {
2100       TSfclose(write_file);
2101     }
2102     return;
2103   } else {
2104     if (ret_val != input_buffer) {
2105       SDK_RPRINT(test, "TSfgets", "TestCase2", TC_FAIL, "reading error");
2106 
2107       // no need to continue, return
2108       *pstatus = REGRESSION_TEST_FAILED;
2109       if (source_read_file != nullptr) {
2110         TSfclose(source_read_file);
2111       }
2112       if (write_file != nullptr) {
2113         TSfclose(write_file);
2114       }
2115       return;
2116     } else {
2117       SDK_RPRINT(test, "TSfgets", "TestCase1", TC_PASS, "ok");
2118     }
2119   }
2120 
2121   // TSfwrite
2122   wrote = TSfwrite(write_file, input_buffer, read_amount);
2123   if (wrote != read_amount) {
2124     SDK_RPRINT(test, "TSfwrite", "TestCase1", TC_FAIL, "writing error");
2125 
2126     // no need to continue, return
2127     *pstatus = REGRESSION_TEST_FAILED;
2128     if (source_read_file != nullptr) {
2129       TSfclose(source_read_file);
2130     }
2131     if (write_file != nullptr) {
2132       TSfclose(write_file);
2133     }
2134     return;
2135   }
2136 
2137   SDK_RPRINT(test, "TSfwrite", "TestCase1", TC_PASS, "ok");
2138 
2139   // TSfflush
2140   if (stat(write_file_name, &stat_buffer_pre) != 0) {
2141     SDK_RPRINT(test, "stat", "std func", TC_FAIL, "TSfwrite error");
2142 
2143     // no need to continue, return
2144     *pstatus = REGRESSION_TEST_FAILED;
2145     if (source_read_file != nullptr) {
2146       TSfclose(source_read_file);
2147     }
2148     if (write_file != nullptr) {
2149       TSfclose(write_file);
2150     }
2151     return;
2152   }
2153 
2154   TSfflush(write_file); // write_file should point to write_file_name
2155 
2156   if (stat(write_file_name, &stat_buffer_post) != 0) {
2157     SDK_RPRINT(test, "stat", "std func", TC_FAIL, "TSfflush error");
2158 
2159     // no need to continue, return
2160     *pstatus = REGRESSION_TEST_FAILED;
2161     if (source_read_file != nullptr) {
2162       TSfclose(source_read_file);
2163     }
2164     if (write_file != nullptr) {
2165       TSfclose(write_file);
2166     }
2167     return;
2168   }
2169 
2170   if ((stat_buffer_pre.st_size == 0) && (stat_buffer_post.st_size == read_amount)) {
2171     SDK_RPRINT(test, "TSfflush", "TestCase1", TC_PASS, "ok");
2172   } else {
2173     SDK_RPRINT(test, "TSfflush", "TestCase1", TC_FAIL, "TSfflush error");
2174 
2175     // no need to continue, return
2176     *pstatus = REGRESSION_TEST_FAILED;
2177     if (source_read_file != nullptr) {
2178       TSfclose(source_read_file);
2179     }
2180     if (write_file != nullptr) {
2181       TSfclose(write_file);
2182     }
2183     return;
2184   }
2185 
2186   // TSfread
2187   // open again for reading
2188   cmp_read_file = TSfopen(write_file_name, "r");
2189   if (cmp_read_file == nullptr) {
2190     SDK_RPRINT(test, "TSfopen", "TestCase3", TC_FAIL, "can't open file for reading");
2191 
2192     // no need to continue, return
2193     *pstatus = REGRESSION_TEST_FAILED;
2194     if (source_read_file != nullptr) {
2195       TSfclose(source_read_file);
2196     }
2197     if (write_file != nullptr) {
2198       TSfclose(write_file);
2199     }
2200     return;
2201   }
2202 
2203   read_amount =
2204     (stat_buffer_input.st_size <= static_cast<off_t>(sizeof(cmp_buffer))) ? (stat_buffer_input.st_size) : (sizeof(cmp_buffer));
2205 
2206   // TSfread on read file
2207   read = TSfread(cmp_read_file, cmp_buffer, read_amount);
2208   if (read != read_amount) {
2209     SDK_RPRINT(test, "TSfread", "TestCase1", TC_FAIL, "can't reading");
2210 
2211     // no need to continue, return
2212     *pstatus = REGRESSION_TEST_FAILED;
2213     if (source_read_file != nullptr) {
2214       TSfclose(source_read_file);
2215     }
2216     if (write_file != nullptr) {
2217       TSfclose(write_file);
2218     }
2219     if (cmp_read_file != nullptr) {
2220       TSfclose(cmp_read_file);
2221     }
2222     return;
2223   } else {
2224     SDK_RPRINT(test, "TSfread", "TestCase1", TC_PASS, "ok");
2225   }
2226 
2227   // compare input_buffer and cmp_buffer buffers
2228   if (memcmp(input_buffer, cmp_buffer, read_amount) != 0) {
2229     SDK_RPRINT(test, "TSfread", "TestCase2", TC_FAIL, "reading error");
2230 
2231     // no need to continue, return
2232     *pstatus = REGRESSION_TEST_FAILED;
2233     if (source_read_file != nullptr) {
2234       TSfclose(source_read_file);
2235     }
2236     if (write_file != nullptr) {
2237       TSfclose(write_file);
2238     }
2239     if (cmp_read_file != nullptr) {
2240       TSfclose(cmp_read_file);
2241     }
2242     return;
2243   } else {
2244     SDK_RPRINT(test, "TSfread", "TestCase2", TC_PASS, "ok");
2245   }
2246 
2247   // remove the tmp file
2248   if (unlink(write_file_name) != 0) {
2249     SDK_RPRINT(test, "unlink", "std func", TC_FAIL, "can't remove temp file");
2250   }
2251   // TSfclose on read file
2252   TSfclose(source_read_file);
2253   SDK_RPRINT(test, "TSfclose", "TestCase1", TC_PASS, "ok");
2254 
2255   // TSfclose on write file
2256   TSfclose(write_file);
2257   SDK_RPRINT(test, "TSfclose", "TestCase2", TC_PASS, "ok");
2258 
2259   *pstatus = REGRESSION_TEST_PASSED;
2260   if (cmp_read_file != nullptr) {
2261     TSfclose(cmp_read_file);
2262   }
2263 }
2264 
2265 /* TSThread */
2266 
2267 //////////////////////////////////////////////
2268 //       SDK_API_TSThread
2269 //
2270 // Unit Test for API: TSThread
2271 //                    TSThreadCreate
2272 //                    TSThreadSelf
2273 //////////////////////////////////////////////
2274 static int thread_err_count = 0;
2275 static RegressionTest *SDK_Thread_test;
2276 static int *SDK_Thread_pstatus;
2277 static void *thread_create_handler(void *arg);
2278 
2279 static void *
thread_create_handler(void *)2280 thread_create_handler(void * /* arg ATS_UNUSED */)
2281 {
2282   TSThread athread;
2283   // Fix me: do more useful work
2284   sleep(10);
2285 
2286   athread = TSThreadSelf();
2287   if (athread == nullptr) {
2288     thread_err_count++;
2289     SDK_RPRINT(SDK_Thread_test, "TSThreadCreate", "TestCase2", TC_FAIL, "can't get thread");
2290   } else {
2291     SDK_RPRINT(SDK_Thread_test, "TSThreadCreate", "TestCase2", TC_PASS, "ok");
2292   }
2293 
2294   if (thread_err_count > 0) {
2295     *SDK_Thread_pstatus = REGRESSION_TEST_FAILED;
2296   } else {
2297     *SDK_Thread_pstatus = REGRESSION_TEST_PASSED;
2298   }
2299 
2300   return nullptr;
2301 }
2302 
2303 // Fix me: Solaris threads/Win2K threads tests
2304 
2305 // Argument data passed to thread init functions
2306 //  cannot be allocated on the stack.
2307 
REGRESSION_TEST(SDK_API_TSThread)2308 REGRESSION_TEST(SDK_API_TSThread)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2309 {
2310   *pstatus           = REGRESSION_TEST_INPROGRESS;
2311   SDK_Thread_test    = test;
2312   SDK_Thread_pstatus = pstatus;
2313 
2314   TSThread curr_thread = nullptr;
2315   //    TSThread created_thread = 0;
2316   pthread_t curr_tid;
2317 
2318   curr_tid = pthread_self();
2319 
2320   // TSThreadSelf
2321   curr_thread = TSThreadSelf();
2322   if (curr_thread == nullptr) {
2323     SDK_RPRINT(test, "TSThreadSelf", "TestCase1", TC_FAIL, "can't get the current thread");
2324     thread_err_count++;
2325   } else {
2326     SDK_RPRINT(test, "TSThreadSelf", "TestCase1", TC_PASS, "ok");
2327   }
2328 
2329   // TSThreadCreate
2330   TSThread created_thread = TSThreadCreate(thread_create_handler, reinterpret_cast<void *>(curr_tid));
2331   if (created_thread == nullptr) {
2332     thread_err_count++;
2333     SDK_RPRINT(test, "TSThreadCreate", "TestCase1", TC_FAIL, "can't create thread");
2334   } else {
2335     SDK_RPRINT(test, "TSThreadCreate", "TestCase1", TC_PASS, "ok");
2336   }
2337 
2338   if (created_thread != nullptr) {
2339     TSThreadWait(created_thread);
2340     TSThreadDestroy(created_thread);
2341   }
2342 }
2343 
2344 //////////////////////////////////////////////
2345 //       SDK_API_TSThread
2346 //
2347 // Unit Test for API: TSThreadInit
2348 //                    TSThreadDestroy
2349 //////////////////////////////////////////////
2350 static int thread_init_err_count = 0;
2351 static RegressionTest *SDK_ThreadInit_test;
2352 static int *SDK_ThreadInit_pstatus;
2353 static void *pthread_start_func(void *arg);
2354 
2355 static void *
pthread_start_func(void *)2356 pthread_start_func(void * /* arg ATS_UNUSED */)
2357 {
2358   TSThread temp_thread = nullptr;
2359 
2360   // TSThreadInit
2361   temp_thread = TSThreadInit();
2362 
2363   if (!temp_thread) {
2364     SDK_RPRINT(SDK_ThreadInit_test, "TSThreadInit", "TestCase2", TC_FAIL, "can't init thread");
2365     thread_init_err_count++;
2366   } else {
2367     SDK_RPRINT(SDK_ThreadInit_test, "TSThreadInit", "TestCase2", TC_PASS, "ok");
2368   }
2369 
2370   // Clean up this thread
2371   if (temp_thread) {
2372     TSThreadDestroy(temp_thread);
2373   }
2374 
2375   if (thread_init_err_count > 0) {
2376     *SDK_ThreadInit_pstatus = REGRESSION_TEST_FAILED;
2377   } else {
2378     *SDK_ThreadInit_pstatus = REGRESSION_TEST_PASSED;
2379   }
2380 
2381   return nullptr;
2382 }
2383 
REGRESSION_TEST(SDK_API_TSThreadInit)2384 REGRESSION_TEST(SDK_API_TSThreadInit)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2385 {
2386   *pstatus               = REGRESSION_TEST_INPROGRESS;
2387   SDK_ThreadInit_test    = test;
2388   SDK_ThreadInit_pstatus = pstatus;
2389 
2390   pthread_t curr_tid, new_tid;
2391 
2392   curr_tid = pthread_self();
2393 
2394   int ret;
2395   errno = 0;
2396   ret   = pthread_create(&new_tid, nullptr, pthread_start_func, reinterpret_cast<void *>(curr_tid));
2397   if (ret != 0) {
2398     thread_init_err_count++;
2399     SDK_RPRINT(test, "TSThreadInit", "TestCase1", TC_FAIL, "can't create pthread");
2400   } else {
2401     SDK_RPRINT(test, "TSThreadInit", "TestCase1", TC_PASS, "ok");
2402   }
2403 }
2404 
2405 /* Action */
2406 
2407 //////////////////////////////////////////////
2408 //       SDK_API_TSAction
2409 //
2410 // Unit Test for API: TSActionCancel
2411 //////////////////////////////////////////////
2412 
2413 static RegressionTest *SDK_ActionCancel_test;
2414 static int *SDK_ActionCancel_pstatus;
2415 
2416 int
action_cancel_handler(TSCont contp,TSEvent event,void *)2417 action_cancel_handler(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
2418 {
2419   if (event == TS_EVENT_IMMEDIATE) { // called from schedule_imm OK
2420     SDK_RPRINT(SDK_ActionCancel_test, "TSActionCancel", "TestCase1", TC_PASS, "ok");
2421     *SDK_ActionCancel_pstatus = REGRESSION_TEST_PASSED;
2422   } else if (event == TS_EVENT_TIMEOUT) { // called from schedule_in Not OK.
2423     SDK_RPRINT(SDK_ActionCancel_test, "TSActionCancel", "TestCase1", TC_FAIL, "bad action");
2424     *SDK_ActionCancel_pstatus = REGRESSION_TEST_FAILED;
2425   } else { // there is sth wrong
2426     SDK_RPRINT(SDK_ActionCancel_test, "TSActionCancel", "TestCase1", TC_FAIL, "bad event");
2427     *SDK_ActionCancel_pstatus = REGRESSION_TEST_FAILED;
2428   }
2429 
2430   TSContDestroy(contp);
2431   return 0;
2432 }
2433 
REGRESSION_TEST(SDK_API_TSActionCancel)2434 REGRESSION_TEST(SDK_API_TSActionCancel)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2435 {
2436   *pstatus = REGRESSION_TEST_INPROGRESS;
2437 
2438   SDK_ActionCancel_test    = test;
2439   SDK_ActionCancel_pstatus = pstatus;
2440 
2441   TSMutex cont_mutex = TSMutexCreate();
2442   TSCont contp       = TSContCreate(action_cancel_handler, cont_mutex);
2443   TSAction actionp   = TSContScheduleOnPool(contp, 10000, TS_THREAD_POOL_NET);
2444 
2445   TSMutexLock(cont_mutex);
2446   if (TSActionDone(actionp)) {
2447     *pstatus = REGRESSION_TEST_FAILED;
2448     TSMutexUnlock(cont_mutex);
2449     return;
2450   } else {
2451     TSActionCancel(actionp);
2452   }
2453   TSMutexUnlock(cont_mutex);
2454 
2455   TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
2456 }
2457 
2458 //////////////////////////////////////////////
2459 //       SDK_API_TSAction
2460 //
2461 // Unit Test for API: TSActionDone
2462 //////////////////////////////////////////////
2463 /* Currently, don't know how to test it because TSAction
2464    is at "done" status only "shortly" after finish
2465    executing action_done_handler. Another possibility is
2466    to use reentrant call. But in both cases it's not
2467    guaranteed to get ActionDone.
2468    */
2469 
2470 /* Continuations */
2471 
2472 //////////////////////////////////////////////
2473 //       SDK_API_TSCont
2474 //
2475 // Unit Test for API: TSContCreate
2476 //                    TSContCall
2477 //////////////////////////////////////////////
2478 
2479 // this is needed for asynchronous APIs
2480 static RegressionTest *SDK_ContCreate_test;
2481 static int *SDK_ContCreate_pstatus;
2482 
2483 int
cont_handler(TSCont,TSEvent,void *)2484 cont_handler(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
2485 {
2486   SDK_RPRINT(SDK_ContCreate_test, "TSContCreate", "TestCase1", TC_PASS, "ok");
2487   SDK_RPRINT(SDK_ContCreate_test, "TSContCall", "TestCase1", TC_PASS, "ok");
2488 
2489   *SDK_ContCreate_pstatus = REGRESSION_TEST_PASSED;
2490 
2491   return 0;
2492 }
2493 
REGRESSION_TEST(SDK_API_TSContCreate)2494 REGRESSION_TEST(SDK_API_TSContCreate)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2495 {
2496   *pstatus = REGRESSION_TEST_INPROGRESS;
2497 
2498   // For asynchronous APIs, use static vars to store test and pstatus
2499   SDK_ContCreate_test    = test;
2500   SDK_ContCreate_pstatus = pstatus;
2501 
2502   TSMutex mutexp = TSMutexCreate();
2503   TSCont contp   = TSContCreate(cont_handler, mutexp);
2504 
2505   if (TS_SUCCESS == TSMutexLockTry(mutexp)) { // Mutex is grabbed successfully
2506     TSContCall(contp, static_cast<TSEvent>(0), nullptr);
2507     TSMutexUnlock(mutexp);
2508   } else { // mutex has problems
2509     SDK_RPRINT(SDK_ContCreate_test, "TSContCreate", "TestCase1", TC_FAIL, "continuation creation has problems");
2510     SDK_RPRINT(SDK_ContCreate_test, "TSContCall", "TestCase1", TC_FAIL, "continuation has problems");
2511 
2512     *pstatus = REGRESSION_TEST_FAILED;
2513   }
2514 
2515   TSContDestroy(contp);
2516 }
2517 
2518 //////////////////////////////////////////////
2519 //       SDK_API_TSCont
2520 //
2521 // Unit Test for API: TSContDataGet
2522 //                    TSContDataSet
2523 //////////////////////////////////////////////
2524 
2525 // this is needed for asynchronous APIs
2526 static RegressionTest *SDK_ContData_test;
2527 static int *SDK_ContData_pstatus;
2528 
2529 // this is specific for this test
2530 typedef struct {
2531   int data1;
2532   int data2;
2533 } MyData;
2534 
2535 int
cont_data_handler(TSCont contp,TSEvent,void *)2536 cont_data_handler(TSCont contp, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
2537 {
2538   MyData *my_data = static_cast<MyData *>(TSContDataGet(contp));
2539 
2540   if (my_data->data1 == 1 && my_data->data2 == 2) {
2541     SDK_RPRINT(SDK_ContData_test, "TSContDataSet", "TestCase1", TC_PASS, "ok");
2542     SDK_RPRINT(SDK_ContData_test, "TSContDataGet", "TestCase1", TC_PASS, "ok");
2543 
2544     *SDK_ContData_pstatus = REGRESSION_TEST_PASSED;
2545   } else {
2546     // If we get bad data, it's a failure
2547     SDK_RPRINT(SDK_ContData_test, "TSContDataSet", "TestCase1", TC_FAIL, "bad data");
2548     SDK_RPRINT(SDK_ContData_test, "TSContDataGet", "TestCase1", TC_FAIL, "bad data");
2549 
2550     *SDK_ContData_pstatus = REGRESSION_TEST_FAILED;
2551   }
2552 
2553   TSfree(my_data);
2554   TSContDestroy(contp);
2555   return 0;
2556 }
2557 
REGRESSION_TEST(SDK_API_TSContDataGet)2558 REGRESSION_TEST(SDK_API_TSContDataGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2559 {
2560   *pstatus = REGRESSION_TEST_INPROGRESS;
2561 
2562   // For asynchronous APIs, use static vars to store test and pstatus
2563   SDK_ContData_test    = test;
2564   SDK_ContData_pstatus = pstatus;
2565 
2566   TSCont contp = TSContCreate(cont_data_handler, TSMutexCreate());
2567 
2568   MyData *my_data = static_cast<MyData *>(TSmalloc(sizeof(MyData)));
2569   my_data->data1  = 1;
2570   my_data->data2  = 2;
2571 
2572   TSContDataSet(contp, (void *)my_data);
2573 
2574   TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
2575 }
2576 
2577 //////////////////////////////////////////////
2578 //       SDK_API_TSCont
2579 //
2580 // Unit Test for API: TSContMutexGet
2581 //////////////////////////////////////////////
2582 
REGRESSION_TEST(SDK_API_TSContMutexGet)2583 REGRESSION_TEST(SDK_API_TSContMutexGet)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2584 {
2585   bool test_passed = false;
2586   *pstatus         = REGRESSION_TEST_INPROGRESS;
2587 
2588   TSMutex mutexp_input;
2589   TSMutex mutexp_output;
2590   TSCont contp;
2591 
2592   mutexp_input = TSMutexCreate();
2593   contp        = TSContCreate(cont_handler, mutexp_input);
2594 
2595   mutexp_output = TSContMutexGet(contp);
2596 
2597   if (mutexp_input == mutexp_output) {
2598     SDK_RPRINT(test, "TSContMutexGet", "TestCase1", TC_PASS, "ok");
2599     test_passed = true;
2600   } else {
2601     SDK_RPRINT(test, "TSContMutexGet", "TestCase1", TC_FAIL, "Continuation's mutex corrupted");
2602   }
2603 
2604   // Status of the whole test
2605   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2606 
2607   TSContDestroy(contp);
2608 }
2609 
2610 //////////////////////////////////////////////
2611 //       SDK_API_TSCont
2612 //
2613 // Unit Test for API: TSContScheduleOnPool
2614 //////////////////////////////////////////////
2615 
2616 // this is needed for asynchronous APIs
2617 static RegressionTest *SDK_ContSchedule_test;
2618 static int *SDK_ContSchedule_pstatus;
2619 
2620 // this is specific for this test
2621 static int tc1_count = 0;
2622 static int tc2_count = 0;
2623 
2624 int
cont_schedule_handler(TSCont contp,TSEvent event,void *)2625 cont_schedule_handler(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
2626 {
2627   if (event == TS_EVENT_IMMEDIATE) {
2628     // Test Case 1
2629     SDK_RPRINT(SDK_ContSchedule_test, "TSContScheduleOnPool", "TestCase1", TC_PASS, "ok");
2630     tc1_count++;
2631   } else if (event == TS_EVENT_TIMEOUT) {
2632     // Test Case 2
2633     SDK_RPRINT(SDK_ContSchedule_test, "TSContScheduleOnPool", "TestCase2", TC_PASS, "ok");
2634     tc2_count++;
2635   } else {
2636     // If we receive a bad event, it's a failure
2637     SDK_RPRINT(SDK_ContSchedule_test, "TSContScheduleOnPool", "TestCase1|2", TC_FAIL, "received unexpected event number %d", event);
2638     *SDK_ContSchedule_pstatus = REGRESSION_TEST_FAILED;
2639     return 0;
2640   }
2641 
2642   // We expect to be called once for TC1 and once for TC2
2643   if ((tc1_count == 1) && (tc2_count == 1)) {
2644     *SDK_ContSchedule_pstatus = REGRESSION_TEST_PASSED;
2645   }
2646   // If TC1 or TC2 executed more than once, something is fishy..
2647   else if (tc1_count + tc2_count >= 2) {
2648     *SDK_ContSchedule_pstatus = REGRESSION_TEST_FAILED;
2649   }
2650 
2651   TSContDestroy(contp);
2652   return 0;
2653 }
2654 
2655 /* Mutex */
2656 
2657 /*
2658    Fix me: test for grabbing the mutex from two
2659    different threads.
2660    */
2661 
2662 //////////////////////////////////////////////
2663 //       SDK_API_TSMutex
2664 //
2665 // Unit Test for API: TSMutexCreate
2666 //                    TSMutexLock
2667 //                    TSMutexUnLock
2668 //////////////////////////////////////////////
2669 
REGRESSION_TEST(SDK_API_TSMutexCreate)2670 REGRESSION_TEST(SDK_API_TSMutexCreate)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2671 {
2672   bool test_passed = false;
2673   *pstatus         = REGRESSION_TEST_INPROGRESS;
2674 
2675   TSMutex mutexp = TSMutexCreate();
2676 
2677   TSMutexLock(mutexp);
2678 
2679   /* This is normal because all locking is from the same thread */
2680   TSReturnCode lock1 = TS_ERROR;
2681   TSReturnCode lock2 = TS_ERROR;
2682 
2683   lock1 = TSMutexLockTry(mutexp);
2684   lock2 = TSMutexLockTry(mutexp);
2685 
2686   if (TS_SUCCESS == lock1 && TS_SUCCESS == lock2) {
2687     SDK_RPRINT(test, "TSMutexCreate", "TestCase1", TC_PASS, "ok");
2688     SDK_RPRINT(test, "TSMutexLock", "TestCase1", TC_PASS, "ok");
2689     SDK_RPRINT(test, "TSMutexLockTry", "TestCase1", TC_PASS, "ok");
2690     test_passed = true;
2691   } else {
2692     SDK_RPRINT(test, "TSMutexCreate", "TestCase1", TC_FAIL, "mutex can't be grabbed twice from the same thread");
2693     SDK_RPRINT(test, "TSMutexLock", "TestCase1", TC_FAIL, "mutex can't be grabbed twice from the same thread");
2694     SDK_RPRINT(test, "TSMutexLockTry", "TestCase1", TC_FAIL, "mutex can't be grabbed twice from the same thread");
2695   }
2696 
2697   TSMutexUnlock(mutexp);
2698   SDK_RPRINT(test, "TSMutexUnLock", "TestCase1", TC_PASS, "ok");
2699 
2700   if (test_passed) {
2701     *pstatus = REGRESSION_TEST_PASSED;
2702   } else {
2703     *pstatus = REGRESSION_TEST_FAILED;
2704   }
2705 }
2706 
2707 /* IOBuffer */
2708 
2709 //////////////////////////////////////////////
2710 //       SDK_API_TSIOBuffer
2711 //
2712 // Unit Test for API: TSIOBufferCreate
2713 //                    TSIOBufferWaterMarkGet
2714 //                    TSIOBufferWaterMarkSet
2715 //////////////////////////////////////////////
2716 
REGRESSION_TEST(SDK_API_TSIOBufferCreate)2717 REGRESSION_TEST(SDK_API_TSIOBufferCreate)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2718 {
2719   bool test_passed = false;
2720   *pstatus         = REGRESSION_TEST_INPROGRESS;
2721 
2722   int64_t watermark = 1000;
2723 
2724   TSIOBuffer bufp = TSIOBufferCreate();
2725 
2726   TSIOBufferWaterMarkSet(bufp, watermark);
2727   watermark = TSIOBufferWaterMarkGet(bufp);
2728 
2729   if (watermark == 1000) {
2730     SDK_RPRINT(test, "TSIOBufferCreate", "TestCase1", TC_PASS, "ok");
2731     SDK_RPRINT(test, "TSIOBufferWaterMarkGet", "TestCase1", TC_PASS, "ok");
2732     SDK_RPRINT(test, "TSIOBufferWaterMarkSet", "TestCase1", TC_PASS, "ok");
2733     test_passed = true;
2734   } else {
2735     SDK_RPRINT(test, "TSIOBufferCreate", "TestCase1", TC_FAIL, "watermark failed");
2736     SDK_RPRINT(test, "TSIOBufferWaterMarkGet", "TestCase1", TC_FAIL, "watermark failed");
2737     SDK_RPRINT(test, "TSIOBufferWaterMarkSet", "TestCase1", TC_FAIL, "watermark failed");
2738   }
2739 
2740   TSIOBufferDestroy(bufp);
2741 
2742   // Status of the whole test
2743   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2744   return;
2745 }
2746 
2747 //////////////////////////////////////////////
2748 //       SDK_API_TSIOBuffer
2749 //
2750 // Unit Test for API: TSIOBufferSizedCreate
2751 //                    TSIOBufferProduce
2752 //                    TSIOBufferReaderAlloc
2753 //                    TSIOBufferReaderAvail
2754 //////////////////////////////////////////////
2755 
REGRESSION_TEST(SDK_API_TSIOBufferProduce)2756 REGRESSION_TEST(SDK_API_TSIOBufferProduce)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2757 {
2758   bool test_passed = false;
2759   *pstatus         = REGRESSION_TEST_INPROGRESS;
2760 
2761   TSIOBuffer bufp = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K); // size is 4096
2762 
2763   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2764 
2765   TSIOBufferProduce(bufp, 10);
2766 
2767   int64_t reader_avail = TSIOBufferReaderAvail(readerp);
2768   if (reader_avail == 10) {
2769     SDK_RPRINT(test, "TSIOBufferProduce", "TestCase1", TC_PASS, "ok");
2770     SDK_RPRINT(test, "TSIOBufferReaderAlloc", "TestCase1", TC_PASS, "ok");
2771     SDK_RPRINT(test, "TSIOBufferReaderAvail", "TestCase1", TC_PASS, "ok");
2772     test_passed = true;
2773   } else {
2774     SDK_RPRINT(test, "TSIOBufferProduce", "TestCase1", TC_FAIL, "failed");
2775     SDK_RPRINT(test, "TSIOBufferReaderAlloc", "TestCase1", TC_FAIL, "failed");
2776     SDK_RPRINT(test, "TSIOBufferReaderAvail", "TestCase1", TC_FAIL, "failed");
2777   }
2778 
2779   // Status of the whole test
2780   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2781   return;
2782 }
2783 
2784 //////////////////////////////////////////////
2785 //       SDK_API_TSIOBuffer
2786 //
2787 // Unit Test for API: TSIOBufferReaderConsume
2788 //////////////////////////////////////////////
2789 
REGRESSION_TEST(SDK_API_TSIOBufferReaderConsume)2790 REGRESSION_TEST(SDK_API_TSIOBufferReaderConsume)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2791 {
2792   bool test_passed = false;
2793   *pstatus         = REGRESSION_TEST_INPROGRESS;
2794 
2795   TSIOBuffer bufp = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2796 
2797   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2798 
2799   TSIOBufferProduce(bufp, 10);
2800   TSIOBufferReaderConsume(readerp, 10);
2801 
2802   int64_t reader_avail = TSIOBufferReaderAvail(readerp);
2803   if (reader_avail == 0) {
2804     SDK_RPRINT(test, "TSIOBufferReaderConsume", "TestCase1", TC_PASS, "ok");
2805     test_passed = true;
2806   } else {
2807     SDK_RPRINT(test, "TSIOBufferReaderConsume", "TestCase1", TC_FAIL, "failed");
2808   }
2809 
2810   // Status of the whole test
2811   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2812   return;
2813 }
2814 
2815 //////////////////////////////////////////////
2816 //       SDK_API_TSIOBuffer
2817 //
2818 // Unit Test for API: TSIOBufferReaderClone
2819 //////////////////////////////////////////////
2820 
REGRESSION_TEST(SDK_API_TSIOBufferReaderClone)2821 REGRESSION_TEST(SDK_API_TSIOBufferReaderClone)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2822 {
2823   bool test_passed = false;
2824   *pstatus         = REGRESSION_TEST_INPROGRESS;
2825 
2826   TSIOBuffer bufp          = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2827   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2828 
2829   TSIOBufferProduce(bufp, 10);
2830   TSIOBufferReaderConsume(readerp, 5);
2831 
2832   TSIOBufferReader readerp2 = TSIOBufferReaderClone(readerp);
2833 
2834   int64_t reader_avail = TSIOBufferReaderAvail(readerp2);
2835   if (reader_avail == 5) {
2836     SDK_RPRINT(test, "TSIOBufferReaderClone", "TestCase1", TC_PASS, "ok");
2837     test_passed = true;
2838   } else {
2839     SDK_RPRINT(test, "TSIOBufferReaderClone", "TestCase1", TC_FAIL, "failed");
2840   }
2841 
2842   // Status of the whole test
2843   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2844   return;
2845 }
2846 
2847 //////////////////////////////////////////////
2848 //       SDK_API_TSIOBuffer
2849 //
2850 // Unit Test for API: TSIOBufferStart
2851 //                    TSIOBufferReaderStart
2852 //////////////////////////////////////////////
2853 
REGRESSION_TEST(SDK_API_TSIOBufferStart)2854 REGRESSION_TEST(SDK_API_TSIOBufferStart)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2855 {
2856   bool test_passed = false;
2857   *pstatus         = REGRESSION_TEST_INPROGRESS;
2858 
2859   TSIOBuffer bufp = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2860 
2861   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2862 
2863   if (TSIOBufferStart(bufp) == TSIOBufferReaderStart(readerp)) {
2864     SDK_RPRINT(test, "TSIOBufferStart", "TestCase1", TC_PASS, "ok");
2865     SDK_RPRINT(test, "TSIOBufferReaderStart", "TestCase1", TC_PASS, "ok");
2866     test_passed = true;
2867   } else {
2868     SDK_RPRINT(test, "TSIOBufferStart", "TestCase1", TC_FAIL, "failed");
2869     SDK_RPRINT(test, "TSIOBufferReaderStart", "TestCase1", TC_FAIL, "failed");
2870   }
2871 
2872   // Status of the whole test
2873   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2874   return;
2875 }
2876 
2877 //////////////////////////////////////////////
2878 //       SDK_API_TSIOBuffer
2879 //
2880 // Unit Test for API: TSIOBufferCopy
2881 //                    TSIOBufferWrite
2882 //                    TSIOBufferReaderCopy
2883 //////////////////////////////////////////////
2884 
REGRESSION_TEST(SDK_API_TSIOBufferCopy)2885 REGRESSION_TEST(SDK_API_TSIOBufferCopy)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2886 {
2887   bool test_passed = false;
2888   *pstatus         = REGRESSION_TEST_INPROGRESS;
2889 
2890   char input_buf[] = "This is the test for TSIOBufferCopy, TSIOBufferWrite, TSIOBufferReaderCopy";
2891   char output_buf[1024];
2892   TSIOBuffer bufp  = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2893   TSIOBuffer bufp2 = TSIOBufferSizedCreate(TS_IOBUFFER_SIZE_INDEX_4K);
2894 
2895   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2896   TSIOBufferWrite(bufp, input_buf, (strlen(input_buf) + 1));
2897   TSIOBufferCopy(bufp2, readerp, (strlen(input_buf) + 1), 0);
2898   TSIOBufferReaderCopy(readerp, output_buf, (strlen(input_buf) + 1));
2899 
2900   if (strcmp(input_buf, output_buf) == 0) {
2901     SDK_RPRINT(test, "TSIOBufferWrite", "TestCase1", TC_PASS, "ok");
2902     SDK_RPRINT(test, "TSIOBufferCopy", "TestCase1", TC_PASS, "ok");
2903     SDK_RPRINT(test, "TSIOBufferReaderCopy", "TestCase1", TC_PASS, "ok");
2904     test_passed = true;
2905   } else {
2906     SDK_RPRINT(test, "TSIOBufferWrite", "TestCase1", TC_FAIL, "failed");
2907     SDK_RPRINT(test, "TSIOBufferCopy", "TestCase1", TC_FAIL, "failed");
2908     SDK_RPRINT(test, "TSIOBufferReaderCopy", "TestCase1", TC_FAIL, "failed");
2909   }
2910 
2911   // Status of the whole test
2912   *pstatus = ((test_passed == true) ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
2913   return;
2914 }
2915 
2916 //////////////////////////////////////////////
2917 //       SDK_API_TSIOBuffer
2918 //
2919 // Unit Test for API: TSIOBuffer
2920 //                    TSIOBufferWrite
2921 //                    TSIOBufferReaderCopy
2922 //////////////////////////////////////////////
2923 
REGRESSION_TEST(SDK_API_TSIOBufferBlockReadAvail)2924 REGRESSION_TEST(SDK_API_TSIOBufferBlockReadAvail)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2925 {
2926   bool test_passed_1 = false;
2927   bool test_passed_2 = false;
2928   *pstatus           = REGRESSION_TEST_INPROGRESS;
2929 
2930   int i           = 10000;
2931   TSIOBuffer bufp = TSIOBufferCreate();
2932   TSIOBufferWrite(bufp, reinterpret_cast<char *>(&i), sizeof(int));
2933   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2934 
2935   int64_t avail_write, avail_read;
2936 
2937   // TODO: This is probably not correct any more.
2938   TSIOBufferBlock blockp = TSIOBufferStart(bufp);
2939 
2940   if ((TSIOBufferBlockWriteStart(blockp, &avail_write) - TSIOBufferBlockReadStart(blockp, readerp, &avail_read)) == sizeof(int)) {
2941     SDK_RPRINT(test, "TSIOBufferBlockReadStart", "TestCase1", TC_PASS, "ok");
2942     SDK_RPRINT(test, "TSIOBufferBlockWriteStart", "TestCase1", TC_PASS, "ok");
2943     test_passed_1 = true;
2944   } else {
2945     SDK_RPRINT(test, "TSIOBufferBlockReadStart", "TestCase1", TC_FAIL, "failed");
2946     SDK_RPRINT(test, "TSIOBufferBlockWriteStart", "TestCase1", TC_FAIL, "failed");
2947   }
2948 
2949   if ((TSIOBufferBlockReadAvail(blockp, readerp) + TSIOBufferBlockWriteAvail(blockp)) == 32768) {
2950     SDK_RPRINT(test, "TSIOBufferBlockReadAvail", "TestCase1", TC_PASS, "ok");
2951     SDK_RPRINT(test, "TSIOBufferBlockWriteAvail", "TestCase1", TC_PASS, "ok");
2952     test_passed_2 = true;
2953   } else {
2954     SDK_RPRINT(test, "TSIOBufferBlockReadAvail", "TestCase1", TC_FAIL, "failed");
2955     SDK_RPRINT(test, "TSIOBufferBlockWriteAvail", "TestCase1", TC_FAIL, "failed");
2956   }
2957 
2958   if (test_passed_1 && test_passed_2) {
2959     *pstatus = REGRESSION_TEST_PASSED;
2960   } else {
2961     *pstatus = REGRESSION_TEST_FAILED;
2962   }
2963 
2964   return;
2965 }
2966 
2967 //////////////////////////////////////////////////
2968 //       SDK_API_TSIOBuffer
2969 //
2970 // Unit Test for API: TSIOBufferBlockNext
2971 //////////////////////////////////////////////////
2972 
REGRESSION_TEST(SDK_API_TSIOBufferBlockNext)2973 REGRESSION_TEST(SDK_API_TSIOBufferBlockNext)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
2974 {
2975   bool test_passed = false;
2976   *pstatus         = REGRESSION_TEST_INPROGRESS;
2977 
2978   int i           = 10000;
2979   TSIOBuffer bufp = TSIOBufferCreate();
2980   TSIOBufferWrite(bufp, reinterpret_cast<char *>(&i), sizeof(int));
2981 
2982   TSIOBufferReader readerp = TSIOBufferReaderAlloc(bufp);
2983   TSIOBufferBlock blockp   = TSIOBufferReaderStart(readerp);
2984 
2985   // TODO: This is probably not the best of regression tests right now ...
2986   // Note that this assumes block size is > sizeof(int) bytes.
2987   if (TSIOBufferBlockNext(blockp) == nullptr) {
2988     SDK_RPRINT(test, "TSIOBufferBlockNext", "TestCase1", TC_PASS, "ok");
2989     test_passed = true;
2990   } else {
2991     SDK_RPRINT(test, "TSIOBufferBlockNext", "TestCase1", TC_FAIL, "fail");
2992   }
2993 
2994   if (test_passed) {
2995     *pstatus = REGRESSION_TEST_PASSED;
2996   } else {
2997     *pstatus = REGRESSION_TEST_FAILED;
2998   }
2999 
3000   return;
3001 }
3002 
REGRESSION_TEST(SDK_API_TSContSchedule)3003 REGRESSION_TEST(SDK_API_TSContSchedule)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
3004 {
3005   *pstatus = REGRESSION_TEST_INPROGRESS;
3006 
3007   // For asynchronous APIs, use static vars to store test and pstatus
3008   SDK_ContSchedule_test    = test;
3009   SDK_ContSchedule_pstatus = pstatus;
3010 
3011   TSCont contp  = TSContCreate(cont_schedule_handler, TSMutexCreate());
3012   TSCont contp2 = TSContCreate(cont_schedule_handler, TSMutexCreate());
3013 
3014   // Test Case 1: schedule immediate
3015   TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
3016 
3017   // Test Case 2: schedule in 10ms
3018   TSContScheduleOnPool(contp2, 10, TS_THREAD_POOL_NET);
3019 }
3020 
3021 //////////////////////////////////////////////////////////////////////////////
3022 //     SDK_API_HttpHookAdd
3023 //
3024 // Unit Test for API: TSHttpHookAdd
3025 //                    TSHttpTxnReenable
3026 //                    TSHttpTxnClientIPGet
3027 //                    TSHttpTxnServerIPGet
3028 //                    TSHttpTxnIncomingAddrGet
3029 //                    TSHttpTxnClientAddrGet
3030 //                    TSHttpTxnClientReqGet
3031 //                    TSHttpTxnClientRespGet
3032 //                    TSHttpTxnServerReqGet
3033 //                    TSHttpTxnServerRespGet
3034 //                    TSHttpTxnNextHopAddrGet
3035 //                    TSHttpTxnClientProtocolStackGet
3036 //                    TSHttpTxnClientProtocolStackContains
3037 //////////////////////////////////////////////////////////////////////////////
3038 
3039 #define HTTP_HOOK_TEST_REQUEST_ID 1
3040 
3041 typedef struct {
3042   RegressionTest *regtest;
3043   int *pstatus;
3044   SocketServer *os;
3045   ClientTxn *browser;
3046   int hook_mask;
3047   int reenable_mask;
3048   bool test_client_ip_get;
3049   bool test_client_incoming_port_get;
3050   bool test_client_remote_port_get;
3051   bool test_client_req_get;
3052   bool test_client_resp_get;
3053   bool test_server_ip_get;
3054   bool test_server_req_get;
3055   bool test_server_resp_get;
3056   bool test_next_hop_ip_get;
3057   bool test_client_protocol_stack_get;
3058   bool test_client_protocol_stack_contains;
3059 
3060   unsigned int magic;
3061 } SocketTest;
3062 
3063 // This func is called by us from mytest_handler to test TSHttpTxnClientIPGet
3064 static int
checkHttpTxnClientIPGet(SocketTest * test,void * data)3065 checkHttpTxnClientIPGet(SocketTest *test, void *data)
3066 {
3067   sockaddr const *ptr;
3068   in_addr_t ip;
3069   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3070   in_addr_t actual_ip = htonl(INADDR_LOOPBACK); /* 127.0.0.1 is expected because the client is on the same machine */
3071 
3072   ptr = TSHttpTxnClientAddrGet(txnp);
3073   if (ptr == nullptr || INADDR_ANY == (ip = ats_ip4_addr_cast(ptr))) {
3074     test->test_client_ip_get = false;
3075     SDK_RPRINT(test->regtest, "TSHttpTxnClientIPGet", "TestCase1", TC_FAIL, "TSHttpTxnClientIPGet returns 0 %s",
3076                ptr ? "address" : "pointer");
3077     return TS_EVENT_CONTINUE;
3078   }
3079 
3080   if (ip == actual_ip) {
3081     test->test_client_ip_get = true;
3082     SDK_RPRINT(test->regtest, "TSHttpTxnClientIPGet", "TestCase1", TC_PASS, "ok [%0.8x]", ip);
3083   } else {
3084     test->test_client_ip_get = false;
3085     SDK_RPRINT(test->regtest, "TSHttpTxnClientIPGet", "TestCase1", TC_FAIL, "Value's Mismatch [expected %.8x got %.8x]", actual_ip,
3086                ip);
3087   }
3088   return TS_EVENT_CONTINUE;
3089 }
3090 
3091 // This func is called by us from mytest_handler to check for TSHttpTxnClientProtocolStackGet
3092 static int
checkHttpTxnClientProtocolStackGet(SocketTest * test,void * data)3093 checkHttpTxnClientProtocolStackGet(SocketTest *test, void *data)
3094 {
3095   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3096   const char *results[10];
3097   int count = 0;
3098   TSHttpTxnClientProtocolStackGet(txnp, 10, results, &count);
3099   // Should return results[0] = "http/1.0", results[1] = "tcp", results[2] = "ipv4"
3100   test->test_client_protocol_stack_get = true;
3101   if (count != 3) {
3102     test->test_client_protocol_stack_get = false;
3103     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "count should be 3 is %d", count);
3104   } else if (strcmp(results[0], "http/1.0") != 0) {
3105     test->test_client_protocol_stack_get = false;
3106     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "results[0] should be http/1.0 is %s",
3107                results[0]);
3108   } else if (strcmp(results[1], "tcp") != 0) {
3109     test->test_client_protocol_stack_get = false;
3110     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "results[1] should be tcp is %s",
3111                results[1]);
3112   } else if (strcmp(results[2], "ipv4") != 0) {
3113     test->test_client_protocol_stack_get = false;
3114     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_FAIL, "results[2] should be ipv4 is %s",
3115                results[2]);
3116   } else {
3117     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackGet", "TestCase1", TC_PASS, "ok stack_size=%d", count);
3118   }
3119   return TS_EVENT_CONTINUE;
3120 }
3121 
3122 // This func is called by us from mytest_handler to check for TSHttpTxnClientProtocolStackContains
3123 static int
checkHttpTxnClientProtocolStackContains(SocketTest * test,void * data)3124 checkHttpTxnClientProtocolStackContains(SocketTest *test, void *data)
3125 {
3126   TSHttpTxn txnp                            = static_cast<TSHttpTxn>(data);
3127   const char *ret_tag                       = TSHttpTxnClientProtocolStackContains(txnp, "tcp");
3128   test->test_client_protocol_stack_contains = true;
3129   if (ret_tag) {
3130     const char *normalized_tag = TSNormalizedProtocolTag("tcp");
3131     if (normalized_tag != ret_tag) {
3132       SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase1", TC_FAIL,
3133                  "contains tcp, but normalized tag is wrong");
3134     } else {
3135       SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase1", TC_PASS, "ok tcp");
3136     }
3137   } else {
3138     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase1", TC_FAIL, "missing tcp");
3139     test->test_client_protocol_stack_contains = false;
3140   }
3141   ret_tag = TSHttpTxnClientProtocolStackContains(txnp, "udp");
3142   if (!ret_tag) {
3143     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase2", TC_PASS, "ok no udp");
3144   } else {
3145     SDK_RPRINT(test->regtest, "TSHttpTxnClientProtocolStackContains", "TestCase2", TC_FAIL, "faulty udp report");
3146     test->test_client_protocol_stack_contains = false;
3147   }
3148   return TS_EVENT_CONTINUE;
3149 }
3150 
3151 // This func is called by us from mytest_handler to check for TSHttpTxnNextHopIPGet
3152 static int
checkHttpTxnNextHopIPGet(SocketTest * test,void * data)3153 checkHttpTxnNextHopIPGet(SocketTest *test, void *data)
3154 {
3155   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3156   in_addr_t actual_ip = htonl(INADDR_LOOPBACK); /* 127.0.0.1 is expected because the client is on the same machine */
3157   sockaddr const *ptr;
3158   in_addr_t nexthopip;
3159 
3160   ptr = TSHttpTxnNextHopAddrGet(txnp);
3161   if (ptr == nullptr || (nexthopip = ats_ip4_addr_cast(ptr)) == 0) {
3162     test->test_next_hop_ip_get = false;
3163     SDK_RPRINT(test->regtest, "TSHttpTxnNextHopIPGet", "TestCase1", TC_FAIL, "TSHttpTxnNextHopIPGet returns 0 %s",
3164                ptr ? "address" : "pointer");
3165     return TS_EVENT_CONTINUE;
3166   }
3167 
3168   if (nexthopip == actual_ip) {
3169     test->test_next_hop_ip_get = true;
3170     SDK_RPRINT(test->regtest, "TSHttpTxnNextHopIPGet", "TestCase1", TC_PASS, "ok");
3171   } else {
3172     test->test_next_hop_ip_get = false;
3173     SDK_RPRINT(test->regtest, "TSHttpTxnNextHopIPGet", "TestCase1", TC_FAIL, "Value's Mismatch [expected %0.8x got %0.8x]",
3174                actual_ip, nexthopip);
3175   }
3176 
3177   return TS_EVENT_CONTINUE;
3178 }
3179 
3180 // This func is called by us from mytest_handler to test TSHttpTxnServerIPGet
3181 static int
checkHttpTxnServerIPGet(SocketTest * test,void * data)3182 checkHttpTxnServerIPGet(SocketTest *test, void *data)
3183 {
3184   sockaddr const *ptr;
3185   in_addr_t ip;
3186   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3187   in_addr_t actual_ip = htonl(INADDR_LOOPBACK); /* 127.0.0.1 is expected because the client is on the same machine */
3188 
3189   ptr = TSHttpTxnServerAddrGet(txnp);
3190   if (nullptr == ptr || 0 == (ip = ats_ip4_addr_cast(ptr))) {
3191     test->test_server_ip_get = false;
3192     SDK_RPRINT(test->regtest, "TSHttpTxnServerIPGet", "TestCase1", TC_FAIL, "TSHttpTxnServerIPGet returns 0 %s",
3193                ptr ? "address" : "pointer");
3194     return TS_EVENT_CONTINUE;
3195   }
3196 
3197   if (ip == actual_ip) {
3198     test->test_server_ip_get = true;
3199     SDK_RPRINT(test->regtest, "TSHttpTxnServerIPGet", "TestCase1", TC_PASS, "ok");
3200   } else {
3201     test->test_server_ip_get = false;
3202     SDK_RPRINT(test->regtest, "TSHttpTxnServerIPGet", "TestCase1", TC_FAIL, "Value's Mismatch");
3203   }
3204 
3205   return TS_EVENT_CONTINUE;
3206 }
3207 
3208 // This func is called by us from mytest_handler to test TSHttpTxnIncomingAddrGet
3209 static int
checkHttpTxnIncomingAddrGet(SocketTest * test,void * data)3210 checkHttpTxnIncomingAddrGet(SocketTest *test, void *data)
3211 {
3212   uint16_t port;
3213   const HttpProxyPort *proxy_port = HttpProxyPort::findHttp(AF_INET);
3214   TSHttpTxn txnp                  = static_cast<TSHttpTxn>(data);
3215   sockaddr const *ptr             = TSHttpTxnIncomingAddrGet(txnp);
3216 
3217   if (nullptr == proxy_port) {
3218     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingPortGet", "TestCase1", TC_FAIL,
3219                "TSHttpTxnIncomingAddrGet failed to find configured HTTP port.");
3220     test->test_client_incoming_port_get = false;
3221     return TS_EVENT_CONTINUE;
3222   }
3223   if (nullptr == ptr) {
3224     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingPortGet", "TestCase1", TC_FAIL, "TSHttpTxnIncomingAddrGet returns 0 pointer");
3225     test->test_client_incoming_port_get = false;
3226     return TS_EVENT_CONTINUE;
3227   }
3228   port = ats_ip_port_host_order(ptr);
3229 
3230   TSDebug(UTDBG_TAG, "TS HTTP port = %x, Txn incoming client port %x", proxy_port->m_port, port);
3231 
3232   if (port == proxy_port->m_port) {
3233     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingAddrGet", "TestCase1", TC_PASS, "ok");
3234     test->test_client_incoming_port_get = true;
3235   } else {
3236     SDK_RPRINT(test->regtest, "TSHttpTxnIncomingAddrGet", "TestCase1", TC_FAIL,
3237                "Value's Mismatch. From Function: %d  Expected value: %d", port, proxy_port->m_port);
3238     test->test_client_incoming_port_get = false;
3239   }
3240   return TS_EVENT_CONTINUE;
3241 }
3242 
3243 // This func is called by us from mytest_handler to test TSHttpTxnClientAddrGet
3244 static int
checkHttpTxnClientAddrGet(SocketTest * test,void * data)3245 checkHttpTxnClientAddrGet(SocketTest *test, void *data)
3246 {
3247   uint16_t port;
3248   uint16_t browser_port;
3249   TSHttpTxn txnp      = static_cast<TSHttpTxn>(data);
3250   sockaddr const *ptr = TSHttpTxnClientAddrGet(txnp);
3251 
3252   browser_port = test->browser->local_port;
3253 
3254   if (nullptr == ptr) {
3255     SDK_RPRINT(test->regtest, "TSHttpTxnClientClientAddrGet", "TestCase2", TC_FAIL, "TSHttpTxnClientAddrGet returned 0 pointer.");
3256     test->test_client_remote_port_get = false;
3257     return TS_EVENT_CONTINUE;
3258   }
3259 
3260   port = ats_ip_port_host_order(ptr);
3261   TSDebug(UTDBG_TAG, "Browser port = %x, Txn remote port = %x", browser_port, port);
3262 
3263   if (port == browser_port) {
3264     SDK_RPRINT(test->regtest, "TSHttpTxnClientAddrGet", "TestCase1", TC_PASS, "ok");
3265     test->test_client_remote_port_get = true;
3266   } else {
3267     SDK_RPRINT(test->regtest, "TSHttpTxnClientAddrGet", "TestCase1", TC_FAIL,
3268                "Value's Mismatch. From Function: %d Expected Value: %d", port, browser_port);
3269     test->test_client_remote_port_get = false;
3270   }
3271   return TS_EVENT_CONTINUE;
3272 }
3273 
3274 // This func is called by us from mytest_handler to test TSHttpTxnClientReqGet
3275 static int
checkHttpTxnClientReqGet(SocketTest * test,void * data)3276 checkHttpTxnClientReqGet(SocketTest *test, void *data)
3277 {
3278   TSMBuffer bufp;
3279   TSMLoc mloc;
3280   TSHttpTxn txnp = static_cast<TSHttpTxn>(data);
3281 
3282   if (TSHttpTxnClientReqGet(txnp, &bufp, &mloc) != TS_SUCCESS) {
3283     test</