Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions | Variables
res_pjsip_transport_websocket.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include "asterisk/module.h"
#include "asterisk/http_websocket.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
#include "asterisk/taskprocessor.h"
Include dependency graph for res_pjsip_transport_websocket.c:

Go to the source code of this file.

Data Structures

struct  transport_create_data
 
struct  transport_read_data
 
struct  ws_transport
 Wrapper for pjsip_transport, for storing the WebSocket session. More...
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static struct ast_taskprocessorcreate_websocket_serializer (void)
 
static int get_write_timeout (void)
 
static int load_module (void)
 
static int transport_create (void *data)
 Create a pjsip transport. More...
 
static void transport_dtor (void *arg)
 
static int transport_read (void *data)
 Pass WebSocket data into pjsip transport manager. More...
 
static int transport_shutdown (void *data)
 
static int unload_module (void)
 
static void websocket_cb (struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
 WebSocket connection handler. More...
 
static pj_bool_t websocket_on_rx_msg (pjsip_rx_data *rdata)
 Store the transport a message came in on, so it can be used for outbound messages to that contact. More...
 
static void websocket_outgoing_invite_request (struct ast_sip_session *session, struct pjsip_tx_data *tdata)
 Function called when an INVITE goes out. More...
 
static pj_status_t ws_destroy (pjsip_transport *transport)
 Destroy the pjsip transport. More...
 
static pj_status_t ws_send_msg (pjsip_transport *transport, pjsip_tx_data *tdata, const pj_sockaddr_t *rem_addr, int addr_len, void *token, pjsip_transport_callback callback)
 Send a message over the WebSocket connection. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP WebSocket Transport 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_APP_DEPEND, .requires = "res_pjsip,res_http_websocket", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int transport_type_wss
 WebSocket transport module. More...
 
static int transport_type_wss_ipv6
 
static pjsip_module websocket_module
 
static struct ast_sip_session_supplement websocket_supplement
 Supplement for adding Websocket functionality to dialog. More...
 
static int ws_obj_name_serial
 

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 535 of file res_pjsip_transport_websocket.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 535 of file res_pjsip_transport_websocket.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 535 of file res_pjsip_transport_websocket.c.

◆ create_websocket_serializer()

static struct ast_taskprocessor* create_websocket_serializer ( void  )
static

Definition at line 349 of file res_pjsip_transport_websocket.c.

References ast_sip_create_serializer(), ast_taskprocessor_build_name(), and AST_TASKPROCESSOR_MAX_NAME.

Referenced by websocket_cb().

350 {
351  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
352 
353  /* Create name with seq number appended. */
354  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/websocket");
355 
356  return ast_sip_create_serializer(tps_name);
357 }
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:60
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:5133

◆ get_write_timeout()

static int get_write_timeout ( void  )
static

Definition at line 311 of file res_pjsip_transport_websocket.c.

References ao2_cleanup, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_debug, AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT, ast_sip_get_sorcery(), ast_sip_get_transport_states(), ast_sorcery_retrieve_by_id(), AST_TRANSPORT_WS, AST_TRANSPORT_WSS, ast_sip_transport_state::id, MAX, ws_transport::transport, transport_states, ast_sip_transport_state::type, ast_sip_transport::type, and ast_sip_transport::write_timeout.

Referenced by websocket_cb().

312 {
313  int write_timeout = -1;
315 
316  transport_states = ast_sip_get_transport_states();
317 
318  if (transport_states) {
319  struct ao2_iterator it_transport_states = ao2_iterator_init(transport_states, 0);
320  struct ast_sip_transport_state *transport_state;
321 
322  for (; (transport_state = ao2_iterator_next(&it_transport_states)); ao2_cleanup(transport_state)) {
323  struct ast_sip_transport *transport;
324 
325  if (transport_state->type != AST_TRANSPORT_WS && transport_state->type != AST_TRANSPORT_WSS) {
326  continue;
327  }
328  transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id);
329  if (!transport) {
330  continue;
331  }
332  ast_debug(5, "Found %s transport with write timeout: %d\n",
333  transport->type == AST_TRANSPORT_WS ? "WS" : "WSS",
334  transport->write_timeout);
335  write_timeout = MAX(write_timeout, transport->write_timeout);
336  }
337  ao2_iterator_destroy(&it_transport_states);
338  ao2_cleanup(transport_states);
339  }
340 
341  if (write_timeout < 0) {
342  write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
343  }
344 
345  ast_debug(1, "Write timeout for WS/WSS transports: %d\n", write_timeout);
346  return write_timeout;
347 }
enum ast_transport type
Definition: res_pjsip.h:101
static struct ao2_container * transport_states
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
enum ast_transport type
Definition: res_pjsip.h:193
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
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define MAX(a, b)
Definition: utils.h:228
Structure for SIP transport information.
Definition: res_pjsip.h:87
struct ao2_container * ast_sip_get_transport_states(void)
Retrieves all transport states.
#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT
Default websocket write timeout, in ms.
Transport to bind to.
Definition: res_pjsip.h:171
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ load_module()

