Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Macros | Functions | Variables
res_pjsip_t38.c File Reference

SIP T.38 handling. More...

#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjmedia.h>
#include <pjlib.h>
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/udptl.h"
#include "asterisk/netsock2.h"
#include "asterisk/channel.h"
#include "asterisk/acl.h"
#include "asterisk/stream.h"
#include "asterisk/format_cache.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
Include dependency graph for res_pjsip_t38.c:

Go to the source code of this file.

Data Structures

struct  t38_parameters_task_data
 Structure for T.38 parameters task data. More...
 
struct  t38_state
 T.38 state information. More...
 

Macros

#define T38_AUTOMATIC_REJECTION_SECONDS   5
 The number of seconds after receiving a T.38 re-invite before automatically rejecting it. More...
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
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. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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. More...
 
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. More...
 
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. More...
 
static int load_module (void)
 Load the module. More...
 
static struct ast_framemedia_session_udptl_read_callback (struct ast_sip_session *session, struct ast_sip_session_media *session_media)
 
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 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. More...
 
static void stream_destroy (struct ast_sip_session_media *session_media)
 Function which destroys the UDPTL instance when session ends. More...
 
static void t38_attach_framehook (struct ast_sip_session *session)
 Function called to attach T.38 framehook to channel when appropriate. More...
 
static int t38_automatic_reject (void *obj)
 Task function which rejects a T.38 re-invite and resumes handling it. More...
 
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. More...
 
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. More...
 
static int t38_consume (void *data, enum ast_frame_type type)
 
static struct ast_sip_session_media_statet38_create_media_state (struct ast_sip_session *session)
 Helper function which creates a media state for strictly T.38. More...
 
static struct ast_framet38_framehook (struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
 Frame hook callback for T.38 related stuff. More...
 
static unsigned int t38_get_rate (enum ast_control_t38_rate rate)
 Get Max T.38 Transmission rate from T38 capabilities. More...
 
static int t38_incoming_invite_request (struct ast_sip_session *session, struct pjsip_rx_data *rdata)
 Function called when an INVITE arrives. More...
 
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. More...
 
static int t38_interpret_parameters (void *obj)
 Task for reacting to T.38 control frame. More...
 
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. More...
 
static void t38_masq (void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan)
 
static void t38_outgoing_invite_request (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 Function called when an INVITE is sent. More...
 
static struct t38_parameters_task_datat38_parameters_task_data_alloc (struct ast_sip_session *session, struct ast_frame *frame)
 Allocator for T.38 data. More...
 
static void t38_parameters_task_data_destroy (void *obj)
 Destructor for T.38 data. More...
 
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. More...
 
static int t38_reinvite_sdp_cb (struct ast_sip_session *session, pjmedia_sdp_session *sdp)
 Callback for when T.38 reinvite SDP is created. More...
 
static void t38_state_destroy (void *obj)
 Destructor for T.38 state information. More...
 
static struct t38_statet38_state_get_or_alloc (struct ast_sip_session *session)
 Helper function which retrieves or allocates a T.38 state information datastore. More...
 
static int unload_module (void)
 Unloads the SIP T.38 module from Asterisk. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP T.38 UDPTL Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .requires = "res_pjsip,res_pjsip_session,udptl", }
 
static struct ast_sockaddr address
 Address for UDPTL. More...
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_sip_session_sdp_handler image_sdp_handler
 SDP handler for 'image' media stream. More...
 
static const struct ast_datastore_info t38_datastore
 Datastore for attaching T.38 state information. More...
 
static const struct ast_datastore_info t38_framehook_datastore
 
static struct ast_sip_session_supplement t38_supplement
 Supplement for adding framehook to session channel. More...
 

Detailed Description

SIP T.38 handling.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file res_pjsip_t38.c.

Macro Definition Documentation

◆ T38_AUTOMATIC_REJECTION_SECONDS

#define T38_AUTOMATIC_REJECTION_SECONDS   5

The number of seconds after receiving a T.38 re-invite before automatically rejecting it.

Definition at line 53 of file res_pjsip_t38.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1171 of file res_pjsip_t38.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1171 of file res_pjsip_t38.c.

◆ apply_negotiated_sdp_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 
)
static

Function which applies a negotiated stream.

Definition at line 1039 of file res_pjsip_t38.c.

1042 {
1043  RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
1044  pjmedia_sdp_media *remote_stream = remote->media[index];
1045  char host[NI_MAXHOST];
1046  struct t38_state *state;
1047 
1048  if (!session_media->udptl) {
1049  ast_debug(3, "Not applying negotiated SDP stream: no UDTPL session\n");
1050  return 0;
1051  }
1052 
1053  if (!(state = t38_state_get_or_alloc(session))) {
1054  return -1;
1055  }
1056 
1057  ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
1058 
1059  /* Ensure that the address provided is valid */
1060  if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
1061  /* The provided host was actually invalid so we error out this negotiation */
1062  ast_debug(3, "Not applying negotiated SDP stream: failed to resolve remote stream host\n");
1063  return -1;
1064  }
1065 
1066  ast_sockaddr_set_port(addrs, remote_stream->desc.port);
1067  ast_udptl_set_peer(session_media->udptl, addrs);
1068 
1069  t38_interpret_sdp(state, session, session_media, remote_stream);
1070 
1072  ast_sip_session_media_add_read_callback(session, session_media, ast_udptl_fd(session_media->udptl),
1074 
1075  return 0;
1076 }
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
enum sip_cc_notify_state state
Definition: chan_sip.c:966
#define ast_debug(level,...)
Log a DEBUG message.
@ AST_AF_UNSPEC
Definition: netsock2.h:54
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_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
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:2035
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_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 media_session_udptl_write_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct ast_frame *frame)
static struct ast_frame * media_session_udptl_read_callback(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
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 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 NULL
Definition: resample.c:96
struct ast_udptl * udptl
UDPTL instance itself.
Socket address structure.
Definition: netsock2.h:97
T.38 state information.
Definition: res_pjsip_t38.c:59
int ast_udptl_fd(const struct ast_udptl *udptl)
Definition: udptl.c:730
void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
Definition: udptl.c:1130
#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:936

References AST_AF_UNSPEC, ast_copy_pj_str(), ast_debug, ast_free, ast_sip_session_media_add_read_callback(), ast_sip_session_media_set_write_callback(), ast_sockaddr_resolve(), ast_sockaddr_set_port, ast_udptl_fd(), ast_udptl_set_peer(), media_session_udptl_read_callback(), media_session_udptl_write_callback(), NULL, PARSE_PORT_FORBID, RAII_VAR, session, state, t38_interpret_sdp(), t38_state_get_or_alloc(), and ast_sip_session_media::udptl.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1171 of file res_pjsip_t38.c.

◆ change_outgoing_sdp_stream_media_address()

static void change_outgoing_sdp_stream_media_address ( pjsip_tx_data *  tdata,
struct pjmedia_sdp_media *  stream,
struct ast_sip_transport transport 
)
static

Function which updates the media stream with external media address, if applicable.

Definition at line 1079 of file res_pjsip_t38.c.

1080 {
1082  char host[NI_MAXHOST];
1083  struct ast_sockaddr our_sdp_addr = { { 0, } };
1084 
1085  /* If the stream has been rejected there will be no connection line */
1086  if (!stream->conn || !transport_state) {
1087  return;
1088  }
1089 
1090  ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
1091  ast_sockaddr_parse(&our_sdp_addr, host, PARSE_PORT_FORBID);
1092 
1093  /* Reversed check here. We don't check the remote endpoint being
1094  * in our local net, but whether our outgoing session IP is
1095  * local. If it is not, we won't do rewriting. No localnet
1096  * configured? Always rewrite. */
1097  if (ast_sip_transport_is_nonlocal(transport_state, &our_sdp_addr) && transport_state->localnet) {
1098  return;
1099  }
1100  ast_debug(5, "Setting media address to %s\n", ast_sockaddr_stringify_host(&transport_state->external_media_address));
1101  pj_strdup2(tdata->pool, &stream->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address));
1102 }
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
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:327
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
#define ast_sip_transport_is_nonlocal(transport_state, addr)
Definition: res_pjsip.h:178
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
Structure for SIP transport information.
Definition: res_pjsip.h:103

