Changeset 2864 for pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
- Timestamp:
- Aug 12, 2009 11:03:23 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
r2859 r2864 25 25 26 26 27 /* Internal prototypes */ 28 static void resolve_stun_entry(pjsua_stun_resolve *sess); 29 30 27 31 /* PJSUA application instance. */ 28 32 struct pjsua_data pjsua_var; … … 60 64 pjsua_var.stun_status = PJ_EUNKNOWN; 61 65 pjsua_var.nat_status = PJ_EPENDING; 66 pj_list_init(&pjsua_var.stun_res); 62 67 } 63 68 … … 93 98 cfg->thread_cnt = 1; 94 99 cfg->nat_type_in_sdp = 1; 100 cfg->stun_ignore_failure = PJ_TRUE; 95 101 cfg->force_lr = PJ_TRUE; 96 102 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) … … 123 129 pj_strdup_with_null(pool, &dst->stun_domain, &src->stun_domain); 124 130 pj_strdup_with_null(pool, &dst->stun_host, &src->stun_host); 131 132 for (i=0; i<src->stun_srv_cnt; ++i) { 133 pj_strdup_with_null(pool, &dst->stun_srv[i], &src->stun_srv[i]); 134 } 125 135 } 126 136 … … 762 772 goto on_error; 763 773 774 /* Convert deprecated STUN settings */ 775 if (pjsua_var.ua_cfg.stun_srv_cnt==0) { 776 if (pjsua_var.ua_cfg.stun_domain.slen) { 777 pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] = 778 pjsua_var.ua_cfg.stun_domain; 779 } 780 if (pjsua_var.ua_cfg.stun_host.slen) { 781 pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] = 782 pjsua_var.ua_cfg.stun_host; 783 } 784 } 764 785 765 786 /* Start resolving STUN server */ 766 767 status = pjsua_resolve_stun_server(PJ_FALSE); 787 status = resolve_stun_server(PJ_FALSE); 768 788 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 769 789 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 860 880 } 861 881 862 863 /* 864 * Callback function to receive notification from the resolver 865 * when the resolution process completes. 866 */ 867 static void stun_dns_srv_resolver_cb(void *user_data, 868 pj_status_t status, 869 const pj_dns_srv_record *rec) 870 { 882 /* Internal function to destroy STUN resolution session 883 * (pj_stun_resolve). 884 */ 885 static void destroy_stun_resolve(pjsua_stun_resolve *sess) 886 { 887 PJSUA_LOCK(); 888 pj_list_erase(sess); 889 PJSUA_UNLOCK(); 890 891 pj_assert(sess->stun_sock==NULL); 892 pj_pool_release(sess->pool); 893 } 894 895 /* This is the internal function to be called when STUN resolution 896 * session (pj_stun_resolve) has completed. 897 */ 898 static void stun_resolve_complete(pjsua_stun_resolve *sess) 899 { 900 pj_stun_resolve_result result; 901 902 pj_bzero(&result, sizeof(result)); 903 result.token = sess->token; 904 result.status = sess->status; 905 result.name = sess->srv[sess->idx]; 906 pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr)); 907 908 if (result.status == PJ_SUCCESS) { 909 char addr[PJ_INET6_ADDRSTRLEN+10]; 910 pj_sockaddr_print(&result.addr, addr, sizeof(addr), 3); 911 PJ_LOG(4,(THIS_FILE, 912 "STUN resolution success, using %.*s, address is %s", 913 (int)sess->srv[sess->idx].slen, 914 sess->srv[sess->idx].ptr, 915 addr)); 916 } else { 917 char errmsg[PJ_ERR_MSG_SIZE]; 918 pj_strerror(result.status, errmsg, sizeof(errmsg)); 919 PJ_LOG(1,(THIS_FILE, "STUN resolution failed: %s", errmsg)); 920 } 921 922 sess->cb(&result); 923 924 if (!sess->blocking) { 925 destroy_stun_resolve(sess); 926 } 927 } 928 929 /* This is the callback called by the STUN socket (pj_stun_sock) 930 * to report it's state. We use this as part of testing the 931 * STUN server. 932 */ 933 static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock, 934 pj_stun_sock_op op, 935 pj_status_t status) 936 { 937 pjsua_stun_resolve *sess; 938 939 sess = pj_stun_sock_get_user_data(stun_sock); 940 pj_assert(stun_sock == sess->stun_sock); 941 942 if (status != PJ_SUCCESS) { 943 char errmsg[PJ_ERR_MSG_SIZE]; 944 pj_strerror(status, errmsg, sizeof(errmsg)); 945 946 PJ_LOG(4,(THIS_FILE, "STUN resolution for %.*s failed: %s", 947 (int)sess->srv[sess->idx].slen, 948 sess->srv[sess->idx].ptr, errmsg)); 949 950 sess->status = status; 951 952 pj_stun_sock_destroy(stun_sock); 953 sess->stun_sock = NULL; 954 955 ++sess->idx; 956 resolve_stun_entry(sess); 957 958 return PJ_FALSE; 959 960 } else if (op == PJ_STUN_SOCK_BINDING_OP) { 961 pj_stun_sock_info ssi; 962 963 pj_stun_sock_get_info(stun_sock, &ssi); 964 pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr)); 965 966 sess->status = PJ_SUCCESS; 967 pj_stun_sock_destroy(stun_sock); 968 sess->stun_sock = NULL; 969 970 stun_resolve_complete(sess); 971 972 return PJ_FALSE; 973 974 } else 975 return PJ_TRUE; 976 977 } 978 979 /* This is an internal function to resolve and test current 980 * server entry in pj_stun_resolve session. It is called by 981 * pjsua_resolve_stun_servers() and test_stun_on_status() above 982 */ 983 static void resolve_stun_entry(pjsua_stun_resolve *sess) 984 { 985 /* Loop while we have entry to try */ 986 for (; sess->idx < sess->count; ++sess->idx) { 987 const int af = pj_AF_INET(); 988 pj_str_t hostpart; 989 pj_uint16_t port; 990 pj_stun_sock_cb stun_sock_cb; 991 992 pj_assert(sess->idx < sess->count); 993 994 /* Parse the server entry into host:port */ 995 sess->status = pj_sockaddr_parse2(af, 0, &sess->srv[sess->idx], 996 &hostpart, &port, NULL); 997 if (sess->status != PJ_SUCCESS) { 998 PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %.*s", 999 (int)sess->srv[sess->idx].slen, 1000 sess->srv[sess->idx].ptr)); 1001 continue; 1002 } 1003 1004 /* Use default port if not specified */ 1005 if (port == 0) 1006 port = PJ_STUN_PORT; 1007 1008 pj_assert(sess->stun_sock == NULL); 1009 1010 PJ_LOG(4,(THIS_FILE, "Trying STUN server %.*s (%d of %d)..", 1011 (int)sess->srv[sess->idx].slen, 1012 sess->srv[sess->idx].ptr, 1013 sess->idx+1, sess->count)); 1014 1015 /* Use STUN_sock to test this entry */ 1016 pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 1017 stun_sock_cb.on_status = &test_stun_on_status; 1018 sess->status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve", 1019 pj_AF_INET(), &stun_sock_cb, 1020 NULL, sess, &sess->stun_sock); 1021 if (sess->status != PJ_SUCCESS) { 1022 char errmsg[PJ_ERR_MSG_SIZE]; 1023 pj_strerror(sess->status, errmsg, sizeof(errmsg)); 1024 PJ_LOG(4,(THIS_FILE, 1025 "Error creating STUN socket for %.*s: %s", 1026 (int)sess->srv[sess->idx].slen, 1027 sess->srv[sess->idx].ptr, errmsg)); 1028 1029 continue; 1030 } 1031 1032 sess->status = pj_stun_sock_start(sess->stun_sock, &hostpart, 1033 port, pjsua_var.resolver); 1034 if (sess->status != PJ_SUCCESS) { 1035 char errmsg[PJ_ERR_MSG_SIZE]; 1036 pj_strerror(sess->status, errmsg, sizeof(errmsg)); 1037 PJ_LOG(4,(THIS_FILE, 1038 "Error starting STUN socket for %.*s: %s", 1039 (int)sess->srv[sess->idx].slen, 1040 sess->srv[sess->idx].ptr, errmsg)); 1041 1042 pj_stun_sock_destroy(sess->stun_sock); 1043 sess->stun_sock = NULL; 1044 continue; 1045 } 1046 1047 /* Done for now, testing will resume/complete asynchronously in 1048 * stun_sock_cb() 1049 */ 1050 return; 1051 } 1052 1053 if (sess->idx >= sess->count) { 1054 /* No more entries to try */ 1055 PJ_ASSERT_ON_FAIL(sess->status != PJ_SUCCESS, 1056 sess->status = PJ_EUNKNOWN); 1057 stun_resolve_complete(sess); 1058 } 1059 } 1060 1061 1062 /* 1063 * Resolve STUN server. 1064 */ 1065 PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count, 1066 pj_str_t srv[], 1067 pj_bool_t wait, 1068 void *token, 1069 pj_stun_resolve_cb cb) 1070 { 1071 pj_pool_t *pool; 1072 pjsua_stun_resolve *sess; 1073 pj_status_t status; 871 1074 unsigned i; 872 1075 873 PJ_UNUSED_ARG(user_data); 874 875 pjsua_var.stun_status = status; 876 877 if (status != PJ_SUCCESS) { 878 /* DNS SRV resolution failed. If stun_host is specified, resolve 879 * it with gethostbyname() 880 */ 881 if (pjsua_var.ua_cfg.stun_host.slen) { 882 pjsua_var.stun_status = 883 pj_sockaddr_parse(pj_AF_INET(), 0, 884 &pjsua_var.ua_cfg.stun_host, 885 &pjsua_var.stun_srv); 886 if (pjsua_var.stun_status != PJ_SUCCESS) { 887 pjsua_perror(THIS_FILE, "Invalid STUN server", 888 pjsua_var.stun_status); 889 } else { 890 if (pj_sockaddr_get_port(&pjsua_var.stun_srv)==0) 891 pj_sockaddr_set_port(&pjsua_var.stun_srv, 3478); 892 893 PJ_LOG(3,(THIS_FILE, 894 "STUN server %.*s resolved, address is %s:%d", 895 (int)pjsua_var.ua_cfg.stun_host.slen, 896 pjsua_var.ua_cfg.stun_host.ptr, 897 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr), 898 (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port))); 1076 PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL); 1077 1078 pool = pjsua_pool_create("stunres", 256, 256); 1079 if (!pool) 1080 return PJ_ENOMEM; 1081 1082 sess = PJ_POOL_ZALLOC_T(pool, pjsua_stun_resolve); 1083 sess->pool = pool; 1084 sess->token = token; 1085 sess->cb = cb; 1086 sess->count = count; 1087 sess->blocking = wait; 1088 sess->status = PJ_EPENDING; 1089 sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t)); 1090 for (i=0; i<count; ++i) { 1091 pj_strdup(pool, &sess->srv[i], &srv[i]); 1092 } 1093 1094 PJSUA_LOCK(); 1095 pj_list_push_back(&pjsua_var.stun_res, sess); 1096 PJSUA_UNLOCK(); 1097 1098 resolve_stun_entry(sess); 1099 1100 if (!wait) 1101 return PJ_SUCCESS; 1102 1103 while (sess->status == PJ_EPENDING) { 1104 pjsua_handle_events(50); 1105 } 1106 1107 status = sess->status; 1108 destroy_stun_resolve(sess); 1109 1110 return status; 1111 } 1112 1113 /* 1114 * Cancel pending STUN resolution. 1115 */ 1116 PJ_DEF(pj_status_t) pjsua_cancel_stun_resolution( void *token, 1117 pj_bool_t notify_cb) 1118 { 1119 pjsua_stun_resolve *sess; 1120 unsigned cancelled_count = 0; 1121 1122 PJSUA_LOCK(); 1123 sess = pjsua_var.stun_res.next; 1124 while (sess != &pjsua_var.stun_res) { 1125 pjsua_stun_resolve *next = sess->next; 1126 1127 if (sess->token == token) { 1128 if (notify_cb) { 1129 pj_stun_resolve_result result; 1130 1131 pj_bzero(&result, sizeof(result)); 1132 result.token = token; 1133 result.status = PJ_ECANCELLED; 1134 1135 sess->cb(&result); 899 1136 } 900 } else { 901 char errmsg[PJ_ERR_MSG_SIZE]; 902 903 pj_strerror(status, errmsg, sizeof(errmsg)); 904 PJ_LOG(1,(THIS_FILE, 905 "DNS SRV resolution failed for STUN server %.*s: %s", 906 (int)pjsua_var.ua_cfg.stun_domain.slen, 907 pjsua_var.ua_cfg.stun_domain.ptr, 908 errmsg)); 909 } 910 return; 911 } 912 913 pj_assert(rec->count != 0 && rec->entry[0].server.addr_count != 0); 914 pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 915 rec->entry[0].port); 916 pjsua_var.stun_srv.ipv4.sin_addr.s_addr = 917 rec->entry[0].server.addr[0].s_addr; 918 919 PJ_LOG(3,(THIS_FILE, "_stun._udp.%.*s resolved, found %d entry(s):", 920 (int)pjsua_var.ua_cfg.stun_domain.slen, 921 pjsua_var.ua_cfg.stun_domain.ptr, 922 rec->count)); 923 924 for (i=0; i<rec->count; ++i) { 925 PJ_LOG(3,(THIS_FILE, 926 " %d: prio=%d, weight=%d %s:%d", 927 i, rec->entry[i].priority, rec->entry[i].weight, 928 pj_inet_ntoa(rec->entry[i].server.addr[0]), 929 (int)rec->entry[i].port)); 930 } 931 1137 1138 destroy_stun_resolve(sess); 1139 ++cancelled_count; 1140 } 1141 1142 sess = next; 1143 } 1144 PJSUA_UNLOCK(); 1145 1146 return cancelled_count ? PJ_SUCCESS : PJ_ENOTFOUND; 1147 } 1148 1149 static void internal_stun_resolve_cb(const pj_stun_resolve_result *result) 1150 { 1151 pjsua_var.stun_status = result->status; 1152 if (result->status == PJ_SUCCESS) { 1153 pj_memcpy(&pjsua_var.stun_srv, &result->addr, sizeof(result->addr)); 1154 } 932 1155 } 933 1156 … … 935 1158 * Resolve STUN server. 936 1159 */ 937 pj_status_t pjsua_resolve_stun_server(pj_bool_t wait)1160 pj_status_t resolve_stun_server(pj_bool_t wait) 938 1161 { 939 1162 if (pjsua_var.stun_status == PJ_EUNKNOWN) { 1163 pj_status_t status; 1164 940 1165 /* Initialize STUN configuration */ 941 1166 pj_stun_config_init(&pjsua_var.stun_cfg, &pjsua_var.cp.factory, 0, … … 944 1169 945 1170 /* Start STUN server resolution */ 946 947 pjsua_var.stun_status = PJ_EPENDING; 948 949 /* If stun_domain is specified, resolve STUN servers with DNS 950 * SRV resolution. 951 */ 952 if (pjsua_var.ua_cfg.stun_domain.slen) { 953 pj_str_t res_type; 954 pj_status_t status; 955 956 /* Fail if resolver is not configured */ 957 if (pjsua_var.resolver == NULL) { 958 PJ_LOG(1,(THIS_FILE, "Nameserver must be configured when " 959 "stun_domain is specified")); 960 pjsua_var.stun_status = PJLIB_UTIL_EDNSNONS; 961 return PJLIB_UTIL_EDNSNONS; 1171 if (pjsua_var.ua_cfg.stun_srv_cnt) { 1172 pjsua_var.stun_status = PJ_EPENDING; 1173 status = pjsua_resolve_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt, 1174 pjsua_var.ua_cfg.stun_srv, 1175 wait, NULL, 1176 &internal_stun_resolve_cb); 1177 if (wait || status != PJ_SUCCESS) { 1178 pjsua_var.stun_status = status; 962 1179 } 963 res_type = pj_str("_stun._udp"); 964 status = 965 pj_dns_srv_resolve(&pjsua_var.ua_cfg.stun_domain, &res_type, 966 3478, pjsua_var.pool, pjsua_var.resolver, 967 0, NULL, &stun_dns_srv_resolver_cb, NULL); 968 if (status != PJ_SUCCESS) { 969 pjsua_perror(THIS_FILE, "Error starting DNS SRV resolution", 970 pjsua_var.stun_status); 971 pjsua_var.stun_status = status; 972 return pjsua_var.stun_status; 973 } else { 974 pjsua_var.stun_status = PJ_EPENDING; 975 } 976 } 977 /* Otherwise if stun_host is specified, resolve STUN server with 978 * gethostbyname(). 979 */ 980 else if (pjsua_var.ua_cfg.stun_host.slen) { 981 pjsua_var.stun_status = 982 pj_sockaddr_parse(pj_AF_INET(), 0, 983 &pjsua_var.ua_cfg.stun_host, 984 &pjsua_var.stun_srv); 985 if (pjsua_var.stun_status != PJ_SUCCESS) { 986 pjsua_perror(THIS_FILE, "Invalid STUN server", 987 pjsua_var.stun_status); 988 return pjsua_var.stun_status; 989 } 990 991 if (pj_sockaddr_get_port(&pjsua_var.stun_srv)==0) 992 pj_sockaddr_set_port(&pjsua_var.stun_srv, 3478); 993 994 PJ_LOG(3,(THIS_FILE, 995 "STUN server %.*s resolved, address is %s:%d", 996 (int)pjsua_var.ua_cfg.stun_host.slen, 997 pjsua_var.ua_cfg.stun_host.ptr, 998 pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr), 999 (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port))); 1000 1001 } 1002 /* Otherwise disable STUN. */ 1003 else { 1180 } else { 1004 1181 pjsua_var.stun_status = PJ_SUCCESS; 1005 1182 } 1006 1007 1008 return pjsua_var.stun_status;1009 1183 1010 1184 } else if (pjsua_var.stun_status == PJ_EPENDING) { … … 1016 1190 pjsua_handle_events(10); 1017 1191 } 1018 1019 return pjsua_var.stun_status; 1020 1021 } else { 1022 /* STUN server has been resolved, return the status */ 1023 return pjsua_var.stun_status; 1024 } 1192 } 1193 1194 if (pjsua_var.stun_status != PJ_EPENDING && 1195 pjsua_var.stun_status != PJ_SUCCESS && 1196 pjsua_var.ua_cfg.stun_ignore_failure) 1197 { 1198 PJ_LOG(2,(THIS_FILE, 1199 "Ignoring STUN resolution failure (by setting)")); 1200 pjsua_var.stun_status = PJ_SUCCESS; 1201 } 1202 1203 return pjsua_var.stun_status; 1025 1204 } 1026 1205 … … 1075 1254 /* Destroy endpoint. */ 1076 1255 if (pjsua_var.endpt) { 1256 1257 /* Terminate any pending STUN resolution */ 1258 if (!pj_list_empty(&pjsua_var.stun_res)) { 1259 pjsua_stun_resolve *sess = pjsua_var.stun_res.next; 1260 while (sess != &pjsua_var.stun_res) { 1261 pjsua_stun_resolve *next = sess->next; 1262 destroy_stun_resolve(sess); 1263 sess = next; 1264 } 1265 } 1266 1077 1267 /* Wait for some time to allow unregistration and ICE/TURN 1078 1268 * transports shutdown to complete: … … 1271 1461 1272 1462 /* Make sure STUN server resolution has completed */ 1273 status = pjsua_resolve_stun_server(PJ_TRUE);1463 status = resolve_stun_server(PJ_TRUE); 1274 1464 if (status != PJ_SUCCESS) { 1275 1465 pjsua_perror(THIS_FILE, "Error resolving STUN server", status); … … 1983 2173 1984 2174 /* Make sure STUN server resolution has completed */ 1985 status = pjsua_resolve_stun_server(PJ_TRUE);2175 status = resolve_stun_server(PJ_TRUE); 1986 2176 if (status != PJ_SUCCESS) { 1987 2177 pjsua_var.nat_status = status;
Note: See TracChangeset
for help on using the changeset viewer.