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: InkMgmtAPI.cc
26  * Purpose: This file implements all traffic server management functions.
27  * Created: 9/11/00
28  * Created by: Lan Tran
29  *
30  *
31  ***************************************************************************/
32 #include "tscore/ink_platform.h"
33 #include "tscore/ink_code.h"
34 #include "tscore/ink_memory.h"
35 #include "tscore/ParseRules.h"
36 #include <climits>
37 #include "tscore/I_Layout.h"
38 
39 #include "mgmtapi.h"
40 #include "CoreAPI.h"
41 #include "CoreAPIShared.h"
42 
43 #include "tscore/TextBuffer.h"
44 
45 /***************************************************************************
46  * API Memory Management
47  ***************************************************************************/
48 void *
_TSmalloc(unsigned int size,const char *)49 _TSmalloc(unsigned int size, const char * /* path ATS_UNUSED */)
50 {
51   return ats_malloc(size);
52 }
53 
54 void *
_TSrealloc(void * ptr,unsigned int size,const char *)55 _TSrealloc(void *ptr, unsigned int size, const char * /* path ATS_UNUSED */)
56 {
57   return ats_realloc(ptr, size);
58 }
59 
60 char *
_TSstrdup(const char * str,int length,const char *)61 _TSstrdup(const char *str, int length, const char * /* path ATS_UNUSED */)
62 {
63   return ats_strndup(str, length);
64 }
65 
66 void
_TSfree(void * ptr)67 _TSfree(void *ptr)
68 {
69   ats_free(ptr);
70 }
71 
72 /***************************************************************************
73  * API Helper Functions for Data Carrier Structures
74  ***************************************************************************/
75 
76 /*--- TSList operations -------------------------------------------------*/
77 tsapi TSList
TSListCreate(void)78 TSListCreate(void)
79 {
80   return (void *)create_queue();
81 }
82 
83 /* NOTE: The List must be EMPTY */
84 tsapi void
TSListDestroy(TSList l)85 TSListDestroy(TSList l)
86 {
87   if (!l) {
88     return;
89   }
90 
91   delete_queue(static_cast<LLQ *>(l));
92   return;
93 }
94 
95 tsapi TSMgmtError
TSListEnqueue(TSList l,void * data)96 TSListEnqueue(TSList l, void *data)
97 {
98   int ret;
99 
100   ink_assert(l && data);
101   if (!l || !data) {
102     return TS_ERR_PARAMS;
103   }
104 
105   ret = enqueue(static_cast<LLQ *>(l), data); /* returns TRUE=1 or FALSE=0 */
106   if (ret == 0) {
107     return TS_ERR_FAIL;
108   } else {
109     return TS_ERR_OKAY;
110   }
111 }
112 
113 tsapi void *
TSListDequeue(TSList l)114 TSListDequeue(TSList l)
115 {
116   ink_assert(l);
117   if (!l || queue_is_empty(static_cast<LLQ *>(l))) {
118     return nullptr;
119   }
120 
121   return dequeue(static_cast<LLQ *>(l));
122 }
123 
124 tsapi bool
TSListIsEmpty(TSList l)125 TSListIsEmpty(TSList l)
126 {
127   ink_assert(l);
128   if (!l) {
129     return true; // list doesn't exist, so it's empty
130   }
131 
132   return queue_is_empty(static_cast<LLQ *>(l));
133 }
134 
135 tsapi int
TSListLen(TSList l)136 TSListLen(TSList l)
137 {
138   ink_assert(l);
139   if (!l) {
140     return -1;
141   }
142 
143   return queue_len(static_cast<LLQ *>(l));
144 }
145 
146 tsapi bool
TSListIsValid(TSList l)147 TSListIsValid(TSList l)
148 {
149   int i, len;
150 
151   if (!l) {
152     return false;
153   }
154 
155   len = queue_len(static_cast<LLQ *>(l));
156   for (i = 0; i < len; i++) {
157     void *ele = dequeue(static_cast<LLQ *>(l));
158     if (!ele) {
159       return false;
160     }
161     enqueue(static_cast<LLQ *>(l), ele);
162   }
163   return true;
164 }
165 
166 /*--- TSStringList operations --------------------------------------*/
167 tsapi TSStringList
TSStringListCreate()168 TSStringListCreate()
169 {
170   return (void *)create_queue(); /* this queue will be a list of char* */
171 }
172 
173 /* usually, must be an empty list before destroying*/
174 tsapi void
TSStringListDestroy(TSStringList strl)175 TSStringListDestroy(TSStringList strl)
176 {
177   if (!strl) {
178     return;
179   }
180 
181   /* dequeue each element and free it */
182   while (!queue_is_empty(static_cast<LLQ *>(strl))) {
183     char *str = static_cast<char *>(dequeue(static_cast<LLQ *>(strl)));
184     ats_free(str);
185   }
186 
187   delete_queue(static_cast<LLQ *>(strl));
188 }
189 
190 tsapi TSMgmtError
TSStringListEnqueue(TSStringList strl,char * str)191 TSStringListEnqueue(TSStringList strl, char *str)
192 {
193   int ret;
194 
195   ink_assert(strl && str);
196   if (!strl || !str) {
197     return TS_ERR_PARAMS;
198   }
199 
200   ret = enqueue(static_cast<LLQ *>(strl), str); /* returns TRUE=1 or FALSE=0 */
201   if (ret == 0) {
202     return TS_ERR_FAIL;
203   } else {
204     return TS_ERR_OKAY;
205   }
206 }
207 
208 tsapi char *
TSStringListDequeue(TSStringList strl)209 TSStringListDequeue(TSStringList strl)
210 {
211   ink_assert(strl);
212   if (!strl || queue_is_empty(static_cast<LLQ *>(strl))) {
213     return nullptr;
214   }
215 
216   return static_cast<char *>(dequeue(static_cast<LLQ *>(strl)));
217 }
218 
219 tsapi bool
TSStringListIsEmpty(TSStringList strl)220 TSStringListIsEmpty(TSStringList strl)
221 {
222   ink_assert(strl);
223   if (!strl) {
224     return true;
225   }
226 
227   return queue_is_empty(static_cast<LLQ *>(strl));
228 }
229 
230 tsapi int
TSStringListLen(TSStringList strl)231 TSStringListLen(TSStringList strl)
232 {
233   ink_assert(strl);
234   if (!strl) {
235     return -1;
236   }
237 
238   return queue_len(static_cast<LLQ *>(strl));
239 }
240 
241 // returns false if any element is NULL string
242 tsapi bool
TSStringListIsValid(TSStringList strl)243 TSStringListIsValid(TSStringList strl)
244 {
245   int i, len;
246 
247   if (!strl) {
248     return false;
249   }
250 
251   len = queue_len(static_cast<LLQ *>(strl));
252   for (i = 0; i < len; i++) {
253     char *str = static_cast<char *>(dequeue(static_cast<LLQ *>(strl)));
254     if (!str) {
255       return false;
256     }
257     enqueue(static_cast<LLQ *>(strl), str);
258   }
259   return true;
260 }
261 
262 /*--- TSIntList operations --------------------------------------*/
263 tsapi TSIntList
TSIntListCreate()264 TSIntListCreate()
265 {
266   return (void *)create_queue(); /* this queue will be a list of int* */
267 }
268 
269 /* usually, must be an empty list before destroying*/
270 tsapi void
TSIntListDestroy(TSIntList intl)271 TSIntListDestroy(TSIntList intl)
272 {
273   if (!intl) {
274     return;
275   }
276 
277   /* dequeue each element and free it */
278   while (!queue_is_empty(static_cast<LLQ *>(intl))) {
279     int *iPtr = static_cast<int *>(dequeue(static_cast<LLQ *>(intl)));
280     ats_free(iPtr);
281   }
282 
283   delete_queue(static_cast<LLQ *>(intl));
284   return;
285 }
286 
287 tsapi TSMgmtError
TSIntListEnqueue(TSIntList intl,int * elem)288 TSIntListEnqueue(TSIntList intl, int *elem)
289 {
290   int ret;
291 
292   ink_assert(intl && elem);
293   if (!intl || !elem) {
294     return TS_ERR_PARAMS;
295   }
296 
297   ret = enqueue(static_cast<LLQ *>(intl), elem); /* returns TRUE=1 or FALSE=0 */
298   if (ret == 0) {
299     return TS_ERR_FAIL;
300   } else {
301     return TS_ERR_OKAY;
302   }
303 }
304 
305 tsapi int *
TSIntListDequeue(TSIntList intl)306 TSIntListDequeue(TSIntList intl)
307 {
308   ink_assert(intl);
309   if (!intl || queue_is_empty(static_cast<LLQ *>(intl))) {
310     return nullptr;
311   }
312 
313   return static_cast<int *>(dequeue(static_cast<LLQ *>(intl)));
314 }
315 
316 tsapi bool
TSIntListIsEmpty(TSIntList intl)317 TSIntListIsEmpty(TSIntList intl)
318 {
319   ink_assert(intl);
320   if (!intl) {
321     return true;
322   }
323 
324   return queue_is_empty(static_cast<LLQ *>(intl));
325 }
326 
327 tsapi int
TSIntListLen(TSIntList intl)328 TSIntListLen(TSIntList intl)
329 {
330   ink_assert(intl);
331   if (!intl) {
332     return -1;
333   }
334 
335   return queue_len(static_cast<LLQ *>(intl));
336 }
337 
338 tsapi bool
TSIntListIsValid(TSIntList intl,int min,int max)339 TSIntListIsValid(TSIntList intl, int min, int max)
340 {
341   if (!intl) {
342     return false;
343   }
344 
345   for (unsigned long i = 0; i < queue_len(static_cast<LLQ *>(intl)); i++) {
346     int *item = static_cast<int *>(dequeue(static_cast<LLQ *>(intl)));
347     if (*item < min) {
348       return false;
349     }
350     if (*item > max) {
351       return false;
352     }
353     enqueue(static_cast<LLQ *>(intl), item);
354   }
355   return true;
356 }
357 
358 /*--- allocate/deallocate operations --------------------------------------*/
359 tsapi TSMgmtEvent *
TSEventCreate(void)360 TSEventCreate(void)
361 {
362   TSMgmtEvent *event = static_cast<TSMgmtEvent *>(ats_malloc(sizeof(TSMgmtEvent)));
363 
364   event->id          = -1;
365   event->name        = nullptr;
366   event->description = nullptr;
367   event->priority    = TS_EVENT_PRIORITY_UNDEFINED;
368 
369   return event;
370 }
371 
372 tsapi void
TSEventDestroy(TSMgmtEvent * event)373 TSEventDestroy(TSMgmtEvent *event)
374 {
375   if (event) {
376     ats_free(event->name);
377     ats_free(event->description);
378     ats_free(event);
379   }
380   return;
381 }
382 
383 tsapi TSRecordEle *
TSRecordEleCreate(void)384 TSRecordEleCreate(void)
385 {
386   TSRecordEle *ele = static_cast<TSRecordEle *>(ats_malloc(sizeof(TSRecordEle)));
387 
388   ele->rec_name = nullptr;
389   ele->rec_type = TS_REC_UNDEFINED;
390 
391   return ele;
392 }
393 
394 tsapi void
TSRecordEleDestroy(TSRecordEle * ele)395 TSRecordEleDestroy(TSRecordEle *ele)
396 {
397   if (ele) {
398     ats_free(ele->rec_name);
399     if (ele->rec_type == TS_REC_STRING && ele->valueT.string_val) {
400       ats_free(ele->valueT.string_val);
401     }
402     ats_free(ele);
403   }
404   return;
405 }
406 
407 /***************************************************************************
408  * API Core
409  ***************************************************************************/
410 
411 /*--- host status operations ----------------------------------------------- */
412 tsapi TSMgmtError
TSHostStatusSetUp(const char * host_name,int down_time,const char * reason)413 TSHostStatusSetUp(const char *host_name, int down_time, const char *reason)
414 {
415   return HostStatusSetUp(host_name, down_time, reason);
416 }
417 
418 tsapi TSMgmtError
TSHostStatusSetDown(const char * host_name,int down_time,const char * reason)419 TSHostStatusSetDown(const char *host_name, int down_time, const char *reason)
420 {
421   return HostStatusSetDown(host_name, down_time, reason);
422 }
423 
424 /*--- statistics operations ----------------------------------------------- */
425 tsapi TSMgmtError
TSStatsReset(const char * name)426 TSStatsReset(const char *name)
427 {
428   return StatsReset(name);
429 }
430 
431 /*--- variable operations ------------------------------------------------- */
432 /* Call the CfgFileIO variable operations */
433 
434 tsapi TSMgmtError
TSRecordGet(const char * rec_name,TSRecordEle * rec_val)435 TSRecordGet(const char *rec_name, TSRecordEle *rec_val)
436 {
437   return MgmtRecordGet(rec_name, rec_val);
438 }
439 
440 TSMgmtError
TSRecordGetInt(const char * rec_name,TSInt * int_val)441 TSRecordGetInt(const char *rec_name, TSInt *int_val)
442 {
443   TSMgmtError ret = TS_ERR_OKAY;
444 
445   TSRecordEle *ele = TSRecordEleCreate();
446   ret              = MgmtRecordGet(rec_name, ele);
447   if (ret != TS_ERR_OKAY) {
448     goto END;
449   }
450 
451   *int_val = ele->valueT.int_val;
452 
453 END:
454   TSRecordEleDestroy(ele);
455   return ret;
456 }
457 
458 TSMgmtError
TSRecordGetCounter(const char * rec_name,TSCounter * counter_val)459 TSRecordGetCounter(const char *rec_name, TSCounter *counter_val)
460 {
461   TSMgmtError ret;
462 
463   TSRecordEle *ele = TSRecordEleCreate();
464   ret              = MgmtRecordGet(rec_name, ele);
465   if (ret != TS_ERR_OKAY) {
466     goto END;
467   }
468   *counter_val = ele->valueT.counter_val;
469 
470 END:
471   TSRecordEleDestroy(ele);
472   return ret;
473 }
474 
475 TSMgmtError
TSRecordGetFloat(const char * rec_name,TSFloat * float_val)476 TSRecordGetFloat(const char *rec_name, TSFloat *float_val)
477 {
478   TSMgmtError ret;
479 
480   TSRecordEle *ele = TSRecordEleCreate();
481   ret              = MgmtRecordGet(rec_name, ele);
482   if (ret != TS_ERR_OKAY) {
483     goto END;
484   }
485   *float_val = ele->valueT.float_val;
486 
487 END:
488   TSRecordEleDestroy(ele);
489   return ret;
490 }
491 
492 TSMgmtError
TSRecordGetString(const char * rec_name,TSString * string_val)493 TSRecordGetString(const char *rec_name, TSString *string_val)
494 {
495   TSMgmtError ret;
496 
497   TSRecordEle *ele = TSRecordEleCreate();
498   ret              = MgmtRecordGet(rec_name, ele);
499   if (ret != TS_ERR_OKAY) {
500     goto END;
501   }
502 
503   *string_val = ats_strdup(ele->valueT.string_val);
504 
505 END:
506   TSRecordEleDestroy(ele);
507   return ret;
508 }
509 
510 /*-------------------------------------------------------------------------
511  * TSRecordGetMlt
512  *-------------------------------------------------------------------------
513  * Purpose: Retrieves list of record values specified in the rec_names list
514  * Input: rec_names - list of record names to retrieve
515  *        rec_vals  - queue of TSRecordEle* that corresponds to rec_names
516  * Output: If at any point, while retrieving one of the records there's a
517  *         a failure then the entire process is aborted, all the allocated
518  *         TSRecordEle's are deallocated and TS_ERR_FAIL is returned.
519  * Note: rec_names is not freed; if function is successful, the rec_names
520  *       list is unchanged!
521  *
522  * IS THIS FUNCTION AN ATOMIC TRANSACTION? Technically, all the variables
523  * requested should refer to the same config file. But a lock is only
524  * put on each variable it is looked up. Need to be able to lock
525  * a file while retrieving all the requested records!
526  */
527 
528 tsapi TSMgmtError
TSRecordGetMlt(TSStringList rec_names,TSList rec_vals)529 TSRecordGetMlt(TSStringList rec_names, TSList rec_vals)
530 {
531   int num_recs, i, j;
532   TSMgmtError ret;
533 
534   if (!rec_names || !rec_vals) {
535     return TS_ERR_PARAMS;
536   }
537 
538   num_recs = queue_len(static_cast<LLQ *>(rec_names));
539   for (i = 0; i < num_recs; i++) {
540     char *rec_name = static_cast<char *>(dequeue(static_cast<LLQ *>(rec_names))); // remove name from list
541     if (!rec_name) {
542       return TS_ERR_PARAMS; // NULL is invalid record name
543     }
544 
545     TSRecordEle *ele = TSRecordEleCreate();
546 
547     ret = MgmtRecordGet(rec_name, ele);
548     enqueue(static_cast<LLQ *>(rec_names), rec_name); // return name to list
549 
550     if (ret != TS_ERR_OKAY) { // RecordGet failed
551       // need to free all the ele's allocated by MgmtRecordGet so far
552       TSRecordEleDestroy(ele);
553       for (j = 0; j < i; j++) {
554         ele = static_cast<TSRecordEle *>(dequeue(static_cast<LLQ *>(rec_vals)));
555         if (ele) {
556           TSRecordEleDestroy(ele);
557         }
558       }
559       return ret;
560     }
561     enqueue(static_cast<LLQ *>(rec_vals), ele); // all is good; add ele to end of list
562   }
563 
564   return TS_ERR_OKAY;
565 }
566 
567 tsapi TSMgmtError
TSRecordGetMatchMlt(const char * regex,TSList rec_vals)568 TSRecordGetMatchMlt(const char *regex, TSList rec_vals)
569 {
570   if (!regex || !rec_vals) {
571     return TS_ERR_PARAMS;
572   }
573 
574   return MgmtRecordGetMatching(regex, rec_vals);
575 }
576 
577 tsapi TSMgmtError
TSRecordSet(const char * rec_name,const char * val,TSActionNeedT * action_need)578 TSRecordSet(const char *rec_name, const char *val, TSActionNeedT *action_need)
579 {
580   return MgmtRecordSet(rec_name, val, action_need);
581 }
582 
583 tsapi TSMgmtError
TSRecordSetInt(const char * rec_name,TSInt int_val,TSActionNeedT * action_need)584 TSRecordSetInt(const char *rec_name, TSInt int_val, TSActionNeedT *action_need)
585 {
586   return MgmtRecordSetInt(rec_name, int_val, action_need);
587 }
588 
589 tsapi TSMgmtError
TSRecordSetCounter(const char * rec_name,TSCounter counter_val,TSActionNeedT * action_need)590 TSRecordSetCounter(const char *rec_name, TSCounter counter_val, TSActionNeedT *action_need)
591 {
592   return MgmtRecordSetCounter(rec_name, counter_val, action_need);
593 }
594 
595 tsapi TSMgmtError
TSRecordSetFloat(const char * rec_name,TSFloat float_val,TSActionNeedT * action_need)596 TSRecordSetFloat(const char *rec_name, TSFloat float_val, TSActionNeedT *action_need)
597 {
598   return MgmtRecordSetFloat(rec_name, float_val, action_need);
599 }
600 
601 tsapi TSMgmtError
TSRecordSetString(const char * rec_name,const char * str_val,TSActionNeedT * action_need)602 TSRecordSetString(const char *rec_name, const char *str_val, TSActionNeedT *action_need)
603 {
604   return MgmtRecordSetString(rec_name, str_val, action_need);
605 }
606 
607 /*-------------------------------------------------------------------------
608  * TSRecordSetMlt
609  *-------------------------------------------------------------------------
610  * Basically iterates through each RecordEle in rec_list and calls the
611  * appropriate "MgmtRecordSetxx" function for that record
612  * Input: rec_list - queue of TSRecordEle*; each TSRecordEle* must have
613  *        a valid record name (remains unchanged on return)
614  * Output: if there is an error during the setting of one of the variables then
615  *         will continue to try to set the other variables. Error response will
616  *         indicate though that not all set operations were successful.
617  *         TS_ERR_OKAY is returned if all the records are set successfully
618  * Note: Determining the action needed is more complex b/c need to keep
619  * track of which record change is the most drastic out of the group of
620  * records; action_need will be set to the most severe action needed of
621  * all the "Set" calls
622  */
623 tsapi TSMgmtError
TSRecordSetMlt(TSList rec_list,TSActionNeedT * action_need)624 TSRecordSetMlt(TSList rec_list, TSActionNeedT *action_need)
625 {
626   int num_recs, ret, i;
627   TSMgmtError status           = TS_ERR_OKAY;
628   TSActionNeedT top_action_req = TS_ACTION_UNDEFINED;
629 
630   if (!rec_list || !action_need) {
631     return TS_ERR_PARAMS;
632   }
633 
634   num_recs = queue_len(static_cast<LLQ *>(rec_list));
635 
636   for (i = 0; i < num_recs; i++) {
637     TSRecordEle *ele = static_cast<TSRecordEle *>(dequeue(static_cast<LLQ *>(rec_list)));
638     if (ele) {
639       switch (ele->rec_type) {
640       case TS_REC_INT:
641         ret = MgmtRecordSetInt(ele->rec_name, ele->valueT.int_val, action_need);
642         break;
643       case TS_REC_COUNTER:
644         ret = MgmtRecordSetCounter(ele->rec_name, ele->valueT.counter_val, action_need);
645         break;
646       case TS_REC_FLOAT:
647         ret = MgmtRecordSetFloat(ele->rec_name, ele->valueT.float_val, action_need);
648         break;
649       case TS_REC_STRING:
650         ret = MgmtRecordSetString(ele->rec_name, ele->valueT.string_val, action_need);
651         break;
652       default:
653         ret = TS_ERR_FAIL;
654         break;
655       }; /* end of switch (ele->rec_type) */
656       if (ret != TS_ERR_OKAY) {
657         status = TS_ERR_FAIL;
658       }
659 
660       // keep track of most severe action; reset if needed
661       // the TSActionNeedT should be listed such that most severe actions have
662       // a lower number (so most severe action == 0)
663       if (*action_need < top_action_req) { // a more severe action
664         top_action_req = *action_need;
665       }
666     }
667     enqueue(static_cast<LLQ *>(rec_list), ele);
668   }
669 
670   // set the action_need to be the most sever action needed of all the "set" calls
671   *action_need = top_action_req;
672 
673   return status;
674 }
675 
676 /*--- api initialization and shutdown -------------------------------------*/
677 tsapi TSMgmtError
TSInit(const char * socket_path,TSInitOptionT options)678 TSInit(const char *socket_path, TSInitOptionT options)
679 {
680   return Init(socket_path, options);
681 }
682 
683 tsapi TSMgmtError
TSTerminate()684 TSTerminate()
685 {
686   return Terminate();
687 }
688 
689 /*--- plugin initialization -----------------------------------------------*/
690 inkexp extern void
TSPluginInit(int,const char * [])691 TSPluginInit(int /* argc ATS_UNUSED */, const char * /* argv ATS_UNUSED */[])
692 {
693 }
694 
695 /*--- network operations --------------------------------------------------*/
696 tsapi TSMgmtError
TSConnect(TSIpAddr,int)697 TSConnect(TSIpAddr /* ip_addr ATS_UNUSED */, int /* port ATS_UNUSED */)
698 {
699   return TS_ERR_OKAY;
700 }
701 tsapi TSMgmtError
TSDisconnectCbRegister(TSDisconnectFunc *,void *)702 TSDisconnectCbRegister(TSDisconnectFunc * /* func ATS_UNUSED */, void * /* data ATS_UNUSED */)
703 {
704   return TS_ERR_OKAY;
705 }
706 tsapi TSMgmtError
TSDisconnectRetrySet(int,int)707 TSDisconnectRetrySet(int /* retries ATS_UNUSED */, int /* retry_sleep_msec ATS_UNUSED */)
708 {
709   return TS_ERR_OKAY;
710 }
711 tsapi TSMgmtError
TSDisconnect()712 TSDisconnect()
713 {
714   return TS_ERR_OKAY;
715 }
716 
717 /*--- control operations --------------------------------------------------*/
718 /* NOTE: these operations are wrappers that make direct calls to the CoreAPI */
719 
720 /* TSProxyStateGet: get the proxy state (on/off)
721  * Input:  <none>
722  * Output: proxy state (on/off)
723  */
724 tsapi TSProxyStateT
TSProxyStateGet()725 TSProxyStateGet()
726 {
727   return ProxyStateGet();
728 }
729 
730 /* TSProxyStateSet: set the proxy state (on/off)
731  * Input:  proxy_state - set to on/off
732  *         clear - start TS with cache clearing option,
733  *                 when stopping TS should always be TS_CACHE_CLEAR_NONE
734  * Output: TSMgmtError
735  */
736 tsapi TSMgmtError
TSProxyStateSet(TSProxyStateT proxy_state,unsigned clear)737 TSProxyStateSet(TSProxyStateT proxy_state, unsigned clear)
738 {
739   unsigned mask = TS_CACHE_CLEAR_NONE | TS_CACHE_CLEAR_CACHE | TS_CACHE_CLEAR_HOSTDB;
740 
741   if (clear & ~mask) {
742     return TS_ERR_PARAMS;
743   }
744 
745   return ProxyStateSet(proxy_state, static_cast<TSCacheClearT>(clear));
746 }
747 
748 tsapi TSMgmtError
TSProxyBacktraceGet(unsigned options,TSString * trace)749 TSProxyBacktraceGet(unsigned options, TSString *trace)
750 {
751   if (options != 0) {
752     return TS_ERR_PARAMS;
753   }
754 
755   if (trace == nullptr) {
756     return TS_ERR_PARAMS;
757   }
758 
759   return ServerBacktrace(options, trace);
760 }
761 
762 /* TSReconfigure: tell traffic_server to re-read its configuration files
763  * Input:  <none>
764  * Output: TSMgmtError
765  */
766 tsapi TSMgmtError
TSReconfigure()767 TSReconfigure()
768 {
769   return Reconfigure();
770 }
771 
772 /* TSRestart: restarts Traffic Server
773  * Input:  options - bitmask of TSRestartOptionT
774  * Output: TSMgmtError
775  */
776 tsapi TSMgmtError
TSRestart(unsigned options)777 TSRestart(unsigned options)
778 {
779   return Restart(options);
780 }
781 
782 /* TSActionDo: based on TSActionNeedT, will take appropriate action
783  * Input: action - action that needs to be taken
784  * Output: TSMgmtError
785  */
786 tsapi TSMgmtError
TSActionDo(TSActionNeedT action)787 TSActionDo(TSActionNeedT action)
788 {
789   TSMgmtError ret;
790 
791   switch (action) {
792   case TS_ACTION_RESTART:
793     ret = Restart(true); // cluster wide by default?
794     break;
795   case TS_ACTION_RECONFIGURE:
796     ret = Reconfigure();
797     break;
798   case TS_ACTION_DYNAMIC:
799     /* do nothing - change takes effect immediately */
800     return TS_ERR_OKAY;
801   case TS_ACTION_SHUTDOWN:
802   default:
803     return TS_ERR_FAIL;
804   }
805 
806   return ret;
807 }
808 
809 /* TSBouncer: restarts the traffic_server process(es)
810  * Input:  options - bitmask of TSRestartOptionT
811  * Output: TSMgmtError
812  */
813 tsapi TSMgmtError
TSBounce(unsigned options)814 TSBounce(unsigned options)
815 {
816   return Bounce(options);
817 }
818 
819 tsapi TSMgmtError
TSStop(unsigned options)820 TSStop(unsigned options)
821 {
822   return Stop(options);
823 }
824 
825 tsapi TSMgmtError
TSDrain(unsigned options)826 TSDrain(unsigned options)
827 {
828   return Drain(options);
829 }
830 
831 tsapi TSMgmtError
TSStorageDeviceCmdOffline(const char * dev)832 TSStorageDeviceCmdOffline(const char *dev)
833 {
834   return StorageDeviceCmdOffline(dev);
835 }
836 
837 tsapi TSMgmtError
TSLifecycleMessage(const char * tag,void const * data,size_t data_size)838 TSLifecycleMessage(const char *tag, void const *data, size_t data_size)
839 {
840   return LifecycleMessage(tag, data, data_size);
841 }
842 
843 /* NOTE: user must deallocate the memory for the string returned */
844 char *
TSGetErrorMessage(TSMgmtError err_id)845 TSGetErrorMessage(TSMgmtError err_id)
846 {
847   char msg[1024]; // need to define a MAX_ERR_MSG_SIZE???
848   char *err_msg = nullptr;
849 
850   switch (err_id) {
851   case TS_ERR_OKAY:
852     snprintf(msg, sizeof(msg), "[%d] Everything's looking good.", err_id);
853     break;
854   case TS_ERR_READ_FILE: /* Error occur in reading file */
855     snprintf(msg, sizeof(msg), "[%d] Unable to find/open file for reading.", err_id);
856     break;
857   case TS_ERR_WRITE_FILE: /* Error occur in writing file */
858     snprintf(msg, sizeof(msg), "[%d] Unable to find/open file for writing.", err_id);
859     break;
860   case TS_ERR_PARSE_CONFIG_RULE: /* Error in parsing configuration file */
861     snprintf(msg, sizeof(msg), "[%d] Error parsing configuration file.", err_id);
862     break;
863   case TS_ERR_INVALID_CONFIG_RULE: /* Invalid Configuration Rule */
864     snprintf(msg, sizeof(msg), "[%d] Invalid configuration rule reached.", err_id);
865     break;
866   case TS_ERR_NET_ESTABLISH:
867     snprintf(msg, sizeof(msg), "[%d] Error establishing socket connection.", err_id);
868     break;
869   case TS_ERR_NET_READ: /* Error reading from socket */
870     snprintf(msg, sizeof(msg), "[%d] Error reading from socket.", err_id);
871     break;
872   case TS_ERR_NET_WRITE: /* Error writing to socket */
873     snprintf(msg, sizeof(msg), "[%d] Error writing to socket.", err_id);
874     break;
875   case TS_ERR_NET_EOF: /* Hit socket EOF */
876     snprintf(msg, sizeof(msg), "[%d] Reached socket EOF.", err_id);
877     break;
878   case TS_ERR_NET_TIMEOUT: /* Timed out waiting for socket read */
879     snprintf(msg, sizeof(msg), "[%d] Timed out waiting for socket read.", err_id);
880     break;
881   case TS_ERR_SYS_CALL: /* Error in sys/utility call, eg.malloc */
882     snprintf(msg, sizeof(msg), "[%d] Error in basic system/utility call.", err_id);
883     break;
884   case TS_ERR_PARAMS: /* Invalid parameters for a fn */
885     snprintf(msg, sizeof(msg), "[%d] Invalid parameters passed into function call.", err_id);
886     break;
887   case TS_ERR_FAIL:
888     snprintf(msg, sizeof(msg), "[%d] Generic Fail message (ie. CoreAPI call).", err_id);
889     break;
890   case TS_ERR_NOT_SUPPORTED:
891     snprintf(msg, sizeof(msg), "[%d] Operation not supported on this platform.", err_id);
892     break;
893   case TS_ERR_PERMISSION_DENIED:
894     snprintf(msg, sizeof(msg), "[%d] Operation not permitted.", err_id);
895     break;
896 
897   default:
898     snprintf(msg, sizeof(msg), "[%d] Invalid error type.", err_id);
899     break;
900   }
901 
902   err_msg = ats_strdup(msg);
903   return err_msg;
904 }
905 
906 /* ReadFromUrl: reads a remotely located config file into a buffer
907  * Input:  url        - remote location of the file
908  *         header     - a buffer is allocated on the header char* pointer
909  *         headerSize - the size of the header buffer is returned
910  *         body       - a buffer is allocated on the body char* pointer
911  *         bodySize   - the size of the body buffer is returned
912  * Output: TSMgmtError   - TS_ERR_OKAY if succeed, TS_ERR_FAIL otherwise
913  * Obsolete:  tsapi TSMgmtError TSReadFromUrl (char *url, char **text, int *size);
914  * NOTE: The URL can be expressed in the following forms:
915  *       - http://www.example.com:80/products/network/index.html
916  *       - http://www.example.com/products/network/index.html
917  *       - http://www.example.com/products/network/
918  *       - http://www.example.com/
919  *       - http://www.example.com
920  *       - www.example.com
921  * NOTE: header and headerSize can be NULL
922  */
923 tsapi TSMgmtError
TSReadFromUrl(char * url,char ** header,int * headerSize,char ** body,int * bodySize)924 TSReadFromUrl(char *url, char **header, int *headerSize, char **body, int *bodySize)
925 {
926   // return ReadFromUrl(url, header, headerSize, body, bodySize);
927   return TSReadFromUrlEx(url, header, headerSize, body, bodySize, URL_TIMEOUT);
928 }
929 
930 tsapi TSMgmtError
TSReadFromUrlEx(const char * url,char ** header,int * headerSize,char ** body,int * bodySize,int timeout)931 TSReadFromUrlEx(const char *url, char **header, int *headerSize, char **body, int *bodySize, int timeout)
932 {
933   int hFD        = -1;
934   char *httpHost = nullptr;
935   char *httpPath = nullptr;
936   int httpPort   = HTTP_PORT;
937   int bufsize    = URL_BUFSIZE;
938   char buffer[URL_BUFSIZE];
939   char request[BUFSIZE];
940   char *hdr_temp;
941   char *bdy_temp;
942   TSMgmtError status = TS_ERR_OKAY;
943 
944   // Sanity check
945   if (!url) {
946     return TS_ERR_FAIL;
947   }
948   if (timeout < 0) {
949     timeout = URL_TIMEOUT;
950   }
951   // Chop the protocol part, if it exists
952   const char *doubleSlash = strstr(url, "//");
953   if (doubleSlash) {
954     url = doubleSlash + 2; // advance two positions to get rid of leading '//'
955   }
956   // the path starts after the first occurrence of '/'
957   const char *tempPath = strstr(url, "/");
958   char *host_and_port;
959   if (tempPath) {
960     host_and_port = ats_strndup(url, strlen(url) - strlen(tempPath));
961     tempPath += 1; // advance one position to get rid of leading '/'
962     httpPath = ats_strdup(tempPath);
963   } else {
964     host_and_port = ats_strdup(url);
965     httpPath      = ats_strdup("");
966   }
967 
968   // the port proceed by a ":", if it exists
969   char *colon = strstr(host_and_port, ":");
970   if (colon) {
971     httpHost = ats_strndup(host_and_port, strlen(host_and_port) - strlen(colon));
972     colon += 1; // advance one position to get rid of leading ':'
973     httpPort = ink_atoi(colon);
974     if (httpPort <= 0) {
975       httpPort = HTTP_PORT;
976     }
977   } else {
978     httpHost = ats_strdup(host_and_port);
979   }
980   ats_free(host_and_port);
981 
982   hFD = connectDirect(httpHost, httpPort, timeout);
983   if (hFD == -1) {
984     status = TS_ERR_NET_ESTABLISH;
985     goto END;
986   }
987 
988   /* sending the HTTP request via the established socket */
989   snprintf(request, BUFSIZE, "http://%s:%d/%s", httpHost, httpPort, httpPath);
990   if ((status = sendHTTPRequest(hFD, request, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
991     goto END;
992   }
993 
994   memset(buffer, 0, bufsize); /* empty the buffer */
995   if ((status = readHTTPResponse(hFD, buffer, bufsize, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
996     goto END;
997   }
998 
999   if ((status = parseHTTPResponse(buffer, &hdr_temp, headerSize, &bdy_temp, bodySize)) != TS_ERR_OKAY) {
1000     goto END;
1001   }
1002 
1003   if (header && headerSize) {
1004     *header = ats_strndup(hdr_temp, *headerSize);
1005   }
1006   *body = ats_strndup(bdy_temp, *bodySize);
1007 
1008 END:
1009   ats_free(httpHost);
1010   ats_free(httpPath);
1011 
1012   return status;
1013 }
1014 
1015 /*--- cache inspector operations -------------------------------------------*/
1016 
1017 tsapi TSMgmtError
TSLookupFromCacheUrl(TSString url,TSString * info)1018 TSLookupFromCacheUrl(TSString url, TSString *info)
1019 {
1020   TSMgmtError err = TS_ERR_OKAY;
1021   int fd;
1022   char request[BUFSIZE];
1023   char response[URL_BUFSIZE];
1024   char *header;
1025   char *body;
1026   int hdr_size;
1027   int bdy_size;
1028   int timeout   = URL_TIMEOUT;
1029   TSInt ts_port = 8080;
1030 
1031   if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) {
1032     goto END;
1033   }
1034 
1035   if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) {
1036     err = TS_ERR_FAIL;
1037     goto END;
1038   }
1039   snprintf(request, BUFSIZE, "http://{cache}/lookup_url?url=%s", url);
1040   if ((err = sendHTTPRequest(fd, request, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1041     goto END;
1042   }
1043 
1044   memset(response, 0, URL_BUFSIZE);
1045   if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1046     goto END;
1047   }
1048 
1049   if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) {
1050     goto END;
1051   }
1052 
1053   *info = ats_strndup(body, bdy_size);
1054 
1055 END:
1056   return err;
1057 }
1058 
1059 tsapi TSMgmtError
TSLookupFromCacheUrlRegex(TSString url_regex,TSString * list)1060 TSLookupFromCacheUrlRegex(TSString url_regex, TSString *list)
1061 {
1062   TSMgmtError err = TS_ERR_OKAY;
1063   int fd          = -1;
1064   char request[BUFSIZE];
1065   char response[URL_BUFSIZE];
1066   char *header;
1067   char *body;
1068   int hdr_size;
1069   int bdy_size;
1070   int timeout   = -1;
1071   TSInt ts_port = 8080;
1072 
1073   if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) {
1074     goto END;
1075   }
1076 
1077   if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) {
1078     err = TS_ERR_FAIL;
1079     goto END;
1080   }
1081   snprintf(request, BUFSIZE, "http://{cache}/lookup_regex?url=%s", url_regex);
1082   if ((err = sendHTTPRequest(fd, request, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1083     goto END;
1084   }
1085 
1086   memset(response, 0, URL_BUFSIZE);
1087   if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1088     goto END;
1089   }
1090 
1091   if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) {
1092     goto END;
1093   }
1094 
1095   *list = ats_strndup(body, bdy_size);
1096 END:
1097   return err;
1098 }
1099 
1100 tsapi TSMgmtError
TSDeleteFromCacheUrl(TSString url,TSString * info)1101 TSDeleteFromCacheUrl(TSString url, TSString *info)
1102 {
1103   TSMgmtError err = TS_ERR_OKAY;
1104   int fd          = -1;
1105   char request[BUFSIZE];
1106   char response[URL_BUFSIZE];
1107   char *header;
1108   char *body;
1109   int hdr_size;
1110   int bdy_size;
1111   int timeout   = URL_TIMEOUT;
1112   TSInt ts_port = 8080;
1113 
1114   if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) {
1115     goto END;
1116   }
1117 
1118   if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) {
1119     err = TS_ERR_FAIL;
1120     goto END;
1121   }
1122   snprintf(request, BUFSIZE, "http://{cache}/delete_url?url=%s", url);
1123   if ((err = sendHTTPRequest(fd, request, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1124     goto END;
1125   }
1126 
1127   memset(response, 0, URL_BUFSIZE);
1128   if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1129     goto END;
1130   }
1131 
1132   if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) {
1133     goto END;
1134   }
1135 
1136   *info = ats_strndup(body, bdy_size);
1137 
1138 END:
1139   return err;
1140 }
1141 
1142 tsapi TSMgmtError
TSDeleteFromCacheUrlRegex(TSString url_regex,TSString * list)1143 TSDeleteFromCacheUrlRegex(TSString url_regex, TSString *list)
1144 {
1145   TSMgmtError err = TS_ERR_OKAY;
1146   int fd          = -1;
1147   char request[BUFSIZE];
1148   char response[URL_BUFSIZE];
1149   char *header;
1150   char *body;
1151   int hdr_size;
1152   int bdy_size;
1153   int timeout   = -1;
1154   TSInt ts_port = 8080;
1155 
1156   if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) {
1157     goto END;
1158   }
1159 
1160   if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) {
1161     err = TS_ERR_FAIL;
1162     goto END;
1163   }
1164   snprintf(request, BUFSIZE, "http://{cache}/delete_regex?url=%s", url_regex);
1165   if ((err = sendHTTPRequest(fd, request, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1166     goto END;
1167   }
1168 
1169   memset(response, 0, URL_BUFSIZE);
1170   if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1171     goto END;
1172   }
1173 
1174   if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) {
1175     goto END;
1176   }
1177 
1178   *list = ats_strndup(body, bdy_size);
1179 END:
1180   return err;
1181 }
1182 
1183 tsapi TSMgmtError
TSInvalidateFromCacheUrlRegex(TSString url_regex,TSString * list)1184 TSInvalidateFromCacheUrlRegex(TSString url_regex, TSString *list)
1185 {
1186   TSMgmtError err = TS_ERR_OKAY;
1187   int fd          = -1;
1188   char request[BUFSIZE];
1189   char response[URL_BUFSIZE];
1190   char *header;
1191   char *body;
1192   int hdr_size;
1193   int bdy_size;
1194   int timeout   = -1;
1195   TSInt ts_port = 8080;
1196 
1197   if ((err = TSRecordGetInt("proxy.config.http.server_port", &ts_port)) != TS_ERR_OKAY) {
1198     goto END;
1199   }
1200 
1201   if ((fd = connectDirect("localhost", ts_port, timeout)) < 0) {
1202     err = TS_ERR_FAIL;
1203     goto END;
1204   }
1205   snprintf(request, BUFSIZE, "http://{cache}/invalidate_regex?url=%s", url_regex);
1206   if ((err = sendHTTPRequest(fd, request, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1207     goto END;
1208   }
1209 
1210   memset(response, 0, URL_BUFSIZE);
1211   if ((err = readHTTPResponse(fd, response, URL_BUFSIZE, static_cast<uint64_t>(timeout))) != TS_ERR_OKAY) {
1212     goto END;
1213   }
1214 
1215   if ((err = parseHTTPResponse(response, &header, &hdr_size, &body, &bdy_size)) != TS_ERR_OKAY) {
1216     goto END;
1217   }
1218 
1219   *list = ats_strndup(body, bdy_size);
1220 END:
1221   return err;
1222 }
1223 
1224 /*--- events --------------------------------------------------------------*/
1225 tsapi TSMgmtError
TSEventSignal(char * event_name,...)1226 TSEventSignal(char *event_name, ...)
1227 {
1228   va_list ap;
1229   TSMgmtError ret;
1230 
1231   va_start(ap, event_name); // initialize the argument pointer ap
1232   ret = EventSignal(event_name, ap);
1233   va_end(ap);
1234   return ret;
1235 }
1236 
1237 tsapi TSMgmtError
TSEventResolve(const char * event_name)1238 TSEventResolve(const char *event_name)
1239 {
1240   return EventResolve(event_name);
1241 }
1242 
1243 tsapi TSMgmtError
TSActiveEventGetMlt(TSList active_events)1244 TSActiveEventGetMlt(TSList active_events)
1245 {
1246   return ActiveEventGetMlt(static_cast<LLQ *>(active_events));
1247 }
1248 
1249 tsapi TSMgmtError
TSEventIsActive(char * event_name,bool * is_current)1250 TSEventIsActive(char *event_name, bool *is_current)
1251 {
1252   return EventIsActive(event_name, is_current);
1253 }
1254 
1255 tsapi TSMgmtError
TSEventSignalCbRegister(char * event_name,TSEventSignalFunc func,void * data)1256 TSEventSignalCbRegister(char *event_name, TSEventSignalFunc func, void *data)
1257 {
1258   return EventSignalCbRegister(event_name, func, data);
1259 }
1260 
1261 tsapi TSMgmtError
TSEventSignalCbUnregister(char * event_name,TSEventSignalFunc func)1262 TSEventSignalCbUnregister(char *event_name, TSEventSignalFunc func)
1263 {
1264   return EventSignalCbUnregister(event_name, func);
1265 }
1266 
1267 TSConfigRecordDescription *
TSConfigRecordDescriptionCreate(void)1268 TSConfigRecordDescriptionCreate(void)
1269 {
1270   TSConfigRecordDescription *val = static_cast<TSConfigRecordDescription *>(ats_malloc(sizeof(TSConfigRecordDescription)));
1271 
1272   ink_zero(*val);
1273   val->rec_type = TS_REC_UNDEFINED;
1274 
1275   return val;
1276 }
1277 
1278 void
TSConfigRecordDescriptionDestroy(TSConfigRecordDescription * val)1279 TSConfigRecordDescriptionDestroy(TSConfigRecordDescription *val)
1280 {
1281   TSConfigRecordDescriptionFree(val);
1282   ats_free(val);
1283 }
1284 
1285 void
TSConfigRecordDescriptionFree(TSConfigRecordDescription * val)1286 TSConfigRecordDescriptionFree(TSConfigRecordDescription *val)
1287 {
1288   if (val) {
1289     ats_free(val->rec_name);
1290     ats_free(val->rec_checkexpr);
1291 
1292     if (val->rec_type == TS_REC_STRING) {
1293       ats_free(val->rec_value.string_val);
1294     }
1295 
1296     ink_zero(*val);
1297     val->rec_type = TS_REC_UNDEFINED;
1298   }
1299 }
1300 
1301 TSMgmtError
TSConfigRecordDescribe(const char * rec_name,unsigned flags,TSConfigRecordDescription * val)1302 TSConfigRecordDescribe(const char *rec_name, unsigned flags, TSConfigRecordDescription *val)
1303 {
1304   if (!rec_name || !val) {
1305     return TS_ERR_PARAMS;
1306   }
1307 
1308   TSConfigRecordDescriptionFree(val);
1309   return MgmtConfigRecordDescribe(rec_name, flags, val);
1310 }
1311 
1312 TSMgmtError
TSConfigRecordDescribeMatchMlt(const char * rec_regex,unsigned flags,TSList rec_vals)1313 TSConfigRecordDescribeMatchMlt(const char *rec_regex, unsigned flags, TSList rec_vals)
1314 {
1315   if (!rec_regex || !rec_vals) {
1316     return TS_ERR_PARAMS;
1317   }
1318 
1319   return MgmtConfigRecordDescribeMatching(rec_regex, flags, rec_vals);
1320 }
1321