Skip to content

Commit 8dd1ae4

Browse files
committed
res_alarmsystem: Fix breach reporting in phone-only mode.
BREACH was an "inferred" event in IP reporting mode, but can't be inferred if reporting by phone (or if IP has failed). The overhead of reporting by IP is small, so always report it from now on so that way it works properly in any configuration. The breach event was getting skipped Also, breach reporting could be delayed by as much as the ping interval; take the floor of the two so that we report breaches as soon as they occur.
1 parent c3f239a commit 8dd1ae4

1 file changed

Lines changed: 66 additions & 48 deletions

File tree

res/res_alarmsystem.c

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,7 +1285,9 @@ static int send_event_ip(struct alarm_client *c, const char *msg, int len)
12851285
return 0;
12861286
}
12871287

1288-
#define INFERRED_EVENT(e) (e == EVENT_INTERNET_LOST || e == EVENT_INTERNET_RESTORED || e == EVENT_ALARM_BREACH)
1288+
/* Breaches can technically be inferred if using IP reporting, but doesn't do much harm to send explicitly either way */
1289+
#define INFERRED_EVENT(e) (e == EVENT_INTERNET_LOST || e == EVENT_INTERNET_RESTORED)
1290+
#define NEED_TO_SEND_EVENT(c, e) (!INFERRED_EVENT(e))
12891291