static int load_module ( void  )
static

Definition at line 490 of file res_pjsip_transport_websocket.c.

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_sip_register_service(), ast_sip_session_register_supplement, ast_sip_session_unregister_supplement(), ast_sip_unregister_service(), ast_websocket_add_protocol(), transport_type_wss, transport_type_wss_ipv6, websocket_cb(), and websocket_module.

Referenced by unload_module().

491 {
492  /*
493  * We only need one transport type name (ws) defined. Firefox
494  * and Chrome do not support anything other than secure websockets
495  * anymore.
496  *
497  * Also we really cannot have two transports with the same name
498  * and address family because it would be ambiguous. Outgoing
499  * requests may try to find the transport by name and pjproject
500  * only finds the first one registered.
501  */
502  pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "ws", 5060, &transport_type_wss);
503  pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_IPV6, "ws", 5060, &transport_type_wss_ipv6);
504 
505  if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) {
507  }
508 
510 
515  }
516 
518 }
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
static pjsip_module websocket_module
int AST_OPTIONAL_API_NAME() ast_websocket_add_protocol(const char *name, ast_websocket_callback callback)
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
static struct ast_sip_session_supplement websocket_supplement
Supplement for adding Websocket functionality to dialog.
static int transport_type_wss
WebSocket transport module.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int transport_type_wss_ipv6
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
static void websocket_cb(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
WebSocket connection handler.
#define ast_sip_session_register_supplement(supplement)

◆ transport_create()

static int transport_create ( void *  data)
static

Create a pjsip transport.

Definition at line 149 of file res_pjsip_transport_websocket.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_cleanup, ao2_ref, ao2_t_alloc_options, ast_atomic_fetchadd_int(), ast_debug, ast_log, ast_sip_get_pjsip_endpoint(), ast_sockaddr_port, ast_sockaddr_stringify(), ast_sockaddr_stringify_addr(), ast_websocket_is_secure(), ast_websocket_local_address(), ast_websocket_ref(), ast_websocket_remote_address(), buf, LOG_ERROR, NULL, pool, status, ws_transport::transport, transport_create_data::transport, transport_dtor(), transport_type_wss, transport_type_wss_ipv6, ws_destroy(), ws_obj_name_serial, ws_send_msg(), ws_transport::ws_session, and transport_create_data::ws_session.

Referenced by websocket_cb().

150 {
151  struct transport_create_data *create_data = data;
152  struct ws_transport *newtransport = NULL;
153  pjsip_tp_state_callback state_cb;
154 
155  pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
156  struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt);
157 
158  char *ws_addr_str;
159  pj_pool_t *pool;
160  pj_str_t buf;
161  pj_status_t status;
162 
163  newtransport = ao2_t_alloc_options(sizeof(*newtransport), transport_dtor,
164  AO2_ALLOC_OPT_LOCK_NOLOCK, "pjsip websocket transport");
165  if (!newtransport) {
166  ast_log(LOG_ERROR, "Failed to allocate WebSocket transport.\n");
167  goto on_error;
168  }
169 
170  /* Give websocket transport a unique name for its lifetime */
171  snprintf(newtransport->transport.obj_name, PJ_MAX_OBJ_NAME, "ws%p-%d",
173 
174  newtransport->transport.endpt = endpt;
175 
176  if (!(pool = pjsip_endpt_create_pool(endpt, "ws", 512, 512))) {
177  ast_log(LOG_ERROR, "Failed to allocate WebSocket endpoint pool.\n");
178  goto on_error;
179  }
180 
181  newtransport->transport.pool = pool;
182  newtransport->ws_session = create_data->ws_session;
183 
184  /* Keep the session until transport dies */
185  ast_websocket_ref(newtransport->ws_session);
186 
187  status = pj_atomic_create(pool, 0, &newtransport->transport.ref_cnt);
188  if (status != PJ_SUCCESS) {
189  goto on_error;
190  }
191 
192  status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &newtransport->transport.lock);
193  if (status != PJ_SUCCESS) {
194  goto on_error;
195  }
196 
197  /*
198  * The type_name here is mostly used by log messages eihter in
199  * pjproject or Asterisk. Other places are reconstituting subscriptions
200  * after a restart (which could never work for a websocket connection anyway),
201  * received MESSAGE requests to set PJSIP_TRANSPORT, and most importantly
202  * by pjproject when generating the Via header.
203  */
204  newtransport->transport.type_name = ast_websocket_is_secure(newtransport->ws_session)
205  ? "WSS" : "WS";
206 
207  ws_addr_str = ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session));
208  ast_debug(4, "Creating websocket transport for %s:%s\n",
209  newtransport->transport.type_name, ws_addr_str);
210 
211  newtransport->transport.info = (char *) pj_pool_alloc(newtransport->transport.pool,
212  strlen(newtransport->transport.type_name) + strlen(ws_addr_str) + sizeof(" to "));
213  sprintf(newtransport->transport.info, "%s to %s", newtransport->transport.type_name, ws_addr_str);
214 
215  pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr);
216  if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) {
217  newtransport->transport.key.type = transport_type_wss_ipv6;
218  } else {
219  newtransport->transport.key.type = transport_type_wss;
220  }
221 
222  newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr);
223 
224  ws_addr_str = ast_sockaddr_stringify(ast_websocket_local_address(newtransport->ws_session));
225  pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.local_addr);
226  pj_strdup2(pool, &newtransport->transport.local_name.host, ast_sockaddr_stringify_addr(ast_websocket_local_address(newtransport->ws_session)));
227  newtransport->transport.local_name.port = ast_sockaddr_port(ast_websocket_local_address(newtransport->ws_session));
228 
229  newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type);
230  newtransport->transport.dir = PJSIP_TP_DIR_INCOMING;
231  newtransport->transport.tpmgr = tpmgr;
232  newtransport->transport.send_msg = &ws_send_msg;
233  newtransport->transport.destroy = &ws_destroy;
234 
235  status = pjsip_transport_register(newtransport->transport.tpmgr,
236  (pjsip_transport *)newtransport);
237  if (status != PJ_SUCCESS) {
238  goto on_error;
239  }
240 
241  /* Add a reference for pjsip transport manager */
242  ao2_ref(newtransport, +1);
243 
244  newtransport->rdata.tp_info.transport = &newtransport->transport;
245  newtransport->rdata.tp_info.pool = pjsip_endpt_create_pool(endpt, "rtd%p",
246  PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC);
247  if (!newtransport->rdata.tp_info.pool) {
248  ast_log(LOG_ERROR, "Failed to allocate WebSocket rdata.\n");
249  pjsip_transport_destroy((pjsip_transport *)newtransport);
250  goto on_error;
251  }
252 
253  create_data->transport = newtransport;
254 
255  /* Notify application of transport state */
256  state_cb = pjsip_tpmgr_get_state_cb(newtransport->transport.tpmgr);
257  if (state_cb) {
258  pjsip_transport_state_info state_info;
259 
260  memset(&state_info, 0, sizeof(state_info));
261  state_cb(&newtransport->transport, PJSIP_TP_STATE_CONNECTED, &state_info);
262  }
263 
264  return 0;
265 
266 on_error:
267  ao2_cleanup(newtransport);
268  return -1;
269 }
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:290
int AST_OPTIONAL_API_NAME() ast_websocket_is_secure(struct ast_websocket *session)
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
struct ast_sockaddr *AST_OPTIONAL_API_NAME() ast_websocket_local_address(struct ast_websocket *session)
static pj_pool_t * pool
Global memory pool for configuration and timers.
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:404
#define NULL
Definition: resample.c:96
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:521
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
void AST_OPTIONAL_API_NAME() ast_websocket_ref(struct ast_websocket *session)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_sockaddr *AST_OPTIONAL_API_NAME() ast_websocket_remote_address(struct ast_websocket *session)
static pj_status_t ws_send_msg(pjsip_transport *transport, pjsip_tx_data *tdata, const pj_sockaddr_t *rem_addr, int addr_len, void *token, pjsip_transport_callback callback)
Send a message over the WebSocket connection.
#define LOG_ERROR
Definition: logger.h:285
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
static int transport_type_wss
WebSocket transport module.
static pj_status_t ws_destroy(pjsip_transport *transport)
Destroy the pjsip transport.
static int ws_obj_name_serial
struct ast_websocket * ws_session
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static void transport_dtor(void *arg)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static int transport_type_wss_ipv6
jack_status_t status
Definition: app_jack.c:146
Wrapper for pjsip_transport, for storing the WebSocket session.