References ao2_cleanup, ast_copy_pj_str(), ast_debug, ast_sip_get_transport_state(), ast_sip_transport_is_nonlocal, ast_sockaddr_parse(), ast_sockaddr_stringify_host(), ast_sorcery_object_get_id(), PARSE_PORT_FORBID, and RAII_VAR.

◆ create_outgoing_sdp_stream()

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 
)
static

Function which creates an outgoing stream.

Definition at line 904 of file res_pjsip_t38.c.

906 {
907  pj_pool_t *pool = session->inv_session->pool_prov;
908  static const pj_str_t STR_IN = { "IN", 2 };
909  static const pj_str_t STR_IP4 = { "IP4", 3};
910  static const pj_str_t STR_IP6 = { "IP6", 3};
911  static const pj_str_t STR_UDPTL = { "udptl", 5 };
912  static const pj_str_t STR_T38 = { "t38", 3 };
913  static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
914  static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
915  static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
916  static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
917  struct t38_state *state;
918  pjmedia_sdp_media *media;
919  const char *hostip = NULL;
920  struct ast_sockaddr addr;
921  char tmp[512];
922  pj_str_t stmp;
923 
924  if (!session->endpoint->media.t38.enabled) {
925  ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
926  return 1;
927  } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
928  (session->t38state != T38_ENABLED)) {
929  ast_debug(3, "Not creating outgoing SDP stream: T.38 not enabled\n");
930  return 1;
931  } else if (!(state = t38_state_get_or_alloc(session))) {
932  return -1;
933  } else if (t38_initialize_session(session, session_media)) {
934  ast_debug(3, "Not creating outgoing SDP stream: Failed to initialize T.38 session\n");
935  return -1;
936  }
937 
938  if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
939  !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
940  return -1;
941  }
942 
943  pj_strdup2(pool, &media->desc.media, ast_codec_media_type2str(session_media->type));
944  media->desc.transport = STR_UDPTL;
945 
946  if (ast_strlen_zero(session->endpoint->media.address)) {
947  hostip = ast_sip_get_host_ip_string(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET());
948  } else {
949  hostip = session->endpoint->media.address;
950  }
951 
952  if (ast_strlen_zero(hostip)) {
953  ast_debug(3, "Not creating outgoing SDP stream: no known host IP\n");
954  return -1;
955  }
956 
957  media->conn->net_type = STR_IN;
958  media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
959  pj_strdup2(pool, &media->conn->addr, hostip);
960  ast_udptl_get_us(session_media->udptl, &addr);
961  media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
962  media->desc.port_count = 1;
963  media->desc.fmt[media->desc.fmt_count++] = STR_T38;
964 
965  snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
966  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
967 
968  snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
969  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));
970 
971  if (state->our_parms.fill_bit_removal) {
972  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
973  }
974 
975  if (state->our_parms.transcoding_mmr) {
976  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
977  }
978 
979  if (state->our_parms.transcoding_jbig) {
980  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
981  }
982 
983  switch (state->our_parms.rate_management) {
985  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
986  break;
988  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
989  break;
990  }
991 
992  snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
993  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));
994 
995  switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
997  break;
999  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
1000  break;
1002  media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
1003  break;
1004  }
1005 
1006  sdp->media[sdp->media_count++] = media;
1007 
1008  return 1;
1009 }
static int tmp()
Definition: bt_open.c:389
#define T38_ENABLED
Definition: chan_ooh323.c:102
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
@ AST_T38_RATE_MANAGEMENT_LOCAL_TCF
@ AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
Definition: res_pjsip.c:2296
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 unsigned int t38_get_rate(enum ast_control_t38_rate rate)
Get Max T.38 Transmission rate from T38 capabilities.
@ T38_PEER_REINVITE
Definition: sip.h:665
@ T38_LOCAL_REINVITE
Definition: sip.h:664
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
enum ast_media_type type
Media type of this session media.
enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
Definition: udptl.c:940
void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
Definition: udptl.c:1140
unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
retrieves local_max_datagram.
Definition: udptl.c:984
@ UDPTL_ERROR_CORRECTION_FEC
Definition: udptl.h:39
@ UDPTL_ERROR_CORRECTION_NONE
Definition: udptl.h:38
@ UDPTL_ERROR_CORRECTION_REDUNDANCY
Definition: udptl.h:40

References ast_codec_media_type2str(), ast_debug, ast_sip_get_host_ip_string(), ast_sockaddr_port, ast_strlen_zero(), AST_T38_RATE_MANAGEMENT_LOCAL_TCF, AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, ast_udptl_get_error_correction_scheme(), ast_udptl_get_local_max_datagram(), ast_udptl_get_us(), NULL, session, state, T38_ENABLED, t38_get_rate(), t38_initialize_session(), T38_LOCAL_REINVITE, T38_PEER_REINVITE, t38_state_get_or_alloc(), tmp(), ast_sip_session_media::type, ast_sip_session_media::udptl, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_NONE, and UDPTL_ERROR_CORRECTION_REDUNDANCY.

◆ defer_incoming_sdp_stream()

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 
)
static

