~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to proxy/mgmt2/Alarms.cc

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 *
 
26
 * Alarms.cc
 
27
 *   Function defs for the Alarms keeper.
 
28
 *
 
29
 * $Date: 2007-10-05 16:56:44 $
 
30
 *
 
31
 *
 
32
 */
 
33
 
 
34
#include "libts.h"
 
35
#include "Main.h"
 
36
#include "Alarms.h"
 
37
#include "Diags.h"
 
38
 
 
39
#if defined(MGMT_API)
 
40
#include "TSControlMain.h"
 
41
#include "Message.h"
 
42
#include "Defs.h"
 
43
#endif
 
44
 
 
45
#include "P_RecCore.h"
 
46
 
 
47
const char *alarmText[] = {
 
48
  "Unknown Alarm",
 
49
  "[TrafficManager] Traffic Server process was reset.",
 
50
  "[TrafficManager] Traffic Server process established.",
 
51
  "New Peer",
 
52
  "Peer Died",
 
53
  "Invalid Configuration",
 
54
  "System Error",
 
55
  "Log Space Crisis",
 
56
  "Cache Error",
 
57
  "Cache Warning",
 
58
  "Logging Error",
 
59
  "Logging Warning",
 
60
  "Mgmt Debugging Alarm",
 
61
  "Configuration File Update Failed",
 
62
  "Unable to Establish Manager User-Interface Services",
 
63
  "Ping Failure",
 
64
  "",
 
65
  "Add OEM Alarm",
 
66
  "",
 
67
  "HTTP Origin Server is Congested",
 
68
  "Congested HTTP Origin Server is now Alleviated",
 
69
  "",                           /* congested server */
 
70
  ""                            /* alleviated server */
 
71
};
 
72
 
 
73
const int alarmTextNum = sizeof(alarmText) / sizeof(char *);
 
74
 
 
75
Alarms::Alarms()
 
76
{
 
77
  bool found;
 
78
 
 
79
  cur_cb = 0;
 
80
  cblist = ink_hash_table_create(InkHashTableKeyType_String);
 
81
  local_alarms = ink_hash_table_create(InkHashTableKeyType_String);
 
82
  remote_alarms = ink_hash_table_create(InkHashTableKeyType_String);
 
83
  ink_mutex_init(&mutex, "alarms-mutex");
 
84
  alarm_bin = REC_readString("proxy.config.alarm.bin", &found);
 
85
  ink_assert(found);
 
86
  alarm_bin_path = REC_readString("proxy.config.alarm.abs_path", &found);
 
87
  ink_assert(found);
 
88
  if (!alarm_bin_path) {
 
89
    alarm_bin_path = REC_readString("proxy.config.bin_path", &found);
 
90
    ink_assert(found);
 
91
  }
 
92
  alarmOEMcount = minOEMkey;
 
93
 
 
94
  return;
 
95
}                               /* End Alarms::Alarms */
 
96
 
 
97
 
 
98
Alarms::~Alarms()
 
99
{
 
100
  ink_hash_table_destroy(cblist);
 
101
  ink_hash_table_destroy_and_xfree_values(local_alarms);
 
102
  ink_hash_table_destroy_and_xfree_values(remote_alarms);
 
103
  ink_mutex_destroy(&mutex);
 
104
  return;
 
105
}                               /* End Alarms::Alarms */
 
106
 
 
107
 
 
108
void
 
109
Alarms::registerCallback(AlarmCallbackFunc func)
 
110
{
 
111
  char cb_buf[80];
 
112
 
 
113
  ink_mutex_acquire(&mutex);
 
114
  snprintf(cb_buf, sizeof(cb_buf), "%d", cur_cb++);
 
115
  Debug("alarm", "[Alarms::registerCallback] Registering Alarms callback\n");
 
116
  ink_hash_table_insert(cblist, cb_buf, (void *) func);
 
117
  ink_mutex_release(&mutex);
 
118
  return;
 
119
}                               /* End Alarms::registerCallback */
 