12901292
/*! \brief Generate an event and add it to the send queue, and schedule it for delivery (but don't actually send it yet) */
12911293
static int generate_event(struct alarm_client *c, enum alarm_event_type event, struct alarm_sensor *s, const char *data)
@@ -1298,30 +1300,40 @@ static int generate_event(struct alarm_client *c, enum alarm_event_type event, s
12981300
struct alarm_event *e;
12991301

13001302
AST_LIST_LOCK(&c->events);
1301-
sequence_no = c->sequence_no;
1303+
1304+
if (NEED_TO_SEND_EVENT(c, event)) {
1305+
sequence_no = c->sequence_no++; /* Increment sequence number for the next event we send */
1306+
} else {
1307+
sequence_no = c->sequence_no;
1308+
}
1309+
13021310
if (event == EVENT_PING) {
13031311
strcpy(seqno, ""); /* No sequence number usage for pings */
13041312
strcpy(ddhhmmss, ""); /* No timestamp for pings */
13051313
} else {
13061314
/* INTERNET events: Since these events aren't sent to the server (they are inferred events by the server),
13071315
* don't consume a sequence number for them, or that will mess up synchronization. */
1308-
if (INFERRED_EVENT(event)) {
1316+
if (!NEED_TO_SEND_EVENT(c, event)) {
13091317
sequence_no = 0;
13101318
}
13111319
snprintf(seqno, sizeof(seqno), "%u", sequence_no);
13121320
build_ddhhmmss(ddhhmmss, sizeof(ddhhmmss));
13131321
}
13141322
len = snprintf(msgbuf, sizeof(msgbuf), "%s*%s*%s*%s*%d*%s*%s#", c->client_id, S_OR(c->client_pin, ""), seqno, ddhhmmss, event, s ? s->sensor_id : "", S_OR(data, ""));
1315-
if (event != EVENT_PING || !c->sequence_no) {
1316-
/* Don't log pings, except the first one, since that would be too noisy */
1323+
if (event != EVENT_PING) {
1324+
/* Don't log pings, since that would be too noisy */
13171325
alarm_client_log(c, sequence_no, ddhhmmss, event, s, data);
13181326
}
13191327

1320-
if (event != EVENT_PING && !INFERRED_EVENT(event)) {
1321-
/* Don't increment sequence number for pings,
1322-
* since it doesn't really matter for those,
1323-
* and that would unnecessarily increment every few seconds. */
1324-
c->sequence_no++;
1328+
if (event == EVENT_PING) {
1329+
AST_LIST_UNLOCK(&c->events);
1330+
/* Send the event directly via UDP now, and don't store it in the queue,
1331+
* since we'll keep retrying pings on a timer, no need to retry specific pings.
1332+
* Since it's UDP, this won't block.
1333+
* Also, we attempt pings regardless of the value of c->ip_connected.
1334+
* No way to know if the connection is back without constantly retrying. */
1335+
send_event_ip(c, msgbuf, len);
1336+
return 0;
13251337
}
13261338

13271339
/* If there is dialplan to execute for this event, do it async now */
@@ -1330,46 +1342,40 @@ static int generate_event(struct alarm_client *c, enum alarm_event_type event, s
13301342
}
13311343

13321344
/* Certain events aren't actually sent across the wire, they can be inferred by the server */
1333-
if (INFERRED_EVENT(event)) {
1345+
if (!NEED_TO_SEND_EVENT(c, event)) {
13341346
AST_LIST_UNLOCK(&c->events);
1347+
ast_debug(10, "Dropping event (can be inferred by server)\n");
13351348
return 0;
13361349
}
13371350

1338-
if (event == EVENT_PING) {
1351+
if (c->sfd == -1 && c->server_dialstr[0] == '\0') {
1352+
/* IP and phone are disabled, so we can't report to any server. */
13391353
AST_LIST_UNLOCK(&c->events);
1340-
/* Send the event directly via UDP now, and don't store it in the queue,
1341-
* since we'll keep retrying pings on a timer, no need to retry specific pings.
1342-
* Since it's UDP, this won't block.
1343-
* Also, we attempt pings regardless of the value of c->ip_connected.
1344-
* No way to know if the connection is back without constantly retrying. */
1345-
send_event_ip(c, msgbuf, len);
1346-
} else {
1347-
if (c->sfd == -1 && c->server_dialstr[0] == '\0') {
1348-
/* IP and phone are disabled, so we can't report to any server. */
1349-
AST_LIST_UNLOCK(&c->events);
1350-
return 1;
1351-
}
1352-
/* Add the event to the send queue for guaranteed FIFO delivery. */
1353-
e = ast_calloc(1, sizeof(*e) + len + 1);
1354-
if (!e) {
1355-
AST_LIST_UNLOCK(&c->events);
1356-
ast_log(LOG_ERROR, "Failed to add message to send queue\n");
1357-
return -1;
1358-
}
1359-
strcpy(e->data, msgbuf); /* Safe */
1360-
e->encoded = e->data;
1361-
e->seqno = sequence_no;
1362-
AST_LIST_INSERT_TAIL(&c->events, e, entry);
1354+
return 1;
1355+
}
1356+
/* Add the event to the send queue for guaranteed FIFO delivery. */
1357+
e = ast_calloc(1, sizeof(*e) + len + 1);
1358+
if (!e) {
1359+
AST_LIST_UNLOCK(&c->events);
1360+
ast_log(LOG_ERROR, "Failed to add message to send queue\n");
1361+
return -1;
1362+
}
1363+
strcpy(e->data, msgbuf); /* Safe */
1364+
e->encoded = e->data;
1365+
e->seqno = sequence_no;
1366+
AST_LIST_INSERT_TAIL(&c->events, e, entry);
13631367

1364-
if (event == EVENT_ALARM_BREACH) {
1365-
c->flush_messages |= FLUSH_BREACH; /* Normally if batch reporting is enabled, messages are queued and not reported in realtime, but breaches trigger immediate reporting */
1366-
}
1368+
if (event == EVENT_ALARM_BREACH) {
1369+
c->flush_messages |= FLUSH_BREACH; /* Normally if batch reporting is enabled, messages are queued and not reported in realtime, but breaches trigger immediate reporting */
1370+
/* Reset the phone sync failure counter as we want to try immediately to report this,
1371+
* even if we were previously unable to report by phone successfully. */
1372+
c->consecutive_failed_phonesyncs = 0;
1373+
}
13671374

1368-
/* Wake up the client thread to tell it to send the message */
1369-
ast_alertpipe_write(c->alertpipe);
1375+
/* Wake up the client thread to tell it to send the message */
1376+
ast_alertpipe_write(c->alertpipe);
13701377

1371-
AST_LIST_UNLOCK(&c->events);
1372-
}
1378+
AST_LIST_UNLOCK(&c->events);
13731379
return 0;
13741380
}
13751381

@@ -1688,7 +1694,7 @@ static int send_events_to_server_by_phone(struct alarm_client *c)
16881694
}
16891695

16901696
/* Wait for initial ACK from AlarmEventReceiver to synchronize */
1691-
res = ast_app_getdata_terminator(c->phonechan, "", buf, sizeof(buf), 60000, "*");
1697+
res = ast_app_getdata_terminator(c->phonechan, "", buf, sizeof(buf), 55000, "*");
16921698
if (res != AST_GETDATA_EMPTY_END_TERMINATED) {
16931699
ast_log(LOG_WARNING, "Failed to synchronize with reporting server\n");
16941700
ast_hangup(c->phonechan);
@@ -1913,9 +1919,21 @@ static void *client_thread(void *arg)
19131919
generate_event(c, EVENT_ALARM_OKAY, NULL, NULL);
19141920

19151921
while (!module_shutting_down) {
1916-
int res;
1922+
int res, this_poll_interval = poll_interval;
19171923
pfds[0].revents = pfds[1].revents = 0;
1918-
res = poll(pfds, numfds, poll_interval);
1924+
if (c->breach_time > 0) {
1925+
time_t now = time(NULL);
1926+
if ((1000 * (c->breach_time - now)) < poll_interval) {
1927+
/* A breach would occur before the poll interval would finish,
1928+
* use the smaller of the two. That way we report a breach as soon as possible. */
1929+
this_poll_interval = 1000 * (c->breach_time - now);
1930+
if (this_poll_interval <= 0) {
1931+
ast_log(LOG_WARNING, "Breach occured in the past? %lu < %lu\n", c->breach_time, now);
1932+
this_poll_interval = 0;
1933+
}
1934+
}
1935+
}
1936+
res = poll(pfds, numfds, this_poll_interval);
19191937
if (res < 0) {
19201938
if (module_shutting_down) {
19211939
ast_debug(3, "Client thread '%s' exiting\n", c->client_id);
@@ -2582,11 +2600,11 @@ static int alarmeventreceiver_exec(struct ast_channel *chan, const char *data)
25822600
}
25832601

25842602
/* Answer, since we need bidirectional audio */
2585-
if (ast_answer(chan)) {
2603+
if (ast_channel_state(chan) != AST_STATE_UP && ast_answer(chan)) {
25862604
return -1;
25872605
}
25882606

2589-
res = ast_dtmf_stream(chan, NULL, "*", 0, DTMF_LEN);
2607+
res = ast_dtmf_stream(chan, NULL, "*", DTMF_INBETWEEN_LEN, DTMF_LEN);
25902608
if (res) {
25912609
ast_log(LOG_WARNING, "Channel disappeared before ACK completed\n");
25922610
return -1;
@@ -2595,7 +2613,7 @@ static int alarmeventreceiver_exec(struct ast_channel *chan, const char *data)
25952613
/* Read the client ID and client PIN */
25962614
res = ast_app_getdata_terminator(chan, "", clientid, sizeof(clientid), 10000, "*");
25972615
if (res != AST_GETDATA_COMPLETE) {
2598-
ast_log(LOG_WARNING, "Failed to receive client ID\n");
2616+
ast_log(LOG_WARNING, "Failed to receive client ID (res: %d)\n", res);
25992617
return -1;
26002618
}
26012619
ast_debug(3, "Client ID received is '%s'\n", clientid);

0 commit comments

Comments
 (0)