Function which defers an incoming media stream.

Definition at line 743 of file res_pjsip_t38.c.

829 {
830  struct t38_state *state;
831 
832  if (!session->endpoint->media.t38.enabled) {
833  ast_debug(3, "Not deferring incoming SDP stream: T.38 not enabled on %s\n", ast_channel_name(session->channel));
835  }
836 
837  if (t38_initialize_session(session, session_media)) {
838  ast_debug(3, "Not deferring incoming SDP stream: Failed to initialize UDPTL on %s\n", ast_channel_name(session->channel));
840  }
841 
844  }
845 
846  t38_interpret_sdp(state, session, session_media, stream);
847 
848  /* If they are initiating the re-invite we need to defer responding until later */
849  if (session->t38state == T38_DISABLED) {
851  ast_debug(3, "Deferring incoming SDP stream on %s for peer re-invite\n", ast_channel_name(session->channel));
853  }
854 
856 }
#define T38_DISABLED
Definition: chan_ooh323.c:101
const char * ast_channel_name(const struct ast_channel *chan)
@ 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
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.

References AST_T38_RATE_12000, AST_T38_RATE_14400, AST_T38_RATE_2400, AST_T38_RATE_4800, AST_T38_RATE_7200, AST_T38_RATE_9600, AST_T38_RATE_MANAGEMENT_LOCAL_TCF, AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, ast_udptl_set_error_correction_scheme(), ast_udptl_set_far_max_datagram(), session, T38_LOCAL_REINVITE, ast_sip_session_media::udptl, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_NONE, and UDPTL_ERROR_CORRECTION_REDUNDANCY.

◆ load_module()

static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 1143 of file res_pjsip_t38.c.

1144 {
1145  if (ast_check_ipv6()) {
1146  ast_sockaddr_parse(&address, "::", 0);
1147  } else {
1148  ast_sockaddr_parse(&address, "0.0.0.0", 0);
1149  }
1150 
1152 
1154  ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
1155  goto end;
1156  }
1157 
1158  return AST_MODULE_LOAD_SUCCESS;
1159 end:
1160  unload_module();
1161 
1162  return AST_MODULE_LOAD_DECLINE;
1163 }
#define ast_log
Definition: astobj2.c:42
char * end
Definition: eagi_proxy.c:73
char * address
Definition: f2c.h:59
#define LOG_ERROR
@ 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
int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Register an SDP handler.
#define ast_sip_session_register_supplement(supplement)
static struct ast_sip_session_sdp_handler image_sdp_handler
SDP handler for 'image' media stream.
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.
int ast_check_ipv6(void)
Test that an OS supports IPv6 Networking.
Definition: main/utils.c:2688

◆ media_session_udptl_read_callback()

static struct ast_frame* media_session_udptl_read_callback ( struct ast_sip_session session,
struct ast_sip_session_media session_media 
)
static

Definition at line 1011 of file res_pjsip_t38.c.

1012 {
1013  struct ast_frame *frame;
1014 
1015  if (!session_media->udptl) {
1016  return &ast_null_frame;
1017  }
1018 
1019  frame = ast_udptl_read(session_media->udptl);
1020  if (!frame) {
1021  return NULL;
1022  }
1023 
1024  frame->stream_num = session_media->stream_num;
1025 
1026  return frame;
1027 }
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Data structure associated with a single frame of data.
int stream_num
The stream number to place into any resulting frames.
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
Definition: udptl.c:762

References ast_null_frame, ast_udptl_read(), NULL, ast_frame::stream_num, ast_sip_session_media::stream_num, and ast_sip_session_media::udptl.

Referenced by apply_negotiated_sdp_stream().

◆ media_session_udptl_write_callback()

static int media_session_udptl_write_callback ( struct ast_sip_session session,
struct ast_sip_session_media session_media,
struct ast_frame frame 
)
static

Definition at line 1029 of file res_pjsip_t38.c.

1030 {
1031  if (!session_media->udptl) {
1032  return 0;
1033  }
1034 
1035  return ast_udptl_write(session_media->udptl, frame);
1036 }
int ast_udptl_write(struct ast_udptl *udptl, struct ast_frame *f)
Definition: udptl.c:1161

References ast_udptl_write(), and ast_sip_session_media::udptl.

Referenced by apply_negotiated_sdp_stream().

◆ negotiate_incoming_sdp_stream()

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 
)
static

Function which negotiates an incoming media stream.

Definition at line 859 of file res_pjsip_t38.c.

862 {
863  struct t38_state *state;
864  char host[NI_MAXHOST];
865  pjmedia_sdp_media *stream = sdp->media[index];
866  RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
867 
868  if (!session->endpoint->media.t38.enabled) {
869  ast_debug(3, "Declining; T.38 not enabled on session\n");
870  return 0;
871  }
872 
874  return 0;
875  }
876 
877  if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
878  ast_debug(3, "Declining; T.38 state is rejected or declined\n");
880  return 0;
881  }
882 
883  ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
884 
885  /* Ensure that the address provided is valid */
886  if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
887  /* The provided host was actually invalid so we error out this negotiation */
888  ast_debug(3, "Declining; provided host is invalid\n");
889  return 0;
890  }
891 
892  /* Check the address family to make sure it matches configured */
893  if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) ||
894  (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
895  /* The address does not match configured */
896  ast_debug(3, "Declining, provided host does not match configured address family\n");
897  return 0;
898  }
899 
900  return 1;
901 }
@ AST_AF_INET
Definition: netsock2.h:55
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:524
int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
Determine if the address is an IPv4 address.
Definition: netsock2.c:497
@ T38_REJECTED
Definition: sip.h:667

References AST_AF_INET, ast_copy_pj_str(), ast_debug, ast_free, ast_sockaddr_is_ipv4(), ast_sockaddr_is_ipv6(), ast_sockaddr_resolve(), NULL, PARSE_PORT_FORBID, RAII_VAR, session, state, t38_change_state(), T38_DISABLED, T38_REJECTED, and t38_state_get_or_alloc().

◆ stream_destroy()

static void stream_destroy ( struct ast_sip_session_media session_media)
static

Function which destroys the UDPTL instance when session ends.

Definition at line 1105 of file res_pjsip_t38.c.

1106 {
1107  if (session_media->udptl) {
1108  ast_udptl_destroy(session_media->udptl);
1109  }
1110  session_media->udptl = NULL;
1111 }
void ast_udptl_destroy(struct ast_udptl *udptl)
Definition: udptl.c:1150

◆ t38_attach_framehook()

static void t38_attach_framehook ( struct ast_sip_session session)
static

Function called to attach T.38 framehook to channel when appropriate.