120
 
 
121
 
 
122
bool
 
123
Alarms::isCurrentAlarm(alarm_t a, char *ip)
 
124
{
 
125
  bool ret = false;
 
126
  char buf[80];
 
127
  InkHashTableValue hash_value;
 
128
 
 
129
  ink_mutex_acquire(&mutex);
 
130
  if (!ip) {
 
131
    snprintf(buf, sizeof(buf), "%d", a);
 
132
  } else {
 
133
    snprintf(buf, sizeof(buf), "%d-%s", a, ip);
 
134
  }
 
135
 
 
136
  if (!ip && ink_hash_table_lookup(local_alarms, buf, &hash_value) != 0) {
 
137
    ret = true;
 
138
  } else if (ip && ink_hash_table_lookup(remote_alarms, buf, &hash_value) != 0) {
 
139
    ret = true;
 
140
  }
 
141
  ink_mutex_release(&mutex);
 
142
  return ret;
 
143
}                               /* End Alarms::isCurrentAlarm */
 
144
 
 
145
 
 
146
void
 
147
Alarms::resolveAlarm(alarm_t a, char *ip)
 
148
{
 
149
  char buf[80];
 
150
  InkHashTableValue hash_value;
 
151
 
 
152
  ink_mutex_acquire(&mutex);
 
153
  if (!ip) {
 
154
    snprintf(buf, sizeof(buf), "%d", a);
 
155
  } else {
 
156
    snprintf(buf, sizeof(buf), "%d-%s", a, ip);
 
157
  }
 
158
 
 
159
  if (!ip && ink_hash_table_lookup(local_alarms, buf, &hash_value) != 0) {
 
160
    ink_hash_table_delete(local_alarms, buf);
 
161
    if (((Alarm *) hash_value)->description) {
 
162
      xfree(((Alarm *) hash_value)->description);
 
163
    }
 
164
    xfree(hash_value);
 
165
  } else if (ip && ink_hash_table_lookup(remote_alarms, buf, &hash_value) != 0) {
 
166
    char buf2[1024];
 
167
 
 
168
    snprintf(buf2, sizeof(buf2), "aresolv: %d\n", a);
 
169
    if (!lmgmt->ccom->sendReliableMessage(inet_addr(ip), buf2, strlen(buf2))) {
 
170
      ink_mutex_release(&mutex);
 
171
      return;
 
172
    }
 
173
    ink_hash_table_delete(remote_alarms, buf);
 
174
    xfree(hash_value);
 
175
  }
 
176
  ink_mutex_release(&mutex);
 
177
 
 
178
  return;
 
179
}                               /* End Alarms::resolveAlarm */
 
180
 
 
181
 
 
182
void
 
183
Alarms::signalAlarm(alarm_t a, const char *desc, const char *ip)
 
