http_websocket.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2012, Digium, Inc.
  5. *
  6. * Joshua Colp <jcolp@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. #ifndef _ASTERISK_HTTP_WEBSOCKET_H
  19. #define _ASTERISK_HTTP_WEBSOCKET_H
  20. #include "asterisk/http.h"
  21. #include "asterisk/optional_api.h"
  22. #include <errno.h>
  23. /*! \brief Default websocket write timeout, in ms */
  24. #define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT 100
  25. /*! \brief Default websocket write timeout, in ms (as a string) */
  26. #define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR "100"
  27. /*!
  28. * \file http_websocket.h
  29. * \brief Support for WebSocket connections within the Asterisk HTTP server and client
  30. * WebSocket connections to a server.
  31. *
  32. * Supported WebSocket versions in server implementation:
  33. * Version 7 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
  34. * Version 8 defined in specification http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
  35. * Version 13 defined in specification http://tools.ietf.org/html/rfc6455
  36. * Supported WebSocket versions in client implementation:
  37. * Version 13 defined in specification http://tools.ietf.org/html/rfc6455
  38. *
  39. * \author Joshua Colp <jcolp@digium.com>
  40. *
  41. */
  42. /*! \brief WebSocket operation codes */
  43. enum ast_websocket_opcode {
  44. AST_WEBSOCKET_OPCODE_TEXT = 0x1, /*!< Text frame */
  45. AST_WEBSOCKET_OPCODE_BINARY = 0x2, /*!< Binary frame */
  46. AST_WEBSOCKET_OPCODE_PING = 0x9, /*!< Request that the other side respond with a pong */
  47. AST_WEBSOCKET_OPCODE_PONG = 0xA, /*!< Response to a ping */
  48. AST_WEBSOCKET_OPCODE_CLOSE = 0x8, /*!< Connection is being closed */
  49. AST_WEBSOCKET_OPCODE_CONTINUATION = 0x0, /*!< Continuation of a previous frame */
  50. };
  51. /*!
  52. * \brief Opaque structure for WebSocket server.
  53. * \since 12
  54. */
  55. struct ast_websocket_server;
  56. /*!
  57. * \brief Opaque structure for WebSocket sessions.
  58. */
  59. struct ast_websocket;
  60. /*!
  61. * \brief Callback from the HTTP request attempting to establish a websocket connection
  62. *
  63. * This callback occurs when an HTTP request is made to establish a websocket connection.
  64. * Implementers of \ref ast_websocket_protocol can use this to deny a request, or to
  65. * set up application specific data before invocation of \ref ast_websocket_callback.
  66. *
  67. * \param ser The TCP/TLS session
  68. * \param parameters Parameters extracted from the request URI
  69. * \param headers Headers included in the request
  70. *
  71. * \retval 0 The session should be accepted
  72. * \retval -1 The session should be rejected. Note that the caller must send an error
  73. * response using \ref ast_http_error.
  74. * \since 13.5.0
  75. */
  76. typedef int (*ast_websocket_pre_callback)(struct ast_tcptls_session_instance *ser, struct ast_variable *parameters, struct ast_variable *headers);
  77. /*!
  78. * \brief Callback for when a new connection for a sub-protocol is established
  79. *
  80. * \param session A WebSocket session structure
  81. * \param parameters Parameters extracted from the request URI
  82. * \param headers Headers included in the request
  83. *
  84. * \note Once called the ownership of the session is transferred to the sub-protocol handler. It
  85. * is responsible for closing and cleaning up.
  86. *
  87. */
  88. typedef void (*ast_websocket_callback)(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers);
  89. /*!
  90. * \brief A websocket protocol implementation
  91. *
  92. * Users of the Websocket API can register themselves as a websocket
  93. * protocol. See \ref ast_websocket_add_protocol2 and \ref ast_websocket_server_add_protocol2.
  94. * Simpler implementations may use only \ref ast_websocket_add_protocol and
  95. * \ref ast_websocket_server_add_protocol.
  96. *
  97. * \since 13.5.0
  98. */
  99. struct ast_websocket_protocol {
  100. /*! \brief Name of the protocol */
  101. char *name;
  102. /*!
  103. * \brief Protocol version. This prevents dynamically loadable modules from registering
  104. * if this struct is changed.
  105. */
  106. #define AST_WEBSOCKET_PROTOCOL_VERSION 1
  107. /*! \brief Protocol version. Should be set to /ref AST_WEBSOCKET_PROTOCOL_VERSION */
  108. unsigned int version;
  109. /*! \brief Callback called when a new session is attempted. Optional. */
  110. ast_websocket_pre_callback session_attempted;
  111. /* \brief Callback called when a new session is established. Mandatory. */
  112. ast_websocket_callback session_established;
  113. };
  114. /*!
  115. * \brief Creates a \ref websocket_server
  116. *
  117. * \retval New \ref websocket_server instance
  118. * \retval \c NULL on error
  119. * \since 12
  120. */
  121. AST_OPTIONAL_API(struct ast_websocket_server *, ast_websocket_server_create, (void), { return NULL; });
  122. /*!
  123. * \brief Callback suitable for use with a \ref ast_http_uri.
  124. *
  125. * Set the data field of the ast_http_uri to \ref ast_websocket_server.
  126. * \since 12
  127. */
  128. AST_OPTIONAL_API(int, 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), { return -1; });
  129. /*!
  130. * \brief Allocate a websocket sub-protocol instance
  131. *
  132. * \retval An instance of \ref ast_websocket_protocol on success
  133. * \retval NULL on error
  134. * \since 13.5.0
  135. */
  136. AST_OPTIONAL_API(struct ast_websocket_protocol *, ast_websocket_sub_protocol_alloc, (const char *name), {return NULL;});
  137. /*!
  138. * \brief Add a sub-protocol handler to the default /ws server
  139. *
  140. * \param name Name of the sub-protocol to register
  141. * \param callback Callback called when a new connection requesting the sub-protocol is established
  142. *
  143. * \retval 0 success
  144. * \retval -1 if sub-protocol handler could not be registered
  145. */
  146. AST_OPTIONAL_API(int, ast_websocket_add_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
  147. /*!
  148. * \brief Add a sub-protocol handler to the default /ws server
  149. *
  150. * \param protocol The sub-protocol to register. Note that this must
  151. * be allocated using /ref ast_websocket_sub_protocol_alloc.
  152. *
  153. * \note This method is reference stealing. It will steal the reference to \ref protocol
  154. * on success.
  155. *
  156. * \retval 0 success
  157. * \retval -1 if sub-protocol handler could not be registered
  158. * \since 13.5.0
  159. */
  160. AST_OPTIONAL_API(int, ast_websocket_add_protocol2, (struct ast_websocket_protocol *protocol), {return -1;});
  161. /*!
  162. * \brief Remove a sub-protocol handler from the default /ws server.
  163. *
  164. * \param name Name of the sub-protocol to unregister
  165. * \param callback Session Established callback that was previously registered with the sub-protocol
  166. *
  167. * \retval 0 success
  168. * \retval -1 if sub-protocol was not found or if callback did not match
  169. */
  170. AST_OPTIONAL_API(int, ast_websocket_remove_protocol, (const char *name, ast_websocket_callback callback), {return -1;});
  171. /*!
  172. * \brief Add a sub-protocol handler to the given server.
  173. *
  174. * \param name Name of the sub-protocol to register
  175. * \param callback Callback called when a new connection requesting the sub-protocol is established
  176. *
  177. * \retval 0 success
  178. * \retval -1 if sub-protocol handler could not be registered
  179. * \since 12
  180. */
  181. AST_OPTIONAL_API(int, ast_websocket_server_add_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
  182. /*!
  183. * \brief Add a sub-protocol handler to the given server.
  184. *
  185. * \param server The server to add the sub-protocol to.
  186. * \param protocol The sub-protocol to register. Note that this must
  187. * be allocated using /ref ast_websocket_sub_protocol_alloc.
  188. *
  189. * \note This method is reference stealing. It will steal the reference to \ref protocol
  190. * on success.
  191. *
  192. * \retval 0 success
  193. * \retval -1 if sub-protocol handler could not be registered
  194. * \since 13.5.0
  195. */
  196. AST_OPTIONAL_API(int, ast_websocket_server_add_protocol2, (struct ast_websocket_server *server, struct ast_websocket_protocol *protocol), {return -1;});
  197. /*!
  198. * \brief Remove a sub-protocol handler from the given server.
  199. *
  200. * \param name Name of the sub-protocol to unregister
  201. * \param callback Callback that was previously registered with the sub-protocol
  202. *
  203. * \retval 0 success
  204. * \retval -1 if sub-protocol was not found or if callback did not match
  205. * \since 12
  206. */
  207. AST_OPTIONAL_API(int, ast_websocket_server_remove_protocol, (struct ast_websocket_server *server, const char *name, ast_websocket_callback callback), {return -1;});
  208. /*!
  209. * \brief Read a WebSocket frame and handle it
  210. *
  211. * \param session Pointer to the WebSocket session
  212. * \param payload Pointer to a char* which will be populated with a pointer to the payload if present
  213. * \param payload_len Pointer to a uint64_t which will be populated with the length of the payload if present
  214. * \param opcode Pointer to an enum which will be populated with the opcode of the frame
  215. * \param fragmented Pointer to an int which is set to 1 if payload is fragmented and 0 if not
  216. *
  217. * \retval -1 on error
  218. * \retval 0 on success
  219. *
  220. * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
  221. */
  222. AST_OPTIONAL_API(int, ast_websocket_read, (struct ast_websocket *session, char **payload, uint64_t *payload_len, enum ast_websocket_opcode *opcode, int *fragmented), { errno = ENOSYS; return -1;});
  223. /*!
  224. * \brief Read a WebSocket frame containing string data.
  225. *
  226. * \note The caller is responsible for freeing the output "buf".
  227. *
  228. * \param ws pointer to the websocket
  229. * \param buf string buffer to populate with data read from socket
  230. * \retval -1 on error
  231. * \retval number of bytes read on success
  232. *
  233. * \note Once an AST_WEBSOCKET_OPCODE_CLOSE opcode is received the socket will be closed
  234. */
  235. AST_OPTIONAL_API(int, ast_websocket_read_string,
  236. (struct ast_websocket *ws, char **buf),
  237. { errno = ENOSYS; return -1;});
  238. /*!
  239. * \brief Construct and transmit a WebSocket frame
  240. *
  241. * \param session Pointer to the WebSocket session
  242. * \param opcode WebSocket operation code to place in the frame
  243. * \param payload Optional pointer to a payload to add to the frame
  244. * \param payload_size Length of the payload (0 if no payload)
  245. *
  246. * \retval 0 if successfully written
  247. * \retval -1 if error occurred
  248. */
  249. AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size), { errno = ENOSYS; return -1;});
  250. /*!
  251. * \brief Construct and transmit a WebSocket frame containing string data.
  252. *
  253. * \param ws pointer to the websocket
  254. * \param buf string data to write to socket
  255. * \retval 0 if successfully written
  256. * \retval -1 if error occurred
  257. */
  258. AST_OPTIONAL_API(int, ast_websocket_write_string,
  259. (struct ast_websocket *ws, const char *buf),
  260. { errno = ENOSYS; return -1;});
  261. /*!
  262. * \brief Close a WebSocket session by sending a message with the CLOSE opcode and an optional code
  263. *
  264. * \param session Pointer to the WebSocket session
  265. * \param reason Reason code for closing the session as defined in the RFC
  266. *
  267. * \retval 0 if successfully written
  268. * \retval -1 if error occurred
  269. */
  270. AST_OPTIONAL_API(int, ast_websocket_close, (struct ast_websocket *session, uint16_t reason), { errno = ENOSYS; return -1;});
  271. /*!
  272. * \brief Enable multi-frame reconstruction up to a certain number of bytes
  273. *
  274. * \param session Pointer to the WebSocket session
  275. * \param bytes If a reconstructed payload exceeds the specified number of bytes the payload will be returned
  276. * and upon reception of the next multi-frame a new reconstructed payload will begin.
  277. */
  278. AST_OPTIONAL_API(void, ast_websocket_reconstruct_enable, (struct ast_websocket *session, size_t bytes), {return;});
  279. /*!
  280. * \brief Disable multi-frame reconstruction
  281. *
  282. * \param session Pointer to the WebSocket session
  283. *
  284. * \note If reconstruction is disabled each message that is part of a multi-frame message will be sent up to
  285. * the user when ast_websocket_read is called.
  286. */
  287. AST_OPTIONAL_API(void, ast_websocket_reconstruct_disable, (struct ast_websocket *session), {return;});
  288. /*!
  289. * \brief Increase the reference count for a WebSocket session
  290. *
  291. * \param session Pointer to the WebSocket session
  292. */
  293. AST_OPTIONAL_API(void, ast_websocket_ref, (struct ast_websocket *session), {return;});
  294. /*!
  295. * \brief Decrease the reference count for a WebSocket session
  296. *
  297. * \param session Pointer to the WebSocket session
  298. */
  299. AST_OPTIONAL_API(void, ast_websocket_unref, (struct ast_websocket *session), {return;});
  300. /*!
  301. * \brief Get the file descriptor for a WebSocket session.
  302. *
  303. * \retval file descriptor
  304. *
  305. * \note You must *not* directly read from or write to this file descriptor. It should only be used for polling.
  306. */
  307. AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
  308. /*!
  309. * \brief Get the remote address for a WebSocket connected session.
  310. *
  311. * \retval ast_sockaddr Remote address
  312. */
  313. AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct ast_websocket *session), {return NULL;});
  314. /*!
  315. * \brief Get the local address for a WebSocket connection session.
  316. *
  317. * \retval ast_sockaddr Local address
  318. *
  319. * \since 13.19.0
  320. */
  321. AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_local_address, (struct ast_websocket *session), {return NULL;});
  322. /*!
  323. * \brief Get whether the WebSocket session is using a secure transport or not.
  324. *
  325. * \retval 0 if unsecure
  326. * \retval 1 if secure
  327. */
  328. AST_OPTIONAL_API(int, ast_websocket_is_secure, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
  329. /*!
  330. * \brief Set the socket of a WebSocket session to be non-blocking.
  331. *
  332. * \retval 0 on success
  333. * \retval -1 on failure
  334. */
  335. AST_OPTIONAL_API(int, ast_websocket_set_nonblock, (struct ast_websocket *session), { errno = ENOSYS; return -1;});
  336. /*!
  337. * \brief Result code for a websocket client.
  338. */
  339. enum ast_websocket_result {
  340. WS_OK,
  341. WS_ALLOCATE_ERROR,
  342. WS_KEY_ERROR,
  343. WS_URI_PARSE_ERROR,
  344. WS_URI_RESOLVE_ERROR,
  345. WS_BAD_STATUS,
  346. WS_INVALID_RESPONSE,
  347. WS_BAD_REQUEST,
  348. WS_URL_NOT_FOUND,
  349. WS_HEADER_MISMATCH,
  350. WS_HEADER_MISSING,
  351. WS_NOT_SUPPORTED,
  352. WS_WRITE_ERROR,
  353. WS_CLIENT_START_ERROR,
  354. };
  355. /*!
  356. * \brief Create, and connect, a websocket client.
  357. *
  358. * \detail If the client websocket successfully connects, then the accepted protocol
  359. * can be checked via a call to ast_websocket_client_accept_protocol.
  360. *
  361. * \note While connecting this *will* block until a response is
  362. * received from the remote host.
  363. * \note Expected uri form: ws[s]://<address>[:port][/<path>] The address (can be a
  364. * host name) and port are parsed out and used to connect to the remote server.
  365. * If multiple IPs are returned during address resolution then the first one is
  366. * chosen.
  367. *
  368. * \param uri uri to connect to
  369. * \param protocols a comma separated string of supported protocols
  370. * \param tls_cfg secure websocket credentials
  371. * \param result result code set on client failure
  372. * \retval a client websocket.
  373. * \retval NULL if object could not be created or connected
  374. * \since 13
  375. */
  376. AST_OPTIONAL_API(struct ast_websocket *, ast_websocket_client_create,
  377. (const char *uri, const char *protocols,
  378. struct ast_tls_config *tls_cfg,
  379. enum ast_websocket_result *result), { return NULL;});
  380. /*!
  381. * \brief Retrieve the server accepted sub-protocol on the client.
  382. *
  383. * \param ws the websocket client
  384. * \retval the accepted client sub-protocol.
  385. * \since 13
  386. */
  387. AST_OPTIONAL_API(const char *, ast_websocket_client_accept_protocol,
  388. (struct ast_websocket *ws), { return NULL;});
  389. /*!
  390. * \brief Set the timeout on a non-blocking WebSocket session.
  391. *
  392. * \since 11.11.0
  393. * \since 12.4.0
  394. *
  395. * \retval 0 on success
  396. * \retval -1 on failure
  397. */
  398. AST_OPTIONAL_API(int, ast_websocket_set_timeout, (struct ast_websocket *session, int timeout), {return -1;});
  399. #endif