Definition at line 650 of file res_pjsip_t38.c.

651 {
652  int framehook_id;
653  struct ast_datastore *datastore = NULL;
654  static struct ast_framehook_interface hook = {
656  .event_cb = t38_framehook,
657  .consume_cb = t38_consume,
658  .chan_fixup_cb = t38_masq,
659  .chan_breakdown_cb = t38_masq,
660  };
661 
662  /* If the channel's already gone, bail */
663  if (!session->channel) {
664  return;
665  }
666 
667  /* Always attach the framehook so we can quickly reject */
668 
669  ast_channel_lock(session->channel);
670 
671  /* Skip attaching the framehook if the T.38 datastore already exists for the channel */
673  NULL);
674  if (datastore) {
675  ast_channel_unlock(session->channel);
676  return;
677  }
678 
679  framehook_id = ast_framehook_attach(session->channel, &hook);
680  if (framehook_id < 0) {
681  ast_log(LOG_WARNING, "Could not attach T.38 Frame hook, T.38 will be unavailable on '%s'\n",
682  ast_channel_name(session->channel));
683  ast_channel_unlock(session->channel);
684  return;
685  }
686 
688  if (!datastore) {
689  ast_log(LOG_ERROR, "Could not alloc T.38 Frame hook datastore, T.38 will be unavailable on '%s'\n",
690  ast_channel_name(session->channel));
691  ast_framehook_detach(session->channel, framehook_id);
692  ast_channel_unlock(session->channel);
693  return;
694  }
695 
696  ast_channel_datastore_add(session->channel, datastore);
697  ast_channel_unlock(session->channel);
698 }
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2384
#define ast_channel_lock(chan)
Definition: channel.h:2922
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:2398
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
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
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 LOG_WARNING
static const struct ast_datastore_info t38_framehook_datastore
static int t38_consume(void *data, enum ast_frame_type type)
static void t38_masq(void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan)
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.
Structure for a data store object.
Definition: datastore.h:64

References ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_datastore_alloc, ast_framehook_attach(), ast_framehook_detach(), AST_FRAMEHOOK_INTERFACE_VERSION, ast_log, LOG_ERROR, LOG_WARNING, NULL, session, t38_consume(), t38_framehook(), t38_framehook_datastore, t38_masq(), and ast_framehook_interface::version.

Referenced by t38_incoming_invite_request(), and t38_outgoing_invite_request().

◆ t38_automatic_reject()

static int t38_automatic_reject ( void *  obj)
static

Task function which rejects a T.38 re-invite and resumes handling it.

Definition at line 202 of file res_pjsip_t38.c.

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 }
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
void ast_sip_session_resume_reinvite(struct ast_sip_session *session)
Resumes processing of a deferred incoming re-invite.
A structure describing a SIP session.

References ao2_cleanup, ast_channel_name(), ast_debug, ast_sip_session_get_datastore(), ast_sip_session_resume_reinvite(), NULL, RAII_VAR, session, t38_change_state(), and T38_REJECTED.

Referenced by t38_automatic_reject_timer_cb().

◆ t38_automatic_reject_timer_cb()

static void t38_automatic_reject_timer_cb ( pj_timer_heap_t *  timer_heap,
struct pj_timer_entry *  entry 
)
static

Timer entry callback which queues a task to reject a T.38 re-invite and resume handling it.

Definition at line 221 of file res_pjsip_t38.c.

222 {
223  struct ast_sip_session *session = entry->user_data;
224 
226  ao2_ref(session, -1);
227  }
228 }
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
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:1933
static int t38_automatic_reject(void *obj)
Task function which rejects a T.38 re-invite and resumes handling it.
Definition: search.h:40

References ao2_ref, ast_sip_push_task(), session, and t38_automatic_reject().

Referenced by t38_state_get_or_alloc().

◆ t38_change_state()

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 
)
static

Helper function for changing the T.38 state.

Definition at line 129 of file res_pjsip_t38.c.

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 }
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:1232
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...
@ AST_T38_TERMINATED
@ AST_T38_REFUSED
@ AST_T38_NEGOTIATED
@ AST_T38_REQUEST_NEGOTIATE
@ AST_CONTROL_T38_PARAMETERS
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:513
ast_sip_session_t38state
T.38 states for a session.
@ T38_MAX_ENUM
#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
enum ast_control_t38 request_response
void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format,...)
Associates a character string 'tag' with a UDPTL session.
Definition: udptl.c:1112
unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
retrieves far max ifp
Definition: udptl.c:1016
#define ast_assert(a)
Definition: utils.h:734

References ao2_ref, ast_assert, ast_channel_name(), ast_channel_set_unbridged(), AST_CONTROL_T38_PARAMETERS, ast_debug, ast_log, ast_queue_control_data(), ast_sip_get_pjsip_endpoint(), AST_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, AST_T38_TERMINATED, ast_udptl_get_far_max_ifp(), ast_udptl_set_tag(), LOG_WARNING, ast_control_t38_parameters::max_ifp, ast_control_t38_parameters::request_response, session, T38_AUTOMATIC_REJECTION_SECONDS, T38_DISABLED, T38_ENABLED, T38_LOCAL_REINVITE, T38_MAX_ENUM, T38_PEER_REINVITE, T38_REJECTED, and ast_sip_session_media::udptl.

Referenced by negotiate_incoming_sdp_stream(), t38_automatic_reject(), t38_interpret_parameters(), and t38_reinvite_response_cb().

◆ t38_consume()

static int t38_consume ( void *  data,
enum ast_frame_type  type 
)
static

Definition at line 640 of file res_pjsip_t38.c.

641 {
642  return (type == AST_FRAME_CONTROL) ? 1 : 0;
643 }
static const char type[]
Definition: chan_ooh323.c:109
@ AST_FRAME_CONTROL

References AST_FRAME_CONTROL, and type.

Referenced by t38_attach_framehook().

◆ t38_create_media_state()

static struct ast_sip_session_media_state* t38_create_media_state ( struct ast_sip_session session)
static

Helper function which creates a media state for strictly T.38.

Definition at line 408 of file res_pjsip_t38.c.

