Asterisk - The Open Source Telephony Project GIT-master-57e2743
Loading...
Searching...
No Matches
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 /* CHANNEL(pjsip,t38state) reads this under the channel lock. */
141 if (session->channel) {
142 ast_channel_lock(session->channel);
143 }
144 session->t38state = new_state;
145 if (session->channel) {
146 ast_channel_unlock(session->channel);
147 }
148 ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n",
149 new_state, old_state,
150 session->channel ? ast_channel_name(session->channel) : "<gone>");
151
152 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
153 &state->timer, 0)) {
154 ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n",
155 session->channel ? ast_channel_name(session->channel) : "<gone>");
156 ao2_ref(session, -1);
157 }
158
159 if (!session->channel) {
160 return;
161 }
162
163 switch (new_state) {
165 ao2_ref(session, +1);
166 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &state->timer, &delay) != PJ_SUCCESS) {
167 ast_log(LOG_WARNING, "Scheduling of automatic T.38 rejection for channel '%s' failed\n",
168 ast_channel_name(session->channel));
169 ao2_ref(session, -1);
170 }
171 parameters = state->their_parms;
172 parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
174 ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
175
176 /* Inform the bridge the channel is in that it needs to be reconfigured */
178 break;
179 case T38_ENABLED:
180 parameters = state->their_parms;
181 parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
183 ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
184 break;
185 case T38_REJECTED:
186 case T38_DISABLED:
187 if (old_state == T38_ENABLED) {
189 } else if (old_state == T38_LOCAL_REINVITE) {
191 }
192 break;
194 /* Inform the bridge the channel is in that it needs to be reconfigured */
196 break;
197 case T38_MAX_ENUM:
198 /* Well, that shouldn't happen */
199 ast_assert(0);
200 break;
201 }
202
203 if (parameters.request_response) {
204 ast_queue_control_data(session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
205 }
206}
207
208/*! \brief Task function which rejects a T.38 re-invite and resumes handling it */
209static int t38_automatic_reject(void *obj)
210{
213
214 if (!datastore) {
215 return 0;
216 }
217
218 ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n",
219 session->channel ? ast_channel_name(session->channel) : "<gone>");
220
221 t38_change_state(session, NULL, datastore->data, T38_REJECTED);
223
224 return 0;
225}
226
227/*! \brief Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it */
228static void t38_automatic_reject_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
229{
230 struct ast_sip_session *session = entry->user_data;
231
233 ao2_ref(session, -1);
234 }
235}
236
237/*! \brief Helper function which retrieves or allocates a T.38 state information datastore */
239{
241 struct t38_state *state;
242
243 /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
244 if (datastore) {
245 return datastore->data;
246 }
247
248 if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38"))
249 || !(datastore->data = ast_calloc(1, sizeof(struct t38_state)))
250 || ast_sip_session_add_datastore(session, datastore)) {
251 return NULL;
252 }
253
254 state = datastore->data;
255
256 /* This will get bumped up before scheduling */
257 pj_timer_entry_init(&state->timer, 0, session, t38_automatic_reject_timer_cb);
258
259 return state;
260}
261
262/*! \brief Initializes UDPTL support on a session, only done when actually needed */
263static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
264{
265 struct ast_sockaddr temp_media_address;
266 struct ast_sockaddr *media_address = &address;
267
268 if (session_media->udptl) {
269 return 0;
270 }
271
272 if (session->endpoint->media.t38.bind_udptl_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
273 if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) {
274 ast_debug(5, "Endpoint %s: Binding UDPTL media to %s\n",
276 session->endpoint->media.address);
277 media_address = &temp_media_address;
278 } else {
279 ast_debug(5, "Endpoint %s: UDPTL media address invalid: %s\n",
281 session->endpoint->media.address);
282 }
283 } else {
284 struct ast_sip_transport *transport;
285
286 transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
287 session->endpoint->transport);
288 if (transport) {
289 struct ast_sip_transport_state *trans_state;
290
292 if (trans_state) {
293 char hoststr[PJ_INET6_ADDRSTRLEN];
294
295 pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0);
296 if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) {
297 ast_debug(5, "Transport %s bound to %s: Using it for UDPTL media.\n",
298 session->endpoint->transport, hoststr);
299 media_address = &temp_media_address;
300 } else {
301 ast_debug(5, "Transport %s bound to %s: Invalid for UDPTL media.\n",
302 session->endpoint->transport, hoststr);
303 }
304 ao2_ref(trans_state, -1);
305 }
306 ao2_ref(transport, -1);
307 }
308 }
309
310 if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, media_address))) {
311 return -1;
312 }
313
314 ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction);
315 ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat);
316 ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram);
317 ast_debug(3, "UDPTL initialized on session for %s\n", ast_channel_name(session->channel));
318
319 return 0;
320}
321
322/*! \brief Callback for when T.38 reinvite SDP is created */
323static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
324{
325 struct t38_state *state;
326
328 if (!state) {
329 return -1;
330 }
331
332 state->media_state = ast_sip_session_media_state_clone(session->active_media_state);
333
334 return 0;
335}
336
337/*! \brief Callback for when a response is received for a T.38 re-invite */
338static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
339{
340 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
341 struct t38_state *state;
342 struct ast_sip_session_media *session_media = NULL;
343
344 if (status.code / 100 <= 1) {
345 /* Ignore any non-final responses (1xx) */
346 return 0;
347 }
348
349 if (session->t38state != T38_LOCAL_REINVITE) {
350 /* Do nothing. We have already processed a final response. */
351 ast_debug(3, "Received %d response to T.38 re-invite on '%s' but already had a final response (T.38 state:%d)\n",
352 status.code,
353 session->channel ? ast_channel_name(session->channel) : "unknown channel",
354 session->t38state);
355 return 0;
356 }
357
359 if (!session->channel || !state) {
360 ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but state unavailable\n",
361 status.code,
362 session->channel ? ast_channel_name(session->channel) : "unknown channel");
363 return 0;
364 }
365
366 if (status.code / 100 == 2) {
367 /* Accept any 2xx response as successfully negotiated */
368 int index;
369
370 session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
371
372 /*
373 * If there is a session_media object, but no udptl object available
374 * then it's assumed the stream was declined.
375 */
376 if (session_media && !session_media->udptl) {
377 session_media = NULL;
378 }
379
380 if (!session_media) {
381 ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n",
382 status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel");
383 } else {
384 t38_change_state(session, session_media, state, T38_ENABLED);
385
386 /* Stop all the streams in the stored away active state, they'll go back to being active once
387 * we reinvite back.
388 */
389 for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
390 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
391
392 if (session_media && session_media->handler && session_media->handler->stream_stop) {
393 session_media->handler->stream_stop(session_media);
394 }
395 }
396
397 return 0;
398 }
399 } else {
400 session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
401 }
402
403 /* If no session_media then response contained a declined stream, so disable */
405
406 /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
408 state->media_state = NULL;
409 ast_sip_session_media_state_reset(session->pending_media_state);
410
411 return 0;
412}
413
414/*! \brief Helper function which creates a media state for strictly T.38 */
416{
417 struct ast_sip_session_media_state *media_state;
418 struct ast_stream *stream;
419 struct ast_format_cap *caps;
420 struct ast_sip_session_media *session_media;
421
422 media_state = ast_sip_session_media_state_alloc();
423 if (!media_state) {
424 return NULL;
425 }
426
427 media_state->topology = ast_stream_topology_alloc();
428 if (!media_state->topology) {
430 return NULL;
431 }
432
433 stream = ast_stream_alloc("t38", AST_MEDIA_TYPE_IMAGE);
434 if (!stream) {
436 return NULL;
437 }
438
440 if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) {
441 ast_stream_free(stream);
443 return NULL;
444 }
445
447 if (!caps) {
449 return NULL;
450 }
451
452 ast_stream_set_formats(stream, caps);
453 /* stream holds a reference to cap, release the local reference
454 * now so we don't have to deal with it in the error condition. */
455 ao2_ref(caps, -1);
458 return NULL;
459 }
460
461 session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0);
462 if (!session_media) {
464 return NULL;
465 }
466
467 if (t38_initialize_session(session, session_media)) {
469 return NULL;
470 }
471
472 return media_state;
473}
474
475/*! \brief Task for reacting to T.38 control frame */
476static int t38_interpret_parameters(void *obj)
477{
478 RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
479 const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
480 struct t38_state *state = t38_state_get_or_alloc(data->session);
481 struct ast_sip_session_media *session_media = NULL;
482
483 if (!state) {
484 return 0;
485 }
486
487 switch (parameters->request_response) {
489 case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
490 /* Negotiation can not take place without a valid max_ifp value. */
491 if (!parameters->max_ifp) {
492 if (data->session->t38state == T38_PEER_REINVITE) {
493 t38_change_state(data->session, NULL, state, T38_REJECTED);
494 ast_sip_session_resume_reinvite(data->session);
495 } else if (data->session->t38state == T38_ENABLED) {
496 t38_change_state(data->session, NULL, state, T38_DISABLED);
497 ast_sip_session_refresh(data->session, NULL, NULL, NULL,
499 state->media_state = NULL;
500 }
501 break;
502 } else if (data->session->t38state == T38_PEER_REINVITE) {
503 state->our_parms = *parameters;
504 /* modify our parameters to conform to the peer's parameters,
505 * based on the rules in the ITU T.38 recommendation
506 */
507 if (!state->their_parms.fill_bit_removal) {
508 state->our_parms.fill_bit_removal = 0;
509 }
510 if (!state->their_parms.transcoding_mmr) {
511 state->our_parms.transcoding_mmr = 0;
512 }
513 if (!state->their_parms.transcoding_jbig) {
514 state->our_parms.transcoding_jbig = 0;
515 }
516 state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
517 state->our_parms.rate_management = state->their_parms.rate_management;
518 session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
519 if (!session_media) {
520 ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n",
521 data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
522 break;
523 }
524 ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
525 t38_change_state(data->session, session_media, state, T38_ENABLED);
526 ast_sip_session_resume_reinvite(data->session);
527 } else if ((data->session->t38state != T38_ENABLED) ||
528 ((data->session->t38state == T38_ENABLED) &&
530 struct ast_sip_session_media_state *media_state;
531
532 media_state = t38_create_media_state(data->session);
533 if (!media_state) {
534 break;
535 }
536 state->our_parms = *parameters;
537 session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE];
538 if (!session_media) {
539 ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n",
540 data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
541 break;
542 }
543 ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
547 }
548 break;
550 case AST_T38_REFUSED:
551 case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
552 if (data->session->t38state == T38_PEER_REINVITE) {
553 t38_change_state(data->session, NULL, state, T38_REJECTED);
554 ast_sip_session_resume_reinvite(data->session);
555 } else if (data->session->t38state == T38_ENABLED) {
556 t38_change_state(data->session, NULL, state, T38_DISABLED);
558 state->media_state = NULL;
559 }
560 break;
561 case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */
562 struct ast_control_t38_parameters parameters = state->their_parms;
563
564 if (data->session->t38state == T38_PEER_REINVITE) {
565 session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
566 if (!session_media) {
567 ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n",
568 data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
569 break;
570 }
571 parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
573 ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
574 }
575 break;
576 }
577 default:
578 break;
579 }
580
581 return 0;
582}
583
584/*! \brief Frame hook callback for T.38 related stuff */
585static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f,
586 enum ast_framehook_event event, void *data)
587{
588 struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
589
591 return f;
592 }
593
596 if (channel->session->endpoint->media.t38.enabled) {
598
600 if (task_data
603 ao2_ref(task_data, -1);
604 }
605 } else {
606 static const struct ast_control_t38_parameters rsp_refused = {
608 };
609 static const struct ast_control_t38_parameters rsp_terminated = {
611 };
612 const struct ast_control_t38_parameters *parameters = f->data.ptr;
613
614 switch (parameters->request_response) {
616 ast_debug(2, "T.38 support not enabled on %s, refusing T.38 negotiation\n",
617 ast_channel_name(chan));
619 &rsp_refused, sizeof(rsp_refused));
620 break;
622 ast_debug(2, "T.38 support not enabled on %s, 'terminating' T.38 session\n",
623 ast_channel_name(chan));
625 &rsp_terminated, sizeof(rsp_terminated));
626 break;
627 default:
628 break;
629 }
630 }
631 }
632
633 return f;
634}
635
636static void t38_masq(void *data, int framehook_id,
637 struct ast_channel *old_chan, struct ast_channel *new_chan)
638{
639 if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) {
640 return;
641 }
642
643 /* This framehook is only applicable to PJSIP channels */
644 ast_framehook_detach(new_chan, framehook_id);
645}
646
647static int t38_consume(void *data, enum ast_frame_type type)
648{
649 return (type == AST_FRAME_CONTROL) ? 1 : 0;
650}
651
653 .type = "T38 framehook",
654};
655
656/*! \brief Function called to attach T.38 framehook to channel when appropriate */
658{
659 int framehook_id;
660 struct ast_datastore *datastore = NULL;
661 static struct ast_framehook_interface hook = {
663 .event_cb = t38_framehook,
664 .consume_cb = t38_consume,
665 .chan_fixup_cb = t38_masq,
666 .chan_breakdown_cb = t38_masq,
667 };
668
669 /* If the channel's already gone, bail */
670 if (!session->channel) {
671 return;
672 }
673
674 /* Always attach the framehook so we can quickly reject */
675
676 ast_channel_lock(session->channel);
677
678 /* Skip attaching the framehook if the T.38 datastore already exists for the channel */
680 NULL);
681 if (datastore) {
682 ast_channel_unlock(session->channel);
683 return;
684 }
685
686 framehook_id = ast_framehook_attach(session->channel, &hook);
687 if (framehook_id < 0) {
688 ast_log(LOG_WARNING, "Could not attach T.38 Frame hook, T.38 will be unavailable on '%s'\n",
689 ast_channel_name(session->channel));
690 ast_channel_unlock(session->channel);
691 return;
692 }
693
695 if (!datastore) {
696 ast_log(LOG_ERROR, "Could not alloc T.38 Frame hook datastore, T.38 will be unavailable on '%s'\n",
697 ast_channel_name(session->channel));
698 ast_framehook_detach(session->channel, framehook_id);
699 ast_channel_unlock(session->channel);
700 return;
701 }
702
703 ast_channel_datastore_add(session->channel, datastore);
704 ast_channel_unlock(session->channel);
705}
706
707/*! \brief Function called when an INVITE arrives */
708static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
709{
711 return 0;
712}
713
714/*! \brief Function called when an INVITE is sent */
715static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
716{
718}
719
720/*! \brief Get Max T.38 Transmission rate from T38 capabilities */
721static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
722{
723 switch (rate) {
725 return 2400;
727 return 4800;
729 return 7200;
731 return 9600;
733 return 12000;
735 return 14400;
736 default:
737 return 0;
738 }
739}
740
741/*! \brief Supplement for adding framehook to session channel */
743 .method = "INVITE",
745 .incoming_request = t38_incoming_invite_request,
746 .outgoing_request = t38_outgoing_invite_request,
747};
748
749/*! \brief Parse a T.38 image stream and store the attribute information */
750static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media,
751 const struct pjmedia_sdp_media *stream)
752{
753 unsigned int attr_i;
754
755 for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
756 pjmedia_sdp_attr *attr = stream->attr[attr_i];
757
758 if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
759 /* This is purposely left empty, it is unused */
760 } else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
761 switch (pj_strtoul(&attr->value)) {
762 case 14400:
763 state->their_parms.rate = AST_T38_RATE_14400;
764 break;
765 case 12000:
766 state->their_parms.rate = AST_T38_RATE_12000;
767 break;
768 case 9600:
769 state->their_parms.rate = AST_T38_RATE_9600;
770 break;
771 case 7200:
772 state->their_parms.rate = AST_T38_RATE_7200;
773 break;
774 case 4800:
775 state->their_parms.rate = AST_T38_RATE_4800;
776 break;
777 case 2400:
778 state->their_parms.rate = AST_T38_RATE_2400;
779 break;
780 }
781 } else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
782 state->their_parms.version = pj_strtoul(&attr->value);
783 } else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
784 if (!session->endpoint->media.t38.maxdatagram) {
785 ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
786 }
787 } else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
788 state->their_parms.fill_bit_removal = 1;
789 } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
790 state->their_parms.transcoding_mmr = 1;
791 } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
792 state->their_parms.transcoding_jbig = 1;
793 } else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
794 if (!pj_stricmp2(&attr->value, "localTCF")) {
795 state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
796 } else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
797 state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
798 }
799 } else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
800 if (session->t38state == T38_LOCAL_REINVITE) {
801 if (session->endpoint->media.t38.error_correction == UDPTL_ERROR_CORRECTION_FEC) {
802 if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
804 } else if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
806 } else {
808 }
809 } else if (session->endpoint->media.t38.error_correction == UDPTL_ERROR_CORRECTION_REDUNDANCY) {
810 if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
812 } else {
814 }
815 } else {
817 }
818 } else {
819 if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
821 } else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
823 } else {
825 }
826 }
827 }
828
829 }
830}
831
832/*! \brief Function which defers an incoming media stream */
834 struct ast_sip_session *session, struct ast_sip_session_media *session_media,
835 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
836{
837 struct t38_state *state;
838
839 if (!session->endpoint->media.t38.enabled) {
840 ast_debug(3, "Not deferring incoming SDP stream: T.38 not enabled on %s\n", ast_channel_name(session->channel));
842 }
843
844 if (t38_initialize_session(session, session_media)) {
845 ast_debug(3, "Not deferring incoming SDP stream: Failed to initialize UDPTL on %s\n", ast_channel_name(session->channel));
847 }
848
851 }
852
853 t38_interpret_sdp(state, session, session_media, stream);
854
855 /* If they are initiating the re-invite we need to defer responding until later */
856 if (session->t38state == T38_DISABLED) {
858 ast_debug(3, "Deferring incoming SDP stream on %s for peer re-invite\n", ast_channel_name(session->channel));
860 }
861
863}
864
865/*! \brief Function which negotiates an incoming media stream */
867 struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp,
868 int index, struct ast_stream *asterisk_stream)
869{
870 struct t38_state *state;
871 char host[NI_MAXHOST];
872 pjmedia_sdp_media *stream = sdp->media[index];
873 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
874
875 if (!session->endpoint->media.t38.enabled) {
876 ast_debug(3, "Declining; T.38 not enabled on session\n");
877 return 0;
878 }
879
881 return 0;
882 }
883
884 if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
885 ast_debug(3, "Declining; T.38 state is rejected or declined\n");
887 return 0;
888 }
889
890 ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
891
892 /* Ensure that the address provided is valid */
893 if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
894 /* The provided host was actually invalid so we error out this negotiation */
895 ast_debug(3, "Declining; provided host is invalid\n");
896 return 0;
897 }
898
899 /* Check the address family to make sure it matches configured */
900 if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) ||
901 (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
902 /* The address does not match configured */
903 ast_debug(3, "Declining, provided host does not match configured address family\n");
904 return 0;
905 }
906
907 return 1;
908}
909
910/*! \brief Function which creates an outgoing stream */
912 struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
913{
914 pj_pool_t *pool = session->inv_session->pool_prov;
915 static const pj_str_t STR_IN = { "IN", 2 };
916 static const pj_str_t STR_IP4 = { "IP4", 3};
917 static const pj_str_t STR_IP6 = { "IP6", 3};
918 static const pj_str_t STR_UDPTL = { "udptl", 5 };
919 static const pj_str_t STR_T38 = { "t38", 3 };
920 static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
921 static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
922 static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
923 static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
924 struct t38_state *state;
925 pjmedia_sdp_media *media;
926 const char *hostip = NULL;
927 struct ast_sockaddr addr;
928 char tmp[512];
929 pj_str_t stmp;
930
931 if (!session->endpoint->media.t38.enabled) {
932 ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
933 return 1;
934 } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
935 (session->t38state != T38_ENABLED)) {
936 ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
937 return 1;
938 } else if (!(state = t38_state_get_or_alloc(session))) {
939 return -1;
940 } else if (t38_initialize_session(session, session_media)) {
941 ast_debug(3, "Not creating outgoing SDP stream: Failed to initialize T.38 session\n");
942 return -1;
943 }
944
945 if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
946 !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
947 return -1;
948 }
949
950 pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type));
951 media->desc.transport = STR_UDPTL;
952
953 if (ast_strlen_zero(session->endpoint->media.address)) {
954 hostip = ast_sip_get_host_ip_string(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET());
955 } else {
956 hostip = session->endpoint->media.address;
957 }
958
959 if (ast_strlen_zero(hostip)) {
960 ast_debug(3, "Not creating outgoing SDP stream: no known host IP\n");
961 return -1;
962 }
963
964 media->conn->net_type = STR_IN;
965 media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
966 pj_strdup2(pool, &media->conn->addr, hostip);
967 ast_udptl_get_us(session_media->udptl, &addr);
968 media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
969 media->desc.port_count = 1;
970 media->desc.fmt[media->desc.fmt_count++] = STR_T38;
971
972 snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
973 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
974
975 snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
976 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));
977
978 if (state->our_parms.fill_bit_removal) {
979 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
980 }
981
982 if (state->our_parms.transcoding_mmr) {
983 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
984 }
985
986 if (state->our_parms.transcoding_jbig) {
987 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
988 }
989
990 switch (state->our_parms.rate_management) {
992 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
993 break;
995 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
996 break;
997 }
998
999 snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
1000 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));
1001
1002 switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
1004 break;
1006 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
1007 break;
1009 media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
1010 break;
1011 }
1012
1013 sdp->media[sdp->media_count++] = media;
1014
1015 return 1;
1016}
1017
1019{
1020 struct ast_frame *frame;
1021
1022 if (!session_media->udptl) {
1023 return &ast_null_frame;
1024 }
1025
1026 frame = ast_udptl_read(session_media->udptl);
1027 if (!frame) {
1028 return NULL;
1029 }
1030
1031 frame->stream_num = session_media->stream_num;
1032
1033 return frame;
1034}
1035
1036static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
1037{
1038 if (!session_media->udptl) {
1039 return 0;
1040 }
1041
1042 return ast_udptl_write(session_media->udptl, frame);
1043}
1044
1045/*! \brief Function which applies a negotiated stream */
1047 struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local,
1048 const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
1049{
1050 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
1051 pjmedia_sdp_media *remote_stream = remote->media[index];
1052 char host[NI_MAXHOST];
1053 struct t38_state *state;
1054
1055 if (!session_media->udptl) {
1056 ast_debug(3, "Not applying negotiated SDP stream: no UDTPL session\n");
1057 return 0;
1058 }
1059
1061 return -1;
1062 }
1063
1064 ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
1065
1066 /* Ensure that the address provided is valid */
1067 if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
1068 /* The provided host was actually invalid so we error out this negotiation */
1069 ast_debug(3, "Not applying negotiated SDP stream: failed to resolve remote stream host\n");
1070 return -1;
1071 }
1072
1073 ast_sockaddr_set_port(addrs, remote_stream->desc.port);
1074 ast_udptl_set_peer(session_media->udptl, addrs);
1075
1076 t38_interpret_sdp(state, session, session_media, remote_stream);
1077
1079 ast_sip_session_media_add_read_callback(session, session_media, ast_udptl_fd(session_media->udptl),
1081
1082 return 0;
1083}
1084
1085/*! \brief Function which updates the media stream with external media address, if applicable */
1086static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
1087{
1089 char host[NI_MAXHOST];
1090 struct ast_sockaddr our_sdp_addr = { { 0, } };
1091
1092 /* If the stream has been rejected there will be no connection line */
1093 if (!stream->conn || !transport_state) {
1094 return;
1095 }
1096
1097 ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
1098 ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
1099
1100 /* Reversed check here. We don't check the remote endpoint being
1101 * in our local net, but whether our outgoing session IP is
1102 * local. If it is not, we won't do rewriting. No localnet
1103 * configured? Always rewrite. */
1104 if (ast_sip_transport_is_nonlocal(transport_state, &our_sdp_addr) && transport_state->localnet) {
1105 return;
1106 }
1107 ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
1108 pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
1109}
1110
1111/*! \brief Function which destroys the UDPTL instance when session ends */
1112static void stream_destroy(struct ast_sip_session_media *session_media)
1113{
1114 if (session_media->udptl) {
1115 ast_udptl_destroy(session_media->udptl);
1116 }
1117 session_media->udptl = NULL;
1118}
1119
1120/*! \brief SDP handler for 'image' media stream */
1122 .id = "image",
1123 .defer_incoming_sdp_stream = defer_incoming_sdp_stream,
1124 .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
1125 .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
1126 .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
1127 .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
1128 .stream_destroy = stream_destroy,
1129};
1130
1131/*! \brief Unloads the SIP T.38 module from Asterisk */
1139
1140/*!
1141 * \brief Load the module
1142 *
1143 * Module loading including tests for configuration or dependencies.
1144 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1145 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1146 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1147 * configuration file or other non-critical problem return
1148 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1149 */
1150static int load_module(void)
1151{
1152 if (ast_check_ipv6()) {
1153 ast_sockaddr_parse(&address, "::", 0);
1154 } else {
1155 ast_sockaddr_parse(&address, "0.0.0.0", 0);
1156 }
1157
1159
1161 ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
1162 goto end;
1163 }
1164
1166end:
1167 unload_module();
1168
1170}
1171
1172AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Support",
1173 .support_level = AST_MODULE_SUPPORT_CORE,
1174 .load = load_module,
1175 .unload = unload_module,
1176 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
1177 .requires = "res_pjsip,res_pjsip_session,udptl",
Access Control of various sorts.
jack_status_t status
Definition app_jack.c:149
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 const char type[]
#define T38_ENABLED
#define T38_DISABLED
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:2376
#define ast_channel_lock(chan)
Definition channel.h:2983
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:1296
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...
#define ast_channel_unlock(chan)
Definition channel.h:2984
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:2390
@ 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.
@ 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
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126
@ AST_T38_REQUEST_PARMS
@ AST_T38_TERMINATED
@ AST_T38_REQUEST_TERMINATE
@ AST_T38_NEGOTIATED
@ AST_T38_REQUEST_NEGOTIATE
#define ast_frdup(fr)
Copies a frame.
#define ast_frfree(fr)
@ 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:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_CHANNEL_DRIVER
Definition module.h:341
@ 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.
#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
@ AST_AF_UNSPEC
Definition netsock2.h:54
#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:2513
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition res_pjsip.h:3413
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:2221
#define ast_sip_transport_is_nonlocal(transport_state, addr)
Definition res_pjsip.h:210
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:717
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_REJECTED
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.
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.
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.
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.
static void t38_parameters_task_data_destroy(void *obj)
Destructor for T.38 data.
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.
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:2381
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:1917
Media Stream API.
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition stream.c:652
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:799
@ 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
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
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
enum ast_frame_type frametype
union ast_frame::@237 data
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:1023
struct ast_sip_endpoint_media_configuration media
Definition res_pjsip.h:1100
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.
struct ast_module *const char * method
A structure describing a SIP session.
struct ast_sip_endpoint * endpoint
struct ast_taskprocessor * serializer
Structure for SIP transport information.
Definition res_pjsip.h:117
struct pjsip_transport * transport
Transport itself.
Definition res_pjsip.h:119
Transport to bind to.
Definition res_pjsip.h:219
Socket address structure.
Definition netsock2.h:97
Structure for T.38 parameters task data.
struct ast_sip_session * session
Session itself.
struct ast_frame * frame
T.38 control frame.
T.38 state information.
enum ast_sip_session_t38state state
Current state.
struct ast_sip_session_media_state * media_state
struct ast_control_t38_parameters their_parms
Their T.38 parameters.
struct ast_control_t38_parameters our_parms
Our T.38 parameters.
pj_timer_entry timer
Timer entry for automatically rejecting an inbound re-invite.
userdata associated with baseline taskprocessor test
UDPTL support for T.38.
void ast_udptl_destroy(struct ast_udptl *udptl)
Definition udptl.c:1175
enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
Definition udptl.c:965
int ast_udptl_fd(const struct ast_udptl *udptl)
Definition udptl.c:755
void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
Definition udptl.c:1155
void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format,...)
Associates a character string 'tag' with a UDPTL session.
Definition udptl.c:1137
void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
Definition udptl.c:998
unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
retrieves far max ifp
Definition udptl.c:1041
void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
Definition udptl.c:770
void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
Definition udptl.c:1165
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
Definition udptl.c:787
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:1053
int ast_udptl_write(struct ast_udptl *udptl, struct ast_frame *f)
Definition udptl.c:1186
unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
retrieves local_max_datagram.
Definition udptl.c:1009
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:1022
void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
Definition udptl.c:970
@ 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:981
#define ast_assert(a)
Definition utils.h:779
#define MIN(a, b)
Definition utils.h:252
int ast_check_ipv6(void)
Test that an OS supports IPv6 Networking.
Definition utils.c:2826
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708