Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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"
47 #include "asterisk/format_cache.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 */
56 static struct ast_sockaddr address;
57 
58 /*! \brief T.38 state information */
59 struct 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 */
73 static 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 */
82 static 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 */
92  struct ast_frame *frame;
93 };
94 
95 /*! \brief Destructor for T.38 data */
96 static void t38_parameters_task_data_destroy(void *obj)
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 */
129 static 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) {
157  case T38_PEER_REINVITE:
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 */
170  ast_channel_set_unbridged(session->channel, 1);
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) {
183  parameters.request_response = AST_T38_REFUSED;
184  }
185  break;
186  case T38_LOCAL_REINVITE:
187  /* Inform the bridge the channel is in that it needs to be reconfigured */
188  ast_channel_set_unbridged(session->channel, 1);
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 */
202 static int t38_automatic_reject(void *obj)
203 {
204  RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup);
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 */
221 static 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 
225  if (ast_sip_push_task(session->serializer, t38_automatic_reject, session)) {
226  ao2_ref(session, -1);
227  }
228 }
229 
230 /*! \brief Helper function which retrieves or allocates a T.38 state information datastore */
232 {
233  RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
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 */
256 static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
257 {
258  if (session_media->udptl) {
259  return 0;
260  }
261 
262  if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, &address))) {
263  return -1;
264  }
265 
267  ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat);
269  ast_debug(3, "UDPTL initialized on session for %s\n", ast_channel_name(session->channel));
270 
271  return 0;
272 }
273 
274 /*! \brief Callback for when T.38 reinvite SDP is created */
275 static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
276 {
277  struct t38_state *state;
278 
279  state = t38_state_get_or_alloc(session);
280  if (!state) {
281  return -1;
282  }
283 
285 
286  return 0;
287 }
288 
289 /*! \brief Callback for when a response is received for a T.38 re-invite */
290 static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_data *rdata)
291 {
292  struct pjsip_status_line status = rdata->msg_info.msg->line.status;
293  struct t38_state *state;
294  struct ast_sip_session_media *session_media = NULL;
295 
296  if (status.code / 100 <= 1) {
297  /* Ignore any non-final responses (1xx) */
298  return 0;
299  }
300 
301  if (session->t38state != T38_LOCAL_REINVITE) {
302  /* Do nothing. We have already processed a final response. */
303  ast_debug(3, "Received %d response to T.38 re-invite on '%s' but already had a final response (T.38 state:%d)\n",
304  status.code,
305  session->channel ? ast_channel_name(session->channel) : "unknown channel",
306  session->t38state);
307  return 0;
308  }
309 
310  state = t38_state_get_or_alloc(session);
311  if (!session->channel || !state) {
312  ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but state unavailable\n",
313  status.code,
314  session->channel ? ast_channel_name(session->channel) : "unknown channel");
315  return 0;
316  }
317 
318  if (status.code / 100 == 2) {
319  /* Accept any 2xx response as successfully negotiated */
320  int index;
321 
322  session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
323 
324  /*
325  * If there is a session_media object, but no udptl object available
326  * then it's assumed the stream was declined.
327  */
328  if (session_media && !session_media->udptl) {
329  session_media = NULL;
330  }
331 
332  if (!session_media) {
333  ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n",
334  status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel");
335  } else {
336  t38_change_state(session, session_media, state, T38_ENABLED);
337 
338  /* Stop all the streams in the stored away active state, they'll go back to being active once
339  * we reinvite back.
340  */
341  for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
342  struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
343 
344  if (session_media && session_media->handler && session_media->handler->stream_stop) {
345  session_media->handler->stream_stop(session_media);
346  }
347  }
348 
349  return 0;
350  }
351  } else {
352  session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
353  }
354 
355  /* If no session_media then response contained a declined stream, so disable */
356  t38_change_state(session, NULL, state, session_media ? T38_REJECTED : T38_DISABLED);
357 
358  /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
360  state->media_state = NULL;
362 
363  return 0;
364 }
365 
366 /*! \brief Helper function which creates a media state for strictly T.38 */
368 {
370  struct ast_stream *stream;
371  struct ast_format_cap *caps;
372  struct ast_sip_session_media *session_media;
373 
374  media_state = ast_sip_session_media_state_alloc();
375  if (!media_state) {
376  return NULL;
377  }
378 
379  media_state->topology = ast_stream_topology_alloc();
380  if (!media_state->topology) {
382  return NULL;
383  }
384 
385  stream = ast_stream_alloc("t38", AST_MEDIA_TYPE_IMAGE);
386  if (!stream) {
388  return NULL;
389  }
390 
392  if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) {
393  ast_stream_free(stream);
395  return NULL;
396  }
397 
399  if (!caps) {
401  return NULL;
402  }
403 
404  ast_stream_set_formats(stream, caps);
405  /* stream holds a reference to cap, release the local reference
406  * now so we don't have to deal with it in the error condition. */
407  ao2_ref(caps, -1);
408  if (ast_format_cap_append(caps, ast_format_t38, 0)) {
410  return NULL;
411  }
412 
413  session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0);
414  if (!session_media) {
416  return NULL;
417  }
418 
419  if (t38_initialize_session(session, session_media)) {
421  return NULL;
422  }
423 
424  return media_state;
425 }
426 
427 /*! \brief Task for reacting to T.38 control frame */
428 static int t38_interpret_parameters(void *obj)
429 {
430  RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
431  const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
432  struct t38_state *state = t38_state_get_or_alloc(data->session);
433  struct ast_sip_session_media *session_media = NULL;
434 
435  if (!state) {
436  return 0;
437  }
438 
439  switch (parameters->request_response) {
440  case AST_T38_NEGOTIATED:
441  case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
442  /* Negotiation can not take place without a valid max_ifp value. */
443  if (!parameters->max_ifp) {
444  if (data->session->t38state == T38_PEER_REINVITE) {
445  t38_change_state(data->session, NULL, state, T38_REJECTED);
446  ast_sip_session_resume_reinvite(data->session);
447  } else if (data->session->t38state == T38_ENABLED) {
448  t38_change_state(data->session, NULL, state, T38_DISABLED);
449  ast_sip_session_refresh(data->session, NULL, NULL, NULL,
451  state->media_state = NULL;
452  }
453  break;
454  } else if (data->session->t38state == T38_PEER_REINVITE) {
455  state->our_parms = *parameters;
456  /* modify our parameters to conform to the peer's parameters,
457  * based on the rules in the ITU T.38 recommendation
458  */
459  if (!state->their_parms.fill_bit_removal) {
460  state->our_parms.fill_bit_removal = 0;
461  }
462  if (!state->their_parms.transcoding_mmr) {
463  state->our_parms.transcoding_mmr = 0;
464  }
465  if (!state->their_parms.transcoding_jbig) {
466  state->our_parms.transcoding_jbig = 0;
467  }
468  state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
470  session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
471  if (!session_media) {
472  ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n",
473  data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
474  break;
475  }
476  ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
477  t38_change_state(data->session, session_media, state, T38_ENABLED);
478  ast_sip_session_resume_reinvite(data->session);
479  } else if ((data->session->t38state != T38_ENABLED) ||
480  ((data->session->t38state == T38_ENABLED) &&
481  (parameters->request_response == AST_T38_REQUEST_NEGOTIATE))) {
483 
484  media_state = t38_create_media_state(data->session);
485  if (!media_state) {
486  break;
487  }
488  state->our_parms = *parameters;
489  session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE];
490  if (!session_media) {
491  ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n",
492  data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
493  break;
494  }
495  ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
496  t38_change_state(data->session, NULL, state, T38_LOCAL_REINVITE);
498  AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, media_state);
499  }
500  break;
501  case AST_T38_TERMINATED:
502  case AST_T38_REFUSED:
503  case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
504  if (data->session->t38state == T38_PEER_REINVITE) {
505  t38_change_state(data->session, NULL, state, T38_REJECTED);
506  ast_sip_session_resume_reinvite(data->session);
507  } else if (data->session->t38state == T38_ENABLED) {
508  t38_change_state(data->session, NULL, state, T38_DISABLED);
510  state->media_state = NULL;
511  }
512  break;
513  case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */
514  struct ast_control_t38_parameters parameters = state->their_parms;
515 
516  if (data->session->t38state == T38_PEER_REINVITE) {
517  session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
518  if (!session_media) {
519  ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n",
520  data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
521  break;
522  }
523  parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
525  ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
526  }
527  break;
528  }
529  default:
530  break;
531  }
532 
533  return 0;
534 }
535 
536 /*! \brief Frame hook callback for T.38 related stuff */
537 static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_frame *f,
538  enum ast_framehook_event event, void *data)
539 {
541 
542  if (event != AST_FRAMEHOOK_EVENT_WRITE) {
543  return f;
544  }
545 
546  if (f->frametype == AST_FRAME_CONTROL
548  if (channel->session->endpoint->media.t38.enabled) {
550 
551  task_data = t38_parameters_task_data_alloc(channel->session, f);
552  if (task_data
553  && ast_sip_push_task(channel->session->serializer,
554  t38_interpret_parameters, task_data)) {
555  ao2_ref(task_data, -1);
556  }
557  } else {
558  static const struct ast_control_t38_parameters rsp_refused = {
560  };
561  static const struct ast_control_t38_parameters rsp_terminated = {
563  };
564  const struct ast_control_t38_parameters *parameters = f->data.ptr;
565 
566  switch (parameters->request_response) {
568  ast_debug(2, "T.38 support not enabled on %s, refusing T.38 negotiation\n",
569  ast_channel_name(chan));
571  &rsp_refused, sizeof(rsp_refused));
572  break;
574  ast_debug(2, "T.38 support not enabled on %s, 'terminating' T.38 session\n",
575  ast_channel_name(chan));
577  &rsp_terminated, sizeof(rsp_terminated));
578  break;
579  default:
580  break;
581  }
582  }
583  }
584 
585  return f;
586 }
587 
588 static void t38_masq(void *data, int framehook_id,
589  struct ast_channel *old_chan, struct ast_channel *new_chan)
590 {
591  if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) {
592  return;
593  }
594 
595  /* This framehook is only applicable to PJSIP channels */
596  ast_framehook_detach(new_chan, framehook_id);
597 }
598 
599 static int t38_consume(void *data, enum ast_frame_type type)
600 {
601  return (type == AST_FRAME_CONTROL) ? 1 : 0;
602 }
603 
605  .type = "T38 framehook",
606 };
607 
608 /*! \brief Function called to attach T.38 framehook to channel when appropriate */
610 {
611  int framehook_id;
612  struct ast_datastore *datastore = NULL;
613  static struct ast_framehook_interface hook = {
615  .event_cb = t38_framehook,
616  .consume_cb = t38_consume,
617  .chan_fixup_cb = t38_masq,
618  .chan_breakdown_cb = t38_masq,
619  };
620 
621  /* If the channel's already gone, bail */
622  if (!session->channel) {
623  return;
624  }
625 
626  /* Always attach the framehook so we can quickly reject */
627 
628  ast_channel_lock(session->channel);
629 
630  /* Skip attaching the framehook if the T.38 datastore already exists for the channel */
631  datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore,
632  NULL);
633  if (datastore) {
634  ast_channel_unlock(session->channel);
635  return;
636  }
637 
638  framehook_id = ast_framehook_attach(session->channel, &hook);
639  if (framehook_id < 0) {
640  ast_log(LOG_WARNING, "Could not attach T.38 Frame hook, T.38 will be unavailable on '%s'\n",
641  ast_channel_name(session->channel));
642  ast_channel_unlock(session->channel);
643  return;
644  }
645 
646  datastore = ast_datastore_alloc(&t38_framehook_datastore, NULL);
647  if (!datastore) {
648  ast_log(LOG_ERROR, "Could not alloc T.38 Frame hook datastore, T.38 will be unavailable on '%s'\n",
649  ast_channel_name(session->channel));
650  ast_framehook_detach(session->channel, framehook_id);
651  ast_channel_unlock(session->channel);
652  return;
653  }
654 
655  ast_channel_datastore_add(session->channel, datastore);
656  ast_channel_unlock(session->channel);
657 }
658 
659 /*! \brief Function called when an INVITE arrives */
660 static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
661 {
662  t38_attach_framehook(session);
663  return 0;
664 }
665 
666 /*! \brief Function called when an INVITE is sent */
667 static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
668 {
669  t38_attach_framehook(session);
670 }
671 
672 /*! \brief Get Max T.38 Transmission rate from T38 capabilities */
673 static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
674 {
675  switch (rate) {
676  case AST_T38_RATE_2400:
677  return 2400;
678  case AST_T38_RATE_4800:
679  return 4800;
680  case AST_T38_RATE_7200:
681  return 7200;
682  case AST_T38_RATE_9600:
683  return 9600;
684  case AST_T38_RATE_12000:
685  return 12000;
686  case AST_T38_RATE_14400:
687  return 14400;
688  default:
689  return 0;
690  }
691 }
692 
693 /*! \brief Supplement for adding framehook to session channel */
695  .method = "INVITE",
696  .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
697  .incoming_request = t38_incoming_invite_request,
698  .outgoing_request = t38_outgoing_invite_request,
699 };
700 
701 /*! \brief Parse a T.38 image stream and store the attribute information */
702 static void t38_interpret_sdp(struct t38_state *state, struct ast_sip_session *session, struct ast_sip_session_media *session_media,
703  const struct pjmedia_sdp_media *stream)
704 {
705  unsigned int attr_i;
706 
707  for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
708  pjmedia_sdp_attr *attr = stream->attr[attr_i];
709 
710  if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
711  /* This is purposely left empty, it is unused */
712  } else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
713  switch (pj_strtoul(&attr->value)) {
714  case 14400:
716  break;
717  case 12000:
719  break;
720  case 9600:
722  break;
723  case 7200:
725  break;
726  case 4800:
728  break;
729  case 2400:
731  break;
732  }
733  } else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
734  state->their_parms.version = pj_strtoul(&attr->value);
735  } else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
736  if (!session->endpoint->media.t38.maxdatagram) {
737  ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
738  }
739  } else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
740  state->their_parms.fill_bit_removal = 1;
741  } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
742  state->their_parms.transcoding_mmr = 1;
743  } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
744  state->their_parms.transcoding_jbig = 1;
745  } else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
746  if (!pj_stricmp2(&attr->value, "localTCF")) {
748  } else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
750  }
751  } else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
752  if (session->t38state == T38_LOCAL_REINVITE) {
754  if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
756  } else if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
758  } else {
760  }
762  if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
764  } else {
766  }
767  } else {
769  }
770  } else {
771  if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
773  } else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
775  } else {
777  }
778  }
779  }
780 
781  }
782 }
783 
784 /*! \brief Function which defers an incoming media stream */
786  struct ast_sip_session *session, struct ast_sip_session_media *session_media,
787  const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
788 {
789  struct t38_state *state;
790 
791  if (!session->endpoint->media.t38.enabled) {
792  ast_debug(3, "Not deferring incoming SDP stream: T.38 not enabled on %s\n", ast_channel_name(session->channel));
794  }
795 
796  if (t38_initialize_session(session, session_media)) {
797  ast_debug(3, "Not deferring incoming SDP stream: Failed to initialize UDPTL on %s\n", ast_channel_name(session->channel));
799  }
800 
801  if (!(state = t38_state_get_or_alloc(session))) {
803  }
804 
805  t38_interpret_sdp(state, session, session_media, stream);
806 
807  /* If they are initiating the re-invite we need to defer responding until later */
808  if (session->t38state == T38_DISABLED) {
809  t38_change_state(session, session_media, state, T38_PEER_REINVITE);
810  ast_debug(3, "Deferring incoming SDP stream on %s for peer re-invite\n", ast_channel_name(session->channel));
812  }
813 
815 }
816 
817 /*! \brief Function which negotiates an incoming media stream */
819  struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp,
820  int index, struct ast_stream *asterisk_stream)
821 {
822  struct t38_state *state;
823  char host[NI_MAXHOST];
824  pjmedia_sdp_media *stream = sdp->media[index];
825  RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
826 
827  if (!session->endpoint->media.t38.enabled) {
828  ast_debug(3, "Declining; T.38 not enabled on session\n");
829  return 0;
830  }
831 
832  if (!(state = t38_state_get_or_alloc(session))) {
833  return 0;
834  }
835 
836  if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
837  ast_debug(3, "Declining; T.38 state is rejected or declined\n");
838  t38_change_state(session, NULL, state, T38_DISABLED);
839  return 0;
840  }
841 
842  ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
843 
844  /* Ensure that the address provided is valid */
845  if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
846  /* The provided host was actually invalid so we error out this negotiation */
847  ast_debug(3, "Declining; provided host is invalid\n");
848  return 0;
849  }
850 
851  /* Check the address family to make sure it matches configured */
852  if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) ||
853  (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
854  /* The address does not match configured */
855  ast_debug(3, "Declining, provided host does not match configured address family\n");
856  return 0;
857  }
858 
859  return 1;
860 }
861 
862 /*! \brief Function which creates an outgoing stream */
864  struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_session *remote, struct ast_stream *stream)
865 {
866  pj_pool_t *pool = session->inv_session->pool_prov;
867  static const pj_str_t STR_IN = { "IN", 2 };
868  static const pj_str_t STR_IP4 = { "IP4", 3};
869  static const pj_str_t STR_IP6 = { "IP6", 3};
870  static const pj_str_t STR_UDPTL = { "udptl", 5 };
871  static const pj_str_t STR_T38 = { "t38", 3 };
872  static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
873  static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
874  static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
875  static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
876  struct t38_state *state;
877  pjmedia_sdp_media *media;
878  const char *hostip = NULL;
879  struct ast_sockaddr addr;
880  char tmp[512];
881  pj_str_t stmp;
882 
883  if (!session->endpoint->media.t38.enabled) {
884  ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
885  return 1;
886  } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
887  (session->t38state != T38_ENABLED)) {
888  ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
889  return 1;
890  } else if (!(state = t38_state_get_or_alloc(session))) {
891  return -1;
892  } else if (t38_initialize_session(session, session_media)) {
893  ast_debug(3, "Not creating outgoing SDP stream: Failed to initialize T.38 session\n");
894  return -1;
895  }
896 
897  if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
898  !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
899  return -1;
900  }
901 
902  pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type));
903  media->desc.transport = STR_UDPTL;
904 
905  if (ast_strlen_zero(session->endpoint->media.address)) {
906  hostip = ast_sip_get_host_ip_string(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET());
907  } else {
908  hostip = session->endpoint->media.address;
909  }
910 
911  if (ast_strlen_zero(hostip)) {
912  ast_debug(3, "Not creating outgoing SDP stream: no known host IP\n");
913  return -1;
914  }
915 
916  media->conn->net_type = STR_IN;
917  media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
918  pj_strdup2(pool, &media->conn->addr, hostip);
919  ast_udptl_get_us(session_media->udptl, &addr);
920  media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
921  media->desc.port_count = 1;
922  media->desc.fmt[media->desc.fmt_count++] = STR_T38;
923 
924  snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
925  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
926 
927  snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
928  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));
929 
930  if (state->our_parms.fill_bit_removal) {
931  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
932  }
933 
934  if (state->our_parms.transcoding_mmr) {
935  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
936  }
937 
938  if (state->our_parms.transcoding_jbig) {
939  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
940  }
941 
942  switch (state->our_parms.rate_management) {
944  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
945  break;
947  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
948  break;
949  }
950 
951  snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
952  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));
953 
954  switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
956  break;
958  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
959  break;
961  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
962  break;
963  }
964 
965  sdp->media[sdp->media_count++] = media;
966 
967  return 1;
968 }
969 
971 {
972  struct ast_frame *frame;
973 
974  if (!session_media->udptl) {
975  return &ast_null_frame;
976  }
977 
978  frame = ast_udptl_read(session_media->udptl);
979  if (!frame) {
980  return NULL;
981  }
982 
983  frame->stream_num = session_media->stream_num;
984 
985  return frame;
986 }
987 
988 static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
989 {
990  if (!session_media->udptl) {
991  return 0;
992  }
993 
994  return ast_udptl_write(session_media->udptl, frame);
995 }
996 
997 /*! \brief Function which applies a negotiated stream */
999  struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local,
1000  const struct pjmedia_sdp_session *remote, int index, struct ast_stream *asterisk_stream)
1001 {
1002  RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
1003  pjmedia_sdp_media *remote_stream = remote->media[index];
1004  char host[NI_MAXHOST];
1005  struct t38_state *state;
1006 
1007  if (!session_media->udptl) {
1008  ast_debug(3, "Not applying negotiated SDP stream: no UDTPL session\n");
1009  return 0;
1010  }
1011 
1012  if (!(state = t38_state_get_or_alloc(session))) {
1013  return -1;
1014  }
1015 
1016  ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
1017 
1018  /* Ensure that the address provided is valid */
1019  if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
1020  /* The provided host was actually invalid so we error out this negotiation */
1021  ast_debug(3, "Not applying negotiated SDP stream: failed to resolve remote stream host\n");
1022  return -1;
1023  }
1024 
1025  ast_sockaddr_set_port(addrs, remote_stream->desc.port);
1026  ast_udptl_set_peer(session_media->udptl, addrs);
1027 
1028  t38_interpret_sdp(state, session, session_media, remote_stream);
1029 
1031  ast_sip_session_media_add_read_callback(session, session_media, ast_udptl_fd(session_media->udptl),
1033 
1034  return 0;
1035 }
1036 
1037 /*! \brief Function which updates the media stream with external media address, if applicable */
1038 static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
1039 {
1041  char host[NI_MAXHOST];
1042  struct ast_sockaddr our_sdp_addr = { { 0, } };
1043 
1044  /* If the stream has been rejected there will be no connection line */
1045  if (!stream->conn || !transport_state) {
1046  return;
1047  }
1048 
1049  ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
1050  ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
1051 
1052  /* Reversed check here. We don't check the remote endpoint being
1053  * in our local net, but whether our outgoing session IP is
1054  * local. If it is not, we won't do rewriting. No localnet
1055  * configured? Always rewrite. */
1056  if (ast_sip_transport_is_nonlocal(transport_state, &our_sdp_addr) && transport_state->localnet) {
1057  return;
1058  }
1059  ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address));
1060  pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address));
1061 }
1062 
1063 /*! \brief Function which destroys the UDPTL instance when session ends */
1064 static void stream_destroy(struct ast_sip_session_media *session_media)
1065 {
1066  if (session_media->udptl) {
1067  ast_udptl_destroy(session_media->udptl);
1068  }
1069  session_media->udptl = NULL;
1070 }
1071 
1072 /*! \brief SDP handler for 'image' media stream */
1074  .id = "image",
1075  .defer_incoming_sdp_stream = defer_incoming_sdp_stream,
1076  .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
1077  .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
1078  .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
1079  .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
1080  .stream_destroy = stream_destroy,
1081 };
1082 
1083 /*! \brief Unloads the SIP T.38 module from Asterisk */
1084 static int unload_module(void)
1085 {
1086  ast_sip_session_unregister_sdp_handler(&image_sdp_handler, "image");
1087  ast_sip_session_unregister_supplement(&t38_supplement);
1088 
1089  return 0;
1090 }
1091 
1092 /*!
1093  * \brief Load the module
1094  *
1095  * Module loading including tests for configuration or dependencies.
1096  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1097  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1098  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1099  * configuration file or other non-critical problem return
1100  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1101  */
1102 static int load_module(void)
1103 {
1104  if (ast_check_ipv6()) {
1105  ast_sockaddr_parse(&address, "::", 0);
1106  } else {
1107  ast_sockaddr_parse(&address, "0.0.0.0", 0);
1108  }
1109 
1110  ast_sip_session_register_supplement(&t38_supplement);
1111 
1112  if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) {
1113  ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
1114  goto end;
1115  }
1116 
1117  return AST_MODULE_LOAD_SUCCESS;
1118 end:
1119  unload_module();
1120 
1121  return AST_MODULE_LOAD_DECLINE;
1122 }
1123 
1124 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Support",
1125  .support_level = AST_MODULE_SUPPORT_CORE,
1126  .load = load_module,
1127  .unload = unload_module,
1128  .load_pri = AST_MODPRI_CHANNEL_DRIVER,
1129  .requires = "res_pjsip,res_pjsip_session,udptl",
1130 );
const char * type
Definition: datastore.h:32
unsigned int maxdatagram
Definition: res_pjsip.h:746
static const char type[]
Definition: chan_ooh323.c:109
enum ast_sip_session_t38state t38state
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define T38_ENABLED
Definition: chan_ooh323.c:102
Main Channel structure associated with a channel.
struct ast_sip_endpoint * endpoint
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.
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
#define ast_frdup(fr)
Copies a frame.
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
Asterisk main include file. File version handling, generic pbx functions.
Structure which contains media state information (streams, sessions)
#define ast_sip_transport_is_nonlocal(transport_state, addr)
Definition: res_pjsip.h:162
struct ast_sip_session_media_state * pending_media_state
void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
Definition: udptl.c:973
static struct ast_frame * media_session_udptl_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
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 struct ast_sip_session_supplement t38_supplement
Supplement for adding framehook to session channel.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
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.
void * ast_channel_tech_pvt(const struct ast_channel *chan)
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.
char * address
Definition: f2c.h:59
struct ast_udptl * udptl
UDPTL instance itself.
enum ast_t38_ec_modes error_correction
Definition: res_pjsip.h:744
#define LOG_WARNING
Definition: logger.h:274
#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
ast_framehook_event
These are the types of events that the framehook&#39;s event callback can receive.
Definition: framehook.h:151
static int tmp()
Definition: bt_open.c:389
static int load_module(void)
Load the module.
T.38 state information.
Definition: res_pjsip_t38.c:59
A handler for SDPs in SIP sessions.
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 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.
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:347
static pj_pool_t * pool
Global memory pool for configuration and timers.
UDPTL support for T.38.
static struct ast_sip_session_sdp_handler image_sdp_handler
SDP handler for &#39;image&#39; media stream.
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
retrieves local_max_datagram.
Definition: udptl.c:984
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
enum ast_control_t38 request_response
Structure for a data store type.
Definition: datastore.h:31
A structure which contains a channel implementation and session.
const ast_string_field address
Definition: res_pjsip.h:758
Definition: astman.c:222
struct ast_sip_session * session
Pointer to session.
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.
enum ast_sip_session_t38state state
Current state.
Definition: res_pjsip_t38.c:61
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:997
#define ast_assert(a)
Definition: utils.h:695
Definition: muted.c:95
Structure for a data store object.
Definition: datastore.h:68
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:5240
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:2404
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
#define NULL
Definition: resample.c:96
void ast_udptl_destroy(struct ast_udptl *udptl)
Definition: udptl.c:1150
static int t38_automatic_reject(void *obj)
Task function which rejects a T.38 re-invite and resumes handling it.
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.
char * end
Definition: eagi_proxy.c:73
struct ast_frame * frame
T.38 control frame.
Definition: res_pjsip_t38.c:92
struct pjsip_inv_session * inv_session
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
Socket address structure.
Definition: netsock2.h:97
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
A structure describing a SIP session.
static int t38_consume(void *data, enum ast_frame_type type)
struct ast_frame_subclass subclass
Media Stream API.
enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
Definition: udptl.c:940
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_sip_session_media_state * active_media_state
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
Definition: res_pjsip.c:5473
struct ast_sip_session * session
Session itself.
Definition: res_pjsip_t38.c:90
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:841
void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
Definition: udptl.c:1140
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:521
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
#define MIN(a, b)
Definition: utils.h:226
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&#39;s vector.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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 char host[256]
Definition: muted.c:77
Structure for SIP transport information.
Definition: res_pjsip.h:87
static void t38_attach_framehook(struct ast_sip_session *session)
Function called to attach T.38 framehook to channel when appropriate.
General Asterisk PBX channel definitions.
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_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
int ast_check_ipv6(void)
Test that an OS supports IPv6 Networking.
Definition: main/utils.c:2540
#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:911
static int t38_incoming_invite_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Function called when an INVITE arrives.
static struct ast_mansession session
struct ast_sip_session_media_state * media_state
Definition: res_pjsip_t38.c:69
static int media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
Access Control of various sorts.
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.
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.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
enum ast_control_t38_rate rate
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_channel * channel
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
void ast_sip_session_resume_reinvite(struct ast_sip_session *session)
Resumes processing of a deferred incoming re-invite.
ast_sip_session_t38state
T.38 states for a session.
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Unregister an SDP handler.
Network socket handling.
struct ast_taskprocessor * serializer
ast_frame_type
Frame types.
int stream_num
The stream number to place into any resulting frames.
unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
retrieves far max ifp
Definition: udptl.c:1016
Set when the stream is sending and receiving media.
Definition: stream.h:82
#define LOG_ERROR
Definition: logger.h:285
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
Definition: udptl.c:1130
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:537
static void t38_masq(void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan)
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:5138
Transport to bind to.
Definition: res_pjsip.h:171
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
#define T38_DISABLED
Definition: chan_ooh323.c:101
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.
userdata associated with baseline taskprocessor test
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct ast_sip_t38_configuration t38
Definition: res_pjsip.h:768
ast_sip_session_sdp_stream_defer
#define ast_channel_unlock(chan)
Definition: channel.h:2946
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
static void t38_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Function called when an INVITE is sent.
#define ast_free(a)
Definition: astmm.h:182
ast_control_t38_rate
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
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.
static int unload_module(void)
Unloads the SIP T.38 module from Asterisk.
struct ast_control_t38_parameters our_parms
Our T.38 parameters.
Definition: res_pjsip_t38.c:63
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
int ast_udptl_fd(const struct ast_udptl *udptl)
Definition: udptl.c:730
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static const struct ast_datastore_info t38_framehook_datastore
static int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
Callback for when T.38 reinvite SDP is created.
struct ast_control_t38_parameters their_parms
Their T.38 parameters.
Definition: res_pjsip_t38.c:65
A structure containing SIP session media information.
pj_timer_entry timer
Timer entry for automatically rejecting an inbound re-invite.
Definition: res_pjsip_t38.c:67
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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:1028
A supplement to SIP message processing.
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
Definition: udptl.c:762
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_frame ast_null_frame
Definition: main/frame.c:79
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
Get Max T.38 Transmission rate from T38 capabilities.
enum ast_media_type type
Media type of this session media.
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_stream_topology * topology
The media stream topology.
Structure for T.38 parameters task data.
Definition: res_pjsip_t38.c:88
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
Definition: udptl.c:945
#define ast_frfree(fr)
int ast_udptl_write(struct ast_udptl *udptl, struct ast_frame *f)
Definition: udptl.c:1161
static const struct ast_datastore_info t38_datastore
Datastore for attaching T.38 state information.
Definition: res_pjsip_t38.c:82
enum ast_control_t38_rate_management rate_management
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
int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
Determine if the address is an IPv4 address.
Definition: netsock2.c:497
void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format,...)
Associates a character string &#39;tag&#39; with a UDPTL session.
Definition: udptl.c:1112
Data structure associated with a single frame of data.
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 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.
Definition: search.h:40
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
union ast_frame::@263 data
enum ast_frame_type frametype
static pj_timer_heap_t * timer_heap
Global timer heap.
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
static void stream_destroy(struct ast_sip_session_media *session_media)
Function which destroys the UDPTL instance when session ends.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
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.
void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
Definition: udptl.c:745
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.
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ast_format * ast_format_t38
Built-in cached T.38 format.
Definition: format_cache.c:246
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:524
static int t38_interpret_parameters(void *obj)
Task for reacting to T.38 control frame.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
static void t38_parameters_task_data_destroy(void *obj)
Destructor for T.38 data.
Definition: res_pjsip_t38.c:96
void(* stream_stop)(struct ast_sip_session_media *session_media)
Stop a session_media created by this handler but do not destroy resources.
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...
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
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...
static char * ast_sockaddr_stringify_host(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only, suitable for a URL (with brack...
Definition: netsock2.h:331
Media Format Cache API.
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
#define ast_sip_session_register_supplement(supplement)
static void t38_state_destroy(void *obj)
Destructor for T.38 state information.
Definition: res_pjsip_t38.c:73