◆ transport_dtor()

static void transport_dtor ( void *  arg)
static

Definition at line 100 of file res_pjsip_transport_websocket.c.

References ast_websocket_unref(), ws_transport::rdata, ws_transport::transport, and ws_transport::ws_session.

Referenced by transport_create().

101 {
102  struct ws_transport *wstransport = arg;
103 
104  if (wstransport->ws_session) {
105  ast_websocket_unref(wstransport->ws_session);
106  }
107 
108  if (wstransport->transport.ref_cnt) {
109  pj_atomic_destroy(wstransport->transport.ref_cnt);
110  }
111 
112  if (wstransport->transport.lock) {
113  pj_lock_destroy(wstransport->transport.lock);
114  }
115 
116  if (wstransport->transport.endpt && wstransport->transport.pool) {
117  pjsip_endpt_release_pool(wstransport->transport.endpt, wstransport->transport.pool);
118  }
119 
120  if (wstransport->rdata.tp_info.pool) {
121  pjsip_endpt_release_pool(wstransport->transport.endpt, wstransport->rdata.tp_info.pool);
122  }
123 }
struct ast_websocket * ws_session
void AST_OPTIONAL_API_NAME() ast_websocket_unref(struct ast_websocket *session)
Wrapper for pjsip_transport, for storing the WebSocket session.

