2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Asterisk  - -  An  open  source  telephony  toolkit . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Copyright  ( C )  2012 ,  Digium ,  Inc . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Joshua  Colp  < jcolp @ digium . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  See  http : //www.asterisk.org for more information about
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  Asterisk  project .  Please  do  not  directly  contact 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  any  of  the  maintainers  of  this  project  for  assistance ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  project  provides  a  web  site ,  mailing  lists  and  IRC 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  channels  for  your  use . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  This  program  is  free  software ,  distributed  under  the  terms  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  GNU  General  Public  License  Version  2.  See  the  LICENSE  file 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  at  the  top  of  the  source  tree . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \file
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  WebSocket  support  for  the  Asterisk  internal  HTTP  server 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ author  Joshua  Colp  < jcolp @ digium . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*** MODULEINFO
  
						 
					
						
							
								
									
										
										
										
											2016-04-05 12:21:32 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									< support_level > core < / support_level > 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 * * */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												git migration: Refactor the ASTERISK_FILE_VERSION macro
Git does not support the ability to replace a token with a version
string during check-in. While it does have support for replacing a
token on clone, this is somewhat sub-optimal: the token is replaced
with the object hash, which is not particularly easy for human
consumption. What's more, in practice, the source file version was often
not terribly useful. Generally, when triaging bugs, the overall version
of Asterisk is far more useful than an individual SVN version of a file. As a
result, this patch removes Asterisk's support for showing source file
versions.
Specifically, it does the following:
* Rename ASTERISK_FILE_VERSION macro to ASTERISK_REGISTER_FILE, and
  remove passing the version in with the macro. Other facilities
  than 'core show file version' make use of the file names, such as
  setting a debug level only on a specific file. As such, the act of
  registering source files with the Asterisk core still has use. The
  macro rename now reflects the new macro purpose.
* main/asterisk:
  - Refactor the file_version structure to reflect that it no longer
    tracks a version field.
  - Remove the "core show file version" CLI command. Without the file
    version, it is no longer useful.
  - Remove the ast_file_version_find function. The file version is no
    longer tracked.
  - Rename ast_register_file_version/ast_unregister_file_version to
    ast_register_file/ast_unregister_file, respectively.
* main/manager: Remove value from the Version key of the ModuleCheck
  Action. The actual key itself has not been removed, as doing so would
  absolutely constitute a backwards incompatible change. However, since
  the file version is no longer tracked, there is no need to attempt to
  include it in the Version key.
* UPGRADE: Add notes for:
  - Modification to the ModuleCheck AMI Action
  - Removal of the "core show file version" CLI command