184
{
 
185
  static time_t last_sent = 0;
 
186
  static char prev_alarm_text[2048] = "";
 
187
 
 
188
  int priority;
 
189
  char buf[80];
 
190
  Alarm *atmp;
 
191
  InkHashTableValue hash_value;
 
192
  InkHashTableEntry *entry;
 
193
  InkHashTableIteratorState iterator_state;
 
194
 
 
195
  /* Assign correct priorities */
 
196
  switch (a) {
 
197
  case MGMT_ALARM_PROXY_CACHE_ERROR:
 
198
    priority = 1;               // INKqa07595
 
199
    break;
 
200
  case MGMT_ALARM_PROXY_CACHE_WARNING:
 
201
    return;
 
202
  case MGMT_ALARM_PROXY_PEER_BORN:
 
203
    priority = 3;
 
204
    break;
 
205
  case MGMT_ALARM_PROXY_PEER_DIED:
 
206
    priority = 3;
 
207
    break;
 
208
  case MGMT_ALARM_PING_FAILURE:
 
209
    priority = 1;
 
210
    break;
 
211
  case MGMT_ALARM_PROXY_PROCESS_DIED:
 
212
    priority = 1;
 
213
    break;
 
214
  case MGMT_ALARM_PROXY_PROCESS_BORN:
 
215
    mgmt_log(stderr, "[Alarms::signalAlarm] Server Process born\n");
 
216
    priority = 2;
 
217
    return;
 
218
  case MGMT_ALARM_ADD_ALARM:
 
219
    priority = 2;
 
220
    break;
 
221
  case MGMT_ALARM_PROXY_HTTP_CONGESTED_SERVER:
 
222
  case MGMT_ALARM_PROXY_HTTP_ALLEVIATED_SERVER:
 
223
    return;
 
224
  case MGMT_ALARM_WDA_BILLING_CONNECTION_DIED:
 
225
  case MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA:
 
226
  case MGMT_ALARM_WDA_XF_ENGINE_DOWN:
 
227
    priority = 2;
 
228
    break;
 
229
  default:
 
230
    priority = 2;
 
231
    break;
 
232
  }
 
233
 
 
234
  /* Quick hack to buffer repeat alarms and only send every 15 min */
 
235
  if (desc && (priority == 1 || priority == 2) && !ip) {
 
236
 
 
237
    if (strcmp(prev_alarm_text, desc) == 0) {   /* a repeated alarm */
 
238
 
 
239
      /* INKqa11884: repeated wireless alarms always signalled */
 
240
      if (a != MGMT_ALARM_WDA_BILLING_CONNECTION_DIED &&
 
241
          a != MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA &&
 
242
          a != MGMT_ALARM_WDA_XF_ENGINE_DOWN) {
 
243
 
 
244
        time_t time_delta = time(0) - last_sent;
 
245
        if (time_delta < 900) {
 
246
          mgmt_log("[Alarms::signalAlarm] Skipping Alarm: '%s'\n", desc);
 
247
          return;
 
248
        } else {
 
249
          last_sent = time(0);
 
250
        }
 
251
      }
 
252
    } else {
 
253
      ink_strncpy(prev_alarm_text, desc, sizeof(prev_alarm_text));
 
254
      last_sent = time(0);
 
255
    }
 
256
  }
 
257
 
 
258
  Debug("alarm", "[Alarms::signalAlarm] Sending Alarm: '%s'", desc);
 
259
 
 
260
  if (!desc)
 
261
    desc = (char *) getAlarmText(a);
 
262
 
 
263
  /*
 
264
   * Exec alarm bin for priority alarms everytime, regardless if they are
 
265
   * potentially duplicates. However, only exec this for you own alarms,
 
266
   * don't want every node in the cluster reporting the same alarm.
 
267
   */
 
268
  if (priority == 1 && alarm_bin && alarm_bin_path && !ip) {
 
269
    execAlarmBin(desc);
 
270
  }
 
271
 
 
272
 
 
273
 
 
274
  ink_mutex_acquire(&mutex);
 
275
  if (!ip) {
 
276
    // if an OEM alarm, then must create the unique key alarm type;
 
277
    // this key is used to hash the new OEM alarm descritption in the hash table
 
278
    if (a == MGMT_ALARM_ADD_ALARM) {
 
279
      a = (alarmOEMcount - minOEMkey) % (maxOEMkey - minOEMkey) + minOEMkey;
 
280
      alarmOEMcount++;
 
281
    }
 
282
    snprintf(buf, sizeof(buf), "%d", a);
 
283
    if (ink_hash_table_lookup(local_alarms, buf, &hash_value) != 0) {
 
284
      // INKqa11884: if wireless alarm already active, just
 
285
      // update desc with new timestamp and skip to actions part
 
286
      if (a == MGMT_ALARM_WDA_BILLING_CONNECTION_DIED ||
 
287
          a == MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA ||
 
288
          a == MGMT_ALARM_WDA_XF_ENGINE_DOWN) {
 
289
        Debug("alarm", "[signalAlarm] wireless alarm already active");
 
290
        atmp = (Alarm *) hash_value;
 
291
        goto ALARM_REPEAT;
 
292
      } else {
 
293
        ink_mutex_release(&mutex);
 
294
        return;
 
295
      }
 
296
    }
 
297
  } else {
 
298
    snprintf(buf, sizeof(buf), "%d-%s", a, ip);
 
299
    if (ink_hash_table_lookup(remote_alarms, buf, &hash_value) != 0) {
 
300
      // Reset the seen flag so that we know the remote alarm is
 
301
      //   still active
 
302
      atmp = (Alarm *) hash_value;
 
303
      atmp->seen = true;
 
304
 
 
305
      // INKqa11884: if wireless alarm already active, just
 
306
      // update desc with new timstamp and skip to actions part
 
307
      if (a == MGMT_ALARM_WDA_BILLING_CONNECTION_DIED ||
 
308
          a == MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA ||
 
309
          a == MGMT_ALARM_WDA_XF_ENGINE_DOWN) {
 
310
        Debug("alarm", "[Alarms::signalAlarm] wireless alarm already active");
 
311
        goto ALARM_REPEAT;
 
312
      } else {
 
313
        ink_mutex_release(&mutex);
 
314
        return;
 
315
      }
 
316
    }
 
317
  }
 
318
 
 
319
  ink_assert((atmp = (Alarm *) xmalloc(sizeof(Alarm))));
 
320
  atmp->type = a;
 
321
  atmp->linger = true;
 
322
  atmp->seen = true;
 
323
  atmp->priority = priority;
 
324
  atmp->description = NULL;
 
325
 
 
326
  if (!ip) {
 
327
    atmp->local = true;
 
328
    atmp->inet_address = 0;
 
329
    ink_hash_table_insert(local_alarms, (InkHashTableKey) (buf), (atmp));
 
330
  } else {
 
331
    atmp->local = false;
 
332
    atmp->inet_address = inet_addr(ip);
 
333
    ink_hash_table_insert(remote_alarms, (InkHashTableKey) (buf), (atmp));
 
334
  }
 
335
 
 
336
ALARM_REPEAT:
 
337
  // Swap desc with time-stamped description.  Kinda hackish
 
338
  // Temporary until we get a new
 
339
  // alarm system in place.  TS 5.0.0, 02/08/2001
 
340
 
 
341
  time_t my_time_t;
 
342
  char my_ctime_str[32];
 
343
  time(&my_time_t);
 
344
  ink_ctime_r(&my_time_t, my_ctime_str);
 
345
  char *p = my_ctime_str;
 
346
  while (*p != '\n' && *p != '\0')
 
347
    p++;
 
348
  if (*p == '\n')
 
349
    *p = '\0';
 
350
  char *new_desc;
 
351
  const size_t new_desc_size = sizeof(char) * (strlen(desc) + strlen(my_ctime_str) + 4);
 
352
  ink_assert(new_desc = (char *) alloca(new_desc_size));
 
353
  snprintf(new_desc, new_desc_size, "[%s] %s", my_ctime_str, desc);
 
354
  desc = new_desc;
 
355
  if (atmp->description)
 
356
    xfree(atmp->description);
 
357
  const size_t atmp_desc_size = sizeof(char) * (strlen(desc) + 1);
 
358
  ink_assert(atmp->description = (char *) xmalloc(atmp_desc_size));
 
359
  ink_strncpy(atmp->description, desc, atmp_desc_size);
 
360
 
 
361
  ink_mutex_release(&mutex);
 
362
 
 
363
#if defined(MGMT_API)
 
364
  if (mgmt_alarm_event_q) {
 
365
    // ADDED CODE here is where we Add to the queue of alarms one more
 
366
    EventNoticeForm *new_alarm;
 
367
 
 
368
    new_alarm = (EventNoticeForm *) xmalloc(sizeof(EventNoticeForm));
 
369
    if (!new_alarm) {
 
370
      Debug("alarm", "can't xmalloc so can't create new alarm struct.\n");
 
371
      return;
 
372
    }
 
373
    // allocated space copy over values
 
374
    // remember AlarmID start from 0 exactly 1 off but everything else
 
375
    // matches
 
376
    new_alarm->alarm_t = (AlarmID) (atmp->type - 1);
 
377
    new_alarm->priority = atmp->priority;
 
378
    new_alarm->linger = atmp->linger;
 
379
    new_alarm->local = atmp->local;
 
380
    new_alarm->seen = atmp->seen;
 
381
    if (!atmp->local)
 
382
      new_alarm->inet_address = atmp->inet_address;
 
383
    if (!atmp->description)
 
384
      new_alarm->description = NULL;
 
385
    else {
 
386
      new_alarm->description = (char *) xmalloc(sizeof(char) * (strlen(atmp->description) + 1));
 
387
      if (!new_alarm->description)
 
388
        new_alarm->description = NULL;  // rather have alarm without description than drop it completely
 
389
      else
 
390
        strcpy(new_alarm->description, atmp->description);
 
391
    }
 
392
 
 
393
    // new alarm is complete now add it
 
394
    ink_mutex_acquire(&mgmt_alarm_event_q->mgmt_alarm_lock);
 
395
 
 
396
    // enqueue
 
397
    enqueue(mgmt_alarm_event_q->mgmt_alarm_q, new_alarm);
 
398
 
 
399
    ink_mutex_release(&mgmt_alarm_event_q->mgmt_alarm_lock);
 
400
  }
 
401
#endif
 
402
 
 
403
  for (entry = ink_hash_table_iterator_first(cblist, &iterator_state);
 
404
       entry != NULL; entry = ink_hash_table_iterator_next(cblist, &iterator_state)) {
 
405
    char *tmp, *tmp2;
 
406
    AlarmCallbackFunc func = (AlarmCallbackFunc) ink_hash_table_entry_value(remote_alarms, entry);
 
407
    if (ip) {
 
408
      const size_t tmp_size = sizeof(char) * (strlen(ip) + 1);
 
409
      ink_assert((tmp = (char *) xmalloc(tmp_size)));
 
410
      ink_strncpy(tmp, ip, tmp_size);
 
411
    } else {
 
412
      tmp = NULL;
 
413
    }
 
414
 
 
415
    if (desc) {
 
416
      const size_t tmp2_size = sizeof(char) * (strlen(desc) + 1);
 
417
      ink_assert((tmp2 = (char *) xmalloc(tmp2_size)));
 
418
      ink_strncpy(tmp2, desc, tmp2_size);
 
419
    } else {
 
420
      tmp2 = NULL;
 
421
    }
 
422
    Debug("alarm", "[Alarms::signalAlarm] invoke callback for %d", a);
 
423
    (*(func)) (a, tmp, tmp2);
 
424
  }
 
425
  /* Priority 2 alarms get signalled if they are the first unsolved occurence. */
 
426
  if (priority == 2 && alarm_bin && alarm_bin_path && !ip) {
 
427
    execAlarmBin(desc);
 
428
  }
 
429
 
 
430
  return;
 
431
}                               /* End Alarms::signalAlarm */
 