◆ transport_read()

static int transport_read ( void *  data)
static

Pass WebSocket data into pjsip transport manager.

Definition at line 280 of file res_pjsip_transport_websocket.c.

References ast_sockaddr_port, ast_sockaddr_stringify(), ast_sockaddr_stringify_addr(), ast_websocket_remote_address(), buf, transport_read_data::payload, transport_read_data::payload_len, ws_transport::rdata, session, transport_read_data::transport, and ws_transport::ws_session.

Referenced by websocket_cb().

281 {
282  struct transport_read_data *read_data = data;
283  struct ws_transport *newtransport = read_data->transport;
284  struct ast_websocket *session = newtransport->ws_session;
285 
286  pjsip_rx_data *rdata = &newtransport->rdata;
287  int recvd;
288  pj_str_t buf;
289  int pjsip_pkt_len;
290 
291  pj_gettimeofday(&rdata->pkt_info.timestamp);
292 
293  pjsip_pkt_len = PJSIP_MAX_PKT_LEN < read_data->payload_len ? PJSIP_MAX_PKT_LEN : read_data->payload_len;
294  pj_memcpy(rdata->pkt_info.packet, read_data->payload, pjsip_pkt_len);
295  rdata->pkt_info.len = pjsip_pkt_len;
296  rdata->pkt_info.zero = 0;
297 
298  pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(session))), &rdata->pkt_info.src_addr);
299  rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr);
300 
301  pj_ansi_strcpy(rdata->pkt_info.src_name, ast_sockaddr_stringify_addr(ast_websocket_remote_address(session)));
302  rdata->pkt_info.src_port = ast_sockaddr_port(ast_websocket_remote_address(session));
303 
304  recvd = pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr, rdata);
305 
306  pj_pool_reset(rdata->tp_info.pool);
307 
308  return (read_data->payload_len == recvd) ? 0 : -1;
309 }
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:290
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:521
static struct ast_mansession session
struct ast_sockaddr *AST_OPTIONAL_API_NAME() ast_websocket_remote_address(struct ast_websocket *session)
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
Structure definition for session.
struct ast_websocket * ws_session
Wrapper for pjsip_transport, for storing the WebSocket session.

