res_pjsip_t38.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 /*! \file
00020  *
00021  * \author Joshua Colp <jcolp@digium.com>
00022  *
00023  * \brief SIP T.38 handling
00024  */
00025 
00026 /*** MODULEINFO
00027    <depend>pjproject</depend>
00028    <depend>res_pjsip</depend>
00029    <depend>res_pjsip_session</depend>
00030    <support_level>core</support_level>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 #include <pjsip.h>
00036 #include <pjsip_ua.h>
00037 #include <pjmedia.h>
00038 #include <pjlib.h>
00039 
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 434689 $")
00041 
00042 #include "asterisk/module.h"
00043 #include "asterisk/udptl.h"
00044 #include "asterisk/netsock2.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/acl.h"
00047 
00048 #include "asterisk/res_pjsip.h"
00049 #include "asterisk/res_pjsip_session.h"
00050 
00051 /*! \brief The number of seconds after receiving a T.38 re-invite before automatically rejecting it */
00052 #define T38_AUTOMATIC_REJECTION_SECONDS 5
00053 
00054 /*! \brief Address for IPv4 UDPTL */
00055 static struct ast_sockaddr address_ipv4;
00056 
00057 /*! \brief Address for IPv6 UDPTL */
00058 static struct ast_sockaddr address_ipv6;
00059 
00060 /*! \brief T.38 state information */
00061 struct t38_state {
00062    /*! \brief Current state */
00063    enum ast_sip_session_t38state state;
00064    /*! \brief Our T.38 parameters */
00065    struct ast_control_t38_parameters our_parms;
00066    /*! \brief Their T.38 parameters */
00067    struct ast_control_t38_parameters their_parms;
00068    /*! \brief Timer entry for automatically rejecting an inbound re-invite */
00069    pj_timer_entry timer;
00070 };
00071 
00072 /*! \brief Destructor for T.38 state information */
00073 static void t38_state_destroy(void *obj)
00074 {
00075    ast_free(obj);
00076 }
00077 
00078 /*! \brief Datastore for attaching T.38 state information */
00079 static const struct ast_datastore_info t38_datastore = {
00080    .type = "t38",
00081    .destroy = t38_state_destroy,
00082 };
00083 
00084 /*! \brief Structure for T.38 parameters task data */
00085 struct t38_parameters_task_data {
00086    /*! \brief Session itself */
00087    struct ast_sip_session *session;
00088    /*! \brief T.38 control frame */
00089    struct ast_frame *frame;
00090 };
00091 
00092 /*! \brief Destructor for T.38 data */
00093 static void t38_parameters_task_data_destroy(void *obj)
00094 {
00095    struct t38_parameters_task_data *data = obj;
00096 
00097    ao2_cleanup(data->session);
00098 
00099    if (data->frame) {
00100       ast_frfree(data->frame);
00101    }
00102 }
00103 
00104 /*! \brief Allocator for T.38 data */
00105 static struct t38_parameters_task_data *t38_parameters_task_data_alloc(struct ast_sip_session *session,
00106    struct ast_frame *frame)
00107 {
00108    struct t38_parameters_task_data *data = ao2_alloc(sizeof(*data), t38_parameters_task_data_destroy);
00109 
00110    if (!data) {
00111       return NULL;
00112    }
00113 
00114    data->session = session;
00115    ao2_ref(session, +1);
00116    data->frame = ast_frdup(frame);
00117    if (!data->frame) {
00118       ao2_ref(data, -1);
00119       data = NULL;
00120    }
00121 
00122    return data;
00123 }
00124 
00125 /*! \brief Helper function for changing the T.38 state */
00126 static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
00127    struct t38_state *state, enum ast_sip_session_t38state new_state)
00128 {
00129    enum ast_sip_session_t38state old_state = session->t38state;
00130    struct ast_control_t38_parameters parameters = { .request_response = 0, };
00131    pj_time_val delay = { .sec = T38_AUTOMATIC_REJECTION_SECONDS };
00132 
00133    if (old_state == new_state) {
00134       return;
00135    }
00136 
00137    session->t38state = new_state;
00138    ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n", new_state, old_state, ast_channel_name(session->channel));
00139 
00140    if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &state->timer)) {
00141       ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n", ast_channel_name(session->channel));
00142       ao2_ref(session, -1);
00143    }
00144 
00145    if (!session->channel) {
00146       return;
00147    }
00148 
00149    switch (new_state) {
00150    case T38_PEER_REINVITE:
00151       ao2_ref(session, +1);
00152       if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &state->timer, &delay) != PJ_SUCCESS) {
00153          ast_log(LOG_WARNING, "Scheduling of automatic T.38 rejection for channel '%s' failed\n",
00154             ast_channel_name(session->channel));
00155          ao2_ref(session, -1);
00156       }
00157       parameters = state->their_parms;
00158       parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
00159       parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
00160       ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
00161       break;
00162    case T38_ENABLED:
00163       parameters = state->their_parms;
00164       parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
00165       parameters.request_response = AST_T38_NEGOTIATED;
00166       ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
00167       break;
00168    case T38_REJECTED:
00169    case T38_DISABLED:
00170       if (old_state == T38_ENABLED) {
00171          parameters.request_response = AST_T38_TERMINATED;
00172       } else if (old_state == T38_LOCAL_REINVITE) {
00173          parameters.request_response = AST_T38_REFUSED;
00174       }
00175       break;
00176    case T38_LOCAL_REINVITE:
00177       /* wait until we get a peer response before responding to local reinvite */
00178       break;
00179    case T38_MAX_ENUM:
00180       /* Well, that shouldn't happen */
00181       ast_assert(0);
00182       break;
00183    }
00184 
00185    if (parameters.request_response) {
00186       ast_queue_control_data(session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
00187    }
00188 }
00189 
00190 /*! \brief Task function which rejects a T.38 re-invite and resumes handling it */
00191 static int t38_automatic_reject(void *obj)
00192 {
00193    RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup);
00194    RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
00195    RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(session->media, "image", OBJ_KEY), ao2_cleanup);
00196 
00197    if (!datastore) {
00198       return 0;
00199    }
00200 
00201    ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n", ast_channel_name(session->channel));
00202 
00203    t38_change_state(session, session_media, datastore->data, T38_REJECTED);
00204    ast_sip_session_resume_reinvite(session);
00205 
00206    return 0;
00207 }
00208 
00209 /*! \brief Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it */
00210 static void t38_automatic_reject_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
00211 {
00212    struct ast_sip_session *session = entry->user_data;
00213 
00214    if (ast_sip_push_task(session->serializer, t38_automatic_reject, session)) {
00215       ao2_ref(session, -1);
00216    }
00217 }
00218 
00219 /*! \brief Helper function which retrieves or allocates a T.38 state information datastore */
00220 static struct t38_state *t38_state_get_or_alloc(struct ast_sip_session *session)
00221 {
00222    RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
00223    struct t38_state *state;
00224 
00225    /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
00226    if (datastore) {
00227       return datastore->data;
00228    }
00229 
00230    if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38")) ||
00231       !(datastore->data = ast_calloc(1, sizeof(struct t38_state))) ||
00232       ast_sip_session_add_datastore(session, datastore)) {
00233       return NULL;
00234    }
00235 
00236    state = datastore->data;
00237 
00238    /* This will get bumped up before scheduling */
00239    state->timer.user_data = session;
00240    state->timer.cb = t38_automatic_reject_timer_cb;
00241 
00242    datastore->data = state;
00243 
00244    return state;
00245 }
00246 
00247 /*! \brief Initializes UDPTL support on a session, only done when actually needed */
00248 static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
00249 {
00250    if (session_media->udptl) {
00251       return 0;
00252    }
00253 
00254    if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0,
00255       session->endpoint->media.t38.ipv6 ? &address_ipv6 : &address_ipv4))) {
00256       return -1;
00257    }
00258 
00259    ast_channel_set_fd(session->channel, 5, ast_udptl_fd(session_media->udptl));
00260    ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction);
00261    ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat);
00262    ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram);
00263 
00264    return 0;
00265 }
00266 
00267 /*! \brief Callback for when T.38 reinvite SDP is created */
00268 static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
00269 {
00270    int stream;
00271 
00272    /* Move the image media stream to the front and have it as the only stream, pjmedia will fill in
00273     * dummy streams for the rest
00274     */
00275    for (stream = 0; stream < sdp->media_count++; ++stream) {
00276       if (!pj_strcmp2(&sdp->media[stream]->desc.media, "image")) {
00277          sdp->media[0] = sdp->media[stream];
00278          sdp->media_count = 1;
00279          break;
00280       }
00281    }
00282 
00283    return 0;
00284 }
00285 
00286 /*! \brief Callback for when a response is received for a T.38 re-invite */
00287 static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
00288 {
00289    struct pjsip_status_line status = rdata->msg_info.msg->line.status;
00290    struct t38_state *state;
00291    RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
00292 
00293    if (status.code == 100) {
00294       return 0;
00295    }
00296 
00297    if (!(state = t38_state_get_or_alloc(session)) ||
00298       !(session_media = ao2_find(session->media, "image", OBJ_KEY))) {
00299       ast_log(LOG_WARNING, "Received response to T.38 re-invite on '%s' but state unavailable\n",
00300          ast_channel_name(session->channel));
00301       return 0;
00302    }
00303 
00304    t38_change_state(session, session_media, state, (status.code == 200) ? T38_ENABLED : T38_REJECTED);
00305 
00306    return 0;
00307 }
00308 
00309 /*! \brief Task for reacting to T.38 control frame */
00310 static int t38_interpret_parameters(void *obj)
00311 {
00312    RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
00313    const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
00314    struct t38_state *state = t38_state_get_or_alloc(data->session);
00315    RAII_VAR(struct ast_sip_session_media *, session_media, ao2_find(data->session->media, "image", OBJ_KEY), ao2_cleanup);
00316 
00317    /* Without session media or state we can't interpret parameters */
00318    if (!session_media || !state) {
00319       return 0;
00320    }
00321 
00322    switch (parameters->request_response) {
00323    case AST_T38_NEGOTIATED:
00324    case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
00325       /* Negotiation can not take place without a valid max_ifp value. */
00326       if (!parameters->max_ifp) {
00327          t38_change_state(data->session, session_media, state, T38_REJECTED);
00328          if (data->session->t38state == T38_PEER_REINVITE) {
00329             ast_sip_session_resume_reinvite(data->session);
00330          }
00331          break;
00332       } else if (data->session->t38state == T38_PEER_REINVITE) {
00333          state->our_parms = *parameters;
00334          /* modify our parameters to conform to the peer's parameters,
00335           * based on the rules in the ITU T.38 recommendation
00336           */
00337          if (!state->their_parms.fill_bit_removal) {
00338             state->our_parms.fill_bit_removal = 0;
00339          }
00340          if (!state->their_parms.transcoding_mmr) {
00341             state->our_parms.transcoding_mmr = 0;
00342          }
00343          if (!state->their_parms.transcoding_jbig) {
00344             state->our_parms.transcoding_jbig = 0;
00345          }
00346          state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
00347          state->our_parms.rate_management = state->their_parms.rate_management;
00348          ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
00349          t38_change_state(data->session, session_media, state, T38_ENABLED);
00350          ast_sip_session_resume_reinvite(data->session);
00351       } else if (data->session->t38state != T38_ENABLED) {
00352          if (t38_initialize_session(data->session, session_media)) {
00353             break;
00354          }
00355          state->our_parms = *parameters;
00356          ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
00357          t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE);
00358          ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb,
00359             AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
00360       }
00361       break;
00362    case AST_T38_TERMINATED:
00363    case AST_T38_REFUSED:
00364    case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
00365       if (data->session->t38state == T38_PEER_REINVITE) {
00366          t38_change_state(data->session, session_media, state, T38_REJECTED);
00367          ast_sip_session_resume_reinvite(data->session);
00368       } else if (data->session->t38state == T38_ENABLED) {
00369          t38_change_state(data->session, session_media, state, T38_DISABLED);
00370          ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
00371       }
00372       break;
00373    case AST_T38_REQUEST_PARMS: {    /* Application wants remote's parameters re-sent */
00374       struct ast_control_t38_parameters parameters = state->their_parms;
00375 
00376       if (data->session->t38state == T38_PEER_REINVITE) {
00377          parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
00378          parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
00379          ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
00380       }
00381       break;
00382    }
00383    default:
00384       break;
00385    }
00386 
00387    return 0;
00388 }
00389 
00390 /*! \brief Frame hook callback for writing */
00391 static struct ast_frame *t38_framehook_write(struct ast_sip_session *session, struct ast_frame *f)
00392 {
00393    if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS &&
00394       session->endpoint->media.t38.enabled) {
00395       struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(session, f);
00396 
00397       if (!data) {
00398          return f;
00399       }
00400 
00401       if (ast_sip_push_task(session->serializer, t38_interpret_parameters, data)) {
00402          ao2_ref(data, -1);
00403       }
00404    } else if (f->frametype == AST_FRAME_MODEM) {
00405       RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
00406 
00407       if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) &&
00408          session_media->udptl) {
00409          ast_udptl_write(session_media->udptl, f);
00410       }
00411    }
00412 
00413    return f;
00414 }
00415 
00416 /*! \brief Frame hook callback for reading */
00417 static struct ast_frame *t38_framehook_read(struct ast_sip_session *session, struct ast_frame *f)
00418 {
00419    if (ast_channel_fdno(session->channel) == 5) {
00420       RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
00421 
00422       if ((session_media = ao2_find(session->media, "image", OBJ_KEY)) &&
00423          session_media->udptl) {
00424          f = ast_udptl_read(session_media->udptl);
00425       }
00426    }
00427 
00428    return f;
00429 }
00430 
00431 /*! \brief Frame hook callback for T.38 related stuff */
00432 static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f,
00433    enum ast_framehook_event event, void *data)
00434 {
00435    struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
00436 
00437    if (event == AST_FRAMEHOOK_EVENT_READ) {
00438       f = t38_framehook_read(channel->session, f);
00439    } else if (event == AST_FRAMEHOOK_EVENT_WRITE) {
00440       f = t38_framehook_write(channel->session, f);
00441    }
00442 
00443    return f;
00444 }
00445 
00446 static void t38_masq(void *data, int framehook_id,
00447         struct ast_channel *old_chan, struct ast_channel *new_chan)
00448 {
00449    if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) {
00450       return;
00451    }
00452 
00453    /* This framehook is only applicable to PJSIP channels */
00454    ast_framehook_detach(new_chan, framehook_id);
00455 }
00456 
00457 static const struct ast_datastore_info t38_framehook_datastore = {
00458    .type = "T38 framehook",
00459 };
00460 
00461 /*! \brief Function called to attach T.38 framehook to channel when appropriate */
00462 static void t38_attach_framehook(struct ast_sip_session *session)
00463 {
00464    int framehook_id;
00465    struct ast_datastore *datastore = NULL;
00466    static struct ast_framehook_interface hook = {
00467       .version = AST_FRAMEHOOK_INTERFACE_VERSION,
00468       .event_cb = t38_framehook,
00469       .chan_fixup_cb = t38_masq,
00470       .chan_breakdown_cb = t38_masq,
00471    };
00472 
00473    /* Only attach the framehook if t38 is enabled for the endpoint */
00474    if (!session->endpoint->media.t38.enabled) {
00475       return;
00476    }
00477 
00478    /* Skip attaching the framehook if the T.38 datastore already exists for the channel */
00479    ast_channel_lock(session->channel);
00480    if ((datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, NULL))) {
00481       ast_channel_unlock(session->channel);
00482       return;
00483    }
00484    ast_channel_unlock(session->channel);
00485 
00486    framehook_id = ast_framehook_attach(session->channel, &hook);
00487    if (framehook_id < 0) {
00488       ast_log(LOG_WARNING, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n",
00489          ast_channel_name(session->channel));
00490       return;
00491    }
00492 
00493    ast_channel_lock(session->channel);
00494    datastore = ast_datastore_alloc(&t38_framehook_datastore, NULL);
00495    if (!datastore) {
00496       ast_log(LOG_ERROR, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n",
00497          ast_channel_name(session->channel));
00498       ast_framehook_detach(session->channel, framehook_id);
00499       ast_channel_unlock(session->channel);
00500       return;
00501    }
00502 
00503    ast_channel_datastore_add(session->channel, datastore);
00504    ast_channel_unlock(session->channel);
00505 }
00506 
00507 /*! \brief Function called when an INVITE goes out */
00508 static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
00509 {
00510    t38_attach_framehook(session);
00511    return 0;
00512 }
00513 
00514 /*! \brief Function called when an INVITE comes in */
00515 static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
00516 {
00517    t38_attach_framehook(session);
00518 }
00519 
00520 /*! \brief Get Max T.38 Transmission rate from T38 capabilities */
00521 static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
00522 {
00523    switch (rate) {
00524    case AST_T38_RATE_2400:
00525       return 2400;
00526    case AST_T38_RATE_4800:
00527       return 4800;
00528    case AST_T38_RATE_7200:
00529       return 7200;
00530    case AST_T38_RATE_9600:
00531       return 9600;
00532    case AST_T38_RATE_12000:
00533       return 12000;
00534    case AST_T38_RATE_14400:
00535       return 14400;
00536    default:
00537       return 0;
00538    }
00539 }
00540 
00541 /*! \brief Supplement for adding framehook to session channel */
00542 static struct ast_sip_session_supplement t38_supplement = {
00543    .method = "INVITE",
00544    .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
00545    .incoming_request = t38_incoming_invite_request,
00546    .outgoing_request = t38_outgoing_invite_request,
00547 };
00548 
00549 /*! \brief Parse a T.38 image stream and store the attribute information */
00550 static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media,
00551    const struct pjmedia_sdp_media *stream)
00552 {
00553    unsigned int attr_i;
00554 
00555    for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
00556       pjmedia_sdp_attr *attr = stream->attr[attr_i];
00557 
00558       if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
00559          /* This is purposely left empty, it is unused */
00560       } else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
00561          switch (pj_strtoul(&attr->value)) {
00562          case 14400:
00563             state->their_parms.rate = AST_T38_RATE_14400;
00564             break;
00565          case 12000:
00566             state->their_parms.rate = AST_T38_RATE_12000;
00567             break;
00568          case 9600:
00569             state->their_parms.rate = AST_T38_RATE_9600;
00570             break;
00571          case 7200:
00572             state->their_parms.rate = AST_T38_RATE_7200;
00573             break;
00574          case 4800:
00575             state->their_parms.rate = AST_T38_RATE_4800;
00576             break;
00577          case 2400:
00578             state->their_parms.rate = AST_T38_RATE_2400;
00579             break;
00580          }
00581       } else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
00582          state->their_parms.version = pj_strtoul(&attr->value);
00583       } else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
00584          if (!session->endpoint->media.t38.maxdatagram) {
00585             ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
00586          }
00587       } else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
00588          state->their_parms.fill_bit_removal = 1;
00589       } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
00590          state->their_parms.transcoding_mmr = 1;
00591       } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
00592          state->their_parms.transcoding_jbig = 1;
00593       } else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
00594          if (!pj_stricmp2(&attr->value, "localTCF")) {
00595             state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
00596          } else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
00597             state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
00598          }
00599       } else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
00600          if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
00601             ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
00602          } else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
00603             ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_FEC);
00604          } else {
00605             ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_NONE);
00606          }
00607       }
00608 
00609    }
00610 }
00611 
00612 /*! \brief Function which defers an incoming media stream */
00613 static enum ast_sip_session_sdp_stream_defer defer_incoming_sdp_stream(
00614    struct ast_sip_session *session, struct ast_sip_session_media *session_media,
00615    const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
00616 {
00617    struct t38_state *state;
00618 
00619    if (!session->endpoint->media.t38.enabled) {
00620       return AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED;
00621    }
00622 
00623    if (t38_initialize_session(session, session_media)) {
00624       return AST_SIP_SESSION_SDP_DEFER_ERROR;
00625    }
00626 
00627    if (!(state = t38_state_get_or_alloc(session))) {
00628       return AST_SIP_SESSION_SDP_DEFER_ERROR;
00629    }
00630 
00631    t38_interpret_sdp(state, session, session_media, stream);
00632 
00633    /* If they are initiating the re-invite we need to defer responding until later */
00634    if (session->t38state == T38_DISABLED) {
00635       t38_change_state(session, session_media, state, T38_PEER_REINVITE);
00636       return AST_SIP_SESSION_SDP_DEFER_NEEDED;
00637    }
00638 
00639    return AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED;
00640 }
00641 
00642 /*! \brief Function which negotiates an incoming media stream */
00643 static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
00644                 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
00645 {
00646    struct t38_state *state;
00647    char host[NI_MAXHOST];
00648    RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
00649 
00650    if (!session->endpoint->media.t38.enabled) {
00651       return -1;
00652    }
00653 
00654    if (!(state = t38_state_get_or_alloc(session))) {
00655       return -1;
00656    }
00657 
00658    if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
00659       t38_change_state(session, session_media, state, T38_DISABLED);
00660       return -1;
00661    }
00662 
00663    ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
00664 
00665    /* Ensure that the address provided is valid */
00666    if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
00667       /* The provided host was actually invalid so we error out this negotiation */
00668       return -1;
00669    }
00670 
00671    /* Check the address family to make sure it matches configured */
00672    if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) ||
00673       (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
00674       /* The address does not match configured */
00675       return -1;
00676    }
00677 
00678    return 1;
00679 }
00680 
00681 /*! \brief Function which creates an outgoing stream */
00682 static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
00683                   struct pjmedia_sdp_session *sdp)
00684 {
00685    pj_pool_t *pool = session->inv_session->pool_prov;
00686    static const pj_str_t STR_IN = { "IN", 2 };
00687    static const pj_str_t STR_IP4 = { "IP4", 3};
00688    static const pj_str_t STR_IP6 = { "IP6", 3};
00689    static const pj_str_t STR_UDPTL = { "udptl", 5 };
00690    static const pj_str_t STR_T38 = { "t38", 3 };
00691    static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
00692    static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
00693    static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
00694    static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
00695    struct t38_state *state;
00696    pjmedia_sdp_media *media;
00697    char hostip[PJ_INET6_ADDRSTRLEN+2];
00698    struct ast_sockaddr addr;
00699    char tmp[512];
00700    pj_str_t stmp;
00701 
00702    if (!session->endpoint->media.t38.enabled) {
00703       return 1;
00704    } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
00705       (session->t38state != T38_ENABLED)) {
00706       return 1;
00707    } else if (!(state = t38_state_get_or_alloc(session))) {
00708       return -1;
00709    } else if (t38_initialize_session(session, session_media)) {
00710       return -1;
00711    }
00712 
00713    if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
00714       !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
00715       return -1;
00716    }
00717 
00718    media->desc.media = pj_str(session_media->stream_type);
00719    media->desc.transport = STR_UDPTL;
00720 
00721    if (ast_strlen_zero(session->endpoint->media.address)) {
00722       pj_sockaddr localaddr;
00723 
00724       if (pj_gethostip(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET(), &localaddr)) {
00725          return -1;
00726       }
00727       pj_sockaddr_print(&localaddr, hostip, sizeof(hostip), 2);
00728    } else {
00729       ast_copy_string(hostip, session->endpoint->media.address, sizeof(hostip));
00730    }
00731 
00732    media->conn->net_type = STR_IN;
00733    media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
00734    pj_strdup2(pool, &media->conn->addr, hostip);
00735    ast_udptl_get_us(session_media->udptl, &addr);
00736    media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
00737    media->desc.port_count = 1;
00738    media->desc.fmt[media->desc.fmt_count++] = STR_T38;
00739 
00740    snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
00741    media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
00742 
00743    snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
00744    media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));
00745 
00746    if (state->our_parms.fill_bit_removal) {
00747       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
00748    }
00749 
00750    if (state->our_parms.transcoding_mmr) {
00751       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
00752    }
00753 
00754    if (state->our_parms.transcoding_jbig) {
00755       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
00756    }
00757 
00758    switch (state->our_parms.rate_management) {
00759    case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
00760       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
00761       break;
00762    case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
00763       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
00764       break;
00765    }
00766 
00767    snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
00768    media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));
00769 
00770    switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
00771    case UDPTL_ERROR_CORRECTION_NONE:
00772       break;
00773    case UDPTL_ERROR_CORRECTION_FEC:
00774       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
00775       break;
00776    case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00777       media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
00778       break;
00779    }
00780 
00781    sdp->media[sdp->media_count++] = media;
00782 
00783    return 1;
00784 }
00785 
00786 /*! \brief Function which applies a negotiated stream */
00787 static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
00788                    const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
00789                    const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
00790 {
00791    RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
00792    char host[NI_MAXHOST];
00793    struct t38_state *state;
00794 
00795    if (!session_media->udptl) {
00796       return 0;
00797    }
00798 
00799    if (!(state = t38_state_get_or_alloc(session))) {
00800       return -1;
00801    }
00802 
00803    ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
00804 
00805    /* Ensure that the address provided is valid */
00806    if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
00807       /* The provided host was actually invalid so we error out this negotiation */
00808       return -1;
00809    }
00810 
00811    ast_sockaddr_set_port(addrs, remote_stream->desc.port);
00812    ast_udptl_set_peer(session_media->udptl, addrs);
00813 
00814    t38_interpret_sdp(state, session, session_media, remote_stream);
00815 
00816    return 0;
00817 }
00818 
00819 /*! \brief Function which updates the media stream with external media address, if applicable */
00820 static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
00821 {
00822    char host[NI_MAXHOST];
00823    struct ast_sockaddr addr = { { 0, } };
00824 
00825    /* If the stream has been rejected there will be no connection line */
00826    if (!stream->conn) {
00827       return;
00828    }
00829 
00830    ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
00831    ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
00832 
00833    /* Is the address within the SDP inside the same network? */
00834    if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) {
00835       return;
00836    }
00837 
00838    pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
00839 }
00840 
00841 /*! \brief Function which destroys the UDPTL instance when session ends */
00842 static void stream_destroy(struct ast_sip_session_media *session_media)
00843 {
00844    if (session_media->udptl) {
00845       ast_udptl_destroy(session_media->udptl);
00846    }
00847    session_media->udptl = NULL;
00848 }
00849 
00850 /*! \brief SDP handler for 'image' media stream */
00851 static struct ast_sip_session_sdp_handler image_sdp_handler = {
00852    .id = "image",
00853    .defer_incoming_sdp_stream = defer_incoming_sdp_stream,
00854    .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
00855    .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
00856    .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
00857    .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
00858    .stream_destroy = stream_destroy,
00859 };
00860 
00861 /*! \brief Unloads the SIP T.38 module from Asterisk */
00862 static int unload_module(void)
00863 {
00864    ast_sip_session_unregister_sdp_handler(&image_sdp_handler, "image");
00865    ast_sip_session_unregister_supplement(&t38_supplement);
00866 
00867    return 0;
00868 }
00869 
00870 /*!
00871  * \brief Load the module
00872  *
00873  * Module loading including tests for configuration or dependencies.
00874  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
00875  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
00876  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
00877  * configuration file or other non-critical problem return
00878  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
00879  */
00880 static int load_module(void)
00881 {
00882    CHECK_PJSIP_SESSION_MODULE_LOADED();
00883 
00884    ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
00885    ast_sockaddr_parse(&address_ipv6, "::", 0);
00886 
00887    if (ast_sip_session_register_supplement(&t38_supplement)) {
00888       ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n");
00889       goto end;
00890    }
00891 
00892    if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) {
00893       ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
00894       goto end;
00895    }
00896 
00897    return AST_MODULE_LOAD_SUCCESS;
00898 end:
00899    unload_module();
00900 
00901    return AST_MODULE_LOAD_FAILURE;
00902 }
00903 
00904 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Support",
00905       .support_level = AST_MODULE_SUPPORT_CORE,
00906       .load = load_module,
00907       .unload = unload_module,
00908       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
00909    );

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