432
 
 
433
 
 
434
/*
 
435
 * resetSeenFlag(...)
 
436
 *   Function resets the "seen" flag for a given peer's alarms. This allows
 
437
 * us to flush alarms that may have expired naturally or were dealt.
 
438
 */
 
439
void
 
440
Alarms::resetSeenFlag(char *ip)
 
441
{
 
442
  InkHashTableEntry *entry;
 
443
  InkHashTableIteratorState iterator_state;
 
444
 
 
445
  ink_mutex_acquire(&mutex);
 
446
  for (entry = ink_hash_table_iterator_first(remote_alarms, &iterator_state);
 
447
       entry != NULL; entry = ink_hash_table_iterator_next(remote_alarms, &iterator_state)) {
 
448
 
 
449
    char *key = (char *) ink_hash_table_entry_key(remote_alarms, entry);
 
450
    Alarm *tmp = (Alarm *) ink_hash_table_entry_value(remote_alarms, entry);
 
451
 
 
452
    if (strstr(key, ip)) {
 
453
      tmp->seen = false;
 
454
    }
 
455
  }
 
456
  ink_mutex_release(&mutex);
 
457
  return;
 
458
}                               /* End Alarms::resetSeenFlag */
 
459
 
 
460
 
 
461
/*
 
462
 * clearUnSeen(...)
 
463
 *   This function is a sweeper functionto clean up those alarms that have
 
464
 * been taken care of through otehr local managers or at the peer itself.
 
465
 */
 