409 {
410  struct ast_sip_session_media_state *media_state;
411  struct ast_stream *stream;
412  struct ast_format_cap *caps;
413  struct ast_sip_session_media *session_media;
414 
415  media_state = ast_sip_session_media_state_alloc();
416  if (!media_state) {
417  return NULL;
418  }
419 
420  media_state->topology = ast_stream_topology_alloc();
421  if (!media_state->topology) {
423  return NULL;
424  }
425 
426  stream = ast_stream_alloc("t38", AST_MEDIA_TYPE_IMAGE);
427  if (!stream) {
429  return NULL;
430  }
431 
433  if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) {
434  ast_stream_free(stream);
436  return NULL;
437  }
438 
440  if (!caps) {
442  return NULL;
443  }
444 
445  ast_stream_set_formats(stream, caps);
446  /* stream holds a reference to cap, release the local reference
447  * now so we don't have to deal with it in the error condition. */
448  ao2_ref(caps, -1);
449  if (ast_format_cap_append(caps, ast_format_t38, 0)) {
451  return NULL;
452  }
453 
454  session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0);
455  if (!session_media) {
457  return NULL;
458  }
459 
460  if (t38_initialize_session(session, session_media)) {
462  return NULL;
463  }
464 
465  return media_state;
466 }
@ AST_MEDIA_TYPE_IMAGE
Definition: codec.h:34
struct ast_format * ast_format_t38
Built-in cached T.38 format.
Definition: format_cache.c:241
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
struct ast_sip_session_media_state * ast_sip_session_media_state_alloc(void)
Allocate a session media state structure.
void ast_sip_session_media_state_free(struct ast_sip_session_media_state *media_state)
Free a session media state structure.
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.
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
@ AST_STREAM_STATE_SENDRECV
Set when the stream is sending and receiving media.
Definition: stream.h:82
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Structure which contains media state information (streams, sessions)
struct ast_stream_topology * topology
The media stream topology.
A structure containing SIP session media information.

References ao2_ref, ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_t38, AST_MEDIA_TYPE_IMAGE, ast_sip_session_media_state_add(), ast_sip_session_media_state_alloc(), ast_sip_session_media_state_free(), ast_stream_alloc(), ast_stream_free(), ast_stream_set_formats(), ast_stream_set_state(), AST_STREAM_STATE_SENDRECV, ast_stream_topology_alloc(), ast_stream_topology_set_stream(), NULL, session, t38_initialize_session(), and ast_sip_session_media_state::topology.

Referenced by t38_interpret_parameters().

◆ t38_framehook()

static struct ast_frame* t38_framehook ( struct ast_channel chan,
struct ast_frame f,
enum ast_framehook_event  event,
void *  data 
)
static

Frame hook callback for T.38 related stuff.

Definition at line 578 of file res_pjsip_t38.c.

580 {
581  struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
582 
584  return f;
585  }
586 
587  if (f->frametype == AST_FRAME_CONTROL
589  if (channel->session->endpoint->media.t38.enabled) {
591 
593  if (task_data
594  && ast_sip_push_task(channel->session->serializer,
596  ao2_ref(task_data, -1);
597  }
598  } else {
599  static const struct ast_control_t38_parameters rsp_refused = {
601  };
602  static const struct ast_control_t38_parameters rsp_terminated = {
604  };
605  const struct ast_control_t38_parameters *parameters = f->data.ptr;
606 
607  switch (parameters->request_response) {
609  ast_debug(2, "T.38 support not enabled on %s, refusing T.38 negotiation\n",
610  ast_channel_name(chan));
612  &rsp_refused, sizeof(rsp_refused));
613  break;
615  ast_debug(2, "T.38 support not enabled on %s, 'terminating' T.38 session\n",
616  ast_channel_name(chan));
618  &rsp_terminated, sizeof(rsp_terminated));
619  break;
620  default:
621  break;
622  }
623  }
624  }
625 
626  return f;
627 }
void * ast_channel_tech_pvt(const struct ast_channel *chan)
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
@ AST_T38_REQUEST_TERMINATE
static int t38_interpret_parameters(void *obj)
Task for reacting to T.38 control frame.
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.
struct ast_frame_subclass subclass
union ast_frame::@254 data
enum ast_frame_type frametype
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
struct ast_sip_t38_configuration t38
Definition: res_pjsip.h:810
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:887
struct ast_sip_endpoint * endpoint
struct ast_taskprocessor * serializer
Definition: astman.c:222
Structure for T.38 parameters task data.
Definition: res_pjsip_t38.c:88
userdata associated with baseline taskprocessor test

References ao2_ref, ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_T38_PARAMETERS, ast_debug, AST_FRAME_CONTROL, AST_FRAMEHOOK_EVENT_WRITE, ast_queue_control_data(), ast_sip_push_task(), AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, AST_T38_REQUEST_TERMINATE, AST_T38_TERMINATED, ast_frame::data, ast_sip_t38_configuration::enabled, ast_sip_session::endpoint, ast_frame::frametype, ast_frame_subclass::integer, ast_sip_endpoint::media, ast_frame::ptr, ast_control_t38_parameters::request_response, ast_sip_session::serializer, ast_sip_channel_pvt::session, ast_frame::subclass, ast_sip_endpoint_media_configuration::t38, t38_interpret_parameters(), and t38_parameters_task_data_alloc().

Referenced by t38_attach_framehook().

◆ t38_get_rate()

static unsigned int t38_get_rate ( enum ast_control_t38_rate  rate)
static

Get Max T.38 Transmission rate from T38 capabilities.

Definition at line 714 of file res_pjsip_t38.c.

715 {
716  switch (rate) {
717  case AST_T38_RATE_2400:
718  return 2400;
719  case AST_T38_RATE_4800:
720  return 4800;
721  case AST_T38_RATE_7200:
722  return 7200;
723  case AST_T38_RATE_9600:
724  return 9600;
725  case AST_T38_RATE_12000:
726  return 12000;
727  case AST_T38_RATE_14400:
728  return 14400;
729  default:
730  return 0;
731  }
732 }
@ AST_T38_RATE_12000
@ AST_T38_RATE_9600
@ AST_T38_RATE_2400
@ AST_T38_RATE_14400
@ AST_T38_RATE_7200
@ AST_T38_RATE_4800

References AST_T38_RATE_12000, AST_T38_RATE_14400, AST_T38_RATE_2400, AST_T38_RATE_4800, AST_T38_RATE_7200, and AST_T38_RATE_9600.

Referenced by create_outgoing_sdp_stream().

◆ t38_incoming_invite_request()

static int t38_incoming_invite_request ( struct ast_sip_session session,
struct pjsip_rx_data *  rdata 
)
static

Function called when an INVITE arrives.

Definition at line 701 of file res_pjsip_t38.c.

702 {
704  return 0;
705 }
static void t38_attach_framehook(struct ast_sip_session *session)
Function called to attach T.38 framehook to channel when appropriate.

References session, and t38_attach_framehook().

◆ t38_initialize_session()

static int t38_initialize_session ( struct ast_sip_session session,
struct ast_sip_session_media session_media 
)
static

Initializes UDPTL support on a session, only done when actually needed.

Definition at line 256 of file res_pjsip_t38.c.