◆ transport_shutdown()

static int transport_shutdown ( void *  data)
static

Definition at line 125 of file res_pjsip_transport_websocket.c.

References ao2_ref, and ws_transport::transport.

Referenced by websocket_cb().

126 {
127  struct ws_transport *wstransport = data;
128 
129  if (!wstransport->transport.is_shutdown && !wstransport->transport.is_destroying) {
130  pjsip_transport_shutdown(&wstransport->transport);
131  }
132 
133  /* Note that the destructor calls PJSIP functions,
134  * therefore it must be called in a PJSIP thread.
135  */
136  ao2_ref(wstransport, -1);
137 
138  return 0;
139 }
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Wrapper for pjsip_transport, for storing the WebSocket session.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 520 of file res_pjsip_transport_websocket.c.

References AST_MODFLAG_LOAD_ORDER, AST_MODPRI_APP_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_sip_session_unregister_supplement(), ast_sip_unregister_service(), ast_websocket_remove_protocol(), ASTERISK_GPL_KEY, load_module(), websocket_cb(), and websocket_module.

521 {
525 
526  return 0;
527 }
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
static pjsip_module websocket_module
int AST_OPTIONAL_API_NAME() ast_websocket_remove_protocol(const char *name, ast_websocket_callback callback)
static struct ast_sip_session_supplement websocket_supplement
Supplement for adding Websocket functionality to dialog.
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
static void websocket_cb(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers)
WebSocket connection handler.

◆ websocket_cb()

static void websocket_cb ( struct ast_websocket session,
struct ast_variable parameters,
struct ast_variable headers 
)
static

WebSocket connection handler.

Definition at line 360 of file res_pjsip_transport_websocket.c.

References ast_log, ast_sip_push_task_wait_serializer(), ast_taskprocessor_unreference(), AST_WEBSOCKET_OPCODE_BINARY, AST_WEBSOCKET_OPCODE_CLOSE, AST_WEBSOCKET_OPCODE_TEXT, ast_websocket_read(), ast_websocket_set_nonblock(), ast_websocket_set_timeout(), ast_websocket_unref(), ast_websocket_wait_for_input(), create_websocket_serializer(), get_write_timeout(), LOG_ERROR, transport_read_data::payload, transport_read_data::payload_len, session, ws_transport::transport, transport_create_data::transport, transport_read_data::transport, transport_create(), transport_read(), transport_shutdown(), and transport_create_data::ws_session.

Referenced by load_module(), and unload_module().

