rvcturn.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // rvcturn.cpp : 定义 DLL 应用程序的导出函数。
  2. //
  3. #include "stdafx.h"
  4. #include "rvcturn.h"
  5. static struct global
  6. {
  7. pj_caching_pool cp;
  8. pj_pool_t *pool;
  9. pj_stun_config stun_config;
  10. pj_thread_t *thread;
  11. pj_bool_t quit;
  12. rvc_peer_t peer[RVC_TURN_PORT_NUM];
  13. } g_param;
  14. static void rvc_stun_callback(rvc_turn_callback_t* pcallback, int* ioption, void* pstuninfo, void* pdata)
  15. {
  16. if (NULL != pcallback) {
  17. if (NULL != pcallback->status_callback) {
  18. pcallback->status_callback(pcallback->user_data, ioption, pstuninfo, pdata);
  19. }
  20. }
  21. }
  22. static void rvc_log(rvc_turn_callback_t* pcallback, const char* fmt, ...)
  23. {
  24. if (NULL != pcallback) {
  25. if (NULL != pcallback->debug) {
  26. va_list arg;
  27. va_start(arg, fmt);
  28. pcallback->debug(pcallback->user_data, fmt, arg);
  29. va_end(arg);
  30. }
  31. }
  32. }
  33. static void rvcturn_log(rvc_turn_callback_t* pCallback, const char *title, pj_status_t status)
  34. {
  35. char errmsg[PJ_ERR_MSG_SIZE] = {0};
  36. pj_strerror(status, errmsg, sizeof(errmsg));
  37. rvc_log(pCallback, "%s: %s", title, errmsg);
  38. }
  39. static int worker_thread(void *usr_data)
  40. {
  41. rvc_turn_callback_t* pcallback = (rvc_turn_callback_t*)usr_data;
  42. while (!g_param.quit) {
  43. const pj_time_val delay = { 0, 10 };
  44. /* Poll ioqueue for the TURN client */
  45. pj_ioqueue_poll(g_param.stun_config.ioqueue, &delay);
  46. /* Poll the timer heap */
  47. pj_timer_heap_poll(g_param.stun_config.timer_heap, NULL);
  48. }
  49. rvc_log(pcallback, "%s", "worker_thread exit!");
  50. return 0;
  51. }
  52. static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock,
  53. pj_stun_sock_op op,
  54. pj_status_t status)
  55. {
  56. rvc_peer_t *peer = (rvc_peer_t*)pj_stun_sock_get_user_data(stun_sock);
  57. if (status == PJ_SUCCESS) {
  58. rvc_log(&peer->stun_status_cb, "peer%d: %s(%d) success", peer - g_param.peer, pj_stun_sock_op_name(op), op);
  59. }
  60. else {
  61. char errmsg[PJ_ERR_MSG_SIZE] = { 0 };
  62. pj_strerror(status, errmsg, sizeof(errmsg));
  63. rvc_log(&peer->stun_status_cb, "peer%d: %s error: %s", peer - g_param.peer, pj_stun_sock_op_name(op), errmsg);
  64. return PJ_FALSE;
  65. }
  66. if (op == PJ_STUN_SOCK_BINDING_OP || op == PJ_STUN_SOCK_KEEP_ALIVE_OP) {
  67. pj_stun_sock_info info;
  68. int cmp;
  69. pj_stun_sock_get_info(stun_sock, &info);
  70. cmp = pj_sockaddr_cmp(&info.mapped_addr, &peer->mapped_addr);
  71. if (cmp) {
  72. rvc_stun_info_t tinfo = { 0 };
  73. pj_sockaddr_cp(&peer->mapped_addr, &info.mapped_addr);
  74. pj_sockaddr_print(&peer->mapped_addr, tinfo.strmappedip, sizeof(tinfo.strmappedip), 2);
  75. tinfo.imappedport = pj_sockaddr_get_port(&peer->mapped_addr);
  76. pj_sockaddr_cp(&peer->bound_addr, &info.bound_addr);
  77. pj_sockaddr_print(&peer->bound_addr, tinfo.strboundip, sizeof(tinfo.strboundip), 2);
  78. tinfo.iboundport = pj_sockaddr_get_port(&peer->bound_addr);
  79. pj_sockaddr_cp(&peer->srv_addr, &info.srv_addr);
  80. pj_sockaddr_print(&peer->srv_addr, tinfo.strservip, sizeof(tinfo.strservip), 2);
  81. tinfo.iservport = pj_sockaddr_get_port(&peer->srv_addr);
  82. int ioption = op;
  83. rvc_stun_callback(&peer->stun_status_cb, &ioption, &tinfo, NULL);
  84. rvc_log(&peer->stun_status_cb, "peer%d: local bound address is %s:%d", peer - g_param.peer, tinfo.strboundip, tinfo.iboundport);
  85. rvc_log(&peer->stun_status_cb, "peer%d: STUN server address is %s:%d", peer - g_param.peer, tinfo.strservip, tinfo.iservport);
  86. rvc_log(&peer->stun_status_cb, "peer%d: STUN mapped address is %s:%d", peer - g_param.peer, tinfo.strmappedip, tinfo.imappedport);
  87. }
  88. }
  89. return PJ_TRUE;
  90. }
  91. static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
  92. void *pkt,
  93. unsigned pkt_len,
  94. const pj_sockaddr_t *src_addr,
  95. unsigned addr_len)
  96. {
  97. rvc_peer_t *peer = (rvc_peer_t*)pj_stun_sock_get_user_data(stun_sock);
  98. char straddr[PJ_INET6_ADDRSTRLEN + 10];
  99. ((char*)pkt)[pkt_len] = '\0';
  100. pj_sockaddr_print(src_addr, straddr, sizeof(straddr), 3);
  101. rvc_log(&peer->stun_status_cb, "peer%d: received %d bytes data from %s: %s", peer - g_param.peer, pkt_len, straddr, (char*)pkt);
  102. return PJ_TRUE;
  103. }
  104. #define RVC_CHECK(expr) status=expr; \
  105. if (status!=PJ_SUCCESS) { \
  106. rvcturn_log(pcallback, #expr, status); \
  107. return status; \
  108. }
  109. static int init(rvc_turn_param_t* pparam, rvc_turn_callback_t* pcallback)
  110. {
  111. pj_status_t status = PJ_EINVAL;
  112. if (NULL == pparam || NULL == pcallback) {
  113. return status;
  114. }
  115. RVC_CHECK(pj_init());
  116. RVC_CHECK(pjlib_util_init());
  117. RVC_CHECK(pjnath_init());
  118. /* Check that server is specified */
  119. if (!pparam->pstrserv && !pparam->pdefaultserv) {
  120. rvc_log(pcallback, "%s", "Error: server must be specified.");
  121. return PJ_EINVAL;
  122. }
  123. pj_caching_pool_init(&g_param.cp, &pj_pool_factory_default_policy, 0);
  124. g_param.quit = 0;
  125. g_param.pool = pj_pool_create(&g_param.cp.factory, "main", 1000, 1000, NULL);
  126. /* Init global STUN config */
  127. pj_stun_config_init(&g_param.stun_config, &g_param.cp.factory, 0, NULL, NULL);
  128. /* Create global timer heap */
  129. RVC_CHECK(pj_timer_heap_create(g_param.pool, 1000, &g_param.stun_config.timer_heap));
  130. /* Create global ioqueue */
  131. RVC_CHECK(pj_ioqueue_create(g_param.pool, 16, &g_param.stun_config.ioqueue));
  132. /*
  133. * Create peers
  134. */
  135. for (int i = 0; i<(int)PJ_ARRAY_SIZE(g_param.peer); ++i) {
  136. pj_stun_sock_cb stun_sock_cb;
  137. char name[] = "rvcpeer0";
  138. pj_uint16_t port;
  139. pj_stun_sock_cfg ss_cfg;
  140. pj_str_t server;
  141. pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
  142. stun_sock_cb.on_rx_data = &stun_sock_on_rx_data;
  143. stun_sock_cb.on_status = &stun_sock_on_status;
  144. //g_param.peer[i].mapped_addr.addr.sa_family = pj_AF_INET();
  145. pj_sockaddr_init(pj_AF_INET(), &g_param.peer[i].mapped_addr, NULL, 0);
  146. memcpy(&g_param.peer[i].stun_status_cb, pcallback, sizeof(rvc_turn_callback_t));
  147. pj_stun_sock_cfg_default(&ss_cfg);
  148. pj_sockaddr_init(pj_AF_INET(), &ss_cfg.bound_addr, NULL, pparam->ilocalport[i]);
  149. if (pparam->bkeepalive) {
  150. /* make reading the log easier */
  151. ss_cfg.ka_interval = pparam->ikainterval;
  152. }
  153. name[strlen(name) - 1] = '0' + i;
  154. status = pj_stun_sock_create(&g_param.stun_config, name, pj_AF_INET(),
  155. &stun_sock_cb, &ss_cfg,
  156. &g_param.peer[i], &g_param.peer[i].stun_sock);
  157. if (status != PJ_SUCCESS) {
  158. rvcturn_log(pcallback, "pj_stun_sock_create()", status);
  159. return status;
  160. }
  161. if (pparam->pstrserv) {
  162. server = pj_str(pparam->pstrserv);
  163. port = (pj_uint16_t)(pparam->pserport ? atoi(pparam->pserport) : PJ_STUN_PORT);
  164. }
  165. else {
  166. server = pj_str(pparam->pdefaultserv);
  167. port = PJ_STUN_PORT;
  168. }
  169. status = pj_stun_sock_start(g_param.peer[i].stun_sock, &server, port, NULL);
  170. rvcturn_log(pcallback, "pj_stun_sock_start()", status);
  171. if (status != PJ_SUCCESS) {
  172. return status;
  173. }
  174. }
  175. /* Start the worker thread */
  176. RVC_CHECK(pj_thread_create(g_param.pool, "stun", &worker_thread, pcallback, 0, 0, &g_param.thread));
  177. return PJ_SUCCESS;
  178. }
  179. static int client_shutdown()
  180. {
  181. if (g_param.thread) {
  182. g_param.quit = 1;
  183. pj_thread_join(g_param.thread);
  184. pj_thread_destroy(g_param.thread);
  185. g_param.thread = NULL;
  186. }
  187. rvc_log(&g_param.peer[0].stun_status_cb, "%s", "pj_thread_join success!");
  188. for (unsigned i = 0; i<PJ_ARRAY_SIZE(g_param.peer); ++i) {
  189. if (g_param.peer[i].stun_sock) {
  190. pj_stun_sock_destroy(g_param.peer[i].stun_sock);
  191. g_param.peer[i].stun_sock = NULL;
  192. }
  193. }
  194. rvc_log(&g_param.peer[0].stun_status_cb, "%s", "pj_stun_sock_destroy success!");
  195. if (g_param.stun_config.timer_heap) {
  196. pj_timer_heap_destroy(g_param.stun_config.timer_heap);
  197. g_param.stun_config.timer_heap = NULL;
  198. }
  199. rvc_log(&g_param.peer[0].stun_status_cb, "%s", "pj_timer_heap_destroy success!");
  200. if (g_param.stun_config.ioqueue) {
  201. pj_ioqueue_destroy(g_param.stun_config.ioqueue);
  202. g_param.stun_config.ioqueue = NULL;
  203. }
  204. rvc_log(&g_param.peer[0].stun_status_cb, "%s", "pj_ioqueue_destroy success!");
  205. if (g_param.pool) {
  206. pj_pool_release(g_param.pool);
  207. g_param.pool = NULL;
  208. }
  209. pj_pool_factory_dump(&g_param.cp.factory, PJ_TRUE);
  210. pj_caching_pool_destroy(&g_param.cp);
  211. return PJ_SUCCESS;
  212. }
  213. int start_turn_connect(rvc_turn_param_t* pparam, rvc_turn_callback_t* pcallback)
  214. {
  215. int iret = -1;
  216. iret = init(pparam, pcallback);
  217. return iret;
  218. }
  219. int stop_turn_connect()
  220. {
  221. int iret = -1;
  222. iret = client_shutdown();
  223. return iret;
  224. }