257 {
258  struct ast_sockaddr temp_media_address;
260 
261  if (session_media->udptl) {
262  return 0;
263  }
264 
265  if (session->endpoint->media.t38.bind_udptl_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
266  if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) {
267  ast_debug(5, "Endpoint %s: Binding UDPTL media to %s\n",
269  session->endpoint->media.address);
270  media_address = &temp_media_address;
271  } else {
272  ast_debug(5, "Endpoint %s: UDPTL media address invalid: %s\n",
274  session->endpoint->media.address);
275  }
276  } else {
277  struct ast_sip_transport *transport;
278 
279  transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
280  session->endpoint->transport);
281  if (transport) {
282  struct ast_sip_transport_state *trans_state;
283 
285  if (trans_state) {
286  char hoststr[PJ_INET6_ADDRSTRLEN];
287 
288  pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0);
289  if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) {
290  ast_debug(5, "Transport %s bound to %s: Using it for UDPTL media.\n",
291  session->endpoint->transport, hoststr);
292  media_address = &temp_media_address;
293  } else {
294  ast_debug(5, "Transport %s bound to %s: Invalid for UDPTL media.\n",
295  session->endpoint->transport, hoststr);
296  }
297  ao2_ref(trans_state, -1);
298  }
299  ao2_ref(transport, -1);
300  }
301  }
302 
303  if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, media_address))) {
304  return -1;
305  }
306 
307  ast_udptl_set_error_correction_scheme(session_media->udptl, session->endpoint->media.t38.error_correction);
308  ast_udptl_setnat(session_media->udptl, session->endpoint->media.t38.nat);
309  ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->media.t38.maxdatagram);
310  ast_debug(3, "UDPTL initialized on session for %s\n", ast_channel_name(session->channel));
311 
312  return 0;
313 }
static struct ast_sockaddr media_address
Definition: chan_sip.c:1139
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static struct ast_sockaddr address
Address for UDPTL.
Definition: res_pjsip_t38.c:56
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:105
Transport to bind to.
Definition: res_pjsip.h:187
void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
Definition: udptl.c:745
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
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
void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
Definition: udptl.c:945

References address, ao2_ref, ast_channel_name(), ast_debug, ast_sip_get_sorcery(), ast_sip_get_transport_state(), ast_sockaddr_parse(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_id(), ast_strlen_zero(), ast_udptl_new_with_bindaddr(), ast_udptl_set_error_correction_scheme(), ast_udptl_set_far_max_datagram(), ast_udptl_setnat(), ast_sip_transport_state::host, media_address, NULL, session, ast_sip_transport_state::transport, and ast_sip_session_media::udptl.

Referenced by create_outgoing_sdp_stream(), and t38_create_media_state().

◆ t38_interpret_parameters()

static int t38_interpret_parameters ( void *  obj)
static

Task for reacting to T.38 control frame.

Definition at line 469 of file res_pjsip_t38.c.

470 {
471  RAII_VAR(struct t38_parameters_task_data *, data, obj, ao2_cleanup);
472  const struct ast_control_t38_parameters *parameters = data->frame->data.ptr;
473  struct t38_state *state = t38_state_get_or_alloc(data->session);
474  struct ast_sip_session_media *session_media = NULL;
475 
476  if (!state) {
477  return 0;
478  }
479 
480  switch (parameters->request_response) {
481  case AST_T38_NEGOTIATED:
482  case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
483  /* Negotiation can not take place without a valid max_ifp value. */
484  if (!parameters->max_ifp) {
485  if (data->session->t38state == T38_PEER_REINVITE) {
486  t38_change_state(data->session, NULL, state, T38_REJECTED);
487  ast_sip_session_resume_reinvite(data->session);
488  } else if (data->session->t38state == T38_ENABLED) {
489  t38_change_state(data->session, NULL, state, T38_DISABLED);
490  ast_sip_session_refresh(data->session, NULL, NULL, NULL,
492  state->media_state = NULL;
493  }
494  break;
495  } else if (data->session->t38state == T38_PEER_REINVITE) {
496  state->our_parms = *parameters;
497  /* modify our parameters to conform to the peer's parameters,
498  * based on the rules in the ITU T.38 recommendation
499  */
500  if (!state->their_parms.fill_bit_removal) {
501  state->our_parms.fill_bit_removal = 0;
502  }
503  if (!state->their_parms.transcoding_mmr) {
504  state->our_parms.transcoding_mmr = 0;
505  }
506  if (!state->their_parms.transcoding_jbig) {
507  state->our_parms.transcoding_jbig = 0;
508  }
509  state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
510  state->our_parms.rate_management = state->their_parms.rate_management;
511  session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
512  if (!session_media) {
513  ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n",
514  data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
515  break;
516  }
517  ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
518  t38_change_state(data->session, session_media, state, T38_ENABLED);
519  ast_sip_session_resume_reinvite(data->session);
520  } else if ((data->session->t38state != T38_ENABLED) ||
521  ((data->session->t38state == T38_ENABLED) &&
522  (parameters->request_response == AST_T38_REQUEST_NEGOTIATE))) {
523  struct ast_sip_session_media_state *media_state;
524 
525  media_state = t38_create_media_state(data->session);
526  if (!media_state) {
527  break;
528  }
529  state->our_parms = *parameters;
530  session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE];
531  if (!session_media) {
532  ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n",
533  data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
534  break;
535  }
536  ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
537  t38_change_state(data->session, NULL, state, T38_LOCAL_REINVITE);
539  AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, media_state);
540  }
541  break;
542  case AST_T38_TERMINATED:
543  case AST_T38_REFUSED:
544  case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
545  if (data->session->t38state == T38_PEER_REINVITE) {
546  t38_change_state(data->session, NULL, state, T38_REJECTED);
547  ast_sip_session_resume_reinvite(data->session);
548  } else if (data->session->t38state == T38_ENABLED) {
549  t38_change_state(data->session, NULL, state, T38_DISABLED);
551  state->media_state = NULL;
552  }
553  break;
554  case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */
555  struct ast_control_t38_parameters parameters = state->their_parms;
556 
557  if (data->session->t38state == T38_PEER_REINVITE) {
558  session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
559  if (!session_media) {
560  ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n",
561  data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
562  break;
563  }
564  parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
566  ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
567  }
568  break;
569  }
570  default:
571  break;
572  }
573 
574  return 0;
575 }
@ AST_T38_REQUEST_PARMS
@ AST_SIP_SESSION_REFRESH_METHOD_INVITE
Definition: res_pjsip.h:507
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 int t38_reinvite_sdp_cb(struct ast_sip_session *session, pjmedia_sdp_session *sdp)
Callback for when T.38 reinvite SDP is created.
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_media_state * t38_create_media_state(struct ast_sip_session *session)
Helper function which creates a media state for strictly T.38.
struct ast_sip_session_media * default_session[AST_MEDIA_TYPE_END]
Default media sessions for each type.
void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
Definition: udptl.c:973
#define MIN(a, b)
Definition: utils.h:226