361 {
363  struct transport_create_data create_data;
364  struct ws_transport *transport;
365  struct transport_read_data read_data;
366 
367  if (ast_websocket_set_nonblock(session)) {
368  ast_websocket_unref(session);
369  return;
370  }
371 
373  ast_websocket_unref(session);
374  return;
375  }
376 
377  serializer = create_websocket_serializer();
378  if (!serializer) {
379  ast_websocket_unref(session);
380  return;
381  }
382 
383  create_data.ws_session = session;
384 
385  if (ast_sip_push_task_wait_serializer(serializer, transport_create, &create_data)) {
386  ast_log(LOG_ERROR, "Could not create WebSocket transport.\n");
387  ast_taskprocessor_unreference(serializer);
388  ast_websocket_unref(session);
389  return;
390  }
391 
392  transport = create_data.transport;
393  read_data.transport = transport;
394 
395  while (ast_websocket_wait_for_input(session, -1) > 0) {
396  enum ast_websocket_opcode opcode;
397  int fragmented;
398 
399  if (ast_websocket_read(session, &read_data.payload, &read_data.payload_len, &opcode, &fragmented)) {
400  break;
401  }
402 
403  if (opcode == AST_WEBSOCKET_OPCODE_TEXT || opcode == AST_WEBSOCKET_OPCODE_BINARY) {
404  if (read_data.payload_len) {
405  ast_sip_push_task_wait_serializer(serializer, transport_read, &read_data);
406  }
407  } else if (opcode == AST_WEBSOCKET_OPCODE_CLOSE) {
408  break;
409  }
410  }
411 
413 
414  ast_taskprocessor_unreference(serializer);
415  ast_websocket_unref(session);
416 }
int AST_OPTIONAL_API_NAME() ast_websocket_read(struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented)
static int transport_create(void *data)
Create a pjsip transport.
static int transport_shutdown(void *data)
#define ast_log
Definition: astobj2.c:42
static struct ast_mansession session
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:5218
static int get_write_timeout(void)
#define LOG_ERROR
Definition: logger.h:285
int AST_OPTIONAL_API_NAME() ast_websocket_set_timeout(struct ast_websocket *session, int timeout)
static int transport_read(void *data)
Pass WebSocket data into pjsip transport manager.
int AST_OPTIONAL_API_NAME() ast_websocket_wait_for_input(struct ast_websocket *session, int timeout)
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
int AST_OPTIONAL_API_NAME() ast_websocket_set_nonblock(struct ast_websocket *session)
void AST_OPTIONAL_API_NAME() ast_websocket_unref(struct ast_websocket *session)
ast_websocket_opcode
WebSocket operation codes.
Wrapper for pjsip_transport, for storing the WebSocket session.
static struct ast_taskprocessor * create_websocket_serializer(void)

◆ websocket_on_rx_msg()

static pj_bool_t websocket_on_rx_msg ( pjsip_rx_data *  rdata)
static

Store the transport a message came in on, so it can be used for outbound messages to that contact.

Definition at line 421 of file res_pjsip_transport_websocket.c.

References ast_log, AST_SOCKADDR_BUFLEN, DEBUG_ATLEAST, LOG_DEBUG, NULL, transport_type_wss, transport_type_wss_ipv6, and type.

422 {
423  static const pj_str_t STR_WS = { "ws", 2 };
424  pjsip_contact_hdr *contact;
425 
426  long type = rdata->tp_info.transport->key.type;
427 
428  if (type != (long) transport_type_wss && type != (long) transport_type_wss_ipv6) {
429  return PJ_FALSE;
430  }
431 
432  contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
433  if (contact
434  && !contact->star
435  && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
436  pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
437  const pj_str_t *txp_str = &STR_WS;
438 
439  if (DEBUG_ATLEAST(4)) {
440  char src_addr_buffer[AST_SOCKADDR_BUFLEN];
441  const char *ipv6_s = "", *ipv6_e = "";
442 
443  if (pj_strchr(&uri->host, ':')) {
444  ipv6_s = "[";
445  ipv6_e = "]";
446  }
447 
448  ast_log(LOG_DEBUG, "%s re-writing Contact URI from %s%.*s%s:%d%s%.*s to %s;transport=%s\n",
449  pjsip_rx_data_get_info(rdata),
450  ipv6_s, (int) pj_strlen(&uri->host), pj_strbuf(&uri->host), ipv6_e, uri->port,
451  pj_strlen(&uri->transport_param) ? ";transport=" : "",
452  (int) pj_strlen(&uri->transport_param), pj_strbuf(&uri->transport_param),
453  pj_sockaddr_print(&rdata->pkt_info.src_addr, src_addr_buffer, sizeof(src_addr_buffer), 3),
454  pj_strbuf(txp_str));
455  }
456 
457  pj_strdup2(rdata->tp_info.pool, &uri->host, rdata->pkt_info.src_name);
458  uri->port = rdata->pkt_info.src_port;
459  pj_strdup(rdata->tp_info.pool, &uri->transport_param, txp_str);
460  }
461 
462  rdata->msg_info.via->rport_param = 0;
463 
464  return PJ_FALSE;
465 }
static const char type[]
Definition: chan_ooh323.c:109
#define AST_SOCKADDR_BUFLEN
Definition: netsock2.h:46
#define NULL
Definition: resample.c:96
#define LOG_DEBUG
Definition: logger.h:241
#define ast_log
Definition: astobj2.c:42
static int transport_type_wss
WebSocket transport module.
static int transport_type_wss_ipv6
#define DEBUG_ATLEAST(level)
Definition: logger.h:441