466
void
 
467
Alarms::clearUnSeen(char *ip)
 
468
{
 
469
  InkHashTableEntry *entry;
 
470
  InkHashTableIteratorState iterator_state;
 
471
 
 
472
  ink_mutex_acquire(&mutex);
 
473
  for (entry = ink_hash_table_iterator_first(remote_alarms, &iterator_state);
 
474
       entry != NULL; entry = ink_hash_table_iterator_next(remote_alarms, &iterator_state)) {
 
475
 
 
476
    char *key = (char *) ink_hash_table_entry_key(remote_alarms, entry);
 
477
    Alarm *tmp = (Alarm *) ink_hash_table_entry_value(remote_alarms, entry);
 
478
 
 
479
    if (strstr(key, ip)) {      /* Make sure alarm is for correct ip */
 
480
      if (!tmp->seen) {         /* Make sure we did not see it in peer's report */
 
481
        ink_hash_table_delete(remote_alarms, key);      /* Safe in iterator? */
 
482
        xfree(tmp->description);
 
483
        xfree(tmp);
 
484
      }
 
485
    }
 
486
  }
 
487
  ink_mutex_release(&mutex);
 
488
  return;
 
489
}                               /* End Alarms::clearUnSeen */
 
490
 
 
491
 
 
492
/*
 
493
 * constructAlarmMessage(...)
 
494
 *   This functions builds a message buffer for passing to peers. It basically
 
495
 * takes the current list of local alarms and builds an alarm message.
 
496
 */
 
