tport_stub_stun.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2006 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@CFILE tport_stub_stun.c Stub interface for STUN
  25. *
  26. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  27. *
  28. * @date Created: Fri Mar 31 12:31:36 EEST 2006
  29. */
  30. #include "config.h"
  31. #include <sofia-sip/stun.h>
  32. #include <sofia-sip/su_tagarg.h>
  33. #define TPORT_STUN_SERVER_T stun_mini_t
  34. #include "tport_internal.h"
  35. #include "sofia-sip/msg_buffer.h"
  36. #include "sofia-sip/msg_addr.h"
  37. #include <assert.h>
  38. #include <string.h>
  39. /* ---------------------------------------------------------------------- */
  40. /* Plugin pointer */
  41. tport_stun_server_vtable_t const *tport_stun_server_vtable = NULL;
  42. static
  43. tport_stun_server_t *vst_create(su_root_t *root, tagi_t const *tags)
  44. {
  45. return stun_mini_create();
  46. }
  47. static
  48. tport_stun_server_vtable_t const stun_mini_vtable =
  49. {
  50. sizeof stun_mini_vtable,
  51. vst_create,
  52. stun_mini_destroy,
  53. stun_mini_add_socket,
  54. stun_mini_remove_socket,
  55. stun_mini_request
  56. };
  57. /** Initialize stun server */
  58. int tport_init_stun_server(tport_master_t *mr, tagi_t const *tags)
  59. {
  60. tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
  61. if (vst == NULL)
  62. /* Nobody has plugged better server in, use miniserver */
  63. tport_stun_server_vtable = vst = &stun_mini_vtable;
  64. if (!vst)
  65. return 0;
  66. if (mr->mr_params->tpp_stun_server)
  67. mr->mr_stun_server = vst->vst_create(mr->mr_root, tags);
  68. mr->mr_master->tp_has_stun_server = mr->mr_stun_server != NULL;
  69. return 0;
  70. }
  71. /** Deinit stun server */
  72. void tport_deinit_stun_server(tport_master_t *mr)
  73. {
  74. tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
  75. if (mr->mr_stun_server) {
  76. assert(vst);
  77. vst->vst_destroy(mr->mr_stun_server), mr->mr_stun_server = NULL;
  78. }
  79. }
  80. int tport_stun_server_add_socket(tport_t *tp)
  81. {
  82. tport_stun_server_t *stun_server = tp->tp_master->mr_stun_server;
  83. if (tport_stun_server_vtable &&
  84. stun_server &&
  85. tp->tp_params->tpp_stun_server) {
  86. if (tport_stun_server_vtable->vst_add_socket(stun_server,
  87. tp->tp_socket) == 0)
  88. tp->tp_has_stun_server = 1;
  89. }
  90. return 0;
  91. }
  92. int tport_stun_server_remove_socket(tport_t *tp)
  93. {
  94. tport_stun_server_t *stun_server = tp->tp_master->mr_stun_server;
  95. if (tport_stun_server_vtable &&
  96. stun_server &&
  97. tp->tp_has_stun_server) {
  98. tport_stun_server_vtable->vst_remove_socket(stun_server, tp->tp_socket);
  99. tp->tp_has_stun_server = 0;
  100. }
  101. return 0;
  102. }
  103. /**Process stun messagee.
  104. *
  105. * @retval -1 error
  106. * @retval 3 stun message received, ignore
  107. */
  108. int tport_recv_stun_dgram(tport_t const *self,
  109. msg_t **in_out_msg,
  110. su_sockaddr_t *from,
  111. socklen_t fromlen)
  112. {
  113. int retval = -1;
  114. msg_t *msg;
  115. uint8_t *request;
  116. size_t n;
  117. assert(in_out_msg); assert(*in_out_msg);
  118. msg = *in_out_msg;
  119. request = msg_buf_committed_data(msg);
  120. n = msg_buf_committed(msg);
  121. if (n < 20 || request == NULL) {
  122. su_seterrno(EBADMSG);
  123. retval = -1;
  124. }
  125. else if (request[0] == 1) {
  126. /* This is a response. */
  127. if (self->tp_pri->pri_vtable->vtp_stun_response) {
  128. if (self->tp_pri->pri_vtable->vtp_stun_response(self, request, n,
  129. from, fromlen) < 0)
  130. retval = -1;
  131. }
  132. else
  133. SU_DEBUG_7(("tport(%p): recv_stun_dgram(): "
  134. "ignoring request with "MOD_ZU" bytes\n", (void *)self, n));
  135. }
  136. else if (request[0] == 0 && self->tp_master->mr_stun_server) {
  137. tport_stun_server_vtable_t const *vst = tport_stun_server_vtable;
  138. vst->vst_request(self->tp_master->mr_stun_server,
  139. self->tp_socket, request, n,
  140. (void *)from, fromlen);
  141. }
  142. else if (request[0] == 0) {
  143. /* Respond to stun request with a simple error message. */
  144. int const status = 600;
  145. char const *error = "Not Implemented";
  146. size_t unpadded = strlen(error);
  147. uint16_t elen;
  148. uint8_t dgram[128];
  149. if (unpadded > sizeof(dgram) - 28)
  150. unpadded = sizeof(dgram) - 28;
  151. elen = (uint16_t)unpadded;
  152. elen = (elen + 3) & -4; /* Round up to 4 */
  153. SU_DEBUG_7(("tport(%p): recv_stun_dgram(): "
  154. "responding %u %s\n", (void *)self, status, error));
  155. /*
  156. 0 1 2 3
  157. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  158. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  159. | STUN Message Type | Message Length |
  160. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  161. |
  162. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  163. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  164. Transaction ID
  165. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  166. |
  167. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  168. */
  169. #define set16(b, offset, value) \
  170. (((b)[(offset) + 0] = ((value) >> 8) & 255), \
  171. ((b)[(offset) + 1] = (value) & 255))
  172. /* Respond to request */
  173. dgram[0] = 1; /* Mark as response */
  174. dgram[1] = request[1] | 0x10; /* Mark as error response */
  175. set16(dgram, 2, elen + 4 + 4);
  176. /* TransactionID is there at bytes 4..19 */
  177. memcpy(dgram + 4, request + 4, 16);
  178. /*
  179. TLV At 20:
  180. 0 1 2 3
  181. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  182. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  183. | Type | Length |
  184. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  185. */
  186. set16(dgram, 20, 0x0009); /* ERROR-CODE */
  187. set16(dgram, 22, elen + 4);
  188. /*
  189. ERROR-CODE at 24:
  190. 0 1 2 3
  191. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  192. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  193. | 0 |Class| Number |
  194. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  195. | Reason Phrase (variable) ..
  196. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  197. */
  198. dgram[24] = 0, dgram[25] = 0;
  199. dgram[26] = status / 100, dgram[27] = status % 100;
  200. memcpy(dgram + 28, error, unpadded);
  201. memset(dgram + 28 + unpadded, 0, elen - unpadded);
  202. sendto(self->tp_socket, (void *)dgram, 28 + elen, 0,
  203. (void *)from, fromlen);
  204. #undef set16
  205. }
  206. else {
  207. SU_DEBUG_0(("tport(%p): recv_stun_dgram(): internal error\n", (void *)self));
  208. su_seterrno(EBADMSG);
  209. retval = -1;
  210. }
  211. *in_out_msg = NULL, msg_destroy(msg);
  212. return retval;
  213. }
  214. /** Activate (STUN) keepalive for transport */
  215. int tport_keepalive(tport_t *tp, su_addrinfo_t const *ai,
  216. tag_type_t tag, tag_value_t value, ...)
  217. {
  218. if (tp && tp->tp_pri && tp->tp_pri->pri_vtable->vtp_keepalive) {
  219. int retval;
  220. ta_list ta;
  221. ta_start(ta, tag, value);
  222. retval = tp->tp_pri->pri_vtable->vtp_keepalive(tp, ai, ta_args(ta));
  223. ta_end(ta);
  224. return retval;
  225. }
  226. return -1;
  227. }
  228. /* ---------------------------------------------------------------------- */
  229. /* Plugin interface */
  230. /** Plug in stun server.
  231. *
  232. * @note This function @b must be called before any transport is initialized.
  233. */
  234. int tport_plug_in_stun_server(tport_stun_server_vtable_t const *vtable)
  235. {
  236. if (!vtable)
  237. return 0;
  238. if (vtable->vst_size <= (int)sizeof *vtable)
  239. return su_seterrno(EINVAL);
  240. if (!vtable->vst_create ||
  241. !vtable->vst_destroy ||
  242. !vtable->vst_add_socket ||
  243. !vtable->vst_remove_socket ||
  244. !vtable->vst_request)
  245. return su_seterrno(EFAULT);
  246. if (tport_stun_server_vtable)
  247. return su_seterrno(EEXIST);
  248. tport_stun_server_vtable = vtable;
  249. return 0;
  250. }