◆ websocket_outgoing_invite_request()

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

Function called when an INVITE goes out.

Definition at line 476 of file res_pjsip_transport_websocket.c.

References ast_sip_session::inv_session, NULL, and websocket_module.

477 {
478  if (session->inv_session->state == PJSIP_INV_STATE_NULL) {
479  pjsip_dlg_add_usage(session->inv_session->dlg, &websocket_module, NULL);
480  }
481 }
#define NULL
Definition: resample.c:96
struct pjsip_inv_session * inv_session
static pjsip_module websocket_module

◆ ws_destroy()

static pj_status_t ws_destroy ( pjsip_transport *  transport)
static

Destroy the pjsip transport.

Called by pjsip transport manager.

Definition at line 85 of file res_pjsip_transport_websocket.c.

References ao2_ref, ast_websocket_close(), ast_websocket_fd(), and ws_transport::ws_session.

Referenced by transport_create().

86 {
87  struct ws_transport *wstransport = (struct ws_transport *)transport;
88  int fd = ast_websocket_fd(wstransport->ws_session);
89 
90  if (fd > 0) {
91  ast_websocket_close(wstransport->ws_session, 1000);
92  shutdown(fd, SHUT_RDWR);
93  }
94 
95  ao2_ref(wstransport, -1);
96 
97  return PJ_SUCCESS;
98 }
int AST_OPTIONAL_API_NAME() ast_websocket_close(struct ast_websocket *session, uint16_t reason)
Close function for websocket session.
int AST_OPTIONAL_API_NAME() ast_websocket_fd(struct ast_websocket *session)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_websocket * ws_session
Wrapper for pjsip_transport, for storing the WebSocket session.

◆ ws_send_msg()

static pj_status_t ws_send_msg ( pjsip_transport *  transport,
pjsip_tx_data *  tdata,
const pj_sockaddr_t *  rem_addr,
int  addr_len,
void *  token,
pjsip_transport_callback  callback 
)
static

Send a message over the WebSocket connection.

Called by pjsip transport manager.

Definition at line 63 of file res_pjsip_transport_websocket.c.

References AST_WEBSOCKET_OPCODE_TEXT, ast_websocket_write(), len(), and ws_transport::ws_session.

Referenced by transport_create().

69 {
70  struct ws_transport *wstransport = (struct ws_transport *)transport;
71  uint64_t len = tdata->buf.cur - tdata->buf.start;
72 
73  if (ast_websocket_write(wstransport->ws_session, AST_WEBSOCKET_OPCODE_TEXT, tdata->buf.start, len)) {
74  return PJ_EUNKNOWN;
75  }
76 
77  return PJ_SUCCESS;
78 }
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int AST_OPTIONAL_API_NAME() ast_websocket_write(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size)
Write function for websocket traffic.
struct ast_websocket * ws_session
Wrapper for pjsip_transport, for storing the WebSocket session.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP WebSocket Transport 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_APP_DEPEND, .requires = "res_pjsip,res_http_websocket", }
static

Definition at line 535 of file res_pjsip_transport_websocket.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 535 of file res_pjsip_transport_websocket.c.

◆ transport_type_wss

int transport_type_wss
static

WebSocket transport module.

Definition at line 41 of file res_pjsip_transport_websocket.c.

Referenced by load_module(), transport_create(), and websocket_on_rx_msg().

◆ transport_type_wss_ipv6

int transport_type_wss_ipv6
static

◆ websocket_module

pjsip_module websocket_module
static

◆ websocket_supplement

struct ast_sip_session_supplement websocket_supplement
static
Initial value:
= {
.method = "INVITE",
.outgoing_request = websocket_outgoing_invite_request,
}
static void websocket_outgoing_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
Function called when an INVITE goes out.

Supplement for adding Websocket functionality to dialog.

Definition at line 484 of file res_pjsip_transport_websocket.c.

◆ ws_obj_name_serial

int ws_obj_name_serial
static

Used to ensure uniqueness among WS transport names

Definition at line 47 of file res_pjsip_transport_websocket.c.

Referenced by transport_create().