Asterisk - The Open Source Telephony Project GIT-master-a358458
res_pjsip_t38.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \author Joshua Colp <jcolp@digium.com>
22 *
23 * \brief SIP T.38 handling
24 */
25
26/*** MODULEINFO
27 <depend>pjproject</depend>
28 <depend>res_pjsip</depend>
29 <depend>res_pjsip_session</depend>
30 <support_level>core</support_level>
31 ***/
32
33#include "asterisk.h"
34
35#include <pjsip.h>
36#include <pjsip_ua.h>
37#include <pjmedia.h>
38#include <pjlib.h>
39
40#include "asterisk/utils.h"
41#include "asterisk/module.h"
42#include "asterisk/udptl.h"
43#include "asterisk/netsock2.h"
44#include "asterisk/channel.h"
45#include "asterisk/acl.h"
46#include "asterisk/stream.h"
48
49#include "asterisk/res_pjsip.h"
51
52/*! \brief The number of seconds after receiving a T.38 re-invite before automatically rejecting it */
53#define T38_AUTOMATIC_REJECTION_SECONDS 5
54
55/*! \brief Address for UDPTL */
56static struct ast_sockaddr address;
57
58/*! \brief T.38 state information */
59struct t38_state {
60 /*! \brief Current state */
62 /*! \brief Our T.38 parameters */
64 /*! \brief Their T.38 parameters */
66 /*! \brief Timer entry for automatically rejecting an inbound re-invite */
67 pj_timer_entry timer;
68 /*! Preserved media state for when T.38 ends */
70};
71
72/*! \brief Destructor for T.38 state information */
73static void t38_state_destroy(void *obj)
74{
75 struct t38_state *state = obj;
76
78 ast_free(obj);
79}
80
81/*! \brief Datastore for attaching T.38 state information */
82static const struct ast_datastore_info t38_datastore = {
83 .type = "t38",
84 .destroy = t38_state_destroy,
85};
86
87/*! \brief Structure for T.38 parameters task data */
89 /*! \brief Session itself */
91 /*! \brief T.38 control frame */
93};
94
95/*! \brief Destructor for T.38 data */
97{
98 struct t38_parameters_task_data *data = obj;
99
100 ao2_cleanup(data->session);
101
102 if (data->frame) {
103 ast_frfree(data->frame);
104 }
105}
106
107/*! \brief Allocator for T.38 data */
109 struct ast_frame *frame)
110{
112
113 if (!data) {
114 return NULL;
115 }
116
117 data->session = session;
118 ao2_ref(session, +1);
119 data->frame = ast_frdup(frame);
120 if (!data->frame) {
121 ao2_ref(data, -1);
122 data = NULL;
123 }
124
125 return data;
126}
127
128/*! \brief Helper function for changing the T.38 state */
129static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
130 struct t38_state *state, enum ast_sip_session_t38state new_state)
131{
132 enum ast_sip_session_t38state old_state = session->t38state;
133 struct ast_control_t38_parameters parameters = { .request_response = 0, };
134 pj_time_val delay = { .sec = T38_AUTOMATIC_REJECTION_SECONDS };
135
136 if (old_state == new_state) {
137 return;
138 }
139
140 session->t38state = new_state;
141 ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n",
142 new_state, old_state,
143 session->channel ? ast_channel_name(session->channel) : "<gone>");
144
145 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
146 &state->timer, 0)) {
147 ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n",
148 session->channel ? ast_channel_name(session->channel) : "<gone>");
149 ao2_ref(session, -1);
150 }
151
152 if (!session->channel) {
153 return;
154 }
155
156 switch (new_state) {
158 ao2_ref(session, +1);
159 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &state->timer, &delay) != PJ_SUCCESS) {
160 ast_log(LOG_WARNING, "Scheduling of automatic T.38 rejection for channel '%s' failed\n",
161 ast_channel_name(session->channel));
162 ao2_ref(session, -1);
163 }
164 parameters = state->their_parms;
165 parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
167 ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
168
169 /* Inform the bridge the channel is in that it needs to be reconfigured */
171 break;
172 case T38_ENABLED:
173 parameters = state->their_parms;
174 parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
176 ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
177 break;
178 case T38_REJECTED:
179 case T38_DISABLED:
180 if (old_state == T38_ENABLED) {
182 } else if (old_state == T38_LOCAL_REINVITE) {
184 }
185 break;
187 /* Inform the bridge the channel is in that it needs to be reconfigured */
189 break;
190 case T38_MAX_ENUM:
191 /* Well, that shouldn't happen */
192 ast_assert(0);
193 break;
194 }
195
196 if (parameters.request_response) {
197 ast_queue_control_data(session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
198 }
199}
200
201/*! \brief Task function which rejects a T.38 re-invite and resumes handling it */
202static int t38_automatic_reject(void *obj)
203{
206
207 if (!datastore) {
208 return 0;
209 }
210
211 ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n",
212 session->channel ? ast_channel_name(session->channel) : "<gone>");
213
214 t38_change_state(session, NULL, datastore->data, T38_REJECTED);
216
217 return 0;
218}
219
220/*! \brief Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it */
221static void t38_automatic_reject_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
222{
223 struct ast_sip_session *session = entry->user_data;
224
226 ao2_ref(session, -1);
227 }
228}
229
230/*! \brief Helper function which retrieves or allocates a T.38 state information datastore */
232{
234 struct t38_state *state;
235
236 /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
237 if (datastore) {
238 return datastore->data;
239 }
240
241 if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38"))
242 || !(datastore->data = ast_calloc(1, sizeof(struct t38_state)))
243 || ast_sip_session_add_datastore(session, datastore)) {
244 return NULL;
245 }
246
247 state = datastore->data;
248
249 /* This will get bumped up before scheduling */
250 pj_timer_entry_init(&state->timer, 0, session, t38_automatic_reject_timer_cb);
251
252 return state;
253}
254
255/*! \brief Initializes UDPTL support on a session, only done when actually needed */
256static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
257{
258 struct ast_sockaddr temp_media_address;
259 struct ast_sockaddr *media_address = &address;
260
261 if (session_media->udptl) {
262 return 0;
263 }
264
265 if (session->endpoint->media.t38.bind_udptl_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
266 if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) {
267 ast_debug(5, "Endpoint %s: Binding UDPTL media to %s\n",
269 session->endpoint->media.address);
270 media_address = &temp_media_address;
271 } else {
272 ast_debug(5, "Endpoint %s: UDPTL media address invalid: %s\n",
274 session->endpoint->media.address);
275 }
276 } else {
277 struct ast_sip_transport *transport;
278
279 transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
280 session->endpoint->transport);
281 if (transport) {
282 struct ast_sip_transport_state *trans_state;
283
285 if (trans_state) {
286 char hoststr[PJ_INET6_ADDRSTRLEN];
287
288 pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0);
289 if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) {
290 ast_debug(5, "Transport %s bound to %s: Using it for UDPTL media.\n",
291 session->endpoint->transport, hoststr);
292 media_address = &temp_media_address;
293 } else {
294 ast_debug(5, "Transport %s bound to %s: Invalid for UDPTL media.\n",
295 session->endpoint->transport, hoststr);
296 }
297 ao2_ref(trans_state, -1);
298 }
299 ao2_ref(transport, -1);
300 }
301 }
302
303 if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, media_address))) {
304 return -1;
305 }
306
307 ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction);
308 ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat);
309 ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram);
310 ast_debug(3, "UDPTL initialized on session for %s\n", ast_channel_name(session->channel));
311
312 return 0;
313}
314
315/*! \brief Callback for when T.38 reinvite SDP is created */
316static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
317{
318 struct t38_state *state;
319
321 if (!state) {
322 return -1;
323 }
324
325 state->media_state = ast_sip_session_media_state_clone(session->active_media_state);
326
327 return 0;
328}
329
330/*! \brief Callback for when a response is received for a T.38 re-invite */
331static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
332{
333 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
334 struct t38_state *state;
335 struct ast_sip_session_media *session_media = NULL;
336
337 if (status.code / 100 <= 1) {
338 /* Ignore any non-final responses (1xx) */
339 return 0;
340 }
341
342 if (session->t38state != T38_LOCAL_REINVITE) {
343 /* Do nothing. We have already processed a final response. */
344 ast_debug(3, "Received %d response to T.38 re-invite on '%s' but already had a final response (T.38 state:%d)\n",
345 status.code,
346 session->channel ? ast_channel_name(session->channel) : "unknown channel",
347 session->t38state);
348 return 0;
349 }
350
352 if (!session->channel || !state) {
353 ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but state unavailable\n",
354 status.code,
355 session->channel ? ast_channel_name(session->channel) : "unknown channel");
356 return 0;
357 }
358
359 if (status.code / 100 == 2) {
360 /* Accept any 2xx response as successfully negotiated */
361 int index;
362
363 session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
364
365 /*
366 * If there is a session_media object, but no udptl object available
367 * then it's assumed the stream was declined.
368 */
369 if (session_media && !session_media->udptl) {
370 session_media = NULL;
371 }
372
373 if (!session_media) {
374 ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n",
375 status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel");
376 } else {
377 t38_change_state(session, session_media, state, T38_ENABLED);
378
379 /* Stop all the streams in the stored away active state, they'll go back to being active once
380 * we reinvite back.
381 */
382 for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
383 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
384
385 if (session_media && session_media->handler && session_media->handler->stream_stop) {
386 session_media->handler->stream_stop(session_media);
387 }
388 }
389
390 return 0;
391 }
392 } else {
393 session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
394 }
395
396 /* If no session_media then response contained a declined stream, so disable */
398
399 /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
401 state->media_state = NULL;
402 ast_sip_session_media_state_reset(session->pending_media_state);
403
404 return 0;
405}
406
407/*! \brief Helper function which creates a media state for strictly T.38 */
409{
410 struct ast_sip_session_media_state *media_state;
411 struct ast_stream *stream;
412 struct ast_format_cap *caps;
413 struct ast_sip_session_media *session_media;
414
415 media_state = ast_sip_session_media_state_alloc();
416 if (!media_state) {
417 return NULL;
418 }
419
420 media_state->topology = ast_stream_topology_alloc();
421 if (!media_state->topology) {
423 return NULL;
424 }
425
426 stream = ast_stream_alloc("t38", AST_MEDIA_TYPE_IMAGE);
427 if (!stream) {
429 return NULL;
430 }
431
433 if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) {
434 ast_stream_free(stream);
436 return NULL;
437 }
438
440 if (!caps) {
442 return NULL;
443 }
444
445 ast_stream_set_formats(stream, caps);
446 /* stream holds a reference to cap, release the local reference
447 * now so we don't have to deal with it in the error condition. */
448 ao2_ref(caps, -1);
451 return NULL;
452 }
453
454 session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0);
455 if (!session_media) {
457 return NULL;
458 }
459
460 if (t38_initialize_session(session, session_media)) {
462 return NULL;
463 }
464
465 return media_state;
466}
467
468/*! \brief Task for reacting to T.38 control frame */
469static int t38_interpret_parameters(void *obj)
470{
471 RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
472 const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
473 struct t38_state *state = t38_state_get_or_alloc(data->session);
474 struct ast_sip_session_media *session_media = NULL;
475
476 if (!state) {
477 return 0;
478 }
479
480 switch (parameters->request_response) {
482 case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
483 /* Negotiation can not take place without a valid max_ifp value. */
484 if (!parameters->max_ifp) {
485 if (data->session->t38state == T38_PEER_REINVITE) {
486 t38_change_state(data->session, NULL, state, T38_REJECTED);
487 ast_sip_session_resume_reinvite(data->session);
488 } else if (data->session->t38state == T38_ENABLED) {
489 t38_change_state(data->session, NULL, state, T38_DISABLED);
490 ast_sip_session_refresh(data->session, NULL, NULL, NULL,
492 state->media_state = NULL;
493 }
494 break;
495 } else if (data->session->t38state == T38_PEER_REINVITE) {
496 state->our_parms = *parameters;
497 /* modify our parameters to conform to the peer's parameters,
498 * based on the rules in the ITU T.38 recommendation
499 */
500 if (!state->their_parms.fill_bit_removal) {
501 state->our_parms.fill_bit_removal = 0;
502 }
503 if (!state->their_parms.transcoding_mmr) {
504 state->our_parms.transcoding_mmr = 0;
505 }
506 if (!state->their_parms.transcoding_jbig) {
507 state->our_parms.transcoding_jbig = 0;
508 }
509 state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
510 state->our_parms.rate_management = state->their_parms.rate_management;
511 session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
512 if (!session_media) {
513 ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n",
514 data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
515 break;
516 }
517 ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
518 t38_change_state(data->session, session_media, state, T38_ENABLED);
519 ast_sip_session_resume_reinvite(data->session);
520 } else if ((data->session->t38state != T38_ENABLED) ||
521 ((data->session->t38state == T38_ENABLED) &&
523 struct ast_sip_session_media_state *media_state;
524
525 media_state = t38_create_media_state(data->session);
526 if (!media_state) {
527 break;
528 }
529 state->our_parms = *parameters;
530 session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE];
531 if (!session_media) {
532 ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n",
533 data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
534 break;
535 }
536 ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
540 }
541 break;
543 case AST_T38_REFUSED:
544 case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
545 if (data->session->t38state == T38_PEER_REINVITE) {
546 t38_change_state(data->session, NULL, state, T38_REJECTED);
547 ast_sip_session_resume_reinvite(data->session);
548 } else if (data->session->t38state == T38_ENABLED) {
549 t38_change_state(data->session, NULL, state, T38_DISABLED);
551 state->media_state = NULL;
552 }
553 break;
554 case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */
555 struct ast_control_t38_parameters parameters = state->their_parms;
556
557 if (data->session->t38state == T38_PEER_REINVITE) {
558 session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
559 if (!session_media) {
560 ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n",
561 data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
562 break;
563 }
564 parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
566 ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
567 }
568 break;
569 }
570 default:
571 break;
572 }
573
574 return 0;
575}
576
577/*! \brief Frame hook callback for T.38 related stuff */
578static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f,
579 enum ast_framehook_event event, void *data)
580{
581 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
582
584 return f;
585 }
586
589 if (channel->session->endpoint->media.t38.enabled) {
591
593 if (task_data
596 ao2_ref(task_data, -1);
597 }
598 } else {
599 static const struct ast_control_t38_parameters rsp_refused = {
601 };
602 static const struct ast_control_t38_parameters rsp_terminated = {
604 };
605 const struct ast_control_t38_parameters *parameters = f->data.ptr;
606
607 switch (parameters->request_response) {
609 ast_debug(2, "T.38 support not enabled on %s, refusing T.38 negotiation\n",
610 ast_channel_name(chan));
612 &rsp_refused, sizeof(rsp_refused));
613 break;
615 ast_debug(2, "T.38 support not enabled on %s, 'terminating' T.38 session\n",
616 ast_channel_name(chan));
618 &rsp_terminated, sizeof(rsp_terminated));
619 break;
620 default:
621 break;
622 }
623 }
624 }
625
626 return f;
627}
628
629static void t38_masq(void *data, int framehook_id,
630 struct ast_channel *old_chan, struct ast_channel *new_chan)
631{
632 if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) {
633 return;
634 }
635
636 /* This framehook is only applicable to PJSIP channels */
637 ast_framehook_detach(new_chan, framehook_id);
638}
639
640static int t38_consume(void *data, enum ast_frame_type type)
641{
642 return (type == AST_FRAME_CONTROL) ? 1 : 0;
643}
644
646 .type = "T38 framehook",
647};
648
649/*! \brief Function called to attach T.38 framehook to channel when appropriate */
651{
652 int framehook_id;
653 struct ast_datastore *datastore = NULL;
654 static struct ast_framehook_interface hook = {
656 .event_cb = t38_framehook,
657 .consume_cb = t38_consume,
658 .chan_fixup_cb = t38_masq,
659 .chan_breakdown_cb = t38_masq,
660 };
661
662 /* If the channel's already gone, bail */
663 if (!session->channel) {
664 return;
665 }
666
667 /* Always attach the framehook so we can quickly reject */
668
669 ast_channel_lock(session->channel);
670
671 /* Skip attaching the framehook if the T.38 datastore already exists for the channel */
673 NULL);
674 if (datastore) {
675 ast_channel_unlock(session->channel);
676 return;
677 }
678
679 framehook_id = ast_framehook_attach(session->channel, &hook);
680 if (framehook_id < 0) {
681 ast_log(LOG_WARNING, "Could not attach T.38 Frame hook, T.38 will be unavailable on '%s'\n",
682 ast_channel_name(session->channel));
683 ast_channel_unlock(session->channel);
684 return;
685 }
686
688 if (!datastore) {
689 ast_log(LOG_ERROR, "Could not alloc T.38 Frame hook datastore, T.38 will be unavailable on '%s'\n",
690 ast_channel_name(session->channel));
691 ast_framehook_detach(session->channel, framehook_id);
692 ast_channel_unlock(session->channel);
693 return;
694 }
695
696 ast_channel_datastore_add(session->channel, datastore);
697 ast_channel_unlock(session->channel);
698}
699
700/*! \brief Function called when an INVITE arrives */
701static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
702{
704 return 0;
705}
706
707/*! \brief Function called when an INVITE is sent */
708static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
709{
711}
712
713/*! \brief Get Max T.38 Transmission rate from T38 capabilities */
714static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
715{
716 switch (rate) {
718 return 2400;
720 return 4800;
722 return 7200;
724 return 9600;
726 return 12000;
728 return 14400;
729 default:
730 return 0;
731 }
732}
733
734/*! \brief Supplement for adding framehook to session channel */
736 .method = "INVITE",
738 .incoming_request = t38_incoming_invite_request,
739 .outgoing_request = t38_outgoing_invite_request,
740};
741
742/*! \brief Parse a T.38 image stream and store the attribute information */
743static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media,
744 const struct pjmedia_sdp_media *stream)
745{
746 unsigned int attr_i;
747
748 for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
749 pjmedia_sdp_attr *attr = stream->attr[attr_i];
750
751 if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
752 /* This is purposely left empty, it is unused */
753 } else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
754 switch (pj_strtoul(&attr->value)) {
755 case 14400:
756 state->their_parms.rate = AST_T38_RATE_14400;
757 break;
758 case 12000:
759 state->their_parms.rate = AST_T38_RATE_12000;
760 break;
761 case 9600:
762 state->their_parms.rate = AST_T38_RATE_9600;
763 break;
764 case 7200:
765 state->their_parms.rate = AST_T38_RATE_7200;
766 break;
767 case 4800:
768 state->their_parms.rate = AST_T38_RATE_4800;
769 break;
770 case 2400:
771 state->their_parms.rate = AST_T38_RATE_2400;
772 break;
773 }
774 } else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
775 state->their_parms.version = pj_strtoul(&attr->value);
776 } else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
777 if (!session->endpoint->media.t38.maxdatagram) {
778 ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
779 }
780 } else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
781 state->their_parms.fill_bit_removal = 1;
782 } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
783 state->their_parms.transcoding_mmr = 1;
784 } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
785 state->their_parms.transcoding_jbig = 1;
786 } else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
787 if (!pj_stricmp2(&attr->value, "localTCF")) {
788 state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
789 } else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
790 state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
791 }
792 } else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
793 if (session->t38state == T38_LOCAL_REINVITE) {
794 if (session->endpoint->media.t38.error_correction == UDPTL_ERROR_CORRECTION_FEC) {
795 if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
797 } else if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
799 } else {
801 }
802 } else if (session->endpoint->media.t38.error_correction == UDPTL_ERROR_CORRECTION_REDUNDANCY) {
803 if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
805 } else {
807 }
808 } else {
810 }
811 } else {
812 if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
814 } else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
816 } else {
818 }
819 }
820 }
821
822 }
823}
824
825/*! \brief Function which defers an incoming media stream */
827 struct ast_sip_session *session, struct ast_sip_session_media *session_media,
828 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
829{
830 struct t38_state *state;
831
832 if (!session->endpoint->media.t38.enabled) {
833 ast_debug(3, "Not deferring incoming SDP stream: T.38 not enabled on %s\n", ast_channel_name(session->channel));
835 }
836
837 if (t38_initialize_session(session, session_media)) {
838 ast_debug(3, "Not deferring incoming SDP stream: Failed to initialize UDPTL on %s\n", ast_channel_name(session->channel));
840 }
841
844 }
845
846 t38_interpret_sdp(state, session, session_media, stream);
847
848 /* If they are initiating the re-invite we need to defer responding until later */
849 if (session->t38state == T38_DISABLED) {
851 ast_debug(3, "Deferring incoming SDP stream on %s for peer re-invite\n", ast_channel_name(session->channel));
853 }
854
856}
857
858/*! \brief Function which negotiates an incoming media stream */
860 struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp,
861 int index, struct ast_stream *asterisk_stream)
862{
863 struct t38_state *state;
864 char host[NI_MAXHOST];
865 pjmedia_sdp_media *stream = sdp->media[index];
866 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
867
868 if (!session->endpoint->media.t38.enabled) {
869 ast_debug(3, "Declining; T.38 not enabled on session\n");
870 return 0;
871 }
872
874 return 0;
875 }
876
877 if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
878 ast_debug(3, "Declining; T.38 state is rejected or declined\n");
880 return 0;
881 }
882
883 ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
884
885 /* Ensure that the address provided is valid */
886 if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
887 /* The provided host was actually invalid so we error out this negotiation */
888 ast_debug(3, "Declining; provided host is invalid\n");
889 return 0;
890 }
891
892 /* Check the address family to make sure it matches configured */
893 if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) ||
894 (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
895 /* The address does not match configured */
896 ast_debug(3, "Declining, provided host does not match configured address family\n");
897 return 0;
898 }
899
900 return 1;
901}
902
903/*! \brief Function which creates an outgoing stream */
905 struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
906{
907 pj_pool_t *pool = session->inv_session->pool_prov;
908 static const pj_str_t STR_IN = { "IN", 2 };
909 static const pj_str_t STR_IP4 = { "IP4", 3};
910 static const pj_str_t STR_IP6 = { "IP6", 3};
911 static const pj_str_t STR_UDPTL = { "udptl", 5 };
912 static const pj_str_t STR_T38 = { "t38", 3 };
913 static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
914 static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
915 static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
916 static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
917 struct t38_state *state;
918 pjmedia_sdp_media *media;
919 const char *hostip = NULL;
920 struct ast_sockaddr addr;
921 char tmp[512];
922 pj_str_t stmp;
923
924 if (!session->endpoint->media.t38.enabled) {
925 ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
926 return 1;
927 } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
928 (session->t38state != T38_ENABLED)) {
929 ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
930 return 1;
931 } else if (!(state = t38_state_get_or_alloc(session))) {
932 return -1;
933 } else if (t38_initialize_session(session, session_media)) {
934 ast_debug(3, "Not creating outgoing SDP stream: Failed to initialize T.38 session\n");
935 return -1;
936 }
937
938 if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
939 !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
940 return -1;
941 }
942
943 pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type));
944 media->desc.transport = STR_UDPTL;
945
946 if (ast_strlen_zero(session->endpoint->media.address)) {
947 hostip = ast_sip_get_host_ip_string(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET());
948 } else {
949 hostip = session->endpoint->media.address;
950 }
951
952 if (ast_strlen_zero(hostip)) {
953 ast_debug(3, "Not creating outgoing SDP stream: no known host IP\n");
954 return -1;
955 }
956
957 media->conn->net_type = STR_IN;
958 media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
959 pj_strdup2(pool, &media->conn->addr, hostip);
960 ast_udptl_get_us(session_media->udptl, &addr);
961 media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
962 media->desc.port_count = 1;
963 media->desc.fmt[media->desc.fmt_count++] = STR_T38;
964
965 snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
966 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
967
968 snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
969 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));
970
971 if (state->our_parms.fill_bit_removal) {
972 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
973 }
974
975 if (state->our_parms.transcoding_mmr) {
976 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
977 }
978
979 if (state->our_parms.transcoding_jbig) {
980 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
981 }
982
983 switch (state->our_parms.rate_management) {
985 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
986 break;
988 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
989 break;
990 }
991
992 snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
993 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));
994
995 switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
997 break;
999 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
1000 break;
1002 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
1003 break;
1004 }
1005
1006 sdp->media[sdp->media_count++] = media;
1007
1008 return 1;
1009}
1010
1012{
1013 struct ast_frame *frame;
1014
1015 if (!session_media->udptl) {
1016 return &ast_null_frame;
1017 }
1018
1019 frame = ast_udptl_read(session_media->udptl);
1020 if (!frame) {
1021 return NULL;
1022 }
1023
1024 frame->stream_num = session_media->stream_num;
1025
1026 return frame;
1027}
1028
1029static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
1030{
1031 if (!session_media->udptl) {
1032 return 0;
1033 }
1034
1035 return ast_udptl_write(session_media->udptl, frame);
1036}
1037
1038/*! \brief Function which applies a negotiated stream */
1040 struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local,
1041 const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
1042{
1043 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
1044 pjmedia_sdp_media *remote_stream = remote->media[index];
1045 char host[NI_MAXHOST];
1046 struct t38_state *state;
1047
1048 if (!session_media->udptl) {
1049 ast_debug(3, "Not applying negotiated SDP stream: no UDTPL session\n");
1050 return 0;
1051 }
1052
1054 return -1;
1055 }
1056
1057 ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
1058
1059 /* Ensure that the address provided is valid */
1060 if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
1061 /* The provided host was actually invalid so we error out this negotiation */
1062 ast_debug(3, "Not applying negotiated SDP stream: failed to resolve remote stream host\n");
1063 return -1;
1064 }
1065
1066 ast_sockaddr_set_port(addrs, remote_stream->desc.port);
1067 ast_udptl_set_peer(session_media->udptl, addrs);
1068
1069 t38_interpret_sdp(state, session, session_media, remote_stream);
1070
1072 ast_sip_session_media_add_read_callback(session, session_media, ast_udptl_fd(session_media->udptl),
1074
1075 return 0;
1076}
1077
1078/*! \brief Function which updates the media stream with external media address, if applicable */
1079static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
1080{
1082 char host[NI_MAXHOST];
1083 struct ast_sockaddr our_sdp_addr = { { 0, } };
1084
1085 /* If the stream has been rejected there will be no connection line */
1086 if (!stream->conn || !transport_state) {
1087 return;
1088 }
1089
1090 ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
1091 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
1092
1093 /* Reversed check here. We don't check the remote endpoint being
1094 * in our local net, but whether our outgoing session IP is
1095 * local. If it is not, we won't do rewriting. No localnet
1096 * configured? Always rewrite. */
1097 if (ast_sip_transport_is_nonlocal(transport_state, &our_sdp_addr) && transport_state->localnet) {
1098 return;
1099 }
1100 ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
1101 pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
1102}
1103
1104/*! \brief Function which destroys the UDPTL instance when session ends */
1105static void stream_destroy(struct ast_sip_session_media *session_media)
1106{
1107 if (session_media->udptl) {
1108 ast_udptl_destroy(session_media->udptl);
1109 }
1110 session_media->udptl = NULL;
1111}
1112
1113/*! \brief SDP handler for 'image' media stream */
1115 .id = "image",
1116 .defer_incoming_sdp_stream = defer_incoming_sdp_stream,
1117 .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
1118 .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
1119 .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
1120 .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
1121 .stream_destroy = stream_destroy,
1122};
1123
1124/*! \brief Unloads the SIP T.38 module from Asterisk */
1125static int unload_module(void)
1126{
1129
1130 return 0;
1131}
1132
1133/*!
1134 * \brief Load the module
1135 *
1136 * Module loading including tests for configuration or dependencies.
1137 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1138 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1139 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1140 * configuration file or other non-critical problem return
1141 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1142 */
1143static int load_module(void)
1144{
1145 if (ast_check_ipv6()) {
1146 ast_sockaddr_parse(&address, "::", 0);
1147 } else {
1148 ast_sockaddr_parse(&address, "0.0.0.0", 0);
1149 }
1150
1152
1154 ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
1155 goto end;
1156 }
1157
1159end:
1160 unload_module();
1161
1163}
1164
1165AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Support",
1166 .support_level = AST_MODULE_SUPPORT_CORE,
1167 .load = load_module,
1168 .unload = unload_module,
1169 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
1170 .requires = "res_pjsip,res_pjsip_session,udptl",
Access Control of various sorts.
jack_status_t status
Definition: app_jack.c:146
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static int tmp()
Definition: bt_open.c:389
enum cc_state state
Definition: ccss.c:393
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
#define ast_channel_lock(chan)
Definition: channel.h:2922
int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame with payload.
Definition: channel.c:1238
void ast_channel_set_unbridged(struct ast_channel *chan, int value)
Sets the unbridged flag and queues a NULL frame on the channel to trigger a check by bridge_channel_w...
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
@ AST_MEDIA_TYPE_IMAGE
Definition: codec.h:34
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:348
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
char * end
Definition: eagi_proxy.c:73
char * address
Definition: f2c.h:59
Media Format Cache API.
struct ast_format * ast_format_t38
Built-in cached T.38 format.
Definition: format_cache.c:241
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition: framehook.c:132
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
@ AST_T38_REQUEST_PARMS
@ AST_T38_TERMINATED
@ AST_T38_REFUSED
@ AST_T38_REQUEST_TERMINATE
@ AST_T38_NEGOTIATED
@ AST_T38_REQUEST_NEGOTIATE
#define ast_frdup(fr)
Copies a frame.
#define ast_frfree(fr)
ast_control_t38_rate
@ AST_T38_RATE_12000
@ AST_T38_RATE_9600
@ AST_T38_RATE_2400
@ AST_T38_RATE_14400
@ AST_T38_RATE_7200
@ AST_T38_RATE_4800
@ AST_T38_RATE_MANAGEMENT_LOCAL_TCF
@ AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF
ast_frame_type
Frame types.
@ AST_FRAME_CONTROL
@ AST_CONTROL_T38_PARAMETERS
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_CHANNEL_DRIVER
Definition: module.h:327
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Network socket handling.
@ AST_AF_UNSPEC
Definition: netsock2.h:54
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:524
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
Definition: netsock2.c:280
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
Determine if the address is an IPv4 address.
Definition: netsock2.c:497
static char * ast_sockaddr_stringify_addr_remote(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:313
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
Definition: res_pjsip.c:2493
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3186
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
#define ast_sip_transport_is_nonlocal(transport_state, addr)
Definition: res_pjsip.h:212
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition: res_pjsip.h:627
void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Unregister an SDP handler.
int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Register an SDP handler.
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
struct ast_sip_session_media_state * ast_sip_session_media_state_clone(const struct ast_sip_session_media_state *media_state)
Clone a media state.
ast_sip_session_t38state
T.38 states for a session.
@ T38_PEER_REINVITE
@ T38_LOCAL_REINVITE
@ T38_MAX_ENUM
@ T38_ENABLED
@ T38_REJECTED
@ T38_DISABLED
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
int ast_sip_session_media_add_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, int fd, ast_sip_session_media_read_cb callback)
Set a read callback for a media session with a specific file descriptor.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
#define ast_sip_session_register_supplement(supplement)
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63
struct ast_sip_session_media * ast_sip_session_media_state_add(struct ast_sip_session *session, struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
Allocate an ast_session_media and add it to the media state's vector.
ast_sip_session_sdp_stream_defer
@ AST_SIP_SESSION_SDP_DEFER_NEEDED
@ AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED
@ AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED
@ AST_SIP_SESSION_SDP_DEFER_ERROR
void ast_sip_session_resume_reinvite(struct ast_sip_session *session)
Resumes processing of a deferred incoming re-invite.
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
int ast_sip_session_refresh(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_sdp_creation_cb on_sdp_creation, ast_sip_session_response_cb on_response, enum ast_sip_session_refresh_method method, int generate_new_sdp, struct ast_sip_session_media_state *media_state)
Send a reinvite or UPDATE on a session.
int ast_sip_session_media_set_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, ast_sip_session_media_write_cb callback)
Set a write callback for a media session.
static const struct ast_datastore_info t38_framehook_datastore
static void t38_automatic_reject_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it.
static struct ast_sockaddr address
Address for UDPTL.
Definition: res_pjsip_t38.c:56
static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Function called when an INVITE arrives.
static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
Callback for when T.38 reinvite SDP is created.
static const struct ast_datastore_info t38_datastore
Datastore for attaching T.38 state information.
Definition: res_pjsip_t38.c:82
static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct t38_state *state, enum ast_sip_session_t38state new_state)
Helper function for changing the T.38 state.
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, int index, struct ast_stream *asterisk_stream)
Function which negotiates an incoming media stream.
static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
Callback for when a response is received for a T.38 re-invite.
static int t38_consume(void *data, enum ast_frame_type type)
static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
static int t38_automatic_reject(void *obj)
Task function which rejects a T.38 re-invite and resumes handling it.
static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
Function which applies a negotiated stream.
static void t38_attach_framehook(struct ast_sip_session *session)
Function called to attach T.38 framehook to channel when appropriate.
static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
Initializes UDPTL support on a session, only done when actually needed.
static struct ast_sip_session_media_state * t38_create_media_state(struct ast_sip_session *session)
Helper function which creates a media state for strictly T.38.
static int t38_interpret_parameters(void *obj)
Task for reacting to T.38 control frame.
static void t38_masq(void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan)
static struct ast_frame * media_session_udptl_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Function called when an INVITE is sent.
#define T38_AUTOMATIC_REJECTION_SECONDS
The number of seconds after receiving a T.38 re-invite before automatically rejecting it.
Definition: res_pjsip_t38.c:53
static void t38_parameters_task_data_destroy(void *obj)
Destructor for T.38 data.
Definition: res_pjsip_t38.c:96
static void stream_destroy(struct ast_sip_session_media *session_media)
Function which destroys the UDPTL instance when session ends.
static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
Function which updates the media stream with external media address, if applicable.
static struct t38_state * t38_state_get_or_alloc(struct ast_sip_session *session)
Helper function which retrieves or allocates a T.38 state information datastore.
static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream)
Parse a T.38 image stream and store the attribute information.
static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
Function which creates an outgoing stream.
static struct ast_frame * t38_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
Frame hook callback for T.38 related stuff.
static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
Get Max T.38 Transmission rate from T38 capabilities.
static struct t38_parameters_task_data * t38_parameters_task_data_alloc(struct ast_sip_session *session, struct ast_frame *frame)
Allocator for T.38 data.
static enum ast_sip_session_sdp_stream_defer defer_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
Function which defers an incoming media stream.
static int load_module(void)
Load the module.
static struct ast_sip_session_sdp_handler image_sdp_handler
SDP handler for 'image' media stream.
static void t38_state_destroy(void *obj)
Destructor for T.38 state information.
Definition: res_pjsip_t38.c:73
static int unload_module(void)
Unloads the SIP T.38 module from Asterisk.
static struct ast_sip_session_supplement t38_supplement
Supplement for adding framehook to session channel.
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
Media Stream API.
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
@ AST_STREAM_STATE_SENDRECV
Set when the stream is sending and receiving media.
Definition: stream.h:82
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Main Channel structure associated with a channel.
enum ast_control_t38 request_response
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
struct ast_sip_t38_configuration t38
Definition: res_pjsip.h:919
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:996
Structure which contains media state information (streams, sessions)
struct ast_stream_topology * topology
The media stream topology.
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
A structure containing SIP session media information.
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
enum ast_media_type type
Media type of this session media.
int stream_num
The stream number to place into any resulting frames.
struct ast_udptl * udptl
UDPTL instance itself.
A handler for SDPs in SIP sessions.
void(* stream_stop)(struct ast_sip_session_media *session_media)
Stop a session_media created by this handler but do not destroy resources.
A supplement to SIP message processing.
A structure describing a SIP session.
struct ast_sip_endpoint * endpoint
struct ast_taskprocessor * serializer
Structure for SIP transport information.
Definition: res_pjsip.h:119
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:121
Transport to bind to.
Definition: res_pjsip.h:221
Socket address structure.
Definition: netsock2.h:97
Definition: search.h:40
Definition: astman.c:222
Structure for T.38 parameters task data.
Definition: res_pjsip_t38.c:88
struct ast_sip_session * session
Session itself.
Definition: res_pjsip_t38.c:90
struct ast_frame * frame
T.38 control frame.
Definition: res_pjsip_t38.c:92
T.38 state information.
Definition: res_pjsip_t38.c:59
enum ast_sip_session_t38state state
Current state.
Definition: res_pjsip_t38.c:61
struct ast_sip_session_media_state * media_state
Definition: res_pjsip_t38.c:69
struct ast_control_t38_parameters their_parms
Their T.38 parameters.
Definition: res_pjsip_t38.c:65
struct ast_control_t38_parameters our_parms
Our T.38 parameters.
Definition: res_pjsip_t38.c:63
pj_timer_entry timer
Timer entry for automatically rejecting an inbound re-invite.
Definition: res_pjsip_t38.c:67
userdata associated with baseline taskprocessor test
UDPTL support for T.38.
void ast_udptl_destroy(struct ast_udptl *udptl)
Definition: udptl.c:1148
enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
Definition: udptl.c:938
int ast_udptl_fd(const struct ast_udptl *udptl)
Definition: udptl.c:728
void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
Definition: udptl.c:1128
void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format,...)
Associates a character string 'tag' with a UDPTL session.
Definition: udptl.c:1110
void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
Definition: udptl.c:971
unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
retrieves far max ifp
Definition: udptl.c:1014
void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
Definition: udptl.c:743
void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
Definition: udptl.c:1138
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
Definition: udptl.c:760
struct ast_udptl * ast_udptl_new_with_bindaddr(struct ast_sched_context *sched, struct io_context *io, int callbackmode, struct ast_sockaddr *in)
Definition: udptl.c:1026
int ast_udptl_write(struct ast_udptl *udptl, struct ast_frame *f)
Definition: udptl.c:1159
unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
retrieves local_max_datagram.
Definition: udptl.c:982
void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram)
sets far max datagram size. If max_datagram is = 0, the far max datagram size is set to a default val...
Definition: udptl.c:995
void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
Definition: udptl.c:943
@ UDPTL_ERROR_CORRECTION_FEC
Definition: udptl.h:39
@ UDPTL_ERROR_CORRECTION_NONE
Definition: udptl.h:38
@ UDPTL_ERROR_CORRECTION_REDUNDANCY
Definition: udptl.h:40
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define MIN(a, b)
Definition: utils.h:231
int ast_check_ipv6(void)
Test that an OS supports IPv6 Networking.
Definition: utils.c:2792
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680