config_transport.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2013, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 #include "asterisk.h"
00020 
00021 #include <pjsip.h>
00022 #include <pjlib.h>
00023 
00024 #include "asterisk/res_pjsip.h"
00025 #include "asterisk/res_pjsip_cli.h"
00026 #include "asterisk/logger.h"
00027 #include "asterisk/astobj2.h"
00028 #include "asterisk/sorcery.h"
00029 #include "asterisk/acl.h"
00030 #include "include/res_pjsip_private.h"
00031 #include "asterisk/http_websocket.h"
00032 
00033 static int sip_transport_to_ami(const struct ast_sip_transport *transport,
00034             struct ast_str **buf)
00035 {
00036    return ast_sip_sorcery_object_to_ami(transport, buf);
00037 }
00038 
00039 static int format_ami_endpoint_transport(const struct ast_sip_endpoint *endpoint,
00040                 struct ast_sip_ami *ami)
00041 {
00042    RAII_VAR(struct ast_str *, buf, NULL, ast_free);
00043    RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
00044 
00045    if (ast_strlen_zero(endpoint->transport)) {
00046       return 0;
00047    }
00048 
00049    buf = ast_sip_create_ami_event("TransportDetail", ami);
00050    if (!buf) {
00051       return -1;
00052    }
00053 
00054    transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
00055       endpoint->transport);
00056    if (!transport) {
00057       astman_send_error_va(ami->s, ami->m, "Unable to retrieve "
00058                  "transport %s\n", endpoint->transport);
00059       return -1;
00060    }
00061 
00062    sip_transport_to_ami(transport, &buf);
00063 
00064    ast_str_append(&buf, 0, "EndpointName: %s\r\n",
00065              ast_sorcery_object_get_id(endpoint));
00066 
00067    astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
00068    ami->count++;
00069 
00070    return 0;
00071 }
00072 
00073 struct ast_sip_endpoint_formatter endpoint_transport_formatter = {
00074    .format_ami = format_ami_endpoint_transport
00075 };
00076 
00077 static int destroy_transport_state(void *data)
00078 {
00079    pjsip_transport *transport = data;
00080    pjsip_transport_shutdown(transport);
00081    return 0;
00082 }
00083 
00084 /*! \brief Destructor for transport state information */
00085 static void transport_state_destroy(void *obj)
00086 {
00087    struct ast_sip_transport_state *state = obj;
00088 
00089    if (state->transport) {
00090       ast_sip_push_task_synchronous(NULL, destroy_transport_state, state->transport);
00091    }
00092 }
00093 
00094 /*! \brief Destructor for transport */
00095 static void transport_destroy(void *obj)
00096 {
00097    struct ast_sip_transport *transport = obj;
00098 
00099    ast_string_field_free_memory(transport);
00100    ast_free_ha(transport->localnet);
00101 
00102    if (transport->external_address_refresher) {
00103       ast_dnsmgr_release(transport->external_address_refresher);
00104    }
00105 
00106    ao2_cleanup(transport->state);
00107 }
00108 
00109 /*! \brief Allocator for transport */
00110 static void *transport_alloc(const char *name)
00111 {
00112    struct ast_sip_transport *transport = ast_sorcery_generic_alloc(sizeof(*transport), transport_destroy);
00113 
00114    if (!transport) {
00115       return NULL;
00116    }
00117 
00118    if (ast_string_field_init(transport, 256)) {
00119       ao2_cleanup(transport);
00120       return NULL;
00121    }
00122 
00123    pjsip_tls_setting_default(&transport->tls);
00124    transport->tls.ciphers = transport->ciphers;
00125 
00126    return transport;
00127 }
00128 
00129 static void set_qos(struct ast_sip_transport *transport, pj_qos_params *qos)
00130 {
00131    int tos_as_dscp = transport->tos >> 2;
00132 
00133    if (transport->tos) {
00134       qos->flags |= PJ_QOS_PARAM_HAS_DSCP;
00135       qos->dscp_val = tos_as_dscp;
00136    }
00137    if (transport->cos) {
00138       qos->flags |= PJ_QOS_PARAM_HAS_SO_PRIO;
00139       qos->so_prio = transport->cos;
00140    }
00141 }
00142 
00143 /*! \brief Apply handler for transports */
00144 static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
00145 {
00146    struct ast_sip_transport *transport = obj;
00147    RAII_VAR(struct ast_sip_transport *, existing, ast_sorcery_retrieve_by_id(sorcery, "transport", ast_sorcery_object_get_id(obj)), ao2_cleanup);
00148    pj_status_t res = -1;
00149 
00150    if (!existing || !existing->state) {
00151       if (!(transport->state = ao2_alloc(sizeof(*transport->state), transport_state_destroy))) {
00152          ast_log(LOG_ERROR, "Transport state for '%s' could not be allocated\n", ast_sorcery_object_get_id(obj));
00153          return -1;
00154       }
00155    } else {
00156       transport->state = existing->state;
00157       ao2_ref(transport->state, +1);
00158    }
00159 
00160    /* Once active a transport can not be reconfigured */
00161    if (transport->state->transport || transport->state->factory) {
00162       return -1;
00163    }
00164 
00165    if (transport->host.addr.sa_family != PJ_AF_INET && transport->host.addr.sa_family != PJ_AF_INET6) {
00166       ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", ast_sorcery_object_get_id(obj));
00167       return -1;
00168    }
00169 
00170    /* Set default port if not present */
00171    if (!pj_sockaddr_get_port(&transport->host)) {
00172       pj_sockaddr_set_port(&transport->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060);
00173    }
00174 
00175    /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */
00176    if (!ast_strlen_zero(transport->external_signaling_address)) {
00177       if (transport->host.addr.sa_family == pj_AF_INET()) {
00178          transport->external_address.ss.ss_family = AF_INET;
00179       } else if (transport->host.addr.sa_family == pj_AF_INET6()) {
00180          transport->external_address.ss.ss_family = AF_INET6;
00181       } else {
00182          ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
00183                ast_sorcery_object_get_id(obj));
00184          return -1;
00185       }
00186 
00187       if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) {
00188          ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj));
00189          return -1;
00190       }
00191    }
00192 
00193    if (transport->type == AST_TRANSPORT_UDP) {
00194       if (transport->host.addr.sa_family == pj_AF_INET()) {
00195          res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &transport->host.ipv4, NULL, transport->async_operations, &transport->state->transport);
00196       } else if (transport->host.addr.sa_family == pj_AF_INET6()) {
00197          res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport);
00198       }
00199 
00200       if (res == PJ_SUCCESS && (transport->tos || transport->cos)) {
00201          pj_sock_t sock;
00202          pj_qos_params qos_params;
00203 
00204          sock = pjsip_udp_transport_get_socket(transport->state->transport);
00205          pj_sock_get_qos_params(sock, &qos_params);
00206          set_qos(transport, &qos_params);
00207          pj_sock_set_qos_params(sock, &qos_params);
00208       }
00209    } else if (transport->type == AST_TRANSPORT_TCP) {
00210       pjsip_tcp_transport_cfg cfg;
00211 
00212       pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family);
00213       cfg.bind_addr = transport->host;
00214       cfg.async_cnt = transport->async_operations;
00215       set_qos(transport, &cfg.qos_params);
00216 
00217       res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory);
00218    } else if (transport->type == AST_TRANSPORT_TLS) {
00219       transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file);
00220 #ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2
00221       transport->tls.ca_list_path = pj_str((char*)transport->ca_list_path);
00222 #else
00223       if (!ast_strlen_zero(transport->ca_list_path)) {
00224          ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject that does not "
00225                "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n");
00226       }
00227 #endif
00228       transport->tls.cert_file = pj_str((char*)transport->cert_file);
00229       transport->tls.privkey_file = pj_str((char*)transport->privkey_file);
00230       transport->tls.password = pj_str((char*)transport->password);
00231       set_qos(transport, &transport->tls.qos_params);
00232 
00233       res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory);
00234    } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
00235       if (transport->cos || transport->tos) {
00236          ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
00237       }
00238       res = PJ_SUCCESS;
00239    }
00240 
00241    if (res != PJ_SUCCESS) {
00242       char msg[PJ_ERR_MSG_SIZE];
00243 
00244       pj_strerror(res, msg, sizeof(msg));
00245       ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg);
00246       return -1;
00247    }
00248    return 0;
00249 }
00250 
00251 /*! \brief Custom handler for turning a string protocol into an enum */
00252 static int transport_protocol_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00253 {
00254    struct ast_sip_transport *transport = obj;
00255 
00256    if (!strcasecmp(var->value, "udp")) {
00257       transport->type = AST_TRANSPORT_UDP;
00258    } else if (!strcasecmp(var->value, "tcp")) {
00259       transport->type = AST_TRANSPORT_TCP;
00260    } else if (!strcasecmp(var->value, "tls")) {
00261       transport->type = AST_TRANSPORT_TLS;
00262    } else if (!strcasecmp(var->value, "ws")) {
00263       transport->type = AST_TRANSPORT_WS;
00264    } else if (!strcasecmp(var->value, "wss")) {
00265       transport->type = AST_TRANSPORT_WSS;
00266    } else {
00267       return -1;
00268    }
00269 
00270    return 0;
00271 }
00272 
00273 static const char *transport_types[] = {
00274    [AST_TRANSPORT_UDP] = "udp",
00275    [AST_TRANSPORT_TCP] = "tcp",
00276    [AST_TRANSPORT_TLS] = "tls",
00277    [AST_TRANSPORT_WS] = "ws",
00278    [AST_TRANSPORT_WSS] = "wss"
00279 };
00280 
00281 static int transport_protocol_to_str(const void *obj, const intptr_t *args, char **buf)
00282 {
00283    const struct ast_sip_transport *transport = obj;
00284 
00285    if (ARRAY_IN_BOUNDS(transport->type, transport_types)) {
00286       *buf = ast_strdup(transport_types[transport->type]);
00287    }
00288 
00289    return 0;
00290 }
00291 
00292 /*! \brief Custom handler for turning a string bind into a pj_sockaddr */
00293 static int transport_bind_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00294 {
00295    struct ast_sip_transport *transport = obj;
00296    pj_str_t buf;
00297    int rc = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &transport->host);
00298 
00299    return rc != PJ_SUCCESS ? -1 : 0;
00300 }
00301 
00302 static int transport_bind_to_str(const void *obj, const intptr_t *args, char **buf)
00303 {
00304    const struct ast_sip_transport *transport = obj;
00305 
00306    if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
00307       return -1;
00308    }
00309 
00310    /* include port as well as brackets if IPv6 */
00311    pj_sockaddr_print(&transport->host, *buf, MAX_OBJECT_FIELD, 1 | 2);
00312 
00313    return 0;
00314 }
00315 
00316 /*! \brief Custom handler for TLS boolean settings */
00317 static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00318 {
00319    struct ast_sip_transport *transport = obj;
00320 
00321    if (!strcasecmp(var->name, "verify_server")) {
00322       transport->tls.verify_server = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
00323    } else if (!strcasecmp(var->name, "verify_client")) {
00324       transport->tls.verify_client = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
00325    } else if (!strcasecmp(var->name, "require_client_cert")) {
00326       transport->tls.require_client_cert = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
00327    } else {
00328       return -1;
00329    }
00330 
00331    return 0;
00332 }
00333 
00334 static int verify_server_to_str(const void *obj, const intptr_t *args, char **buf)
00335 {
00336    const struct ast_sip_transport *transport = obj;
00337    *buf = ast_strdup(AST_YESNO(transport->tls.verify_server));
00338    return 0;
00339 }
00340 
00341 static int verify_client_to_str(const void *obj, const intptr_t *args, char **buf)
00342 {
00343    const struct ast_sip_transport *transport = obj;
00344    *buf = ast_strdup(AST_YESNO(transport->tls.verify_client));
00345    return 0;
00346 }
00347 
00348 static int require_client_cert_to_str(const void *obj, const intptr_t *args, char **buf)
00349 {
00350    const struct ast_sip_transport *transport = obj;
00351    *buf = ast_strdup(AST_YESNO(transport->tls.require_client_cert));
00352    return 0;
00353 }
00354 
00355 /*! \brief Custom handler for TLS method setting */
00356 static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00357 {
00358    struct ast_sip_transport *transport = obj;
00359 
00360    if (ast_strlen_zero(var->value) || !strcasecmp(var->value, "default")) {
00361       transport->tls.method = PJSIP_SSL_DEFAULT_METHOD;
00362    } else if (!strcasecmp(var->value, "unspecified")) {
00363       transport->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD;
00364    } else if (!strcasecmp(var->value, "tlsv1")) {
00365       transport->tls.method = PJSIP_TLSV1_METHOD;
00366    } else if (!strcasecmp(var->value, "sslv2")) {
00367       transport->tls.method = PJSIP_SSLV2_METHOD;
00368    } else if (!strcasecmp(var->value, "sslv3")) {
00369       transport->tls.method = PJSIP_SSLV3_METHOD;
00370    } else if (!strcasecmp(var->value, "sslv23")) {
00371       transport->tls.method = PJSIP_SSLV23_METHOD;
00372    } else {
00373       return -1;
00374    }
00375 
00376    return 0;
00377 }
00378 
00379 static const char *tls_method_map[] = {
00380    [PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified",
00381    [PJSIP_TLSV1_METHOD] = "tlsv1",
00382    [PJSIP_SSLV2_METHOD] = "sslv2",
00383    [PJSIP_SSLV3_METHOD] = "sslv3",
00384    [PJSIP_SSLV23_METHOD] = "sslv23",
00385 };
00386 
00387 static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf)
00388 {
00389    const struct ast_sip_transport *transport = obj;
00390    if (ARRAY_IN_BOUNDS(transport->tls.method, tls_method_map)) {
00391       *buf = ast_strdup(tls_method_map[transport->tls.method]);
00392    }
00393    return 0;
00394 }
00395 
00396 /*! \brief Helper function which turns a cipher name into an identifier */
00397 static pj_ssl_cipher cipher_name_to_id(const char *name)
00398 {
00399    pj_ssl_cipher ciphers[100];
00400    pj_ssl_cipher id = 0;
00401    unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
00402    int pos;
00403    const char *pos_name;
00404 
00405    if (pj_ssl_cipher_get_availables(ciphers, &cipher_num)) {
00406       return 0;
00407    }
00408 
00409    for (pos = 0; pos < cipher_num; ++pos) {
00410       pos_name = pj_ssl_cipher_name(ciphers[pos]);
00411       if (!pos_name || strcmp(pos_name, name)) {
00412          continue;
00413       }
00414 
00415       id = ciphers[pos];
00416       break;
00417    }
00418 
00419    return id;
00420 }
00421 
00422 /*!
00423  * \internal
00424  * \brief Add a new cipher to the transport's cipher list array.
00425  *
00426  * \param transport Which transport to add the cipher to.
00427  * \param name Cipher identifier name.
00428  *
00429  * \retval 0 on success.
00430  * \retval -1 on error.
00431  */
00432 static int transport_cipher_add(struct ast_sip_transport *transport, const char *name)
00433 {
00434    pj_ssl_cipher cipher;
00435    int idx;
00436 
00437    cipher = cipher_name_to_id(name);
00438    if (!cipher) {
00439       /* TODO: Check this over/tweak - it's taken from pjsua for now */
00440       if (!strnicmp(name, "0x", 2)) {
00441          pj_str_t cipher_st = pj_str((char *) name + 2);
00442          cipher = pj_strtoul2(&cipher_st, NULL, 16);
00443       } else {
00444          cipher = atoi(name);
00445       }
00446    }
00447 
00448    if (pj_ssl_cipher_is_supported(cipher)) {
00449       for (idx = transport->tls.ciphers_num; idx--;) {
00450          if (transport->ciphers[idx] == cipher) {
00451             /* The cipher is already in the list. */
00452             return 0;
00453          }
00454       }
00455       transport->ciphers[transport->tls.ciphers_num++] = cipher;
00456       return 0;
00457    } else {
00458       ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", name);
00459       return -1;
00460    }
00461 }
00462 
00463 /*! \brief Custom handler for TLS cipher setting */
00464 static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00465 {
00466    struct ast_sip_transport *transport = obj;
00467    char *parse;
00468    char *name;
00469    int res = 0;
00470 
00471    parse = ast_strdupa(S_OR(var->value, ""));
00472    while ((name = strsep(&parse, ","))) {
00473       name = ast_strip(name);
00474       if (ast_strlen_zero(name)) {
00475          continue;
00476       }
00477       if (ARRAY_LEN(transport->ciphers) <= transport->tls.ciphers_num) {
00478          ast_log(LOG_ERROR, "Too many ciphers specified\n");
00479          res = -1;
00480          break;
00481       }
00482       res |= transport_cipher_add(transport, name);
00483    }
00484    return res ? -1 : 0;
00485 }
00486 
00487 static void cipher_to_str(char **buf, const pj_ssl_cipher *ciphers, unsigned int cipher_num)
00488 {
00489    struct ast_str *str;
00490    int idx;
00491 
00492    str = ast_str_create(128);
00493    if (!str) {
00494       *buf = NULL;
00495       return;
00496    }
00497 
00498    for (idx = 0; idx < cipher_num; ++idx) {
00499       ast_str_append(&str, 0, "%s", pj_ssl_cipher_name(ciphers[idx]));
00500       if (idx < cipher_num - 1) {
00501          ast_str_append(&str, 0, ", ");
00502       }
00503    }
00504 
00505    *buf = ast_strdup(ast_str_buffer(str));
00506    ast_free(str);
00507 }
00508 
00509 static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
00510 {
00511    const struct ast_sip_transport *transport = obj;
00512 
00513    cipher_to_str(buf, transport->ciphers, transport->tls.ciphers_num);
00514    return *buf ? 0 : -1;
00515 }
00516 
00517 static char *handle_pjsip_list_ciphers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00518 {
00519    pj_ssl_cipher ciphers[100];
00520    unsigned int cipher_num = PJ_ARRAY_SIZE(ciphers);
00521    char *buf;
00522 
00523    switch (cmd) {
00524    case CLI_INIT:
00525       e->command = "pjsip list ciphers";
00526       e->usage = "Usage: pjsip list ciphers\n"
00527          "       List available OpenSSL cipher names.\n";
00528       return NULL;
00529    case CLI_GENERATE:
00530       return NULL;
00531    }
00532 
00533    if (pj_ssl_cipher_get_availables(ciphers, &cipher_num) || !cipher_num) {
00534       buf = NULL;
00535    } else {
00536       cipher_to_str(&buf, ciphers, cipher_num);
00537    }
00538 
00539    if (!ast_strlen_zero(buf)) {
00540       ast_cli(a->fd, "Available ciphers: '%s'\n", buf);
00541    } else {
00542       ast_cli(a->fd, "No available ciphers\n");
00543    }
00544    ast_free(buf);
00545    return CLI_SUCCESS;
00546 }
00547 
00548 /*! \brief Custom handler for localnet setting */
00549 static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00550 {
00551    struct ast_sip_transport *transport = obj;
00552    int error = 0;
00553 
00554    if (ast_strlen_zero(var->value)) {
00555       ast_free_ha(transport->localnet);
00556       transport->localnet = NULL;
00557       return 0;
00558    }
00559 
00560    if (!(transport->localnet = ast_append_ha("d", var->value, transport->localnet, &error))) {
00561       return -1;
00562    }
00563 
00564    return error;
00565 }
00566 
00567 static int localnet_to_vl(const void *obj, struct ast_variable **fields)
00568 {
00569    const struct ast_sip_transport *transport = obj;
00570 
00571    char str[MAX_OBJECT_FIELD];
00572    struct ast_variable *head = NULL;
00573    struct ast_ha *ha = transport->localnet;
00574 
00575    for (; ha; ha = ha->next) {
00576       const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
00577       snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
00578          addr, ast_sockaddr_stringify_addr(&ha->netmask));
00579 
00580       ast_variable_list_append(&head, ast_variable_new("local_net", str, ""));
00581    }
00582 
00583    if (head) {
00584       *fields = head;
00585    }
00586 
00587    return 0;
00588 }
00589 
00590 static int localnet_to_str(const void *obj, const intptr_t *args, char **buf)
00591 {
00592    RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
00593    const struct ast_sip_transport *transport = obj;
00594 
00595    ast_ha_join(transport->localnet, &str);
00596    *buf = ast_strdup(ast_str_buffer(str));
00597    return 0;
00598 }
00599 
00600 /*! \brief Custom handler for TOS setting */
00601 static int transport_tos_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
00602 {
00603    struct ast_sip_transport *transport = obj;
00604    unsigned int value;
00605 
00606    if (ast_str2tos(var->value, &value)) {
00607       ast_log(LOG_ERROR, "Error configuring transport '%s' - Could not "
00608          "interpret 'tos' value '%s'\n",
00609          ast_sorcery_object_get_id(transport), var->value);
00610       return -1;
00611    }
00612 
00613    if (value % 4) {
00614       value = value >> 2;
00615       value = value << 2;
00616       ast_log(LOG_WARNING,
00617          "transport '%s' - 'tos' value '%s' uses bits that are "
00618          "discarded when converted to DSCP. Using equivalent %u instead.\n",
00619          ast_sorcery_object_get_id(transport), var->value, value);
00620    }
00621 
00622    transport->tos = value;
00623    return 0;
00624 }
00625 
00626 static int tos_to_str(const void *obj, const intptr_t *args, char **buf)
00627 {
00628    const struct ast_sip_transport *transport = obj;
00629 
00630    if (ast_asprintf(buf, "%u", transport->tos) == -1) {
00631       return -1;
00632    }
00633    return 0;
00634 }
00635 
00636 static struct ao2_container *cli_get_container(void)
00637 {
00638    RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
00639    struct ao2_container *s_container;
00640 
00641    container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport",
00642       AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
00643    if (!container) {
00644       return NULL;
00645    }
00646 
00647    s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
00648       ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
00649    if (!s_container) {
00650       return NULL;
00651    }
00652 
00653    if (ao2_container_dup(s_container, container, 0)) {
00654       ao2_ref(s_container, -1);
00655       return NULL;
00656    }
00657 
00658    return s_container;
00659 }
00660 
00661 static int cli_iterate(void *container, ao2_callback_fn callback, void *args)
00662 {
00663    const struct ast_sip_endpoint *endpoint = container;
00664    struct ast_sip_transport *transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
00665       "transport", endpoint->transport);
00666 
00667    if (!transport) {
00668       return -1;
00669    }
00670 
00671    return callback(transport, args, 0);
00672 }
00673 
00674 static void *cli_retrieve_by_id(const char *id)
00675 {
00676    return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", id);
00677 }
00678 
00679 static int cli_print_header(void *obj, void *arg, int flags)
00680 {
00681    struct ast_sip_cli_context *context = arg;
00682    int indent = CLI_INDENT_TO_SPACES(context->indent_level);
00683    int filler = CLI_MAX_WIDTH - indent - 61;
00684 
00685    ast_assert(context->output_buffer != NULL);
00686 
00687    ast_str_append(&context->output_buffer, 0,
00688       "%*s:  <TransportId........>  <Type>  <cos>  <tos>  <BindAddress%*.*s>\n",
00689       indent, "Transport", filler, filler, CLI_HEADER_FILLER);
00690 
00691    return 0;
00692 }
00693 
00694 static int cli_print_body(void *obj, void *arg, int flags)
00695 {
00696    struct ast_sip_transport *transport = obj;
00697    struct ast_sip_cli_context *context = arg;
00698    char hoststr[PJ_INET6_ADDRSTRLEN];
00699 
00700    ast_assert(context->output_buffer != NULL);
00701 
00702    pj_sockaddr_print(&transport->host, hoststr, sizeof(hoststr), 3);
00703 
00704    ast_str_append(&context->output_buffer, 0, "%*s:  %-21s  %6s  %5u  %5u  %s\n",
00705       CLI_INDENT_TO_SPACES(context->indent_level), "Transport",
00706       ast_sorcery_object_get_id(transport),
00707       ARRAY_IN_BOUNDS(transport->type, transport_types) ? transport_types[transport->type] : "Unknown",
00708       transport->cos, transport->tos, hoststr);
00709 
00710    if (context->show_details
00711       || (context->show_details_only_level_0 && context->indent_level == 0)) {
00712       ast_str_append(&context->output_buffer, 0, "\n");
00713       ast_sip_cli_print_sorcery_objectset(transport, context, 0);
00714    }
00715 
00716    return 0;
00717 }
00718 
00719 static struct ast_cli_entry cli_commands[] = {
00720    AST_CLI_DEFINE(handle_pjsip_list_ciphers, "List available OpenSSL cipher names"),
00721    AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
00722       .command = "pjsip list transports",
00723       .usage = "Usage: pjsip list transports\n"
00724              "       List the configured PJSIP Transports\n"),
00725    AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transports",
00726       .command = "pjsip show transports",
00727       .usage = "Usage: pjsip show transports\n"
00728              "       Show the configured PJSIP Transport\n"),
00729    AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Transport",
00730       .command = "pjsip show transport",
00731       .usage = "Usage: pjsip show transport <id>\n"
00732              "       Show the configured PJSIP Transport\n"),
00733 };
00734 
00735 static struct ast_sip_cli_formatter_entry *cli_formatter;
00736 
00737 /*! \brief Initialize sorcery with transport support */
00738 int ast_sip_initialize_sorcery_transport(void)
00739 {
00740    struct ast_sorcery *sorcery = ast_sip_get_sorcery();
00741 
00742    ast_sorcery_apply_default(sorcery, "transport", "config", "pjsip.conf,criteria=type=transport");
00743 
00744    if (ast_sorcery_object_register_no_reload(sorcery, "transport", transport_alloc, NULL, transport_apply)) {
00745       return -1;
00746    }
00747 
00748    ast_sorcery_object_field_register(sorcery, "transport", "type", "", OPT_NOOP_T, 0, 0);
00749    ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, NULL, 0, 0);
00750    ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, NULL, 0, 0);
00751    ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations));
00752    ast_sorcery_object_field_register(sorcery, "transport", "ca_list_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_file));
00753    ast_sorcery_object_field_register(sorcery, "transport", "ca_list_path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_path));
00754    ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file));
00755    ast_sorcery_object_field_register(sorcery, "transport", "priv_key_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, privkey_file));
00756    ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password));
00757    ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address));
00758    ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535);
00759    ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address));
00760    ast_sorcery_object_field_register(sorcery, "transport", "domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, domain));
00761    ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, verify_server_to_str, NULL, 0, 0);
00762    ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, NULL, 0, 0);
00763    ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, NULL, 0, 0);
00764    ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, NULL, 0, 0);
00765    ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, NULL, 0, 0);
00766    ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, localnet_to_vl, 0, 0);
00767    ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0);
00768    ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
00769    ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX);
00770 
00771    internal_sip_register_endpoint_formatter(&endpoint_transport_formatter);
00772 
00773    cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
00774    if (!cli_formatter) {
00775       ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
00776       return -1;
00777    }
00778    cli_formatter->name = "transport";
00779    cli_formatter->print_header = cli_print_header;
00780    cli_formatter->print_body = cli_print_body;
00781    cli_formatter->get_container = cli_get_container;
00782    cli_formatter->iterate = cli_iterate;
00783    cli_formatter->get_id = ast_sorcery_object_get_id;
00784    cli_formatter->retrieve_by_id = cli_retrieve_by_id;
00785 
00786    ast_sip_register_cli_formatter(cli_formatter);
00787    ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
00788 
00789    return 0;
00790 }
00791 
00792 int ast_sip_destroy_sorcery_transport(void)
00793 {
00794    ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
00795    ast_sip_unregister_cli_formatter(cli_formatter);
00796 
00797    internal_sip_unregister_endpoint_formatter(&endpoint_transport_formatter);
00798 
00799    return 0;
00800 }

Generated on Thu Apr 16 06:27:31 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6