1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /*****************************************************************************
25  * Filename: APITestCliRemote.cc
26  * Purpose: An interactive cli to test remote mgmt API; UNIT TEST for mgmtAPI
27  * Created: lant
28  *
29  ***************************************************************************/
30 
31 /***************************************************************************
32  * Possible Commands:
33  ***************************************************************************
34  * Control Operations:
35  * -------------------
36  * state:   returns ON (proxy is on) or OFF (proxy is off)
37  * start:<tsArgs>  -   turns Proxy on, the tsArgs is optional;
38  *                     it can either be  "hostdb" or "all",
39  *                 eg. start, start:hostdb, start:all
40  * stop:    turns Proxy off
41  * restart: restarts Traffic Manager (Traffic Cop must be running)
42  *
43  * File operations:
44  * ---------------
45  * read_file:  reads hosting.config file
46  * proxy.config.xxx (a records.config variable): returns value of that record
47  * records: tests get/set/get a record of each different type
48  *          (int, float, counter, string)
49  * err_recs: stress test record get/set functions by purposely entering
50  *              invalid record names and/or values
51  * get_mlt: tests TSRecordGetMlt
52  * set_mlt: tests TSRecordSetMlt
53  *
54  * read_url: tests TSReadFromUrl works by retrieving two valid urls
55  * test_url: tests robustness of TSReadFromUrl using invalid urls
56  *
57  * Event Operations:
58  * ----------------
59  * active_events: lists the names of all currently active events
60  * MGMT_ALARM_xxx (event_name specified in CoreAPIShared.h or Alarms.h):
61  *                 resolves the specified event
62  * register: registers a generic callback (=eventCallbackFn) which
63  *           prints out the event name whenever an event is signalled
64  * unregister: unregisters the generic callback function eventCallbackFn
65  *
66  * Diags
67  * ----
68  * diags - uses STATUS, NOTE, FATAL, ERROR diags
69  *
70  * Statistics
71  * ----------
72  * set_stats - sets dummy values for selected group of NODE, PROCESS
73  *             records
74  * print_stats - prints the values for the same selected group of records
75  * reset_stats - resets all statistics to default values
76  */
77 
78 #include "tscore/ink_config.h"
79 #include "tscore/ink_defs.h"
80 #include "tscore/ink_memory.h"
81 #include <cstdlib>
82 #include <cstring>
83 #include <cstdio>
84 #include <strings.h>
85 #include "tscore/ink_string.h"
86 
87 #include "mgmtapi.h"
88 
89 // refer to test_records() function
90 #define TEST_STRING 1
91 #define TEST_FLOAT 1
92 #define TEST_INT 1
93 #define TEST_COUNTER 1
94 #define TEST_REC_SET 1
95 #define TEST_REC_GET 0
96 #define TEST_REC_GET_2 0
97 
98 #define SET_INT 0
99 
100 /***************************************************************************
101  * Printing Helper Functions
102  ***************************************************************************/
103 
104 /* ------------------------------------------------------------------------
105  * print_err
106  * ------------------------------------------------------------------------
107  * used to print the error description associated with the TSMgmtError err
108  */
109 void
print_err(const char * module,TSMgmtError err)110 print_err(const char *module, TSMgmtError err)
111 {
112   char *err_msg;
113 
114   err_msg = TSGetErrorMessage(err);
115   printf("(%s) ERROR: %s\n", module, err_msg);
116 
117   if (err_msg) {
118     TSfree(err_msg);
119   }
120 }
121 
122 /*-------------------------------------------------------------
123  * print_string_list
124  *-------------------------------------------------------------*/
125 void
print_string_list(TSStringList list)126 print_string_list(TSStringList list)
127 {
128   int i, count, buf_pos = 0;
129   char buf[1000];
130 
131   if (!list) {
132     return;
133   }
134   count = TSStringListLen(list);
135   for (i = 0; i < count; i++) {
136     char *str = TSStringListDequeue(list);
137     snprintf(buf + buf_pos, sizeof(buf) - buf_pos, "%s,", str);
138     buf_pos = strlen(buf);
139     TSStringListEnqueue(list, str);
140   }
141   printf("%s \n", buf);
142 }
143 
144 /*-------------------------------------------------------------
145  * print_int_list
146  *-------------------------------------------------------------*/
147 void
print_int_list(TSIntList list)148 print_int_list(TSIntList list)
149 {
150   int i, count, buf_pos = 0;
151   char buf[1000];
152 
153   count = TSIntListLen(list);
154   for (i = 0; i < count; i++) {
155     int *elem = TSIntListDequeue(list);
156     snprintf(buf + buf_pos, sizeof(buf) - buf_pos, "%d:", *elem);
157     buf_pos = strlen(buf);
158     TSIntListEnqueue(list, elem);
159   }
160   printf("Int List: %s \n", buf);
161 }
162 
163 /***************************************************************************
164  * Control Testing
165  ***************************************************************************/
166 void
print_proxy_state()167 print_proxy_state()
168 {
169   TSProxyStateT state = TSProxyStateGet();
170 
171   switch (state) {
172   case TS_PROXY_ON:
173     printf("Proxy State = ON\n");
174     break;
175   case TS_PROXY_OFF:
176     printf("Proxy State = OFF\n");
177     break;
178   default:
179     printf("ERROR: Proxy State Undefined!\n");
180     break;
181   }
182 }
183 
184 // starts Traffic Server (turns proxy on)
185 void
start_TS(char * tsArgs)186 start_TS(char *tsArgs)
187 {
188   TSMgmtError ret;
189   TSCacheClearT clear = TS_CACHE_CLEAR_NONE;
190   char *args;
191 
192   strtok(tsArgs, ":");
193   args = strtok(nullptr, ":");
194   if (args) {
195     if (strcmp(args, "all\n") == 0) {
196       clear = TS_CACHE_CLEAR_CACHE;
197     } else if (strcmp(args, "hostdb\n") == 0) {
198       clear = TS_CACHE_CLEAR_HOSTDB;
199     }
200   } else {
201     clear = TS_CACHE_CLEAR_NONE;
202   }
203 
204   printf("STARTING PROXY with cache: %d\n", clear);
205   if ((ret = TSProxyStateSet(TS_PROXY_ON, clear)) != TS_ERR_OKAY) {
206     printf("[TSProxyStateSet] turn on FAILED\n");
207   }
208   print_err("start_TS", ret);
209 }
210 
211 // stops Traffic Server (turns proxy off)
212 void
stop_TS()213 stop_TS()
214 {
215   TSMgmtError ret;
216 
217   printf("STOPPING PROXY\n");
218   if ((ret = TSProxyStateSet(TS_PROXY_OFF, TS_CACHE_CLEAR_NONE)) != TS_ERR_OKAY) {
219     printf("[TSProxyStateSet] turn off FAILED\n");
220   }
221   print_err("stop_TS", ret);
222 }
223 
224 // restarts Traffic Manager (Traffic Cop must be running)
225 void
restart()226 restart()
227 {
228   TSMgmtError ret;
229 
230   printf("RESTART\n");
231   if ((ret = TSRestart(true)) != TS_ERR_OKAY) {
232     printf("[TSRestart] FAILED\n");
233   }
234 
235   print_err("restart", ret);
236 }
237 
238 // rereads all the configuration files
239 void
reconfigure()240 reconfigure()
241 {
242   TSMgmtError ret;
243 
244   printf("RECONFIGURE\n");
245   if ((ret = TSReconfigure()) != TS_ERR_OKAY) {
246     printf("[TSReconfigure] FAILED\n");
247   }
248 
249   print_err("reconfigure", ret);
250 }
251 
252 /* ------------------------------------------------------------------------
253  * test_action_need
254  * ------------------------------------------------------------------------
255  * tests if correct action need is returned when requested record is set
256  */
257 void
test_action_need()258 test_action_need()
259 {
260   TSActionNeedT action;
261 
262   // RU_NULL record
263   TSRecordSetString("proxy.config.proxy_name", "proxy_dorky", &action);
264   printf("[TSRecordSetString] proxy.config.proxy_name \n\tAction Should: [%d]\n\tAction is    : [%d]\n", TS_ACTION_UNDEFINED,
265          action);
266 }
267 
268 /* Bouncer the traffic_server process(es) */
269 void
bounce()270 bounce()
271 {
272   TSMgmtError ret;
273 
274   printf("BOUNCER\n");
275   if ((ret = TSBounce(true)) != TS_ERR_OKAY) {
276     printf("[TSBounce] FAILED\n");
277   }
278 
279   print_err("bounce", ret);
280 }
281 
282 /***************************************************************************
283  * Record Testing
284  ***************************************************************************/
285 
286 /* ------------------------------------------------------------------------
287  * test_error_records
288  * ------------------------------------------------------------------------
289  * stress test error handling by purposely being dumb; send requests to
290  * get invalid record names
291  */
292 void
test_error_records()293 test_error_records()
294 {
295   TSInt port1, new_port = 8080;
296   TSActionNeedT action;
297   TSMgmtError ret;
298   TSCounter ctr1;
299 
300   printf("\n");
301   // test get integer
302   fprintf(stderr, "Test invalid record names\n");
303 
304   ret = TSRecordGetInt("proy.config.cop.core_signal", &port1);
305   if (ret != TS_ERR_OKAY) {
306     print_err("TSRecordGetInt", ret);
307   } else {
308     printf("[TSRecordGetInt] proxy.config.cop.core_signal=%" PRId64 " \n", port1);
309   }
310 
311   // test set integer
312   ret = TSRecordSetInt("proy.config.cop.core_signal", new_port, &action);
313   print_err("TSRecordSetInt", ret);
314 
315   printf("\n");
316   if (TSRecordGetCounter("proxy.press.socks.connections_successful", &ctr1) != TS_ERR_OKAY) {
317     printf("TSRecordGetCounter FAILED!\n");
318   } else {
319     printf("[TSRecordGetCounter]proxy.process.socks.connections_successful=%" PRId64 " \n", ctr1);
320   }
321 }
322 
323 /* ------------------------------------------------------------------------
324  * test_records
325  * ------------------------------------------------------------------------
326  * stress test record functionality by getting and setting different
327  * records types; use the #defines defined above to determine which
328  * type of tests you'd like turned on/off
329  */
330 void
test_records()331 test_records()
332 {
333   TSActionNeedT action;
334   char *rec_value;
335   char new_str[] = "new_record_value";
336   TSInt port1, port2, new_port  = 52432;
337   TSCounter ctr1, ctr2, new_ctr = 6666;
338   TSMgmtError err;
339 
340   /********************* START TEST SECTION *****************/
341   printf("\n\n");
342 
343 #if SET_INT
344   // test set integer
345   if (TSRecordSetInt("proxy.config.cop.core_signal", new_port, &action) != TS_ERR_OKAY)
346     printf("TSRecordSetInt FAILED!\n");
347   else
348     printf("[TSRecordSetInt] proxy.config.cop.core_signal=%" PRId64 " \n", new_port);
349 #endif
350 
351 #if TEST_REC_GET
352   TSRecordEle *rec_ele;
353   // retrieve a string value record using generic RecordGet
354   rec_ele = TSRecordEleCreate();
355   if (TSRecordGet("proxy.config.http.cache.vary_default_other", rec_ele) != TS_ERR_OKAY)
356     printf("TSRecordGet FAILED!\n");
357   else
358     printf("[TSRecordGet] proxy.config.http.cache.vary_default_other=%s\n", rec_ele->string_val);
359 
360   TSRecordEleDestroy(rec_ele);
361   printf("\n\n");
362 #endif
363 
364 #if TEST_REC_GET_2
365   // retrieve a string value record using generic RecordGet
366   rec_ele = TSRecordEleCreate();
367   if (TSRecordGet("proxy.config.proxy_name", rec_ele) != TS_ERR_OKAY)
368     printf("TSRecordGet FAILED!\n");
369   else
370     printf("[TSRecordGet] proxy.config.proxy_name=%s\n", rec_ele->string_val);
371 
372   TSRecordEleDestroy(rec_ele);
373   printf("\n\n");
374 #endif
375 
376 #if TEST_STRING
377   // retrieve an string value record using GetString
378   err = TSRecordGetString("proxy.config.proxy_name", &rec_value);
379   if (err != TS_ERR_OKAY) {
380     print_err("TSRecordGetString", err);
381   } else {
382     printf("[TSRecordGetString] proxy.config.proxy_name=%s\n", rec_value);
383   }
384   TSfree(rec_value);
385   rec_value = nullptr;
386 
387   // test RecordSet
388   err = TSRecordSetString("proxy.config.proxy_name", (TSString)new_str, &action);
389   if (err != TS_ERR_OKAY) {
390     print_err("TSRecordSetString", err);
391   } else {
392     printf("[TSRecordSetString] proxy.config.proxy_name=%s\n", new_str);
393   }
394 
395   // get
396   err = TSRecordGetString("proxy.config.proxy_name", &rec_value);
397   if (err != TS_ERR_OKAY) {
398     print_err("TSRecordGetString", err);
399   } else {
400     printf("[TSRecordGetString] proxy.config.proxy_name=%s\n", rec_value);
401   }
402   printf("\n");
403   TSfree(rec_value);
404 #endif
405 
406 #if TEST_INT
407   printf("\n");
408   // test get integer
409   if (TSRecordGetInt("proxy.config.cop.core_signal", &port1) != TS_ERR_OKAY) {
410     printf("TSRecordGetInt FAILED!\n");
411   } else {
412     printf("[TSRecordGetInt] proxy.config.cop.core_signal=%" PRId64 " \n", port1);
413   }
414 
415   // test set integer
416   if (TSRecordSetInt("proxy.config.cop.core_signal", new_port, &action) != TS_ERR_OKAY) {
417     printf("TSRecordSetInt FAILED!\n");
418   } else {
419     printf("[TSRecordSetInt] proxy.config.cop.core_signal=%" PRId64 " \n", new_port);
420   }
421 
422   if (TSRecordGetInt("proxy.config.cop.core_signal", &port2) != TS_ERR_OKAY) {
423     printf("TSRecordGetInt FAILED!\n");
424   } else {
425     printf("[TSRecordGetInt] proxy.config.cop.core_signal=%" PRId64 " \n", port2);
426   }
427   printf("\n");
428 #endif
429 
430 #if TEST_COUNTER
431   printf("\n");
432 
433   if (TSRecordGetCounter("proxy.process.socks.connections_successful", &ctr1) != TS_ERR_OKAY) {
434     printf("TSRecordGetCounter FAILED!\n");
435   } else {
436     printf("[TSRecordGetCounter]proxy.process.socks.connections_successful=%" PRId64 " \n", ctr1);
437   }
438 
439   if (TSRecordSetCounter("proxy.process.socks.connections_successful", new_ctr, &action) != TS_ERR_OKAY) {
440     printf("TSRecordSetCounter FAILED!\n");
441   } else {
442     printf("[TSRecordSetCounter] proxy.process.socks.connections_successful=%" PRId64 " \n", new_ctr);
443   }
444 
445   if (TSRecordGetCounter("proxy.process.socks.connections_successful", &ctr2) != TS_ERR_OKAY) {
446     printf("TSRecordGetCounter FAILED!\n");
447   } else {
448     printf("[TSRecordGetCounter]proxy.process.socks.connections_successful=%" PRId64 " \n", ctr2);
449   }
450   printf("\n");
451 #endif
452 }
453 
454 // retrieves the value of the "proxy.config.xxx" record requested at input
455 void
test_rec_get(char * rec_name)456 test_rec_get(char *rec_name)
457 {
458   TSRecordEle *rec_ele;
459   TSMgmtError ret;
460   char *name;
461 
462   name = ats_strdup(rec_name);
463   printf("[test_rec_get] Get Record: %s\n", name);
464 
465   // retrieve a string value record using generic RecordGet
466   rec_ele = TSRecordEleCreate();
467   if ((ret = TSRecordGet(name, rec_ele)) != TS_ERR_OKAY) {
468     printf("TSRecordGet FAILED!\n");
469   } else {
470     switch (rec_ele->rec_type) {
471     case TS_REC_INT:
472       printf("[TSRecordGet] %s=%" PRId64 "\n", name, rec_ele->valueT.int_val);
473       break;
474     case TS_REC_COUNTER:
475       printf("[TSRecordGet] %s=%" PRId64 "\n", name, rec_ele->valueT.counter_val);
476       break;
477     case TS_REC_FLOAT:
478       printf("[TSRecordGet] %s=%f\n", name, rec_ele->valueT.float_val);
479       break;
480     case TS_REC_STRING:
481       printf("[TSRecordGet] %s=%s\n", name, rec_ele->valueT.string_val);
482       break;
483     default:
484       // Handled here:
485       // TS_REC_UNDEFINED
486       break;
487     }
488   }
489 
490   print_err("TSRecordGet", ret);
491 
492   TSRecordEleDestroy(rec_ele);
493   TSfree(name);
494 }
495 
496 /* ------------------------------------------------------------------------
497  * test_record_get_mlt
498  * ------------------------------------------------------------------------
499  * Creates a list of record names to retrieve, and then batch request to
500  * get list of records
501  */
502 void
test_record_get_mlt()503 test_record_get_mlt()
504 {
505   TSStringList name_list;
506   TSList rec_list;
507   int i, num;
508   char *v1, *v2, *v3, *v6, *v7;
509   TSMgmtError ret;
510 
511   name_list = TSStringListCreate();
512   rec_list  = TSListCreate();
513 
514   const size_t v1_size = (sizeof(char) * (strlen("proxy.config.proxy_name") + 1));
515   v1                   = static_cast<char *>(TSmalloc(v1_size));
516   ink_strlcpy(v1, "proxy.config.proxy_name", v1_size);
517   const size_t v2_size = (sizeof(char) * (strlen("proxy.config.bin_path") + 1));
518   v2                   = static_cast<char *>(TSmalloc(v2_size));
519   ink_strlcpy(v2, "proxy.config.bin_path", v2_size);
520   const size_t v3_size = (sizeof(char) * (strlen("proxy.config.manager_binary") + 1));
521   v3                   = static_cast<char *>(TSmalloc(v3_size));
522   ink_strlcpy(v3, "proxy.config.manager_binary", v3_size);
523   const size_t v6_size = (sizeof(char) * (strlen("proxy.config.env_prep") + 1));
524   v6                   = static_cast<char *>(TSmalloc(v6_size));
525   ink_strlcpy(v6, "proxy.config.env_prep", v6_size);
526   const size_t v7_size = (sizeof(char) * (strlen("proxy.config.cop.core_signal") + 1));
527   v7                   = static_cast<char *>(TSmalloc(v7_size));
528   ink_strlcpy(v7, "proxy.config.cop.core_signal", v7_size);
529 
530   // add the names to the get_list
531   TSStringListEnqueue(name_list, v1);
532   TSStringListEnqueue(name_list, v2);
533   TSStringListEnqueue(name_list, v3);
534   TSStringListEnqueue(name_list, v6);
535   TSStringListEnqueue(name_list, v7);
536 
537   num = TSStringListLen(name_list);
538   printf("Num Records to Get: %d\n", num);
539   ret = TSRecordGetMlt(name_list, rec_list);
540   // free the string list
541   TSStringListDestroy(name_list);
542   if (ret != TS_ERR_OKAY) {
543     print_err("TSStringListDestroy", ret);
544   }
545 
546   for (i = 0; i < num; i++) {
547     TSRecordEle *rec_ele = static_cast<TSRecordEle *>(TSListDequeue(rec_list));
548     if (!rec_ele) {
549       printf("ERROR\n");
550       break;
551     }
552     printf("Record: %s = ", rec_ele->rec_name);
553     switch (rec_ele->rec_type) {
554     case TS_REC_INT:
555       printf("%" PRId64 "\n", rec_ele->valueT.int_val);
556       break;
557     case TS_REC_COUNTER:
558       printf("%" PRId64 "\n", rec_ele->valueT.counter_val);
559       break;
560     case TS_REC_FLOAT:
561       printf("%f\n", rec_ele->valueT.float_val);
562       break;
563     case TS_REC_STRING:
564       printf("%s\n", rec_ele->valueT.string_val);
565       break;
566     default:
567       // Handled here:
568       // TS_REC_UNDEFINED
569       break;
570     }
571     TSRecordEleDestroy(rec_ele);
572   }
573 
574   TSListDestroy(rec_list); // must dequeue and free each string individually
575 
576   return;
577 }
578 
579 /* ------------------------------------------------------------------------
580  * test_record_set_mlt
581  * ------------------------------------------------------------------------
582  * Creates a list of TSRecordEle's, and then batch request to set records
583  * Also checks to make sure correct action_need type is set.
584  */
585 void
test_record_set_mlt()586 test_record_set_mlt()
587 {
588   TSList list;
589   TSRecordEle *ele1, *ele2;
590   TSActionNeedT action = TS_ACTION_UNDEFINED;
591   TSMgmtError err;
592 
593   list = TSListCreate();
594 
595   ele1                    = TSRecordEleCreate(); // TS_TYPE_UNDEFINED action
596   ele1->rec_name          = TSstrdup("proxy.config.cli_binary");
597   ele1->rec_type          = TS_REC_STRING;
598   ele1->valueT.string_val = TSstrdup(ele1->rec_name);
599 
600   ele2                 = TSRecordEleCreate(); // undefined action
601   ele2->rec_name       = TSstrdup("proxy.config.cop.core_signal");
602   ele2->rec_type       = TS_REC_INT;
603   ele2->valueT.int_val = -4;
604 
605   TSListEnqueue(list, ele1);
606   TSListEnqueue(list, ele2);
607 
608   err = TSRecordSetMlt(list, &action);
609   print_err("TSRecordSetMlt", err);
610   fprintf(stderr, "[TSRecordSetMlt] Action Required: %d\n", action);
611 
612   // cleanup: need to iterate through list and delete each ele
613   int count = TSListLen(list);
614   for (int i = 0; i < count; i++) {
615     TSRecordEle *ele = static_cast<TSRecordEle *>(TSListDequeue(list));
616     TSRecordEleDestroy(ele);
617   }
618   TSListDestroy(list);
619 }
620 
621 /***************************************************************************
622  * File I/O Testing
623  ***************************************************************************/
624 
625 // if valid==true, then use a valid url to read
626 void
test_read_url(bool valid)627 test_read_url(bool valid)
628 {
629   char *header = nullptr;
630   int headerSize;
631   char *body = nullptr;
632   int bodySize;
633   TSMgmtError err;
634 
635   if (!valid) {
636     // first try
637 
638     err = TSReadFromUrlEx("hsdfasdf.com:80/index.html", &header, &headerSize, &body, &bodySize, 50000);
639     if (err != TS_ERR_OKAY) {
640       print_err("TSReadFromUrlEx", err);
641     } else {
642       printf("--------------------------------------------------------------\n");
643       //  printf("The header...\n%s\n%d\n", *header, *headerSize);
644       printf("--------------------------------------------------------------\n");
645       printf("The body...\n%s\n%d\n", body, bodySize);
646     }
647     if (body) {
648       TSfree(body);
649     }
650     if (header) {
651       TSfree(header);
652     }
653 
654     err = TSReadFromUrlEx("http://sadfasdfi.com:80/", &header, &headerSize, &body, &bodySize, 50000);
655     if (err != TS_ERR_OKAY) {
656       print_err("TSReadFromUrlEx", err);
657     } else {
658       printf("---------------------------------------------------------------\n");
659       printf("The header...\n%s\n%d\n", header, headerSize);
660       printf("-------------------------------------------------------------\n");
661       printf("The body...\n%s\n%d\n", body, bodySize);
662     }
663     if (header) {
664       TSfree(header);
665     }
666     if (body) {
667       TSfree(body);
668     }
669 
670   } else { // use valid urls
671     err = TSReadFromUrlEx("lakota.example.com:80/", &header, &headerSize, &body, &bodySize, 50000);
672 
673     if (err != TS_ERR_OKAY) {
674       print_err("TSReadFromUrlEx", err);
675     } else {
676       printf("---------------------------------------------------------------\n");
677       printf("The header...\n%s\n%d\n", header, headerSize);
678       printf("-------------------------------------------------------------\n");
679       printf("The body...\n%s\n%d\n", body, bodySize);
680     }
681     if (header) {
682       TSfree(header);
683     }
684     if (body) {
685       TSfree(body);
686     }
687 
688     // read second url
689     err = TSReadFromUrlEx("http://www.apache.org:80/index.html", &header, &headerSize, &body, &bodySize, 50000);
690     if (err != TS_ERR_OKAY) {
691       print_err("TSReadFromUrlEx", err);
692     } else {
693       printf("---------------------------------------------------------------\n");
694       printf("The header...\n%s\n%d\n", header, headerSize);
695       printf("-------------------------------------------------------------\n");
696       printf("The body...\n%s\n%d\n", body, bodySize);
697     }
698     if (header) {
699       TSfree(header);
700     }
701     if (body) {
702       TSfree(body);
703     }
704   }
705 }
706 
707 /***************************************************************************
708  * Events Testing
709  ***************************************************************************/
710 /* ------------------------------------------------------------------------
711  * print_active_events
712  * ------------------------------------------------------------------------
713  * retrieves a list of all active events and prints out each event name,
714  * one event per line
715  */
716 void
print_active_events()717 print_active_events()
718 {
719   TSList events;
720   TSMgmtError ret;
721   int count, i;
722   char *name;
723 
724   printf("[print_active_events]\n");
725 
726   events = TSListCreate();
727   ret    = TSActiveEventGetMlt(events);
728   if (ret != TS_ERR_OKAY) {
729     print_err("TSActiveEventGetMlt", ret);
730     goto END;
731   } else { // successful get
732     count = TSListLen(events);
733     for (i = 0; i < count; i++) {
734       name = static_cast<char *>(TSListDequeue(events));
735       printf("\t%s\n", name);
736       TSfree(name);
737     }
738   }
739 
740 END:
741   TSListDestroy(events);
742   return;
743 }
744 
745 /* ------------------------------------------------------------------------
746  * check_active
747  * ------------------------------------------------------------------------
748  * returns true if the event named event_name is currently active (unresolved)
749  * returns false otherwise
750  */
751 bool
check_active(char * event_name)752 check_active(char *event_name)
753 {
754   bool active;
755   TSMgmtError ret;
756 
757   ret = TSEventIsActive(event_name, &active);
758   print_err("TSEventIsActive", ret);
759 
760   if (active) {
761     printf("%s is ACTIVE\n", event_name);
762   } else {
763     printf("%s is NOT-ACTIVE\n", event_name);
764   }
765 
766   return active;
767 }
768 
769 /* ------------------------------------------------------------------------
770  * try_resolve
771  * ------------------------------------------------------------------------
772  * checks if the event_name is still unresolved; if it is, it then
773  * resolves it, and checks the status of the event again to make sure
774  * the event was actually resolved
775  *
776  * NOTE: all the special string manipulation is needed because the CLI
777  * appends extra newline character to end of the user input; normally
778  * do not have to do all this special string manipulation
779  */
780 void
try_resolve(char * event_name)781 try_resolve(char *event_name)
782 {
783   TSMgmtError ret;
784   char *name;
785 
786   name = TSstrdup(event_name);
787   printf("[try_resolve] Resolving event: %s\n", name);
788 
789   if (check_active(name)) { // resolve events
790     ret = TSEventResolve(name);
791     print_err("TSEventResolve", ret);
792     check_active(name); // should be non-active now
793   }
794 
795   TSfree(name);
796 }
797 
798 /* ------------------------------------------------------------------------
799  * eventCallbackFn
800  * ------------------------------------------------------------------------
801  * the callback function; when called, it just prints out the name
802  * of the event that was signalled
803  */
804 void
eventCallbackFn(char * name,char * msg,int,void *)805 eventCallbackFn(char *name, char *msg, int /* pri ATS_UNUSED */, void * /* data ATS_UNUSED */)
806 {
807   printf("[eventCallbackFn] EVENT: %s, %s\n", name, msg);
808   return;
809 }
810 
811 /* ------------------------------------------------------------------------
812  * register_event_callback
813  * ------------------------------------------------------------------------
814  * registers the eventCallbackFn above for all events; this just means
815  * that for any event that's signalled, the callback fn will also be called
816  */
817 void
register_event_callback()818 register_event_callback()
819 {
820   TSMgmtError err;
821 
822   printf("\n[register_event_callback] \n");
823   err = TSEventSignalCbRegister(nullptr, eventCallbackFn, nullptr);
824   print_err("TSEventSignalCbRegister", err);
825 }
826 
827 /* ------------------------------------------------------------------------
828  * unregister_event_callback
829  * ------------------------------------------------------------------------
830  * unregisters the eventCallbackFn above for all events; this just means
831  * that it will remove this eventCallbackFn entirely so that for any
832  * event called, the eventCallbackFn will NOT be called
833  */
834 void
unregister_event_callback()835 unregister_event_callback()
836 {
837   TSMgmtError err;
838 
839   printf("\n[unregister_event_callback]\n");
840   err = TSEventSignalCbUnregister(nullptr, eventCallbackFn);
841   print_err("TSEventSignalCbUnregister", err);
842 }
843 
844 /***************************************************************************
845  * Statistics
846  ***************************************************************************/
847 
848 // generate dummy values for statistics
849 void
set_stats()850 set_stats()
851 {
852   TSActionNeedT action;
853 
854   fprintf(stderr, "[set_stats] Set Dummy Stat Values\n");
855 
856   TSRecordSetInt("proxy.process.http.user_agent_response_document_total_size", 100, &action);
857   TSRecordSetInt("proxy.process.http.user_agent_response_header_total_size", 100, &action);
858   TSRecordSetInt("proxy.process.http.current_client_connections", 100, &action);
859   TSRecordSetInt("proxy.process.http.current_client_transactions", 100, &action);
860   TSRecordSetInt("proxy.process.http.origin_server_response_document_total_size", 100, &action);
861   TSRecordSetInt("proxy.process.http.origin_server_response_header_total_size", 100, &action);
862   TSRecordSetInt("proxy.process.http.current_server_connections", 100, &action);
863   TSRecordSetInt("proxy.process.http.current_server_transactions", 100, &action);
864 
865   TSRecordSetInt("proxy.node.proxy_running", 110, &action);
866   TSRecordSetInt("proxy.node.proxy_running", 110, &action);
867 }
868 
869 void
print_stats()870 print_stats()
871 {
872   TSInt i1, i2, i3, i4, i5, i6, i7, i8;
873 
874   fprintf(stderr, "[print_stats]\n");
875 
876   TSRecordGetInt("proxy.process.http.user_agent_response_document_total_size", &i1);
877   TSRecordGetInt("proxy.process.http.user_agent_response_header_total_size", &i2);
878   TSRecordGetInt("proxy.process.http.current_client_connections", &i3);
879   TSRecordGetInt("proxy.process.http.current_client_transactions", &i4);
880   TSRecordGetInt("proxy.process.http.origin_server_response_document_total_size", &i5);
881   TSRecordGetInt("proxy.process.http.origin_server_response_header_total_size", &i6);
882   TSRecordGetInt("proxy.process.http.current_server_connections", &i7);
883   TSRecordGetInt("proxy.process.http.current_server_transactions", &i8);
884 
885   fprintf(stderr, "%" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n", i1,
886           i2, i3, i4, i5, i6, i7, i8);
887 
888   TSRecordGetInt("proxy.node.proxy_running", &i4);
889   TSRecordGetInt("proxy.node.proxy_running", &i6);
890 
891   fprintf(stderr, "%" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n", i1, i7, i2, i3, i4,
892           i5, i6);
893 
894   fprintf(stderr, "PROCESS stats: \n");
895   fprintf(stderr, "%" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n", i1, i2, i3, i4);
896 }
897 
898 void
reset_stats()899 reset_stats()
900 {
901   TSMgmtError err = TSStatsReset(nullptr);
902   print_err("TSStatsReset", err);
903   return;
904 }
905 
906 void
sync_test()907 sync_test()
908 {
909   TSActionNeedT action;
910 
911   TSRecordSetString("proxy.config.proxy_name", "dorkface", &action);
912   printf("[TSRecordSetString] proxy.config.proxy_name \n\tAction Should: [%d]\n\tAction is    : [%d]\n", TS_ACTION_UNDEFINED,
913          action);
914 
915   TSMgmtError ret;
916   if ((ret = TSProxyStateSet(TS_PROXY_OFF, TS_CACHE_CLEAR_NONE)) != TS_ERR_OKAY) {
917     printf("[TSProxyStateSet] turn off FAILED\n");
918   }
919   print_err("stop_TS", ret);
920 }
921 
922 /* ########################################################################*/
923 /* ------------------------------------------------------------------------
924  * runInteractive
925  * ------------------------------------------------------------------------
926  * the loop that processes the commands inputted by user
927  */
928 static void
runInteractive()929 runInteractive()
930 {
931   char buf[512]; // holds request from interactive prompt
932 
933   // process input from command line
934   while (true) {
935     // Display a prompt
936     printf("api_cli-> ");
937 
938     // get input from command line
939     ATS_UNUSED_RETURN(fgets(buf, 512, stdin));
940 
941     // check status of 'stdin' after reading
942     if (feof(stdin) != 0) {
943       printf("EXIT api_cli_remote\n");
944       return;
945     } else if (ferror(stdin) != 0) {
946       printf("EXIT api_cli_remote\n");
947       return;
948     }
949     // continue on newline
950     if (strcmp(buf, "\n") == 0) {
951       continue;
952     }
953     // exiting/quitting?
954     if (strcasecmp("quit\n", buf) == 0 || strcasecmp("exit\n", buf) == 0) {
955       // Don't wait for response LM
956       // exit(0);
957       return;
958     }
959     // check what operation user typed in
960     if (strstr(buf, "state")) {
961       print_proxy_state();
962     } else if (strncmp(buf, "start", 5) == 0) {
963       start_TS(buf);
964     } else if (strstr(buf, "stop")) {
965       stop_TS();
966     } else if (strstr(buf, "restart")) {
967       restart();
968     } else if (strstr(buf, "reconfig")) {
969       reconfigure();
970     } else if (strstr(buf, "records")) {
971       test_records();
972     } else if (strstr(buf, "err_recs")) {
973       test_error_records();
974     } else if (strstr(buf, "get_mlt")) {
975       test_record_get_mlt();
976     } else if (strstr(buf, "set_mlt")) {
977       test_record_set_mlt();
978     } else if (strstr(buf, "proxy.")) {
979       test_rec_get(buf);
980     } else if (strstr(buf, "active_events")) {
981       print_active_events();
982     } else if (strstr(buf, "MGMT_ALARM_")) {
983       try_resolve(buf);
984     } else if (strncmp(buf, "register", 8) == 0) {
985       register_event_callback();
986     } else if (strstr(buf, "unregister")) {
987       unregister_event_callback();
988     } else if (strstr(buf, "read_url")) {
989       test_read_url(true);
990     } else if (strstr(buf, "test_url")) {
991       test_read_url(false);
992     } else if (strstr(buf, "reset_stats")) {
993       reset_stats();
994     } else if (strstr(buf, "set_stats")) {
995       set_stats();
996     } else if (strstr(buf, "print_stats")) {
997       print_stats();
998     } else {
999       sync_test();
1000     }
1001 
1002   } // end while(1)
1003 
1004 } // end runInteractive
1005 
1006 /* ------------------------------------------------------------------------
1007  * main
1008  * ------------------------------------------------------------------------
1009  * Main entry point which connects the client to the API, does any
1010  * clean up on exit, and gets the interactive command-line running
1011  */
1012 int
main(int,char **)1013 main(int /* argc ATS_UNUSED */, char ** /* argv ATS_UNUSED */)
1014 {
1015   TSMgmtError ret;
1016 
1017   if ((ret = TSInit(nullptr, TS_MGMT_OPT_DEFAULTS)) == TS_ERR_OKAY) {
1018     runInteractive();
1019     TSTerminate();
1020     printf("END REMOTE API TEST\n");
1021   } else {
1022     print_err("main", ret);
1023   }
1024 
1025   return 0;
1026 } // end main()
1027