aboutsummaryrefslogtreecommitdiffstats
path: root/res
diff options
context:
space:
mode:
authorbbryant <bbryant@f38db490-d61c-443f-a65b-d21fe96a405b>2010-09-09 18:51:52 +0000
committerbbryant <bbryant@f38db490-d61c-443f-a65b-d21fe96a405b>2010-09-09 18:51:52 +0000
commit722eb3c4c3cfa1c0cee915c949c5f95199ee24dd (patch)
tree25683963c5e51bdedd6211cd0ea92a85639505c3 /res
parent815b5b09da5e555add7bba3d8fca588e7611248a (diff)
Merged revisions 285710 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ........ r285710 | bbryant | 2010-09-09 14:50:13 -0400 (Thu, 09 Sep 2010) | 8 lines Fixes an issue with dialplan pattern matching where the specificity for pattern ranges and pattern special characters was inconsistent. (closes issue #16903) Reported by: Nick_Lewis Patches: pbx.c-specificity.patch uploaded by Nick Lewis (license 657) Tested by: Nick_Lewis ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.8@285711 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res')
-rw-r--r--res/res_ais.c20
-rw-r--r--res/res_calendar.c22
-rw-r--r--res/res_calendar_caldav.c14
-rw-r--r--res/res_calendar_ews.c82
-rw-r--r--res/res_calendar_icalendar.c8
-rw-r--r--res/res_config_odbc.c2
-rw-r--r--res/res_config_pgsql.c16
-rw-r--r--res/res_fax.c128
-rw-r--r--res/res_jabber.c23
-rw-r--r--res/res_musiconhold.c124
-rw-r--r--res/res_odbc.c3
-rw-r--r--res/res_pktccops.c35
-rw-r--r--res/res_rtp_asterisk.c21
-rw-r--r--res/res_srtp.c96
-rw-r--r--res/res_stun_monitor.c311
15 files changed, 786 insertions, 119 deletions
diff --git a/res/res_ais.c b/res/res_ais.c
index adb3290e1..9bcceeade 100644
--- a/res/res_ais.c
+++ b/res/res_ais.c
@@ -113,9 +113,9 @@ const char *ais_err2str(SaAisErrorT error)
static void *dispatch_thread_handler(void *data)
{
- SaSelectionObjectT clm_fd, evt_fd, max_fd;
+ SaSelectionObjectT clm_fd, evt_fd;
int res;
- fd_set read_fds;
+ struct pollfd pfd[2] = { { .events = POLLIN, }, { .events = POLLIN, } };
SaAisErrorT ais_res;
ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd);
@@ -132,24 +132,26 @@ static void *dispatch_thread_handler(void *data)
return NULL;
}
- max_fd = clm_fd > evt_fd ? clm_fd : evt_fd;
+ pfd[0].fd = clm_fd;
+ pfd[1].fd = evt_fd;
while (!dispatch_thread.stop) {
- FD_ZERO(&read_fds);
- FD_SET(clm_fd, &read_fds);
- FD_SET(evt_fd, &read_fds);
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
- res = ast_select(max_fd + 1, &read_fds, NULL, NULL, NULL);
+ res = ast_poll(pfd, 2, -1);
if (res == -1 && errno != EINTR && errno != EAGAIN) {
ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, "
"and the module will no longer operate.\n", strerror(errno));
break;
}
- if (FD_ISSET(clm_fd, &read_fds))
+ if (pfd[0].revents & POLLIN) {
saClmDispatch(clm_handle, SA_DISPATCH_ALL);
- if (FD_ISSET(evt_fd, &read_fds))
+ }
+ if (pfd[1].revents & POLLIN) {
saEvtDispatch(evt_handle, SA_DISPATCH_ALL);
+ }
}
return NULL;
diff --git a/res/res_calendar.c b/res/res_calendar.c
index 2de995933..183b40845 100644
--- a/res/res_calendar.c
+++ b/res/res_calendar.c
@@ -65,6 +65,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="description"><para>The text description of the event</para></enum>
<enum name="organizer"><para>The organizer of the event</para></enum>
<enum name="location"><para>The location of the eventt</para></enum>
+ <enum name="categories"><para>The categories of the event</para></enum>
+ <enum name="priority"><para>The priority of the event</para></enum>
<enum name="calendar"><para>The name of the calendar associated with the event</para></enum>
<enum name="uid"><para>The unique identifier for this event</para></enum>
<enum name="start"><para>The start time of the event</para></enum>
@@ -112,6 +114,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="description"><para>The full event description</para></enum>
<enum name="organizer"><para>The event organizer</para></enum>
<enum name="location"><para>The event location</para></enum>
+ <enum name="categories"><para>The categories of the event</para></enum>
+ <enum name="priority"><para>The priority of the event</para></enum>
<enum name="calendar"><para>The name of the calendar associted with the event</para></enum>
<enum name="uid"><para>The unique identifier for the event</para></enum>
<enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
@@ -142,6 +146,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="description"><para>The full event description</para></enum>
<enum name="organizer"><para>The event organizer</para></enum>
<enum name="location"><para>The event location</para></enum>
+ <enum name="categories"><para>The categories of the event</para></enum>
+ <enum name="priority"><para>The priority of the event</para></enum>
<enum name="uid"><para>The unique identifier for the event</para></enum>
<enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
<enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
@@ -786,6 +792,8 @@ static void copy_event_data(struct ast_calendar_event *dst, struct ast_calendar_
ast_string_field_set(dst, organizer, src->organizer);
ast_string_field_set(dst, location, src->location);
ast_string_field_set(dst, uid, src->uid);
+ ast_string_field_set(dst, categories, src->categories);
+ dst->priority = src->priority;
dst->owner = src->owner;
dst->start = src->start;
dst->end = src->end;
@@ -1228,6 +1236,10 @@ static int calendar_query_result_exec(struct ast_channel *chan, const char *cmd,
ast_copy_string(buf, entry->event->organizer, len);
} else if (!strcasecmp(args.field, "location")) {
ast_copy_string(buf, entry->event->location, len);
+ } else if (!strcasecmp(args.field, "categories")) {
+ ast_copy_string(buf, entry->event->categories, len);
+ } else if (!strcasecmp(args.field, "priority")) {
+ snprintf(buf, len, "%d", entry->event->priority);
} else if (!strcasecmp(args.field, "calendar")) {
ast_copy_string(buf, entry->event->owner->name, len);
} else if (!strcasecmp(args.field, "uid")) {
@@ -1313,6 +1325,10 @@ static int calendar_write_exec(struct ast_channel *chan, const char *cmd, char *
ast_string_field_set(event, organizer, values.value[j]);
} else if (!strcasecmp(fields.field[i], "location")) {
ast_string_field_set(event, location, values.value[j]);
+ } else if (!strcasecmp(fields.field[i], "categories")) {
+ ast_string_field_set(event, categories, values.value[j]);
+ } else if (!strcasecmp(fields.field[i], "priority")) {
+ event->priority = atoi(values.value[j]);
} else if (!strcasecmp(fields.field[i], "uid")) {
ast_string_field_set(event, uid, values.value[j]);
} else if (!strcasecmp(fields.field[i], "start")) {
@@ -1468,6 +1484,8 @@ static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, FORMAT2, "Description", event->description);
ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
ast_cli(a->fd, FORMAT2, "Location", event->location);
+ ast_cli(a->fd, FORMAT2, "Cartegories", event->categories);
+ ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
ast_cli(a->fd, FORMAT2, "UID", event->uid);
ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
@@ -1539,6 +1557,10 @@ static int calendar_event_read(struct ast_channel *chan, const char *cmd, char *
ast_copy_string(buf, event->organizer, len);
} else if (!strcasecmp(data, "location")) {
ast_copy_string(buf, event->location, len);
+ } else if (!strcasecmp(data, "categories")) {
+ ast_copy_string(buf, event->categories, len);
+ } else if (!strcasecmp(data, "priority")) {
+ snprintf(buf, len, "%d", event->priority);
} else if (!strcasecmp(data, "calendar")) {
ast_copy_string(buf, event->owner->name, len);
} else if (!strcasecmp(data, "uid")) {
diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c
index 664f25b87..e0d8c483e 100644
--- a/res/res_calendar_caldav.c
+++ b/res/res_calendar_caldav.c
@@ -216,6 +216,12 @@ static int caldav_write_event(struct ast_calendar_event *event)
if (!ast_strlen_zero(event->location)) {
icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
}
+ if (!ast_strlen_zero(event->categories)) {
+ icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories));
+ }
+ if (event->priority > 0) {
+ icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority));
+ }
switch (event->busy_state) {
case AST_CALENDAR_BS_BUSY:
@@ -365,6 +371,14 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
}
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
+ ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
+ }
+
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
+ event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
+ }
+
if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
} else {
diff --git a/res/res_calendar_ews.c b/res/res_calendar_ews.c
index 931e36854..840ca104e 100644
--- a/res/res_calendar_ews.c
+++ b/res/res_calendar_ews.c
@@ -87,6 +87,9 @@ enum {
XML_EVENT_ATTENDEE,
XML_EVENT_MAILBOX,
XML_EVENT_EMAIL_ADDRESS,
+ XML_EVENT_CATEGORIES,
+ XML_EVENT_CATEGORY,
+ XML_EVENT_IMPORTANCE,
};
struct ewscal_pvt {
@@ -271,6 +274,23 @@ static int startelm(void *userdata, int parent, const char *nspace, const char *
}
ast_str_reset(ctx->cdata);
return XML_EVENT_LOCATION;
+ } else if (!strcmp(name, "Categories")) {
+ /* Event categories */
+ if (!ctx->cdata) {
+ return NE_XML_ABORT;
+ }
+ ast_str_reset(ctx->cdata);
+ return XML_EVENT_CATEGORIES;
+ } else if (parent == XML_EVENT_CATEGORIES && !strcmp(name, "String")) {
+ /* Event category */
+ return XML_EVENT_CATEGORY;
+ } else if (!strcmp(name, "Importance")) {
+ /* Event importance (priority) */
+ if (!ctx->cdata) {
+ return NE_XML_ABORT;
+ }
+ ast_str_reset(ctx->cdata);
+ return XML_EVENT_IMPORTANCE;
} else if (!strcmp(name, "RequiredAttendees") || !strcmp(name, "OptionalAttendees")) {
return XML_EVENT_ATTENDEE_LIST;
} else if (!strcmp(name, "Attendee") && parent == XML_EVENT_ATTENDEE_LIST) {
@@ -331,6 +351,13 @@ static int cdata(void *userdata, int state, const char *cdata, size_t len)
ctx->event->busy_state = AST_CALENDAR_BS_FREE;
}
break;
+ case XML_EVENT_CATEGORY:
+ if (ast_str_strlen(ctx->cdata) == 0) {
+ ast_str_set(&ctx->cdata, 0, "%s", data);
+ } else {
+ ast_str_append(&ctx->cdata, 0, ",%s", data);
+ }
+ break;
default:
ast_str_append(&ctx->cdata, 0, "%s", data);
}
@@ -364,6 +391,22 @@ static int endelm(void *userdata, int state, const char *nspace, const char *nam
ast_string_field_set(ctx->event, location, ast_str_buffer(ctx->cdata));
ast_debug(3, "EWS: XML: Location: %s\n", ctx->event->location);
ast_str_reset(ctx->cdata);
+ } else if (!strcmp(name, "Categories")) {
+ /* Event categories end */
+ ast_string_field_set(ctx->event, categories, ast_str_buffer(ctx->cdata));
+ ast_debug(3, "EWS: XML: Categories: %s\n", ctx->event->categories);
+ ast_str_reset(ctx->cdata);
+ } else if (!strcmp(name, "Importance")) {
+ /* Event importance end */
+ if (!strcmp(ast_str_buffer(ctx->cdata), "Low")) {
+ ctx->event->priority = 9;
+ } else if (!strcmp(ast_str_buffer(ctx->cdata), "Normal")) {
+ ctx->event->priority = 5;
+ } else if (!strcmp(ast_str_buffer(ctx->cdata), "High")) {
+ ctx->event->priority = 1;
+ }
+ ast_debug(3, "EWS: XML: Importance: %s (%d)\n", ast_str_buffer(ctx->cdata), ctx->event->priority);
+ ast_str_reset(ctx->cdata);
} else if (state == XML_EVENT_EMAIL_ADDRESS) {
struct ast_calendar_attendee *attendee;
@@ -501,6 +544,7 @@ static int ewscal_write_event(struct ast_calendar_event *event)
.pvt = pvt,
};
int ret;
+ char *category, *categories;
if (!pvt) {
return -1;
@@ -531,12 +575,7 @@ static int ewscal_write_event(struct ast_calendar_event *event)
"<End>%s</End>"
"<IsAllDayEvent>false</IsAllDayEvent>"
"<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>"
- "<Location>%s</Location>"
- "</t:CalendarItem>"
- "</Items>"
- "</CreateItem>"
- "</soap:Body>"
- "</soap:Envelope>",
+ "<Location>%s</Location>",
event->summary,
event->description,
mstime(event->start, start, sizeof(start)),
@@ -544,6 +583,37 @@ static int ewscal_write_event(struct ast_calendar_event *event)
msstatus(event->busy_state),
event->location
);
+ /* Event priority */
+ switch (event->priority) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ ast_str_append(&request, 0, "<Importance>High</Importance>");
+ break;
+ case 5:
+ ast_str_append(&request, 0, "<Importance>Normal</Importance>");
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ ast_str_append(&request, 0, "<Importance>Low</Importance>");
+ break;
+ }
+ /* Event categories*/
+ if (strlen(event->categories) > 0) {
+ ast_str_append(&request, 0, "<Categories>");
+ categories = ast_strdupa(event->categories); /* Duplicate string, since strsep() is destructive */
+ category = strsep(&categories, ",");
+ while (category != NULL) {
+ ast_str_append(&request, 0, "<String>%s</String>", category);
+ category = strsep(&categories, ",");
+ }
+ ast_str_append(&request, 0, "</Categories>");
+ }
+ /* Finish request */
+ ast_str_append(&request, 0, "</t:CalendarItem></Items></CreateItem></soap:Body></soap:Envelope>");
ret = send_ews_request_and_parse(request, &ctx);
diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c
index 2eda35245..300da2ac9 100644
--- a/res/res_calendar_icalendar.c
+++ b/res/res_calendar_icalendar.c
@@ -224,6 +224,14 @@ static void icalendar_add_event(icalcomponent *comp, struct icaltime_span *span,
ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
}
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
+ ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
+ }
+
+ if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
+ event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
+ }
+
if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
} else {
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index 15534c7fa..64628c286 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -62,7 +62,7 @@ static void decode_chunk(char *chunk)
{
for (; *chunk; chunk++) {
if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
- sscanf(chunk + 1, "%02hhd", chunk);
+ sscanf(chunk + 1, "%02hhX", chunk);
memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
}
}
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index e356e8f83..b4398e8c9 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -1179,12 +1179,16 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap
size, column->type);
res = -1;
}
- } else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
- ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
- res = -1;
- } else if (strncmp(column->type, "timestamp", 9) == 0 && type != RQ_DATETIME) {
- ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
- res = -1;
+ } else if (strncmp(column->type, "float", 5) == 0) {
+ if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
+ ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
+ res = -1;
+ }
+ } else if (strncmp(column->type, "timestamp", 9) == 0) {
+ if (type != RQ_DATETIME && type != RQ_DATE) {
+ ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
+ res = -1;
+ }
} else { /* There are other types that no module implements yet */
ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
res = -1;
diff --git a/res/res_fax.c b/res/res_fax.c
index 03fd128a7..3da2d02f8 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -387,9 +387,6 @@ static struct ast_fax_session_details *session_details_new(void)
d->modems = general_options.modems;
d->minrate = general_options.minrate;
d->maxrate = general_options.maxrate;
- ast_string_field_set(d, result, "FAILED");
- ast_string_field_set(d, resultstr, "error starting fax session");
- ast_string_field_set(d, error, "INIT_ERROR");
return d;
}
@@ -500,6 +497,45 @@ static int ast_fax_modem_to_str(enum ast_fax_modems bits, char *tbuf, size_t buf
return 0;
}
+static int check_modem_rate(enum ast_fax_modems modems, unsigned int rate)
+{
+ switch (rate) {
+ case 2400:
+ if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 4800:
+ if (!(modems & (AST_FAX_MODEM_V27 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 7200:
+ case 9600:
+ if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V29 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 12000:
+ case 14400:
+ if (!(modems & (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V34))) {
+ return 1;
+ }
+ break;
+ case 28800:
+ case 33600:
+ if (!(modems & AST_FAX_MODEM_V34)) {
+ return 1;
+ }
+ break;
+ default:
+ /* this should never happen */
+ return 1;
+ }
+
+ return 0;
+}
+
/*! \brief register a FAX technology module */
int ast_fax_tech_register(struct ast_fax_tech *tech)
{
@@ -1363,7 +1399,7 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
/*! \brief initiate a receive FAX session */
static int receivefax_exec(struct ast_channel *chan, const char *data)
{
- char *parse;
+ char *parse, modems[128] = "";
int channel_alive;
struct ast_fax_session_details *details;
struct ast_fax_document *doc;
@@ -1390,8 +1426,40 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
return -1;
}
+ ast_string_field_set(details, result, "FAILED");
+ ast_string_field_set(details, resultstr, "error starting fax session");
+ ast_string_field_set(details, error, "INIT_ERROR");
set_channel_variables(chan, details);
+ if (details->maxrate < details->minrate) {
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "maxrate is less than minrate");
+ set_channel_variables(chan, details);
+ ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->minrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->maxrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
if (ast_strlen_zero(data)) {
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "invalid arguments");
@@ -1768,7 +1836,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
/*! \brief initiate a send FAX session */
static int sendfax_exec(struct ast_channel *chan, const char *data)
{
- char *parse, *filenames, *c;
+ char *parse, *filenames, *c, modems[128] = "";
int channel_alive, file_count;
struct ast_fax_session_details *details;
struct ast_fax_document *doc;
@@ -1795,8 +1863,40 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
return -1;
}
+ ast_string_field_set(details, result, "FAILED");
+ ast_string_field_set(details, resultstr, "error starting fax session");
+ ast_string_field_set(details, error, "INIT_ERROR");
set_channel_variables(chan, details);
+ if (details->maxrate < details->minrate) {
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "maxrate is less than minrate");
+ set_channel_variables(chan, details);
+ ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", details->maxrate, details->minrate);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->minrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, details->minrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'minrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
+ if (check_modem_rate(details->modems, details->maxrate)) {
+ ast_fax_modem_to_str(details->modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, details->maxrate);
+ ast_string_field_set(details, error, "INVALID_ARGUMENTS");
+ ast_string_field_set(details, resultstr, "incompatible 'modems' and 'maxrate' settings");
+ set_channel_variables(chan, details);
+ ao2_ref(details, -1);
+ return -1;
+ }
+
if (ast_strlen_zero(data)) {
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
ast_string_field_set(details, resultstr, "invalid arguments");
@@ -2292,6 +2392,7 @@ static int set_config(const char *config_file)
struct ast_config *cfg;
struct ast_variable *v;
struct ast_flags config_flags = { 0 };
+ char modems[128] = "";
/* set defaults */
general_options.minrate = RES_FAX_MINRATE;
@@ -2342,6 +2443,23 @@ static int set_config(const char *config_file)
ast_config_destroy(cfg);
+ if (general_options.maxrate < general_options.minrate) {
+ ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", general_options.maxrate, general_options.minrate);
+ return -1;
+ }
+
+ if (check_modem_rate(general_options.modems, general_options.minrate)) {
+ ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, general_options.minrate);
+ return -1;
+ }
+
+ if (check_modem_rate(general_options.modems, general_options.maxrate)) {
+ ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
+ ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, general_options.maxrate);
+ return -1;
+ }
+
return 0;
}
diff --git a/res/res_jabber.c b/res/res_jabber.c
index 5238441f1..13c7bf2cd 100644
--- a/res/res_jabber.c
+++ b/res/res_jabber.c
@@ -1283,38 +1283,27 @@ static int aji_tls_handshake(struct aji_client *client)
*/
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
{
- int sock;
- fd_set fds;
- struct timeval tv, *tvptr = NULL;
+ struct pollfd pfd = { .events = POLLIN };
int len, res;
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
- sock = SSL_get_fd(client->ssl_session);
- if (sock < 0) {
+ pfd.fd = SSL_get_fd(client->ssl_session);
+ if (pfd.fd < 0) {
return -1;
}
} else
#endif /* HAVE_OPENSSL */
- sock = iks_fd(client->p);
-
- memset(&tv, 0, sizeof(struct timeval));
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
- tv.tv_sec = timeout;
-
- /* NULL value for tvptr makes ast_select wait indefinitely */
- tvptr = (timeout != -1) ? &tv : NULL;
+ pfd.fd = iks_fd(client->p);
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
+ res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
if (res > 0) {
#ifdef HAVE_OPENSSL
if (aji_is_secure(client)) {
len = SSL_read(client->ssl_session, buffer, buf_len);
} else
#endif /* HAVE_OPENSSL */
- len = recv(sock, buffer, buf_len, 0);
+ len = recv(pfd.fd, buffer, buf_len, 0);
if (len > 0) {
return len;
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 2361b2280..6024e9da8 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -41,16 +41,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
-#include <sys/ioctl.h>
#ifdef SOLARIS
#include <thread.h>
#endif
-#ifdef HAVE_DAHDI
-#include <dahdi/user.h>
-#endif
-
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
@@ -68,6 +63,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/manager.h"
#include "asterisk/paths.h"
#include "asterisk/astobj2.h"
+#include "asterisk/timing.h"
+#include "asterisk/time.h"
+#include "asterisk/poll-compat.h"
#define INITIAL_NUM_FILES 8
#define HANDLE_REF 1
@@ -198,10 +196,10 @@ struct mohclass {
pthread_t thread;
/*! Source of audio */
int srcfd;
- /*! FD for timing source */
- int pseudofd;
+ /*! Generic timer */
+ struct ast_timer *timer;
/*! Created on the fly, from RT engine */
- int realtime;
+ unsigned int realtime:1;
unsigned int delete:1;
AST_LIST_HEAD_NOLOCK(, mohdata) members;
AST_LIST_ENTRY(mohclass) list;
@@ -320,10 +318,17 @@ static int ast_moh_files_next(struct ast_channel *chan)
state->samples = 0;
}
- if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
+ for (tries = 0; tries < state->class->total_files; ++tries) {
+ if (ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
+ break;
+ }
+
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
state->pos++;
state->pos %= state->class->total_files;
+ }
+
+ if (tries == state->class->total_files) {
return -1;
}
@@ -607,9 +612,8 @@ static void *monmp3thread(void *data)
struct mohclass *class = data;
struct mohdata *moh;
- char buf[8192];
short sbuf[8192];
- int res, res2;
+ int res = 0, res2;
int len;
struct timeval deadline, tv_tmp;
@@ -626,12 +630,22 @@ static void *monmp3thread(void *data)
pthread_testcancel();
}
}
- if (class->pseudofd > -1) {
+ if (class->timer) {
+ struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN, };
+ struct timeval tv;
+
#ifdef SOLARIS
thr_yield();
#endif
/* Pause some amount of time */
- res = read(class->pseudofd, buf, sizeof(buf));
+ tv = ast_tvnow();
+ if (ast_poll(&pfd, 1, -1) > 0) {
+ ast_timer_ack(class->timer, 1);
+ res = 320;
+ } else {
+ ast_log(LOG_ERROR, "poll() failed: %s\n", strerror(errno));
+ res = 0;
+ }
pthread_testcancel();
} else {
long delta;
@@ -1107,6 +1121,19 @@ static int init_files_class(struct mohclass *class)
return 0;
}
+static void moh_rescan_files(void) {
+ struct ao2_iterator i;
+ struct mohclass *c;
+
+ i = ao2_iterator_init(mohclasses, 0);
+
+ while ((c = ao2_iterator_next(&i))) {
+ moh_scan_files(c);
+ ao2_ref(c, -1);
+ }
+
+ ao2_iterator_destroy(&i);
+}
static int moh_diff(struct mohclass *old, struct mohclass *new)
{
@@ -1129,10 +1156,6 @@ static int moh_diff(struct mohclass *old, struct mohclass *new)
static int init_app_class(struct mohclass *class)
{
-#ifdef HAVE_DAHDI
- int x;
-#endif
-
if (!strcasecmp(class->mode, "custom")) {
ast_set_flag(class, MOH_CUSTOM);
} else if (!strcasecmp(class->mode, "mp3nb")) {
@@ -1142,27 +1165,23 @@ static int init_app_class(struct mohclass *class)
} else if (!strcasecmp(class->mode, "quietmp3")) {
ast_set_flag(class, MOH_QUIET);
}
-
+
class->srcfd = -1;
- class->pseudofd = -1;
-
-#ifdef HAVE_DAHDI
- /* Open /dev/zap/pseudo for timing... Is
- there a better, yet reliable way to do this? */
- class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
- if (class->pseudofd < 0) {
- ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n");
- } else {
- x = 320;
- ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
+
+ if (!(class->timer = ast_timer_open())) {
+ ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
+ }
+ if (class->timer && ast_timer_set_rate(class->timer, 25)) {
+ ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
+ ast_timer_close(class->timer);
+ class->timer = NULL;
}
-#endif
if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
ast_log(LOG_WARNING, "Unable to create moh thread...\n");
- if (class->pseudofd > -1) {
- close(class->pseudofd);
- class->pseudofd = -1;
+ if (class->timer) {
+ ast_timer_close(class->timer);
+ class->timer = NULL;
}
return -1;
}
@@ -1192,7 +1211,7 @@ static int _moh_register(struct mohclass *moh, int reload, int unref, const char
time(&moh->start);
moh->start -= respawn_time;
-
+
if (!strcasecmp(moh->mode, "files")) {
if (init_files_class(moh)) {
if (unref) {
@@ -1222,7 +1241,7 @@ static int _moh_register(struct mohclass *moh, int reload, int unref, const char
if (unref) {
moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
}
-
+
return 0;
}
@@ -1390,7 +1409,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
time(&mohclass->start);
mohclass->start -= respawn_time;
-
+
if (!strcasecmp(mohclass->mode, "files")) {
if (!moh_scan_files(mohclass)) {
mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
@@ -1408,21 +1427,17 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
else if (!strcasecmp(mohclass->mode, "quietmp3"))
ast_set_flag(mohclass, MOH_QUIET);
-
+
mohclass->srcfd = -1;
-#ifdef HAVE_DAHDI
- /* Open /dev/dahdi/pseudo for timing... Is
- there a better, yet reliable way to do this? */
- mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
- if (mohclass->pseudofd < 0) {
- ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n");
- } else {
- int x = 320;
- ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
+ if (!(mohclass->timer = ast_timer_open())) {
+ ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
}
-#else
- mohclass->pseudofd = -1;
-#endif
+ if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
+ ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
+ ast_timer_close(mohclass->timer);
+ mohclass->timer = NULL;
+ }
+
/* Let's check if this channel already had a moh class before */
if (state && state->class) {
/* Class already exist for this channel */
@@ -1435,9 +1450,9 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
} else {
if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
ast_log(LOG_WARNING, "Unable to create moh...\n");
- if (mohclass->pseudofd > -1) {
- close(mohclass->pseudofd);
- mohclass->pseudofd = -1;
+ if (mohclass->timer) {
+ ast_timer_close(mohclass->timer);
+ mohclass->timer = NULL;
}
mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
return -1;
@@ -1612,13 +1627,16 @@ static int load_moh_classes(int reload)
ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
}
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+ moh_rescan_files();
+ }
return 0;
}
if (reload) {
ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
}
-
+
ast_clear_flag(global_flags, AST_FLAGS_ALL);
cat = ast_category_browse(cfg, NULL);
diff --git a/res/res_odbc.c b/res/res_odbc.c
index d2ee97948..6e179efff 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -780,6 +780,7 @@ static int load_odbc_config(void)
pooling = 0;
limit = 0;
bse = 1;
+ conntimeout = 10;
forcecommit = 0;
isolation = SQL_TXN_READ_COMMITTED;
for (v = ast_variable_browse(config, cat); v; v = v->next) {
@@ -1203,7 +1204,7 @@ struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags
unsigned char state[10], diagnostic[256];
if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
- ast_debug(1, "Class not found!\n");
+ ast_debug(1, "Class '%s' not found!\n", name);
return NULL;
}
diff --git a/res/res_pktccops.c b/res/res_pktccops.c
index 8069e723d..33ecc3817 100644
--- a/res/res_pktccops.c
+++ b/res/res_pktccops.c
@@ -703,9 +703,8 @@ static void *do_pktccops(void *data)
int res, nfds, len;
struct copsmsg *recmsg, *sendmsg;
struct copsmsg recmsgb, sendmsgb;
- fd_set rfds;
- struct timeval tv;
- struct pktcobj *pobject;
+ struct pollfd *pfds = NULL, *tmp;
+ struct pktcobj *pobject;
struct cops_cmts *cmts;
struct cops_gate *gate;
char *sobjp;
@@ -719,9 +718,8 @@ static void *do_pktccops(void *data)
ast_debug(3, "COPS: thread started\n");
for (;;) {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- FD_ZERO(&rfds);
+ ast_free(pfds);
+ pfds = NULL;
nfds = 0;
AST_LIST_LOCK(&cmts_list);
AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
@@ -735,15 +733,27 @@ static void *do_pktccops(void *data)
}
}
if (cmts->sfd > 0) {
- FD_SET(cmts->sfd, &rfds);
- if (cmts->sfd > nfds) nfds = cmts->sfd;
+ if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
+ continue;
+ }
+ pfds = tmp;
+ pfds[nfds].fd = cmts->sfd;
+ pfds[nfds].events = POLLIN;
+ pfds[nfds].revents = 0;
+ nfds++;
} else {
cmts->sfd = cops_connect(cmts->host, cmts->port);
if (cmts->sfd > 0) {
cmts->state = 1;
if (cmts->sfd > 0) {
- FD_SET(cmts->sfd, &rfds);
- if (cmts->sfd > nfds) nfds = cmts->sfd;
+ if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
+ continue;
+ }
+ pfds = tmp;
+ pfds[nfds].fd = cmts->sfd;
+ pfds[nfds].events = POLLIN;
+ pfds[nfds].revents = 0;
+ nfds++;
}
}
}
@@ -781,10 +791,11 @@ static void *do_pktccops(void *data)
if (pktcreload == 2) {
pktcreload = 0;
}
- if ((res = select(nfds + 1, &rfds, NULL, NULL, &tv))) {
+ if ((res = ast_poll(pfds, nfds, 1000))) {
AST_LIST_LOCK(&cmts_list);
AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
- if (FD_ISSET(cmts->sfd, &rfds)) {
+ int idx;
+ if ((idx = ast_poll_fd_index(pfds, nfds, cmts->sfd)) > -1 && (pfds[idx].revents & POLLIN)) {
len = cops_getmsg(cmts->sfd, recmsg);
if (len > 0) {
ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%i\n",
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 396aed533..6ddd33902 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -270,6 +270,7 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1);
static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username);
static void ast_rtp_stop(struct ast_rtp_instance *instance);
+static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char* desc);
/* RTP Engine Declaration */
static struct ast_rtp_engine asterisk_rtp_engine = {
@@ -293,6 +294,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
.dtmf_compatible = ast_rtp_dtmf_compatible,
.stun_request = ast_rtp_stun_request,
.stop = ast_rtp_stop,
+ .qos = ast_rtp_qos_set,
};
static inline int rtp_debug_test_addr(struct ast_sockaddr *addr)
@@ -715,12 +717,24 @@ static void ast_rtp_update_source(struct ast_rtp_instance *instance)
static void ast_rtp_change_source(struct ast_rtp_instance *instance)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
unsigned int ssrc = ast_random();
+ if (!rtp->lastts) {
+ ast_debug(3, "Not changing SSRC since we haven't sent any RTP yet\n");
+ return;
+ }
+
/* We simply set this bit so that the next packet sent will have the marker bit turned on */
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
+
+ if (srtp) {
+ ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
+ res_srtp->change_source(srtp, rtp->ssrc, ssrc);
+ }
+
rtp->ssrc = ssrc;
return;
@@ -2549,6 +2563,13 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance)
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
}
+static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
+{
+ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+ return ast_set_qos(rtp->s, tos, cos, desc);
+}
+
static char *rtp_do_debug_ip(struct ast_cli_args *a)
{
char *arg = ast_strdupa(a->argv[4]);
diff --git a/res/res_srtp.c b/res/res_srtp.c
index 546f0733d..f92154f90 100644
--- a/res/res_srtp.c
+++ b/res/res_srtp.c
@@ -53,14 +53,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/rtp_engine.h"
+#include "asterisk/astobj2.h"
struct ast_srtp {
struct ast_rtp_instance *rtp;
+ struct ao2_container *policies;
srtp_t session;
const struct ast_srtp_cb *cb;
void *data;
unsigned char buf[8192 + AST_FRIENDLY_OFFSET];
- unsigned int has_stream:1;
};
struct ast_srtp_policy {
@@ -73,6 +74,7 @@ static int g_initialized = 0;
static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy);
static void ast_srtp_destroy(struct ast_srtp *srtp);
static int ast_srtp_add_stream(struct ast_srtp *srtp, struct ast_srtp_policy *policy);
+static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc);
static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rtcp);
static int ast_srtp_protect(struct ast_srtp *srtp, void **buf, int *len, int rtcp);
@@ -90,6 +92,7 @@ static struct ast_srtp_res srtp_res = {
.create = ast_srtp_create,
.destroy = ast_srtp_destroy,
.add_stream = ast_srtp_add_stream,
+ .change_source = ast_srtp_change_source,
.set_cb = ast_srtp_set_cb,
.unprotect = ast_srtp_unprotect,
.protect = ast_srtp_protect,
@@ -144,6 +147,32 @@ static const char *srtp_errstr(int err)
}
}
+static int policy_hash_fn(const void *obj, const int flags)
+{
+ const struct ast_srtp_policy *policy = obj;
+
+ return policy->sp.ssrc.type == ssrc_specific ? policy->sp.ssrc.value : policy->sp.ssrc.type;
+}
+
+static int policy_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct ast_srtp_policy *one = obj, *two = arg;
+
+ return one->sp.ssrc.type == two->sp.ssrc.type && one->sp.ssrc.value == two->sp.ssrc.value;
+}
+
+static struct ast_srtp_policy *find_policy(struct ast_srtp *srtp, const srtp_policy_t *policy, int flags)
+{
+ struct ast_srtp_policy tmp = {
+ .sp = {
+ .ssrc.type = policy->ssrc.type,
+ .ssrc.value = policy->ssrc.value,
+ },
+ };
+
+ return ao2_t_find(srtp->policies, &tmp, flags, "Looking for policy");
+}
+
static struct ast_srtp *res_srtp_new(void)
{
struct ast_srtp *srtp;
@@ -153,6 +182,11 @@ static struct ast_srtp *res_srtp_new(void)
return NULL;
}
+ if (!(srtp->policies = ao2_t_container_alloc(5, policy_hash_fn, policy_cmp_fn, "SRTP policy container"))) {
+ ast_free(srtp);
+ return NULL;
+ }
+
return srtp;
}
@@ -188,11 +222,21 @@ static void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy,
}
}
+static void policy_destructor(void *obj)
+{
+ struct ast_srtp_policy *policy = obj;
+
+ if (policy->sp.key) {
+ ast_free(policy->sp.key);
+ policy->sp.key = NULL;
+ }
+}
+
static struct ast_srtp_policy *ast_srtp_policy_alloc()
{
struct ast_srtp_policy *tmp;
- if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+ if (!(tmp = ao2_t_alloc(sizeof(*tmp), policy_destructor, "Allocating policy"))) {
ast_log(LOG_ERROR, "Unable to allocate memory for srtp_policy\n");
}
@@ -201,11 +245,7 @@ static struct ast_srtp_policy *ast_srtp_policy_alloc()
static void ast_srtp_policy_destroy(struct ast_srtp_policy *policy)
{
- if (policy->sp.key) {
- ast_free(policy->sp.key);
- policy->sp.key = NULL;
- }
- ast_free(policy);
+ ao2_t_ref(policy, -1, "Destroying policy");
}
static int policy_set_suite(crypto_policy_t *p, enum ast_srtp_suite suite)
@@ -344,6 +384,8 @@ static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp,
temp->rtp = rtp;
*srtp = temp;
+ ao2_t_link((*srtp)->policies, policy, "Created initial policy");
+
return 0;
}
@@ -353,16 +395,52 @@ static void ast_srtp_destroy(struct ast_srtp *srtp)
srtp_dealloc(srtp->session);
}
+ ao2_t_callback(srtp->policies, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Unallocate policy");
+ ao2_t_ref(srtp->policies, -1, "Destroying container");
+
ast_free(srtp);
}
static int ast_srtp_add_stream(struct ast_srtp *srtp, struct ast_srtp_policy *policy)
{
- if (!srtp->has_stream && srtp_add_stream(srtp->session, &policy->sp) != err_status_ok) {
+ struct ast_srtp_policy *match;
+
+ if ((match = find_policy(srtp, &policy->sp, OBJ_POINTER))) {
+ ast_debug(3, "Policy already exists, not re-adding\n");
+ ao2_t_ref(match, -1, "Unreffing already existing policy");
return -1;
}
- srtp->has_stream = 1;
+ if (srtp_add_stream(srtp->session, &policy->sp) != err_status_ok) {
+ return -1;
+ }
+
+ ao2_t_link(srtp->policies, policy, "Added additional stream");
+
+ return 0;
+}
+
+static int ast_srtp_change_source(struct ast_srtp *srtp, unsigned int from_ssrc, unsigned int to_ssrc)
+{
+ struct ast_srtp_policy *match;
+ struct srtp_policy_t sp = {
+ .ssrc.type = ssrc_specific,
+ .ssrc.value = from_ssrc,
+ };
+ err_status_t status;
+
+ /* If we find a mach, return and unlink it from the container so we
+ * can change the SSRC (which is part of the hash) and then have
+ * ast_srtp_add_stream link it back in if all is well */
+ if ((match = find_policy(srtp, &sp, OBJ_POINTER | OBJ_UNLINK))) {
+ match->sp.ssrc.value = to_ssrc;
+ if (ast_srtp_add_stream(srtp, match)) {
+ ast_log(LOG_WARNING, "Couldn't add stream\n");
+ } else if ((status = srtp_remove_stream(srtp->session, from_ssrc))) {
+ ast_debug(3, "Couldn't remove stream (%d)\n", status);
+ }
+ ao2_t_ref(match, -1, "Unreffing found policy in change_source");
+ }
return 0;
}
diff --git a/res/res_stun_monitor.c b/res/res_stun_monitor.c
new file mode 100644
index 000000000..54be1e44c
--- /dev/null
+++ b/res/res_stun_monitor.c
@@ -0,0 +1,311 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * David Vossel <dvossel@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief STUN Network Monitor
+ *
+ * \author David Vossel <dvossel@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/event.h"
+#include "asterisk/sched.h"
+#include "asterisk/config.h"
+#include "asterisk/stun.h"
+#include "asterisk/netsock2.h"
+#include "asterisk/lock.h"
+#include <fcntl.h>
+
+static const int STANDARD_STUN_PORT = 3478;
+static const int DEFAULT_MONITOR_REFRESH = 30;
+
+static const char stun_conf_file[] = "res_stun_monitor.conf";
+static struct ast_sched_thread *sched;
+
+static struct {
+ struct sockaddr_in stunaddr; /*!< The stun address we send requests to*/
+ struct sockaddr_in externaladdr; /*!< current perceived external address. */
+ ast_mutex_t lock;
+ unsigned int refresh;
+ int stunsock;
+ unsigned int monitor_enabled:1;
+ unsigned int externaladdr_known:1;
+} args;
+
+static inline void stun_close_sock(void)
+{
+ if (args.stunsock != -1) {
+ close(args.stunsock);
+ args.stunsock = -1;
+ memset(&args.externaladdr, 0, sizeof(args.externaladdr));
+ args.externaladdr_known = 0;
+ }
+}
+
+/* \brief purge the stun socket's receive buffer before issuing a new request
+ *
+ * XXX Note that this is somewhat of a hack. This function is essentially doing
+ * a cleanup on the socket rec buffer to handle removing any STUN responses we have not
+ * handled. This is called before sending out a new STUN request so we don't read
+ * a latent previous response thinking it is new.
+ */
+static void stun_purge_socket(void)
+{
+ int flags = fcntl(args.stunsock, F_GETFL);
+ int res = 0;
+ unsigned char reply_buf[1024];
+
+ fcntl(args.stunsock, F_SETFL, flags | O_NONBLOCK);
+ while (res != -1) {
+ /* throw away everything in the buffer until we reach the end. */
+ res = recv(args.stunsock, reply_buf, sizeof(reply_buf), 0);
+ }
+ fcntl(args.stunsock, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+/* \brief called by scheduler to send STUN request */
+static int stun_monitor_request(const void *blarg)
+{
+ int res;
+ int generate_event = 0;
+ struct sockaddr_in answer = { 0, };
+
+
+ /* once the stun socket goes away, this scheduler item will go away as well */
+ ast_mutex_lock(&args.lock);
+ if (args.stunsock == -1) {
+ ast_log(LOG_ERROR, "STUN monitor: can not send STUN request, socket is not open\n");
+ goto monitor_request_cleanup;
+ }
+
+ stun_purge_socket();
+
+ if (!(ast_stun_request(args.stunsock, &args.stunaddr, NULL, &answer)) &&
+ (memcmp(&args.externaladdr, &answer, sizeof(args.externaladdr)))) {
+ const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
+ int newport = ntohs(answer.sin_port);
+
+ ast_log(LOG_NOTICE, "STUN MONITOR: Old external address/port %s:%d now seen as %s:%d \n",
+ ast_inet_ntoa(args.externaladdr.sin_addr), ntohs(args.externaladdr.sin_port),
+ newaddr, newport);
+
+ memcpy(&args.externaladdr, &answer, sizeof(args.externaladdr));
+
+ if (args.externaladdr_known) {
+ /* the external address was already known, and has changed... generate event. */
+ generate_event = 1;
+
+ } else {
+ /* this was the first external address we found, do not alert listeners
+ * until this address changes to something else. */
+ args.externaladdr_known = 1;
+ }
+ }
+
+ if (generate_event) {
+ struct ast_event *event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
+ if (!event) {
+ ast_log(LOG_ERROR, "STUN monitor: could not create AST_EVENT_NETWORK_CHANGE event.\n");
+ goto monitor_request_cleanup;
+ }
+ if (ast_event_queue(event)) {
+ ast_event_destroy(event);
+ event = NULL;
+ ast_log(LOG_ERROR, "STUN monitor: could not queue AST_EVENT_NETWORK_CHANGE event.\n");
+ goto monitor_request_cleanup;
+ }
+ }
+
+monitor_request_cleanup:
+ /* always refresh this scheduler item. It will be removed elsewhere when
+ * it is supposed to go away */
+ res = args.refresh * 1000;
+ ast_mutex_unlock(&args.lock);
+
+ return res;
+}
+
+/* \brief stops the stun monitor thread
+ * \note do not hold the args->lock while calling this
+ */
+static void stun_stop_monitor(void)
+{
+ if (sched) {
+ sched = ast_sched_thread_destroy(sched);
+ ast_log(LOG_NOTICE, "STUN monitor stopped\n");
+ }
+ /* it is only safe to destroy the socket without holding arg->lock
+ * after the sched thread is destroyed */
+ stun_close_sock();
+}
+
+/* \brief starts the stun monitor thread
+ * \note The args->lock MUST be held when calling this function
+ */
+static int stun_start_monitor(void)
+{
+ struct ast_sockaddr dst;
+ /* clean up any previous open socket */
+ stun_close_sock();
+
+ /* create destination ast_sockaddr */
+ ast_sockaddr_from_sin(&dst, &args.stunaddr);
+
+ /* open new socket binding */
+ args.stunsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (args.stunsock < 0) {
+ ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (ast_connect(args.stunsock, &dst) != 0) {
+ ast_log(LOG_WARNING, "SIP STUN Failed to connect to %s\n", ast_sockaddr_stringify(&dst));
+ stun_close_sock();
+ return -1;
+ }
+
+ /* if scheduler thread is not started, make sure to start it now */
+ if (sched) {
+ return 0; /* already started */
+ }
+
+ if (!(sched = ast_sched_thread_create())) {
+ ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n");
+ stun_close_sock();
+ return -1;
+ }
+
+ if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
+ ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
+ sched = ast_sched_thread_destroy(sched);
+ stun_close_sock();
+ return -1;
+ }
+
+ ast_log(LOG_NOTICE, "STUN monitor started\n");
+ return 0;
+}
+
+static int load_config(int startup)
+{
+ struct ast_flags config_flags = { 0, };
+ struct ast_config *cfg;
+ struct ast_variable *v;
+
+ if (!startup) {
+ ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+ }
+
+ if (!(cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags)) ||
+ cfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(LOG_ERROR, "Unable to load config %s\n", stun_conf_file);
+ return -1;
+ }
+
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED && !startup) {
+ return 0;
+ }
+
+ /* set defaults */
+ args.monitor_enabled = 0;
+ memset(&args.stunaddr, 0, sizeof(args.stunaddr));
+ args.refresh = DEFAULT_MONITOR_REFRESH;
+
+ for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+ if (!strcasecmp(v->name, "stunaddr")) {
+ args.stunaddr.sin_port = htons(STANDARD_STUN_PORT);
+ if (ast_parse_arg(v->value, PARSE_INADDR, &args.stunaddr)) {
+ ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
+ } else {
+ ast_log(LOG_NOTICE, "STUN monitor enabled: %s\n", v->value);
+ args.monitor_enabled = 1;
+ }
+ } else if (!strcasecmp(v->name, "stunrefresh")) {
+ if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
+ ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
+ args.refresh = DEFAULT_MONITOR_REFRESH;
+ } else {
+ ast_log(LOG_NOTICE, "STUN Monitor set to refresh every %d seconds\n", args.refresh);
+ }
+ } else {
+ ast_log(LOG_WARNING, "SIP STUN: invalid config option %s at line %d\n", v->value, v->lineno);
+ }
+ }
+
+ ast_config_destroy(cfg);
+
+ return 0;
+}
+
+static int __reload(int startup)
+{
+ int res;
+
+ ast_mutex_lock(&args.lock);
+ if (!(res = load_config(startup)) && args.monitor_enabled) {
+ res = stun_start_monitor();
+ }
+ ast_mutex_unlock(&args.lock);
+
+ if ((res == -1) || !args.monitor_enabled) {
+ args.monitor_enabled = 0;
+ stun_stop_monitor();
+ }
+
+ return res;
+}
+
+static int reload(void)
+{
+ return __reload(0);
+}
+
+static int unload_module(void)
+{
+ stun_stop_monitor();
+ ast_mutex_destroy(&args.lock);
+ return 0;
+}
+
+static int load_module(void)
+{
+ ast_mutex_init(&args.lock);
+ args.stunsock = -1;
+ memset(&args.externaladdr, 0, sizeof(args.externaladdr));
+ args.externaladdr_known = 0;
+ sched = NULL;
+ if (__reload(1)) {
+ stun_stop_monitor();
+ ast_mutex_destroy(&args.lock);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND
+ );