Change-Id: I6cf0ff280e1668bf4957dc21f32a5ff43444a40e
											 
										 
										
											2015-04-11 21:38:22 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								ASTERISK_REGISTER_FILE ( )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/module.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/http.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/astobj2.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/strings.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/file.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/unaligned.h" 
  
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/uri.h" 
  
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/uuid.h" 
  
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define AST_API_MODULE 
  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/http_websocket.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief GUID used to compute the accept key, defined in the specifications */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*! \brief Length of a websocket's client key */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define CLIENT_KEY_SIZE 16 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*! \brief Number of buckets for registered protocols */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define MAX_PROTOCOL_BUCKETS 7 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Size of the pre-determined buffer for WebSocket frames */  
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# define MAXIMUM_FRAME_SIZE 16384 
  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Default reconstruction size for multi-frame payload reconstruction. If exceeded the next frame will start a
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *          payload . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define DEFAULT_RECONSTRUCTION_CEILING 16384 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Maximum reconstruction size for multi-frame payload reconstruction. */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define MAXIMUM_RECONSTRUCTION_CEILING 16384 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*! \brief Maximum size of a websocket frame header
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  1  byte  flags  and  opcode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  1  byte  mask  flag  +  payload  len 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  8  bytes  max  extended  length 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  4  bytes  optional  masking  key 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  . . .  payload  follows  . . . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define MAX_WS_HDR_SZ 14 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define MIN_WS_HDR_SZ 2 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*! \brief Structure definition for session */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  ast_websocket  {  
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									FILE  * f ;                            /*!< Pointer to the file instance used for writing and reading */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  fd ;                             /*!< File descriptor for the session, only used for polling */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_sockaddr  address ;        /*!< Address of the remote client */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_websocket_opcode  opcode ;   /*!< Cached opcode for multi-frame messages */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size_t  payload_len ;                 /*!< Length of the payload */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * payload ;                      /*!< Pointer to the payload */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size_t  reconstruct ;                 /*!< Number of bytes before a reconstructed payload will be returned and a new one started */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  timeout ;                        /*!< The timeout for operations on the socket */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  secure : 1 ;              /*!< Bit to indicate that the transport is secure */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  closing : 1 ;             /*!< Bit to indicate that the session is in the process of being closed */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  close_sent : 1 ;          /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  websocket_client  * client ;    /*!< Client object when connected as a client websocket */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  session_id [ AST_UUID_STR_LEN ] ;  /*!< The identifier for the websocket session */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Hashing function for protocols */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  protocol_hash_fn ( const  void  * obj ,  const  int  flags )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									const  struct  ast_websocket_protocol  * protocol  =  obj ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									const  char  * name  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ast_str_case_hash ( flags  &  OBJ_KEY  ?  name  :  protocol - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Comparison function for protocols */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  protocol_cmp_fn ( void  * obj ,  void  * arg ,  int  flags )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									const  struct  ast_websocket_protocol  * protocol1  =  obj ,  * protocol2  =  arg ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									const  char  * protocol  =  arg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ! strcasecmp ( protocol1 - > name ,  flags  &  OBJ_KEY  ?  protocol  :  protocol2 - > name )  ?  CMP_MATCH  |  CMP_STOP  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Destructor function for protocols */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  protocol_destroy_fn ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_websocket_protocol  * protocol  =  obj ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_free ( protocol - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*! \brief Structure for a WebSocket server */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  ast_websocket_server  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ao2_container  * protocols ;  /*!< Container for registered protocols */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  websocket_server_internal_dtor ( void  * obj )  
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket_server  * server  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( server - > protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									server - > protocols  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  websocket_server_dtor ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									websocket_server_internal_dtor ( obj ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_module_unref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  ast_websocket_server  * websocket_server_create_impl ( void  ( * dtor ) ( void  * ) )  
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									RAII_VAR ( struct  ast_websocket_server  * ,  server ,  NULL ,  ao2_cleanup ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									server  =  ao2_alloc ( sizeof ( * server ) ,  dtor ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! server )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									server - > protocols  =  ao2_container_alloc ( MAX_PROTOCOL_BUCKETS ,  protocol_hash_fn ,  protocol_cmp_fn ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! server - > protocols )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( server ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  server ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  struct  ast_websocket_server  * websocket_server_internal_create ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  websocket_server_create_impl ( websocket_server_internal_dtor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  ast_websocket_server  * AST_OPTIONAL_API_NAME ( ast_websocket_server_create ) ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_module_ref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  websocket_server_create_impl ( websocket_server_dtor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*! \brief Destructor function for sessions */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  session_destroy_fn ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket  * session  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( session - > f )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_websocket_close ( session ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-13 07:26:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( session - > f )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fclose ( session - > f ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_verb ( 2 ,  " WebSocket connection %s '%s' closed \n " ,  session - > client  ?  " to "  :  " from " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_sockaddr_stringify ( & session - > address ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_cleanup ( session - > client ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_free ( session - > payload ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								struct  ast_websocket_protocol  * AST_OPTIONAL_API_NAME ( ast_websocket_sub_protocol_alloc ) ( const  char  * name )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket_protocol  * protocol ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									protocol  =  ao2_alloc ( sizeof ( * protocol ) ,  protocol_destroy_fn ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! protocol )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									protocol - > name  =  ast_strdup ( name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! protocol - > name )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( protocol ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									protocol - > version  =  AST_WEBSOCKET_PROTOCOL_VERSION ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  protocol ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_server_add_protocol ) ( struct  ast_websocket_server  * server ,  const  char  * name ,  ast_websocket_callback  callback )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_websocket_protocol  * protocol ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! server - > protocols )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-04-08 15:38:34 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									protocol  =  ast_websocket_sub_protocol_alloc ( name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! protocol )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									protocol - > session_established  =  callback ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ast_websocket_server_add_protocol2 ( server ,  protocol ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										ao2_ref ( protocol ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_server_add_protocol2 ) ( struct  ast_websocket_server  * server ,  struct  ast_websocket_protocol  * protocol )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket_protocol  * existing ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! server - > protocols )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( protocol - > version  ! =  AST_WEBSOCKET_PROTOCOL_VERSION )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket could not register sub-protocol '%s':  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											" expected version '%u', got version '%u' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											protocol - > name ,  AST_WEBSOCKET_PROTOCOL_VERSION ,  protocol - > version ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_lock ( server - > protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Ensure a second protocol handler is not registered for the same protocol */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									existing  =  ao2_find ( server - > protocols ,  protocol - > name ,  OBJ_KEY  |  OBJ_NOLOCK ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( existing )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( existing ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_unlock ( server - > protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_link_flags ( server - > protocols ,  protocol ,  OBJ_NOLOCK ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_unlock ( server - > protocols ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_verb ( 2 ,  " WebSocket registered sub-protocol '%s' \n " ,  protocol - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( protocol ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_server_remove_protocol ) ( struct  ast_websocket_server  * server ,  const  char  * name ,  ast_websocket_callback  callback )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_websocket_protocol  * protocol ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! ( protocol  =  ao2_find ( server - > protocols ,  name ,  OBJ_KEY ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( protocol - > session_established  ! =  callback )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										ao2_ref ( protocol ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_unlink ( server - > protocols ,  protocol ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ao2_ref ( protocol ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_verb ( 2 ,  " WebSocket unregistered sub-protocol '%s' \n " ,  name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Close function for websocket session */  
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_close ) ( struct  ast_websocket  * session ,  uint16_t  reason )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  frame [ 4 ]  =  {  0 ,  } ;  /* The header is 2 bytes and the reason code takes up another 2 bytes */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( session - > close_sent )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									frame [ 0 ]  =  AST_WEBSOCKET_OPCODE_CLOSE  |  0x80 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									frame [ 1 ]  =  2 ;  /* The reason code is always 2 bytes */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If no reason has been specified assume 1000 which is normal closure */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									put_unaligned_uint16 ( & frame [ 2 ] ,  htons ( reason  ?  reason  :  1000 ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > closing  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									session - > close_sent  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_lock ( session ) ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Close websocket correctly and use careful fwrite
When a client takes a long time to process information received from Asterisk,
a write operation using fwrite may fail to write all information. This causes
the underlying file stream to be in an unknown state, such that the socket
must be disconnected. Unfortunately, there are two problems with this in
Asterisk's existing websocket code:
1. Periodically, during the read loop, Asterisk must write to the connected
   websocket to respond to pings. As such, Asterisk maintains a reference to
   the session during the loop. When ast_http_websocket_write fails, it may
   cause the session to decrement its ref count, but this in and of itself
   does not break the read loop. The read loop's write, on the other hand,
   does not break the loop if it fails. This causes the socket to get in a
   'stuck' state, preventing the client from reconnecting to the server.
2. More importantly, however, is that the fwrite in ast_http_websocket_write
   fails with a large volume of data when the client takes awhile to process
   the information. When it does fail, it fails writing only a portion of
   the bytes. With some debugging, it was shown that this was failing in a
   similar fashion to ASTERISK-12767. Switching this over to ast_careful_fwrite
   with a long enough timeout solved the problem.
Note that this version of the patch, unlike r417310 in Asterisk 11, exposes
configuration options beyond just chan_sip's sip.conf. Configuration options
to configure the write timeout have also been added to pjsip.conf and ari.conf.
#ASTERISK-23917 #close
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/3624/
........
Merged revisions 417310 from http://svn.asterisk.org/svn/asterisk/branches/11
........
Merged revisions 417311 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417317 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2014-06-26 12:21:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									res  =  ast_careful_fwrite ( session - > f ,  session - > fd ,  frame ,  4 ,  session - > timeout ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If an error occurred when trying to close this connection explicitly terminate it now.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  Doing  so  will  cause  the  thread  polling  on  it  to  wake  up  and  terminate . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( res )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fclose ( session - > f ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										session - > f  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_verb ( 2 ,  " WebSocket connection %s '%s' forcefully closed due to fatal write error \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											session - > client  ?  " to "  :  " from " ,  ast_sockaddr_stringify ( & session - > address ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-08-04 09:47:34 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  const  char  * opcode_map [ ]  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									[ AST_WEBSOCKET_OPCODE_CONTINUATION ]  =  " continuation " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									[ AST_WEBSOCKET_OPCODE_TEXT ]  =  " text " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									[ AST_WEBSOCKET_OPCODE_BINARY ]  =  " binary " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									[ AST_WEBSOCKET_OPCODE_CLOSE ]  =  " close " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									[ AST_WEBSOCKET_OPCODE_PING ]  =  " ping " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									[ AST_WEBSOCKET_OPCODE_PONG ]  =  " pong " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  const  char  * websocket_opcode2str ( enum  ast_websocket_opcode  opcode )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( opcode  <  AST_WEBSOCKET_OPCODE_CONTINUATION  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											opcode  >  AST_WEBSOCKET_OPCODE_PONG )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  " <unknown> " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  opcode_map [ opcode ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Write function for websocket traffic */  
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_write ) ( struct  ast_websocket  * session ,  enum  ast_websocket_opcode  opcode ,  char  * payload ,  uint64_t  payload_size )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size_t  header_size  =  2 ;  /* The minimum size of a websocket frame is 2 bytes */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * frame ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-12-19 20:56:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uint64_t  length ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uint64_t  frame_size ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-08-04 09:47:34 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Writing websocket %s frame, length % "  PRIu64  " \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											websocket_opcode2str ( opcode ) ,  payload_size ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-04 09:47:34 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( payload_size  <  126 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										length  =  payload_size ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( payload_size  <  ( 1  < <  16 ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										length  =  126 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* We need an additional 2 bytes to store the extended length */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										header_size  + =  2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										length  =  127 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* We need an additional 8 bytes to store the really really extended length */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										header_size  + =  8 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									frame_size  =  header_size  +  payload_size ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									frame  =  ast_alloca ( frame_size  +  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									memset ( frame ,  0 ,  frame_size  +  1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									frame [ 0 ]  =  opcode  |  0x80 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									frame [ 1 ]  =  length ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Use the additional available bytes to store the length */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( length  = =  126 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										put_unaligned_uint16 ( & frame [ 2 ] ,  htons ( payload_size ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}  else  if  ( length  = =  127 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										put_unaligned_uint64 ( & frame [ 2 ] ,  htonll ( payload_size ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									memcpy ( & frame [ header_size ] ,  payload ,  payload_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_lock ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( session - > closing )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ast_careful_fwrite ( session - > f ,  session - > fd ,  frame ,  frame_size ,  session - > timeout ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-11 16:52:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/* 1011 - server terminating connection due to not being able to fulfill the request */ 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_debug ( 1 ,  " Closing WS with 1011 because we can't fulfill a write request \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-11 16:52:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_websocket_close ( session ,  1011 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-12-24 20:19:59 -08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fflush ( session - > f ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  AST_OPTIONAL_API_NAME ( ast_websocket_reconstruct_enable ) ( struct  ast_websocket  * session ,  size_t  bytes )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > reconstruct  =  MIN ( bytes ,  MAXIMUM_RECONSTRUCTION_CEILING ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  AST_OPTIONAL_API_NAME ( ast_websocket_reconstruct_disable ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > reconstruct  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  AST_OPTIONAL_API_NAME ( ast_websocket_ref ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( session ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  AST_OPTIONAL_API_NAME ( ast_websocket_unref ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2013-07-03 16:32:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_cleanup ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_fd ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  session - > closing  ?  - 1  :  session - > fd ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								struct  ast_sockaddr  *  AST_OPTIONAL_API_NAME ( ast_websocket_remote_address ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & session - > address ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_is_secure ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  session - > secure ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_set_nonblock ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
									
										
										
										
											2012-07-16 12:35:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  flags ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( flags  =  fcntl ( session - > fd ,  F_GETFL ) )  = =  - 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flags  | =  O_NONBLOCK ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( flags  =  fcntl ( session - > fd ,  F_SETFL ,  flags ) )  = =  - 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Close websocket correctly and use careful fwrite
When a client takes a long time to process information received from Asterisk,
a write operation using fwrite may fail to write all information. This causes
the underlying file stream to be in an unknown state, such that the socket
must be disconnected. Unfortunately, there are two problems with this in
Asterisk's existing websocket code:
1. Periodically, during the read loop, Asterisk must write to the connected
   websocket to respond to pings. As such, Asterisk maintains a reference to
   the session during the loop. When ast_http_websocket_write fails, it may
   cause the session to decrement its ref count, but this in and of itself
   does not break the read loop. The read loop's write, on the other hand,
   does not break the loop if it fails. This causes the socket to get in a
   'stuck' state, preventing the client from reconnecting to the server.
2. More importantly, however, is that the fwrite in ast_http_websocket_write
   fails with a large volume of data when the client takes awhile to process
   the information. When it does fail, it fails writing only a portion of
   the bytes. With some debugging, it was shown that this was failing in a
   similar fashion to ASTERISK-12767. Switching this over to ast_careful_fwrite
   with a long enough timeout solved the problem.
Note that this version of the patch, unlike r417310 in Asterisk 11, exposes
configuration options beyond just chan_sip's sip.conf. Configuration options
to configure the write timeout have also been added to pjsip.conf and ari.conf.
#ASTERISK-23917 #close
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/3624/
........
Merged revisions 417310 from http://svn.asterisk.org/svn/asterisk/branches/11
........
Merged revisions 417311 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417317 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2014-06-26 12:21:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_set_timeout ) ( struct  ast_websocket  * session ,  int  timeout )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > timeout  =  timeout ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								const  char  *  AST_OPTIONAL_API_NAME ( ast_websocket_session_id ) ( struct  ast_websocket  * session )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  session - > session_id ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/* MAINTENANCE WARNING on ast_websocket_read()!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  We  have  to  keep  in  mind  during  this  function  that  the  fact  that  session - > fd  seems  ready 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  ( via  poll )  does  not  necessarily  mean  we  have  application  data  ready ,  because  in  the  case 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  of  an  SSL  socket ,  there  is  some  encryption  data  overhead  that  needs  to  be  read  from  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  TCP  socket ,  so  poll ( )  may  say  there  are  bytes  to  be  read ,  but  whether  it  is  just  1  byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  or  N  bytes  we  do  not  know  that ,  and  we  do  not  know  how  many  of  those  bytes  ( if  any )  are 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  for  application  data  ( for  us )  and  not  just  for  the  SSL  protocol  consumption 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  There  used  to  be  a  couple  of  nasty  bugs  here  that  were  fixed  in  last  refactoring  but  I 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  want  to  document  them  so  the  constraints  are  clear  and  we  do  not  re - introduce  them : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  -  This  function  would  incorrectly  assume  that  fread ( )  would  necessarily  return  more  than 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    1  byte  of  data ,  just  because  a  websocket  frame  is  always  > =  2  bytes ,  but  the  thing 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    is  we ' re  dealing  with  a  TCP  bitstream  here ,  we  could  read  just  one  byte  and  that ' s  normal . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    The  problem  before  was  that  if  just  one  byte  was  read ,  the  function  bailed  out  and  returned 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    an  error ,  effectively  dropping  the  first  byte  of  a  websocket  frame  header ! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  -  Another  subtle  bug  was  that  it  would  just  read  up  to  MAX_WS_HDR_SZ  ( 14  bytes )  via  fread ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    then  assume  that  executing  poll ( )  would  tell  you  if  there  is  more  to  read ,  but  since 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    we ' re  dealing  with  a  buffered  stream  ( session - > f  is  a  FILE * ) ,  poll  would  say  there  is 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    nothing  else  to  read  ( in  the  real  tcp  socket  session - > fd )  and  we  would  get  stuck  here 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    without  processing  the  rest  of  the  data  in  session - > f  internal  buffers  until  another  packet 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    came  on  the  network  to  unblock  us ! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Note  during  the  header  parsing  stage  we  try  to  read  in  small  chunks  just  what  we  need ,  this 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  is  buffered  data  anyways ,  no  expensive  syscall  required  most  of  the  time  . . . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  inline  int  ws_safe_read ( struct  ast_websocket  * session ,  char  * buf ,  int  len ,  enum  ast_websocket_opcode  * opcode )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size_t  rlen ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  xlen  =  len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * rbuf  =  buf ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  sanity  =  10 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_lock ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! session - > f )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										errno  =  ECONNABORTED ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  ( ; ; )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										clearerr ( session - > f ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										rlen  =  fread ( rbuf ,  1 ,  xlen ,  session - > f ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ! rlen )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( feof ( session - > f ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_log ( LOG_WARNING ,  " Web socket closed abruptly \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												* opcode  =  AST_WEBSOCKET_OPCODE_CLOSE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												session - > closing  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( ferror ( session - > f )  & &  errno  ! =  EAGAIN )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_log ( LOG_ERROR ,  " Error reading from web socket: %s \n " ,  strerror ( errno ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												* opcode  =  AST_WEBSOCKET_OPCODE_CLOSE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												session - > closing  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( ! - - sanity )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_log ( LOG_WARNING ,  " Websocket seems unresponsive, disconnecting ... \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												* opcode  =  AST_WEBSOCKET_OPCODE_CLOSE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												session - > closing  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-25 20:47:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-27 02:47:03 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										xlen  =  xlen  -  rlen ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										rbuf  =  rbuf  +  rlen ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-27 02:47:03 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ! xlen )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_wait_for_input ( session - > fd ,  1000 )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " ast_wait_for_input returned err: %s \n " ,  strerror ( errno ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-27 02:47:03 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											* opcode  =  AST_WEBSOCKET_OPCODE_CLOSE ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											session - > closing  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_unlock ( session ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-09-27 17:12:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								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 )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  buf [ MAXIMUM_FRAME_SIZE ]  =  " " ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  fin  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  mask_present  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * mask  =  NULL ,  * new_payload  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size_t  options_len  =  0 ,  frame_size  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* payload  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* payload_len  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* fragmented  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ws_safe_read ( session ,  & buf [ 0 ] ,  MIN_WS_HDR_SZ ,  opcode ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									frame_size  + =  MIN_WS_HDR_SZ ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* ok, now we have the first 2 bytes, so we know some flags, opcode and payload length (or whether payload length extension will be required) */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									* opcode  =  buf [ 0 ]  &  0xf ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									* payload_len  =  buf [ 1 ]  &  0x7f ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( * opcode  = =  AST_WEBSOCKET_OPCODE_TEXT  | |  * opcode  = =  AST_WEBSOCKET_OPCODE_BINARY  | |  * opcode  = =  AST_WEBSOCKET_OPCODE_CONTINUATION  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									    * opcode  = =  AST_WEBSOCKET_OPCODE_PING  | |  * opcode  = =  AST_WEBSOCKET_OPCODE_PONG )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										fin  =  ( buf [ 0 ]  > >  7 )  &  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										mask_present  =  ( buf [ 1 ]  > >  7 )  &  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Based on the mask flag and payload length, determine how much more we need to read before start parsing the rest of the header */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										options_len  + =  mask_present  ?  4  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										options_len  + =  ( * payload_len  = =  126 )  ?  2  :  ( * payload_len  = =  127 )  ?  8  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( options_len )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* read the rest of the header options */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( ws_safe_read ( session ,  & buf [ frame_size ] ,  options_len ,  opcode ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											frame_size  + =  options_len ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( * payload_len  = =  126 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											/* Grab the 2-byte payload length  */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											* payload_len  =  ntohs ( get_unaligned_uint16 ( & buf [ 2 ] ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											mask  =  & buf [ 4 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										}  else  if  ( * payload_len  = =  127 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											/* Grab the 8-byte payload length  */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											* payload_len  =  ntohl ( get_unaligned_uint64 ( & buf [ 2 ] ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											mask  =  & buf [ 10 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Just set the mask after the small 2-byte header */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											mask  =  & buf [ 2 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/* Now read the rest of the payload */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* payload  =  & buf [ frame_size ] ;  /* payload will start here, at the end of the options, if any */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										frame_size  =  frame_size  +  ( * payload_len ) ;  /* final frame size is header + optional headers + payload data */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( frame_size  >  MAXIMUM_FRAME_SIZE )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-09 22:49:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Cannot fit huge websocket frame of %zu bytes \n " ,  frame_size ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											/* The frame won't fit :-( */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ast_websocket_close ( session ,  1009 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-27 02:47:03 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ws_safe_read ( session ,  * payload ,  * payload_len ,  opcode ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* If a mask is present unmask the payload */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( mask_present )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											unsigned  int  pos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  ( pos  =  0 ;  pos  <  * payload_len ;  pos + + )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												( * payload ) [ pos ]  ^ =  mask [ pos  %  4 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Per the RFC for PING we need to send back an opcode with the application data as received */ 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Close websocket correctly and use careful fwrite
When a client takes a long time to process information received from Asterisk,
a write operation using fwrite may fail to write all information. This causes
the underlying file stream to be in an unknown state, such that the socket
must be disconnected. Unfortunately, there are two problems with this in
Asterisk's existing websocket code:
1. Periodically, during the read loop, Asterisk must write to the connected
   websocket to respond to pings. As such, Asterisk maintains a reference to
   the session during the loop. When ast_http_websocket_write fails, it may
   cause the session to decrement its ref count, but this in and of itself
   does not break the read loop. The read loop's write, on the other hand,
   does not break the loop if it fails. This causes the socket to get in a
   'stuck' state, preventing the client from reconnecting to the server.
2. More importantly, however, is that the fwrite in ast_http_websocket_write
   fails with a large volume of data when the client takes awhile to process
   the information. When it does fail, it fails writing only a portion of
   the bytes. With some debugging, it was shown that this was failing in a
   similar fashion to ASTERISK-12767. Switching this over to ast_careful_fwrite
   with a long enough timeout solved the problem.
Note that this version of the patch, unlike r417310 in Asterisk 11, exposes
configuration options beyond just chan_sip's sip.conf. Configuration options
to configure the write timeout have also been added to pjsip.conf and ari.conf.
#ASTERISK-23917 #close
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/3624/
........
Merged revisions 417310 from http://svn.asterisk.org/svn/asterisk/branches/11
........
Merged revisions 417311 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417317 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2014-06-26 12:21:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ( * opcode  = =  AST_WEBSOCKET_OPCODE_PING )  & &  ( ast_websocket_write ( session ,  AST_WEBSOCKET_OPCODE_PONG ,  * payload ,  * payload_len ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											* payload_len  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_websocket_close ( session ,  1009 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-12-10 13:35:52 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( * payload_len )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( ! ( new_payload  =  ast_realloc ( session - > payload ,  ( session - > payload_len  +  * payload_len ) ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_log ( LOG_WARNING ,  " Failed allocation: %p, %zu, % " PRIu64 " \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													session - > payload ,  session - > payload_len ,  * payload_len ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												* payload_len  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_websocket_close ( session ,  1009 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-12-10 13:35:52 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											session - > payload  =  new_payload ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											memcpy ( ( session - > payload  +  session - > payload_len ) ,  ( * payload ) ,  ( * payload_len ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											session - > payload_len  + =  * payload_len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! session - > payload_len  & &  session - > payload )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_free ( session - > payload ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											session - > payload  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! fin  & &  session - > reconstruct  & &  ( session - > payload_len  <  session - > reconstruct ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* If this is not a final message we need to defer returning it until later */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( * opcode  ! =  AST_WEBSOCKET_OPCODE_CONTINUATION )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												session - > opcode  =  * opcode ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											* opcode  =  AST_WEBSOCKET_OPCODE_CONTINUATION ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											* payload_len  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											* payload  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( * opcode  = =  AST_WEBSOCKET_OPCODE_CONTINUATION )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( ! fin )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													/* If this was not actually the final message tell the user it is fragmented so they can deal with it accordingly */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													* fragmented  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													/* Final frame in multi-frame so push up the actual opcode */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													* opcode  =  session - > opcode ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											* payload_len  =  session - > payload_len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											* payload  =  session - > payload ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											session - > payload_len  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( * opcode  = =  AST_WEBSOCKET_OPCODE_CLOSE )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Make the payload available so the user can look at the reason code if they so desire */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ( * payload_len )  & &  ( new_payload  =  ast_realloc ( session - > payload ,  * payload_len ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ( ws_safe_read ( session ,  & buf [ frame_size ] ,  ( * payload_len ) ,  opcode ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-11 07:24:30 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											session - > payload  =  new_payload ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											memcpy ( session - > payload ,  & buf [ frame_size ] ,  * payload_len ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											* payload  =  session - > payload ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											frame_size  + =  ( * payload_len ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-04-30 13:08:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										session - > closing  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-09 22:49:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket unknown opcode %u \n " ,  * opcode ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										/* We received an opcode that we don't understand, the RFC states that 1003 is for a type of data that can't be accepted... opcodes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  fit  that ,  I  think .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_websocket_close ( session ,  1003 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-07-03 16:32:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  If  the  server  has  exactly  one  configured  protocol ,  return  it . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  struct  ast_websocket_protocol  * one_protocol (  
						 
					
						
							
								
									
										
										
										
											2013-07-03 16:32:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_websocket_server  * server ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SCOPED_AO2LOCK ( lock ,  server - > protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ao2_container_count ( server - > protocols )  ! =  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ao2_callback ( server - > protocols ,  OBJ_NOLOCK ,  NULL ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  char  * websocket_combine_key ( const  char  * key ,  char  * res ,  int  res_size )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * combined ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  combined_length  =  strlen ( key )  +  strlen ( WEBSOCKET_GUID )  +  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									uint8_t  sha [ 20 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									combined  =  ast_alloca ( combined_length ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									snprintf ( combined ,  combined_length ,  " %s%s " ,  key ,  WEBSOCKET_GUID ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sha1_hash_uint ( sha ,  combined ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_base64encode ( res ,  ( const  unsigned  char * ) sha ,  20 ,  res_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  websocket_bad_request ( struct  ast_tcptls_session_instance  * ser )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_str  * http_header  =  ast_str_create ( 64 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! http_header )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_http_request_close_on_completion ( ser ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_http_error ( ser ,  500 ,  " Server Error " ,  " Out of memory " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_str_set ( & http_header ,  0 ,  " Sec-WebSocket-Version: 7, 8, 13 \r \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_http_send ( ser ,  AST_HTTP_UNKNOWN ,  400 ,  " Bad Request " ,  http_header ,  NULL ,  0 ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_uri_cb ) ( struct  ast_tcptls_session_instance  * ser ,  const  struct  ast_http_uri  * urih ,  const  char  * uri ,  enum  ast_http_method  method ,  struct  ast_variable  * get_vars ,  struct  ast_variable  * headers )  
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_variable  * v ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * upgrade  =  NULL ,  * key  =  NULL ,  * key1  =  NULL ,  * key2  =  NULL ,  * protos  =  NULL ,  * requested_protocols  =  NULL ,  * protocol  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  version  =  0 ,  flags  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_websocket_protocol  * protocol_handler  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket  * session ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_websocket_server  * server ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SCOPED_MODULE_USE ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									/* Upgrade requests are only permitted on GET methods */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( method  ! =  AST_HTTP_GET )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_http_error ( ser ,  501 ,  " Not Implemented " ,  " Attempt to use unimplemented / unsupported method " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									server  =  urih - > data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									/* Get the minimum headers required to satisfy our needs */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  ( v  =  headers ;  v ;  v  =  v - > next )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! strcasecmp ( v - > name ,  " Upgrade " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											upgrade  =  ast_strip ( ast_strdupa ( v - > value ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! strcasecmp ( v - > name ,  " Sec-WebSocket-Key " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											key  =  ast_strip ( ast_strdupa ( v - > value ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! strcasecmp ( v - > name ,  " Sec-WebSocket-Key1 " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											key1  =  ast_strip ( ast_strdupa ( v - > value ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! strcasecmp ( v - > name ,  " Sec-WebSocket-Key2 " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											key2  =  ast_strip ( ast_strdupa ( v - > value ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! strcasecmp ( v - > name ,  " Sec-WebSocket-Protocol " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											requested_protocols  =  ast_strip ( ast_strdupa ( v - > value ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											protos  =  ast_strdupa ( requested_protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! strcasecmp ( v - > name ,  " Sec-WebSocket-Version " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( sscanf ( v - > value ,  " %30d " ,  & version )  ! =  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												version  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If this is not a websocket upgrade abort */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! upgrade  | |  strcasecmp ( upgrade ,  " websocket " ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-11-20 22:06:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - did not request WebSocket \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ast_sockaddr_stringify ( & ser - > remote_address ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_http_error ( ser ,  426 ,  " Upgrade Required " ,  NULL ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}  else  if  ( ast_strlen_zero ( requested_protocols ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2013-07-03 16:32:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/* If there's only a single protocol registered, and the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  client  doesn ' t  specify  what  protocol  it ' s  using ,  go  ahead 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  and  accept  the  connection  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										protocol_handler  =  one_protocol ( server ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! protocol_handler )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Multiple registered subprotocols; client must specify */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - no protocols requested \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_sockaddr_stringify ( & ser - > remote_address ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-07-03 16:32:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}  else  if  ( key1  & &  key2 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 and
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  http : //tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00 -- not currently supported*/
 
							 
						 
					
						
							
								
									
										
										
										
											2012-11-20 22:06:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - unsupported version '00/76' chosen \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ast_sockaddr_stringify ( & ser - > remote_address ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Iterate through the requested protocols trying to find one that we have a handler for */ 
							 
						 
					
						
							
								
									
										
										
										
											2013-07-03 16:32:00 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									while  ( ! protocol_handler  & &  ( protocol  =  strsep ( & requested_protocols ,  " , " ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										protocol_handler  =  ao2_find ( server - > protocols ,  ast_strip ( protocol ) ,  OBJ_KEY ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If no protocol handler exists bump this back to the requester */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! protocol_handler )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - no protocols out of '%s' supported \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_sockaddr_stringify ( & ser - > remote_address ) ,  protos ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Determine how to respond depending on the version */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( version  = =  7  | |  version  = =  8  | |  version  = =  13 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										char  base64 [ 64 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! key  | |  strlen ( key )  +  strlen ( WEBSOCKET_GUID )  +  1  >  8192 )  {  /* no stack overflows please */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_http_body_discard ( ser ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-06-12 21:08:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ! ( session  =  ao2_alloc ( sizeof ( * session )  +  AST_UUID_STR_LEN  +  1 ,  session_destroy_fn ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-11-20 22:06:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												ast_sockaddr_stringify ( & ser - > remote_address ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Close websocket correctly and use careful fwrite
When a client takes a long time to process information received from Asterisk,
a write operation using fwrite may fail to write all information. This causes
the underlying file stream to be in an unknown state, such that the socket
must be disconnected. Unfortunately, there are two problems with this in
Asterisk's existing websocket code:
1. Periodically, during the read loop, Asterisk must write to the connected
   websocket to respond to pings. As such, Asterisk maintains a reference to
   the session during the loop. When ast_http_websocket_write fails, it may
   cause the session to decrement its ref count, but this in and of itself
   does not break the read loop. The read loop's write, on the other hand,
   does not break the loop if it fails. This causes the socket to get in a
   'stuck' state, preventing the client from reconnecting to the server.
2. More importantly, however, is that the fwrite in ast_http_websocket_write
   fails with a large volume of data when the client takes awhile to process
   the information. When it does fail, it fails writing only a portion of
   the bytes. With some debugging, it was shown that this was failing in a
   similar fashion to ASTERISK-12767. Switching this over to ast_careful_fwrite
   with a long enough timeout solved the problem.
Note that this version of the patch, unlike r417310 in Asterisk 11, exposes
configuration options beyond just chan_sip's sip.conf. Configuration options
to configure the write timeout have also been added to pjsip.conf and ari.conf.
#ASTERISK-23917 #close
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/3624/
........
Merged revisions 417310 from http://svn.asterisk.org/svn/asterisk/branches/11
........
Merged revisions 417311 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417317 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2014-06-26 12:21:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										session - > timeout  =   AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/* Generate the session id */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ast_uuid_generate_str ( session - > session_id ,  sizeof ( session - > session_id ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - failed to generate a session id \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_sockaddr_stringify ( & ser - > remote_address ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_http_error ( ser ,  500 ,  " Internal Server Error " ,  " Allocation failed " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-18 14:24:17 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( protocol_handler - > session_attempted 
							 
						 
					
						
							
								
									
										
										
										
											2015-07-31 11:27:23 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										    & &  protocol_handler - > session_attempted ( ser ,  get_vars ,  headers ,  session - > session_id ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " WebSocket connection from '%s' rejected by protocol handler '%s' \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_sockaddr_stringify ( & ser - > remote_address ) ,  protocol_handler - > name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-08-18 16:06:54 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-09-13 14:19:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										/* RFC 6455, Section 4.1:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  6.  If  the  response  includes  a  | Sec - WebSocket - Protocol |  header 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *     field  and  this  header  field  indicates  the  use  of  a 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *     subprotocol  that  was  not  present  in  the  client ' s  handshake 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *     ( the  server  has  indicated  a  subprotocol  not  requested  by 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *     the  client ) ,  the  client  MUST  _Fail  the  WebSocket 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *     Connection_ . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( protocol )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-07-04 20:22:01 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											fprintf ( ser - > f ,  " HTTP/1.1 101 Switching Protocols \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Upgrade: %s \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Connection: Upgrade \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Sec-WebSocket-Accept: %s \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Sec-WebSocket-Protocol: %s \r \n \r \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												upgrade , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												websocket_combine_key ( key ,  base64 ,  sizeof ( base64 ) ) , 
							 
						 
					
						
							
								
									
										
										
										
											2013-09-13 14:19:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												protocol ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-07-04 20:22:01 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fprintf ( ser - > f ,  " HTTP/1.1 101 Switching Protocols \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Upgrade: %s \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Connection: Upgrade \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Sec-WebSocket-Accept: %s \r \n \r \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												upgrade , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												websocket_combine_key ( key ,  base64 ,  sizeof ( base64 ) ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-09-13 14:19:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										fflush ( ser - > f ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* Specification defined in http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 or completely unknown */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-11-20 22:06:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - unsupported version '%d' chosen \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ast_sockaddr_stringify ( & ser - > remote_address ) ,  version  ?  version  :  75 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Enable keepalive on all sessions so the underlying user does not have to */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( setsockopt ( ser - > fd ,  SOL_SOCKET ,  SO_KEEPALIVE ,  & flags ,  sizeof ( flags ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-11-20 22:06:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " WebSocket connection from '%s' could not be accepted - failed to enable keepalive \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											ast_sockaddr_stringify ( & ser - > remote_address ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										websocket_bad_request ( ser ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										ao2_ref ( session ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2013-07-16 15:30:09 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_verb ( 2 ,  " WebSocket connection from '%s' for protocol '%s' accepted using version '%d' \n " ,  ast_sockaddr_stringify ( & ser - > remote_address ) ,  protocol  ?  :  " " ,  version ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Populate the session with all the needed details */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > f  =  ser - > f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > fd  =  ser - > fd ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sockaddr_copy ( & session - > address ,  & ser - > remote_address ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > opcode  =  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > reconstruct  =  DEFAULT_RECONSTRUCTION_CEILING ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									session - > secure  =  ser - > ssl  ?  1  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Give up ownership of the socket and pass it to the protocol handler */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-07-03 17:16:55 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_tcptls_stream_set_exclusive_input ( ser - > stream_cookie ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									protocol_handler - > session_established ( session ,  get_vars ,  headers ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ao2_ref ( protocol_handler ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-12 17:00:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  By  dropping  the  FILE *  and  fd  from  the  session  the  connection 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  won ' t  get  closed  when  the  HTTP  server  cleans  up  because  we 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  passed  the  connection  to  the  protocol  handler . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ser - > f  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-12 17:00:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ser - > fd  =  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  ast_http_uri  websocketuri  =  {  
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. callback  =  AST_OPTIONAL_API_NAME ( ast_websocket_uri_cb ) , 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									. description  =  " Asterisk HTTP WebSocket " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. uri  =  " ws " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. has_subtree  =  0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. data  =  NULL , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. key  =  __FILE__ , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! \brief Simple echo implementation which echoes received text and binary frames */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  websocket_echo_callback ( struct  ast_websocket  * session ,  struct  ast_variable  * parameters ,  struct  ast_variable  * headers )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  flags ,  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 1 ,  " Entering WebSocket echo loop \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ( ( flags  =  fcntl ( ast_websocket_fd ( session ) ,  F_GETFL ) )  = =  - 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										goto  end ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flags  | =  O_NONBLOCK ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( fcntl ( ast_websocket_fd ( session ) ,  F_SETFL ,  flags )  = =  - 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										goto  end ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( ( res  =  ast_wait_for_input ( ast_websocket_fd ( session ) ,  - 1 ) )  >  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										char  * payload ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										uint64_t  payload_len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										enum  ast_websocket_opcode  opcode ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										int  fragmented ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_websocket_read ( session ,  & payload ,  & payload_len ,  & opcode ,  & fragmented ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* We err on the side of caution and terminate the session if any error occurs */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Read failure during WebSocket echo loop \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( opcode  = =  AST_WEBSOCKET_OPCODE_TEXT  | |  opcode  = =  AST_WEBSOCKET_OPCODE_BINARY )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_websocket_write ( session ,  opcode ,  payload ,  payload_len ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( opcode  = =  AST_WEBSOCKET_OPCODE_CLOSE )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-03-05 16:22:44 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-05-09 22:49:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_debug ( 1 ,  " Ignored WebSocket opcode %u \n " ,  opcode ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								end :  
						 
					
						
							
								
									
										
										
										
											2014-10-27 02:47:03 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 1 ,  " Exiting WebSocket echo loop \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_websocket_unref ( session ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  websocket_add_protocol_internal ( const  char  * name ,  ast_websocket_callback  callback )  
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket_server  * ws_server  =  websocketuri . data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ws_server )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ast_websocket_server_add_protocol ( ws_server ,  name ,  callback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_add_protocol ) ( const  char  * name ,  ast_websocket_callback  callback )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  res  =  websocket_add_protocol_internal ( name ,  callback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( res  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_module_ref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-05-13 09:55:58 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_add_protocol2 ) ( struct  ast_websocket_protocol  * protocol )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket_server  * ws_server  =  websocketuri . data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ws_server )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ast_websocket_server_add_protocol2 ( ws_server ,  protocol ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_module_ref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  websocket_remove_protocol_internal ( const  char  * name ,  ast_websocket_callback  callback )  
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket_server  * ws_server  =  websocketuri . data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ws_server )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ast_websocket_server_remove_protocol ( ws_server ,  name ,  callback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_remove_protocol ) ( const  char  * name ,  ast_websocket_callback  callback )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  res  =  websocket_remove_protocol_internal ( name ,  callback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( res  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_module_unref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*! \brief Parse the given uri into a path and remote address.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Expected  uri  form :  [ ws [ s ] ] : //<host>[:port][/<path>]
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  The  returned  host  will  contain  the  address  and  optional  port  while 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  path  will  contain  everything  after  the  address / port  if  included . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-17 16:11:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  websocket_client_parse_uri ( const  char  * uri ,  char  * * host ,  struct  ast_str  * * path )  
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_uri  * parsed_uri  =  ast_uri_parse_websocket ( uri ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! parsed_uri )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									* host  =  ast_uri_make_host_with_port ( parsed_uri ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-08-17 16:11:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ast_uri_path ( parsed_uri )  | |  ast_uri_query ( parsed_uri ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* path  =  ast_str_create ( 64 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! * path )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_ref ( parsed_uri ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_uri_path ( parsed_uri ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_str_set ( path ,  0 ,  " %s " ,  ast_uri_path ( parsed_uri ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_uri_query ( parsed_uri ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_str_append ( path ,  0 ,  " ?%s " ,  ast_uri_query ( parsed_uri ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( parsed_uri ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  websocket_client_args_destroy ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_tcptls_session_args  * args  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( args - > tls_cfg )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( args - > tls_cfg - > certfile ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( args - > tls_cfg - > pvtfile ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( args - > tls_cfg - > cipher ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( args - > tls_cfg - > cafile ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( args - > tls_cfg - > capath ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_ssl_teardown ( args - > tls_cfg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( args - > tls_cfg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  ast_tcptls_session_args  * websocket_client_args_create (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  char  * host ,  struct  ast_tls_config  * tls_cfg , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_websocket_result  * result ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_sockaddr  * addr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_tcptls_session_args  * args  =  ao2_alloc ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sizeof ( * args ) ,  websocket_client_args_destroy ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! args )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* result  =  WS_ALLOCATE_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args - > accept_fd  =  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args - > tls_cfg  =  tls_cfg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args - > name  =  " websocket client " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ast_sockaddr_resolve ( & addr ,  host ,  0 ,  0 ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Unable to resolve address %s \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											host ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( args ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* result  =  WS_URI_RESOLVE_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sockaddr_copy ( & args - > remote_address ,  addr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( addr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  args ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  char  * websocket_client_create_key ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									static  int  encoded_size  =  CLIENT_KEY_SIZE  *  2  *  sizeof ( char )  +  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* key is randomly selected 16-byte base64 encoded value */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  char  key [ CLIENT_KEY_SIZE  +  sizeof ( long )  -  1 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * encoded  =  ast_malloc ( encoded_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									long  i  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! encoded )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Unable to allocate client websocket key \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( i  <  CLIENT_KEY_SIZE )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										long  num  =  ast_random ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										memcpy ( key  +  i ,  & num ,  sizeof ( long ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										i  + =  sizeof ( long ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_base64encode ( encoded ,  key ,  CLIENT_KEY_SIZE ,  encoded_size ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  encoded ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  websocket_client  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! host portion of client uri */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * host ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! path for logical websocket connection */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-17 16:11:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_str  * resource_name ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! unique key used during server handshaking */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * key ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! container for registered protocols */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * protocols ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! the protocol accepted by the server */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * accept_protocol ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! websocket protocol version */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  version ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! tcptls connection arguments */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_tcptls_session_args  * args ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! tcptls connection instance */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_tcptls_session_instance  * ser ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  websocket_client_destroy ( void  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  websocket_client  * client  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( client - > ser ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_cleanup ( client - > args ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( client - > accept_protocol ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( client - > protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( client - > key ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( client - > resource_name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( client - > host ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  ast_websocket  *  websocket_client_create (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  char  * uri ,  const  char  * protocols , 	struct  ast_tls_config  * tls_cfg , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_websocket_result  * result ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket  * ws  =  ao2_alloc ( sizeof ( * ws ) ,  session_destroy_fn ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ws )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Unable to allocate websocket \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* result  =  WS_ALLOCATE_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( ws - > client  =  ao2_alloc ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										      sizeof ( * ws - > client ) ,  websocket_client_destroy ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Unable to allocate websocket client \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* result  =  WS_ALLOCATE_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( ws - > client - > key  =  websocket_client_create_key ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( ws ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* result  =  WS_KEY_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( websocket_client_parse_uri ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    uri ,  & ws - > client - > host ,  & ws - > client - > resource_name ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( ws ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* result  =  WS_URI_PARSE_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( ws - > client - > args  =  websocket_client_args_create ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										      ws - > client - > host ,  tls_cfg ,  result ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( ws ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > client - > protocols  =  ast_strdup ( protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > client - > version  =  13 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > opcode  =  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > reconstruct  =  DEFAULT_RECONSTRUCTION_CEILING ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ws ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  char  *  AST_OPTIONAL_API_NAME (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_websocket_client_accept_protocol ) ( struct  ast_websocket  * ws ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ws - > client - > accept_protocol ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  enum  ast_websocket_result  websocket_client_handle_response_code (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  websocket_client  * client ,  int  response_code ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( response_code  < =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  WS_INVALID_RESPONSE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  ( response_code )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  101 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  400 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Received response 400 - Bad Request  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											" - from %s \n " ,  client - > host ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  WS_BAD_REQUEST ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  404 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Received response 404 - Request URL not  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											" found - from %s \n " ,  client - > host ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  WS_URL_NOT_FOUND ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_log ( LOG_ERROR ,  " Invalid HTTP response code %d from %s \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										response_code ,  client - > host ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  WS_INVALID_RESPONSE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  enum  ast_websocket_result  websocket_client_handshake_get_response (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  websocket_client  * client ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_websocket_result  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  buf [ 4096 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  base64 [ 64 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  has_upgrade  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  has_connection  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  has_accept  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  has_protocol  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! fgets ( buf ,  sizeof ( buf ) ,  client - > ser - > f ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Unable to retrieve HTTP status line. " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  WS_BAD_STATUS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( res  =  websocket_client_handle_response_code ( client , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    ast_http_response_status_line ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											    buf ,  " HTTP/1.1 " ,  101 ) ) )  ! =  WS_OK )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Ignoring line folding - assuming header field values are contained
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									   within  a  single  line  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( fgets ( buf ,  sizeof ( buf ) ,  client - > ser - > f ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										char  * name ,  * value ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										int  parsed  =  ast_http_header_parse ( buf ,  & name ,  & value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( parsed  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( parsed  >  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! has_upgrade  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    ( has_upgrade  =  ast_http_header_match ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											    name ,  " upgrade " ,  value ,  " websocket " ) )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  WS_HEADER_MISMATCH ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! has_connection  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											   ( has_connection  =  ast_http_header_match ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												   name ,  " connection " ,  value ,  " upgrade " ) )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  WS_HEADER_MISMATCH ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! has_accept  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											   ( has_accept  =  ast_http_header_match ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												   name ,  " sec-websocket-accept " ,  value , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											    websocket_combine_key ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												    client - > key ,  base64 ,  sizeof ( base64 ) ) ) )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  WS_HEADER_MISMATCH ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! has_protocol  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											   ( has_protocol  =  ast_http_header_match_in ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												   name ,  " sec-websocket-protocol " ,  value ,  client - > protocols ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( has_protocol  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  WS_HEADER_MISMATCH ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											client - > accept_protocol  =  ast_strdup ( value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( ! strcasecmp ( name ,  " sec-websocket-extensions " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Extensions received, but not  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" supported by client \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  WS_NOT_SUPPORTED ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  has_upgrade  & &  has_connection  & &  has_accept  ? 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										WS_OK  :  WS_HEADER_MISSING ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  enum  ast_websocket_result  websocket_client_handshake (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  websocket_client  * client ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  protocols [ 100 ]  =  " " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ast_strlen_zero ( client - > protocols ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sprintf ( protocols ,  " Sec-WebSocket-Protocol: %s \r \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											client - > protocols ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( fprintf ( client - > ser - > f , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " GET /%s HTTP/1.1 \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " Sec-WebSocket-Version: %d \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " Upgrade: websocket \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " Connection: Upgrade \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " Host: %s \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " Sec-WebSocket-Key: %s \r \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    " %s \r \n " , 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-17 16:11:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										    client - > resource_name  ?  ast_str_buffer ( client - > resource_name )  :  " " , 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										    client - > version , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    client - > host , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    client - > key , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										    protocols )  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_ERROR ,  " Failed to send handshake. \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  WS_WRITE_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* wait for a response before doing anything else */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  websocket_client_handshake_get_response ( client ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  enum  ast_websocket_result  websocket_client_connect ( struct  ast_websocket  * ws )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_websocket_result  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* create and connect the client - note client_start
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									   releases  the  session  instance  on  failure  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ( ws - > client - > ser  =  ast_tcptls_client_start ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										      ast_tcptls_client_create ( ws - > client - > args ) ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  WS_CLIENT_START_ERROR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( res  =  websocket_client_handshake ( ws - > client ) )  ! =  WS_OK )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( ws - > client - > ser ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ws - > client - > ser  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > f  =  ws - > client - > ser - > f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > fd  =  ws - > client - > ser - > fd ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ws - > secure  =  ws - > client - > ser - > ssl  ?  1  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_sockaddr_copy ( & ws - > address ,  & ws - > client - > ser - > remote_address ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  WS_OK ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  ast_websocket  * AST_OPTIONAL_API_NAME ( ast_websocket_client_create )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									( const  char  * uri ,  const  char  * protocols ,  struct  ast_tls_config  * tls_cfg , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 enum  ast_websocket_result  * result ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_websocket  * ws  =  websocket_client_create ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										uri ,  protocols ,  tls_cfg ,  result ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ws )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( * result  =  websocket_client_connect ( ws ) )  ! =  WS_OK )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( ws ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ws ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_read_string )  
						 
					
						
							
								
									
										
										
										
											2014-06-16 16:22:33 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									( struct  ast_websocket  * ws ,  char  * * buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * payload ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									uint64_t  payload_len ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									enum  ast_websocket_opcode  opcode ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  fragmented  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( fragmented )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ast_websocket_read ( ws ,  & payload ,  & payload_len , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												       & opcode ,  & fragmented ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Client WebSocket string read -  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" error reading string data \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-16 16:22:33 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( opcode  = =  AST_WEBSOCKET_OPCODE_CONTINUATION )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( opcode  = =  AST_WEBSOCKET_OPCODE_CLOSE )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( opcode  ! =  AST_WEBSOCKET_OPCODE_TEXT )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Client WebSocket string read -  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" non string data received \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-16 16:22:33 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-16 16:22:33 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! ( * buf  =  ast_malloc ( payload_len  +  1 ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-16 16:22:33 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_copy_string ( * buf ,  payload ,  payload_len  +  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  payload_len  +  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								int  AST_OPTIONAL_API_NAME ( ast_websocket_write_string )  
						 
					
						
							
								
									
										
										
										
											2014-06-16 16:22:33 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									( struct  ast_websocket  * ws ,  const  char  * buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Avoid passing strlen() to ast_websocket_write().
We have seen a rash of test failures on a 32-bit build agent. Commit
48698a5e21d7307f61b5fb2bd39fd593bc1423ca solved an obvious problem where
we were not encoding a 64-bit value correctly over the wire. This
commit, however, did not solve the test failures.
In the failing tests, ARI is attempting to send a 537 byte text frame
over a websocket. When sending a frame this small, 16 bits are all that
is required in order to encode the payload length on the websocket
frame. However, ast_websocket_write() thinks that the payload length is
greater than 65535 and therefore writes out a 64 bit payload length.
Inspecting this payload length, the lower 32 bits are exactly what we
would expect it to be, 537 in hex. The upper 32 bits, are junk values
that are not expected to be there.
In the failure, we are passing the result of strlen() to a function that
expects a uint64_t parameter to be passed in. strlen() returns a size_t,
which on this 32-bit machine is 32 bits wide. Normally, passing a 32-bit
unsigned value to somewhere where a 64-bit unsigned value is expected
would cause no problems. In fact, in manual runs of failing tests, this
works just fine. However, ast_websocket_write() uses the Asterisk
optional API, which means that rather than a simple function call, there
are a series of macros that are used for its declaration and
implementation. These macros may be causing some sort of error to occur
when converting from a 32 bit quantity to a 64 bit quantity.
This commit changes the logic by making existing ast_websocket_write()
calls use ast_websocket_write_string() instead. Within
ast_websocket_write_string(), the 64-bit converted strlen is saved in a
local variable, and that variable is passed to ast_websocket_write()
instead.
Note that this commit message is full of speculation rather than
certainty. This is because the observed test failures, while always
present in automated test runs, never occur when tests are manually
attempted on the same test agent. The idea behind this commit is to fix
a theoretical issue by performing changes that should, at the least,
cause no harm. If it turns out that this change does not fix the failing
tests, then this commit should be reverted.
Change-Id: I4458dd87d785ca322b89c152b223a540a3d23e67
											 
										 
										
											2015-08-03 11:06:07 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uint64_t  len  =  strlen ( buf ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-08-04 09:47:34 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Writing websocket string of length % "  PRIu64  " \n " ,  len ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Avoid passing strlen() to ast_websocket_write().
We have seen a rash of test failures on a 32-bit build agent. Commit
48698a5e21d7307f61b5fb2bd39fd593bc1423ca solved an obvious problem where
we were not encoding a 64-bit value correctly over the wire. This
commit, however, did not solve the test failures.
In the failing tests, ARI is attempting to send a 537 byte text frame
over a websocket. When sending a frame this small, 16 bits are all that
is required in order to encode the payload length on the websocket
frame. However, ast_websocket_write() thinks that the payload length is
greater than 65535 and therefore writes out a 64 bit payload length.
Inspecting this payload length, the lower 32 bits are exactly what we
would expect it to be, 537 in hex. The upper 32 bits, are junk values
that are not expected to be there.
In the failure, we are passing the result of strlen() to a function that
expects a uint64_t parameter to be passed in. strlen() returns a size_t,
which on this 32-bit machine is 32 bits wide. Normally, passing a 32-bit
unsigned value to somewhere where a 64-bit unsigned value is expected
would cause no problems. In fact, in manual runs of failing tests, this
works just fine. However, ast_websocket_write() uses the Asterisk
optional API, which means that rather than a simple function call, there
are a series of macros that are used for its declaration and
implementation. These macros may be causing some sort of error to occur
when converting from a 32 bit quantity to a 64 bit quantity.
This commit changes the logic by making existing ast_websocket_write()
calls use ast_websocket_write_string() instead. Within
ast_websocket_write_string(), the 64-bit converted strlen is saved in a
local variable, and that variable is passed to ast_websocket_write()
instead.
Note that this commit message is full of speculation rather than
certainty. This is because the observed test failures, while always
present in automated test runs, never occur when tests are manually
attempted on the same test agent. The idea behind this commit is to fix
a theoretical issue by performing changes that should, at the least,
cause no harm. If it turns out that this change does not fix the failing
tests, then this commit should be reverted.
Change-Id: I4458dd87d785ca322b89c152b223a540a3d23e67
											 
										 
										
											2015-08-03 11:06:07 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* We do not pass strlen(buf) to ast_websocket_write() directly because the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  size_t  returned  by  strlen ( )  may  not  require  the  same  storage  size 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  as  the  uint64_t  that  ast_websocket_write ( )  uses .  This  normally 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  would  not  cause  a  problem ,  but  since  ast_websocket_write ( )  uses 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  the  optional  API ,  this  function  call  goes  through  a  series  of  macros 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  that  may  cause  a  32 - bit  to  64 - bit  conversion  to  go  awry . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  ast_websocket_write ( ws ,  AST_WEBSOCKET_OPCODE_TEXT , 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_http_websocket: Avoid passing strlen() to ast_websocket_write().
We have seen a rash of test failures on a 32-bit build agent. Commit
48698a5e21d7307f61b5fb2bd39fd593bc1423ca solved an obvious problem where
we were not encoding a 64-bit value correctly over the wire. This
commit, however, did not solve the test failures.
In the failing tests, ARI is attempting to send a 537 byte text frame
over a websocket. When sending a frame this small, 16 bits are all that
is required in order to encode the payload length on the websocket
frame. However, ast_websocket_write() thinks that the payload length is
greater than 65535 and therefore writes out a 64 bit payload length.
Inspecting this payload length, the lower 32 bits are exactly what we
would expect it to be, 537 in hex. The upper 32 bits, are junk values
that are not expected to be there.
In the failure, we are passing the result of strlen() to a function that
expects a uint64_t parameter to be passed in. strlen() returns a size_t,
which on this 32-bit machine is 32 bits wide. Normally, passing a 32-bit
unsigned value to somewhere where a 64-bit unsigned value is expected
would cause no problems. In fact, in manual runs of failing tests, this
works just fine. However, ast_websocket_write() uses the Asterisk
optional API, which means that rather than a simple function call, there
are a series of macros that are used for its declaration and
implementation. These macros may be causing some sort of error to occur
when converting from a 32 bit quantity to a 64 bit quantity.
This commit changes the logic by making existing ast_websocket_write()
calls use ast_websocket_write_string() instead. Within
ast_websocket_write_string(), the 64-bit converted strlen is saved in a
local variable, and that variable is passed to ast_websocket_write()
instead.
Note that this commit message is full of speculation rather than
certainty. This is because the observed test failures, while always
present in automated test runs, never occur when tests are manually
attempted on the same test agent. The idea behind this commit is to fix
a theoretical issue by performing changes that should, at the least,
cause no harm. If it turns out that this change does not fix the failing
tests, then this commit should be reverted.
Change-Id: I4458dd87d785ca322b89c152b223a540a3d23e67
											 
										 
										
											2015-08-03 11:06:07 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												   ( char  * ) buf ,  len ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-05 17:22:35 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								static  int  load_module ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									websocketuri . data  =  websocket_server_internal_create ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! websocketuri . data )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  AST_MODULE_LOAD_FAILURE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_http_uri_link ( & websocketuri ) ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												optional_api: Fix linking problems between modules that export global symbols
With the new work in Asterisk 12, there are some uses of the
optional_api that are prone to failure. The details are rather involved,
and captured on [the wiki][1].
This patch addresses the issue by removing almost all of the magic from
the optional API implementation. Instead of relying on weak symbol
resolution, a new optional_api.c module was added to Asterisk core.
For modules providing an optional API, the pointer to the implementation
function is registered with the core. For modules that use an optional
API, a pointer to a stub function, along with a optional_ref function
pointer are registered with the core. The optional_ref function pointers
is set to the implementation function when it's provided, or the stub
function when it's now.
Since the implementation no longer relies on magic, it is now supported
on all platforms. In the spirit of choice, an OPTIONAL_API flag was
added, so we can disable the optional_api if needed (maybe it's buggy on
some bizarre platform I haven't tested on)
The AST_OPTIONAL_API*() macros themselves remained unchanged, so
existing code could remain unchanged. But to help with debugging the
optional_api, the patch limits the #include of optional API's to just
the modules using the API. This also reduces resource waste maintaining
optional_ref pointers that aren't used.
Other changes made as a part of this patch:
 * The stubs for http_websocket that wrap system calls set errno to
   ENOSYS.
 * res_http_websocket now properly increments module use count.
 * In loader.c, the while() wrappers around dlclose() were removed. The
   while(!dlclose()) is actually an anti-pattern, which can lead to
   infinite loops if the module you're attempting to unload exports a
   symbol that was directly linked to.
 * The special handling of nonoptreq on systems without weak symbol
   support was removed, since we no longer rely on weak symbols for
   optional_api.
 [1]: https://wiki.asterisk.org/wiki/x/wACUAQ
(closes issue ASTERISK-22296)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2797/
........
Merged revisions 397989 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397990 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											 
										 
										
											2013-08-30 13:40:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									websocket_add_protocol_internal ( " echo " ,  websocket_echo_callback ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  unload_module ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2014-11-04 19:33:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									websocket_remove_protocol_internal ( " echo " ,  websocket_echo_callback ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									ast_http_uri_unlink ( & websocketuri ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2013-04-18 17:30:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_ref ( websocketuri . data ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									websocketuri . data  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-06-02 21:13:36 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								AST_MODULE_INFO ( ASTERISK_GPL_KEY ,  AST_MODFLAG_GLOBAL_SYMBOLS  |  AST_MODFLAG_LOAD_ORDER ,  " HTTP WebSocket Support " ,  
						 
					
						
							
								
									
										
										
										
											2015-05-05 20:49:04 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. support_level  =  AST_MODULE_SUPPORT_EXTENDED , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. load  =  load_module , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. unload  =  unload_module , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. load_pri  =  AST_MODPRI_CHANNEL_DEPEND , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								) ;