References ao2_cleanup, ast_channel_name(), AST_CONTROL_T38_PARAMETERS, ast_log, AST_MEDIA_TYPE_IMAGE, ast_queue_control_data(), ast_sip_session_refresh(), AST_SIP_SESSION_REFRESH_METHOD_INVITE, ast_sip_session_resume_reinvite(), AST_T38_NEGOTIATED, AST_T38_REFUSED, AST_T38_REQUEST_NEGOTIATE, AST_T38_REQUEST_PARMS, AST_T38_REQUEST_TERMINATE, AST_T38_TERMINATED, ast_udptl_get_far_max_ifp(), ast_udptl_set_local_max_ifp(), ast_sip_session_media_state::default_session, LOG_ERROR, ast_control_t38_parameters::max_ifp, MIN, NULL, RAII_VAR, ast_control_t38_parameters::request_response, t38_change_state(), t38_create_media_state(), T38_DISABLED, T38_ENABLED, T38_LOCAL_REINVITE, T38_PEER_REINVITE, t38_reinvite_response_cb(), t38_reinvite_sdp_cb(), T38_REJECTED, t38_state_get_or_alloc(), and ast_sip_session_media::udptl.

Referenced by t38_framehook().

◆ t38_interpret_sdp()

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 
)
static

Parse a T.38 image stream and store the attribute information.

Definition at line 743 of file res_pjsip_t38.c.

745 {
746  unsigned int attr_i;
747 
748  for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
749  pjmedia_sdp_attr *attr = stream->attr[attr_i];
750 
751  if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
752  /* This is purposely left empty, it is unused */
753  } else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
754  switch (pj_strtoul(&attr->value)) {
755  case 14400:
756  state->their_parms.rate = AST_T38_RATE_14400;
757  break;
758  case 12000:
759  state->their_parms.rate = AST_T38_RATE_12000;
760  break;
761  case 9600:
762  state->their_parms.rate = AST_T38_RATE_9600;
763  break;
764  case 7200:
765  state->their_parms.rate = AST_T38_RATE_7200;
766  break;
767  case 4800:
768  state->their_parms.rate = AST_T38_RATE_4800;
769  break;
770  case 2400:
771  state->their_parms.rate = AST_T38_RATE_2400;
772  break;
773  }
774  } else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
775  state->their_parms.version = pj_strtoul(&attr->value);
776  } else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
777  if (!session->endpoint->media.t38.maxdatagram) {
778  ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
779  }
780  } else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
781  state->their_parms.fill_bit_removal = 1;
782  } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
783  state->their_parms.transcoding_mmr = 1;
784  } else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
785  state->their_parms.transcoding_jbig = 1;
786  } else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
787  if (!pj_stricmp2(&attr->value, "localTCF")) {
788  state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
789  } else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
790  state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
791  }
792  } else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
793  if (session->t38state == T38_LOCAL_REINVITE) {
794  if (session->endpoint->media.t38.error_correction == UDPTL_ERROR_CORRECTION_FEC) {
795  if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
797  } else if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
799  } else {
801  }
802  } else if (session->endpoint->media.t38.error_correction == UDPTL_ERROR_CORRECTION_REDUNDANCY) {
803  if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
805  } else {
807  }
808  } else {
810  }
811  } else {
812  if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
814  } else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
816  } else {
818  }
819  }
820  }
821 
822  }
823 }

Referenced by apply_negotiated_sdp_stream().

◆ t38_masq()

static void t38_masq ( void *  data,
int  framehook_id,
struct ast_channel old_chan,
struct ast_channel new_chan 
)
static

Definition at line 629 of file res_pjsip_t38.c.

631 {
632  if (ast_channel_tech(old_chan) == ast_channel_tech(new_chan)) {
633  return;
634  }
635 
636  /* This framehook is only applicable to PJSIP channels */
637  ast_framehook_detach(new_chan, framehook_id);
638 }
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)

References ast_channel_tech(), and ast_framehook_detach().

Referenced by t38_attach_framehook().

◆ t38_outgoing_invite_request()

static void t38_outgoing_invite_request ( struct ast_sip_session session,
struct pjsip_tx_data *  tdata 
)
static

Function called when an INVITE is sent.

Definition at line 708 of file res_pjsip_t38.c.

709 {
711 }

References session, and t38_attach_framehook().

◆ t38_parameters_task_data_alloc()

static struct t38_parameters_task_data* t38_parameters_task_data_alloc ( struct ast_sip_session session,
struct ast_frame frame 
)
static

Allocator for T.38 data.

Definition at line 108 of file res_pjsip_t38.c.

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 }
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ast_frdup(fr)
Copies a frame.
static void t38_parameters_task_data_destroy(void *obj)
Destructor for T.38 data.
Definition: res_pjsip_t38.c:96
struct ast_sip_session * session
Session itself.
Definition: res_pjsip_t38.c:90
struct ast_frame * frame
T.38 control frame.
Definition: res_pjsip_t38.c:92

References ao2_alloc, ao2_ref, ast_frdup, t38_parameters_task_data::frame, NULL, t38_parameters_task_data::session, session, and t38_parameters_task_data_destroy().

Referenced by t38_framehook().

◆ t38_parameters_task_data_destroy()

static void t38_parameters_task_data_destroy ( void *  obj)
static

Destructor for T.38 data.

Definition at line 96 of file res_pjsip_t38.c.

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 }
#define ast_frfree(fr)

References ao2_cleanup, ast_frfree, t38_parameters_task_data::frame, and t38_parameters_task_data::session.

Referenced by t38_parameters_task_data_alloc().

◆ t38_reinvite_response_cb()

static int t38_reinvite_response_cb ( struct ast_sip_session session,
pjsip_rx_data *  rdata 
)
static

Callback for when a response is received for a T.38 re-invite.

Definition at line 331 of file res_pjsip_t38.c.