497
void
 
498
Alarms::constructAlarmMessage(char *ip, char *message, int max)
 
499
{
 
500
  int n = 0, bsum = 0;
 
501
  char buf[4096];
 
502
  InkHashTableEntry *entry;
 
503
  InkHashTableIteratorState iterator_state;
 
504
 
 
505
  if (!ip) {
 
506
    return;
 
507
  }
 
508
  // Insert the standard mcast packet header
 
509
  n = ClusterCom::constructSharedPacketHeader(message, ip, max);
 
510
 
 
511
  ink_mutex_acquire(&mutex);
 
512
  if (!((n + (int) strlen("type: alarm\n")) < max)) {
 
513
    if (max >= 1) {
 
514
      message[0] = '\0';
 
515
    }
 
516
    return;
 
517
  }
 
518
 
 
519
  ink_strncpy(&message[n], "type: alarm\n", max - n);
 
520
  n += strlen("type: alarm\n");
 
521
  bsum = n;
 
522
  for (entry = ink_hash_table_iterator_first(local_alarms, &iterator_state);
 
523
       (entry != NULL && n < max); entry = ink_hash_table_iterator_next(local_alarms, &iterator_state)) {
 
524
 
 
525
    Alarm *tmp = (Alarm *) ink_hash_table_entry_value(remote_alarms, entry);
 
526
 
 
527
    if (tmp->description) {
 
528
      snprintf(buf, sizeof(buf), "alarm: %d %s\n", tmp->type, tmp->description);
 
529
    } else {
 
530
      snprintf(buf, sizeof(buf), "alarm: %d No details available\n", tmp->type);
 
531
    }
 
532
 
 
533
    if (!((n + (int) strlen(buf)) < max)) {
 
534
      break;
 
535
    }
 
536
    ink_strncpy(&message[n], buf, max - n);
 
537
    n += strlen(buf);
 
538
  }
 
539
 
 
540
  if (n == bsum) {              /* No alarms */
 
541
    if (!((n + (int) strlen("alarm: none\n")) < max)) {
 
542
      if (max >= 1) {
 
543
        message[0] = '\0';
 
544
      }
 
545
      return;
 
546
    }
 
547
    ink_strncpy(&message[n], "alarm: none\n", max - n);
 
548
    n += strlen("alarm: none\n");
 
549
  }
 
550
  ink_mutex_release(&mutex);
 
551
  return;
 
552
}                               /* End Alarms::constructAlarmMessage */
 