332 {
333  struct pjsip_status_line status = rdata->msg_info.msg->line.status;
334  struct t38_state *state;
335  struct ast_sip_session_media *session_media = NULL;
336 
337  if (status.code / 100 <= 1) {
338  /* Ignore any non-final responses (1xx) */
339  return 0;
340  }
341 
342  if (session->t38state != T38_LOCAL_REINVITE) {
343  /* Do nothing. We have already processed a final response. */
344  ast_debug(3, "Received %d response to T.38 re-invite on '%s' but already had a final response (T.38 state:%d)\n",
345  status.code,
346  session->channel ? ast_channel_name(session->channel) : "unknown channel",
347  session->t38state);
348  return 0;
349  }
350 
352  if (!session->channel || !state) {
353  ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but state unavailable\n",
354  status.code,
355  session->channel ? ast_channel_name(session->channel) : "unknown channel");
356  return 0;
357  }
358 
359  if (status.code / 100 == 2) {
360  /* Accept any 2xx response as successfully negotiated */
361  int index;
362 
363  session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
364 
365  /*
366  * If there is a session_media object, but no udptl object available
367  * then it's assumed the stream was declined.
368  */
369  if (session_media && !session_media->udptl) {
370  session_media = NULL;
371  }
372 
373  if (!session_media) {
374  ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n",
375  status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel");
376  } else {
377  t38_change_state(session, session_media, state, T38_ENABLED);
378 
379  /* Stop all the streams in the stored away active state, they'll go back to being active once
380  * we reinvite back.
381  */
382  for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
383  struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
384 
385  if (session_media && session_media->handler && session_media->handler->stream_stop) {
386  session_media->handler->stream_stop(session_media);
387  }
388  }
389 
390  return 0;
391  }
392  } else {
393  session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
394  }
395 
396  /* If no session_media then response contained a declined stream, so disable */
398 
399  /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
401  state->media_state = NULL;
402  ast_sip_session_media_state_reset(session->pending_media_state);
403 
404  return 0;
405 }
jack_status_t status
Definition: app_jack.c:146
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
Reset a media state to a clean state.
struct ast_sip_session_sdp_handler * handler
SDP handler that setup the RTP.
void(* stream_stop)(struct ast_sip_session_media *session_media)
Stop a session_media created by this handler but do not destroy resources.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References ast_channel_name(), ast_debug, ast_log, AST_MEDIA_TYPE_IMAGE, ast_sip_session_media_state_free(), ast_sip_session_media_state_reset(), AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_session_media::handler, LOG_WARNING, NULL, session, state, status, ast_sip_session_sdp_handler::stream_stop, t38_change_state(), T38_DISABLED, T38_ENABLED, T38_LOCAL_REINVITE, T38_REJECTED, t38_state_get_or_alloc(), and ast_sip_session_media::udptl.

Referenced by t38_interpret_parameters().

◆ t38_reinvite_sdp_cb()

static int t38_reinvite_sdp_cb ( struct ast_sip_session session,
pjmedia_sdp_session *  sdp 
)
static

Callback for when T.38 reinvite SDP is created.

Definition at line 316 of file res_pjsip_t38.c.

317 {
318  struct t38_state *state;
319 
321  if (!state) {
322  return -1;
323  }
324 
325  state->media_state = ast_sip_session_media_state_clone(session->active_media_state);
326 
327  return 0;
328 }
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.

References ast_sip_session_media_state_clone(), session, state, and t38_state_get_or_alloc().

Referenced by t38_interpret_parameters().

◆ t38_state_destroy()

static void t38_state_destroy ( void *  obj)
static

Destructor for T.38 state information.

Definition at line 73 of file res_pjsip_t38.c.

74 {
75  struct t38_state *state = obj;
76 
78  ast_free(obj);
79 }

◆ t38_state_get_or_alloc()

static struct t38_state* t38_state_get_or_alloc ( struct ast_sip_session session)
static

Helper function which retrieves or allocates a T.38 state information datastore.

Definition at line 231 of file res_pjsip_t38.c.

232 {
234  struct t38_state *state;
235 
236  /* While the datastore refcount is decremented this is operating in the serializer so it will remain valid regardless */
237  if (datastore) {
238  return datastore->data;
239  }
240 
241  if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38"))
242  || !(datastore->data = ast_calloc(1, sizeof(struct t38_state)))
243  || ast_sip_session_add_datastore(session, datastore)) {
244  return NULL;
245  }
246 
247  state = datastore->data;
248 
249  /* This will get bumped up before scheduling */
250  pj_timer_entry_init(&state->timer, 0, session, t38_automatic_reject_timer_cb);
251 
252  return state;
253 }
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
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 const struct ast_datastore_info t38_datastore
Datastore for attaching T.38 state information.
Definition: res_pjsip_t38.c:82

References ao2_cleanup, ast_calloc, ast_sip_session_add_datastore(), ast_sip_session_alloc_datastore(), ast_sip_session_get_datastore(), NULL, RAII_VAR, session, state, t38_automatic_reject_timer_cb(), and t38_datastore.

Referenced by apply_negotiated_sdp_stream(), create_outgoing_sdp_stream(), negotiate_incoming_sdp_stream(), t38_interpret_parameters(), t38_reinvite_response_cb(), and t38_reinvite_sdp_cb().

◆ unload_module()

static int unload_module ( void  )
static

Unloads the SIP T.38 module from Asterisk.

Definition at line 1125 of file res_pjsip_t38.c.

1126 {
1129 
1130  return 0;
1131 }
void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
Unregister an SDP handler.
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

References ast_sip_session_unregister_sdp_handler(), ast_sip_session_unregister_supplement(), image_sdp_handler, and t38_supplement.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP T.38 UDPTL Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .requires = "res_pjsip,res_pjsip_session,udptl", }
static

Definition at line 1143 of file res_pjsip_t38.c.

◆ address

struct ast_sockaddr address
static

Address for UDPTL.

Definition at line 1 of file res_pjsip_t38.c.

Referenced by t38_initialize_session().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1171 of file res_pjsip_t38.c.

◆ image_sdp_handler

struct ast_sip_session_sdp_handler image_sdp_handler
static

SDP handler for 'image' media stream.

Definition at line 1105 of file res_pjsip_t38.c.

Referenced by unload_module().

◆ t38_datastore

const struct ast_datastore_info t38_datastore
static
Initial value:
= {
.type = "t38",
.destroy = t38_state_destroy,
}
static void t38_state_destroy(void *obj)
Destructor for T.38 state information.
Definition: res_pjsip_t38.c:73

Datastore for attaching T.38 state information.

Definition at line 73 of file res_pjsip_t38.c.

Referenced by t38_state_get_or_alloc().

◆ t38_framehook_datastore

const struct ast_datastore_info t38_framehook_datastore
static
Initial value:
= {
.type = "T38 framehook",
}

Definition at line 640 of file res_pjsip_t38.c.

Referenced by t38_attach_framehook().

◆ t38_supplement

struct ast_sip_session_supplement t38_supplement
static

Supplement for adding framehook to session channel.

Definition at line 714 of file res_pjsip_t38.c.

Referenced by unload_module().