553
 
 
554
 
 
555
/*
 
556
 * checkSystemNAlert(...)
 
557
 *   This function should test the system and signal local alarms. Sending
 
558
 * out remote notification commands if necessary.
 
559
 */
 
560
void
 
561
Alarms::checkSystemNAlert()
 
562
{
 
563
  return;
 
564
}                               /* End Alarms::checkSystenNAlert */
 
565
 
 
566
void
 
567
Alarms::execAlarmBin(const char *desc)
 
568
{
 
569
  char cmd_line[1024];
 
570
  char *alarm_email_from_name = 0;
 
571
  char *alarm_email_from_addr = 0;
 
572
  char *alarm_email_to_addr = 0;
 
573
  bool found;
 
574
 
 
575
  // get email info
 
576
  alarm_email_from_name = REC_readString("proxy.config.product_name", &found);
 
577
  if (!found)
 
578
    alarm_email_from_name = 0;
 
579
  alarm_email_from_addr = REC_readString("proxy.config.admin.admin_user", &found);
 
580
  if (!found)
 
581
    alarm_email_from_addr = 0;
 
582
  alarm_email_to_addr = REC_readString("proxy.config.alarm_email", &found);
 
583
  if (!found)
 
584
    alarm_email_to_addr = 0;
 
585
 
 
586
#ifndef _WIN32
 
587
 
 
588
  int status;
 
589
  pid_t pid;
 
590
 
 
591
  ink_filepath_make(cmd_line, sizeof(cmd_line), alarm_bin_path, alarm_bin);
 
592
 
 
593
#ifdef POSIX_THREAD
 
594
  if ((pid = fork()) < 0)
 
595
#else
 
596
  if ((pid = fork1()) < 0)
 
597
#endif
 
598
  {
 
599
    mgmt_elog(stderr, "[Alarms::execAlarmBin] Unable to fork1 process\n");
 
600
  } else if (pid > 0) {         /* Parent */
 
601
    // INKqa11769
 
602
    bool script_done = false;
 
603
    time_t timeout = (time_t) REC_readInteger("proxy.config.alarm.script_runtime", &found);
 
604
    if (!found)
 
605
      timeout = 5;              // default time = 5 secs
 
606
    time_t time_delta = 0;
 
607
    time_t first_time = time(0);
 
608
    while (time_delta <= timeout) {
 
609
      // waitpid will return child's pid if status is available
 
610
      // or -1 if there is some problem; returns 0 if child status
 
611
      // is not available
 
612
      if (waitpid(pid, &status, WNOHANG) != 0) {
 
613
        Debug("alarm", "[Alarms::execAlarmBin] child pid %d has status", pid);
 
614
        script_done = true;
 
615
        break;
 
616
      }
 
617
      time_delta = time(0) - first_time;
 
618
    }
 
619
    // need to kill the child script process if it's not complete
 
620
    if (!script_done) {
 
621
      Debug("alarm", "[Alarms::execAlarmBin] kill child pid %d", pid);
 
622
      kill(pid, SIGKILL);
 
623
      waitpid(pid, &status, 0); // to reap the thread
 
624
    }
 
625
  } else {
 
626
    int res;
 
627
    if (alarm_email_from_name && alarm_email_from_addr && alarm_email_to_addr) {
 
628
      res = execl(cmd_line, alarm_bin, desc, alarm_email_from_name, alarm_email_from_addr, alarm_email_to_addr, (char*)NULL);
 
629
    } else {
 
630
      res = execl(cmd_line, alarm_bin, desc, (char*)NULL);
 
631
    }
 
632
    _exit(res);
 
633
  }
 
634
 
 
635
#else
 
636
 
 
637
  bool is_exe = true;
 
638
  char *fileExt = NULL;
 
639
 
 
640
  if ((fileExt = strchr(alarm_bin, '.')) != NULL) {
 
641
    if (ink_strcasecmp(fileExt, ".CMD") == 0 || ink_strcasecmp(fileExt, ".BAT") == 0) {
 
642
      is_exe = false;
 
643
    }
 
644
  }
 
645
 
 
646
  if (is_exe) {
 
647
    ink_filepath_make(cmd_line, alarm_bin_path, alarm_bin);
 
648
  } else {
 
649
    sprintf(cmd_line, "CMD.EXE /C \"%s\\%s\"", alarm_bin_path, alarm_bin);
 
650
  }
 
651
 
 
652
  SetEnvironmentVariable("TRAFFIC_SERVER_ALARM_MSG", desc);
 
653
  SetEnvironmentVariable("ADMIN_EMAIL", alarm_email_to_addr);
 
654
 
 
655
  STARTUPINFO suInfo;
 
656
  PROCESS_INFORMATION procInfo;
 
657
  ZeroMemory((PVOID) & suInfo, sizeof(suInfo));
 
658
 
 
659
  // hide the new console window from the user
 
660
  suInfo.cb = sizeof(STARTUPINFO);
 
661
  suInfo.dwFlags = STARTF_USESHOWWINDOW;
 
662
  suInfo.wShowWindow = SW_HIDE;
 
663
 
 
664
  if (CreateProcess(NULL, cmd_line, NULL,       // FIX THIS: process security attributes
 
665
                    NULL,       // FIX THIS: thread security attributes
 
666
                    FALSE,      // no need to make handles inheritable
 
667
                    0,          // FIX THIS: specify a priority
 
668
                    NULL,       // FIX THIS: specify environment variables
 
669
                    ts_base_dir,        // make script run from TSBase
 
670
                    &suInfo, &procInfo) == FALSE) {
 
671
    mgmt_elog(stderr, "[Alarm::execAlarmBin] CreateProcess error: %s\n", ink_last_err());
 
672
  } else {
 
673
    CloseHandle(procInfo.hThread);
 
674
    CloseHandle(procInfo.hProcess);
 
675
  }
 
676
 
 
677
#endif // !_WIN32
 
678
 
 
679
  // free memory
 
680
  if (alarm_email_from_name)
 
681
    xfree(alarm_email_from_name);
 
682
  if (alarm_email_from_addr)
 
683
    xfree(alarm_email_from_addr);
 
684
  if (alarm_email_to_addr)
 
685
    xfree(alarm_email_to_addr);
 
686
 
 
687
}
 
688
 
 
689
//
 
690
// getAlarmText
 
691
//
 
692
// returns the corresponding text for the alarm id
 
693
//
 
694
const char *
 
695
Alarms::getAlarmText(alarm_t id)
 
696
{
 
697
  const char *wda_conn_died = "The connection to the billing system is broken. Unable to retrieve user profile.";
 
698
  const char *wda_corr_data =
 
699
    "Could not read user profile or URL list from the billing system. The data received doesn't have the expected format.";
 
700
  const char *wda_xf_down = "The XF engine heartbeat could not be properly detected. It appears dead.";
 
701
 
 
702
  switch (id) {
 
703
  case MGMT_ALARM_WDA_BILLING_CONNECTION_DIED:
 
704
    return wda_conn_died;
 
705
  case MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA:
 
706
    return wda_corr_data;
 
707
  case MGMT_ALARM_WDA_XF_ENGINE_DOWN:
 
708
    return wda_xf_down;
 
709
  default:
 
710
    if (id < alarmTextNum)
 
711
      return alarmText[id];
 
712
    else
 
713
      return alarmText[0];      // "Unknown Alarm";
 
714
  }
 
715
}