src/stun.c

changeset 12686
ec3e7c4ff045
parent 11898
a40601f1aed2
child 12700
18c264976a45
equal deleted inserted replaced
12685:aeb6bb044cdc 12686:ec3e7c4ff045
38 #include "dnssrv.h" 38 #include "dnssrv.h"
39 #include "proxy.h" 39 #include "proxy.h"
40 #include "stun.h" 40 #include "stun.h"
41 #include "prefs.h" 41 #include "prefs.h"
42 42
43 static struct stun_nattype nattype = {-1, 0, "\0"}; 43 struct stun_header {
44 short type;
45 short len;
46 int transid[4];
47 };
48
49 struct stun_attrib {
50 short type;
51 short len;
52 };
53
54 struct stun_change {
55 struct stun_header hdr;
56 struct stun_attrib attrib;
57 char value[4];
58 };
59
60 static GaimStunNatDiscovery nattype = {-1, 0, "\0"};
44 61
45 static GSList *callbacks = 0; 62 static GSList *callbacks = 0;
46 static int fd = -1; 63 static int fd = -1;
47 static gint incb = -1; 64 static gint incb = -1;
48 static gint timeout = -1; 65 static gint timeout = -1;
61 } 78 }
62 } 79 }
63 80
64 static gboolean timeoutfunc(void *blah) { 81 static gboolean timeoutfunc(void *blah) {
65 if(retry > 2) { 82 if(retry > 2) {
66 if(test == 2) nattype.type = 5; 83 if(test == 2)
84 nattype.type = GAIM_STUN_NAT_TYPE_SYMMETRIC;
85
67 /* remove input */ 86 /* remove input */
68 gaim_input_remove(incb); 87 gaim_input_remove(incb);
69 88
70 /* set unknown */ 89 /* set unknown */
71 nattype.status = 0; 90 nattype.status = GAIM_STUN_STATUS_UNKNOWN;
72 91
73 /* callbacks */ 92 /* callbacks */
74 do_callbacks(); 93 do_callbacks();
75 94
76 return FALSE; 95 return FALSE;
129 strcpy(nattype.publicip, inet_ntoa(in)); 148 strcpy(nattype.publicip, inet_ntoa(in));
130 } 149 }
131 tmp += sizeof(struct stun_attrib) + attrib->len; 150 tmp += sizeof(struct stun_attrib) + attrib->len;
132 } 151 }
133 gaim_debug_info("stun", "got public ip %s\n", nattype.publicip); 152 gaim_debug_info("stun", "got public ip %s\n", nattype.publicip);
134 nattype.status = 2; 153 nattype.status = GAIM_STUN_STATUS_DISCOVERED;
135 nattype.type = 1; 154 nattype.type = GAIM_STUN_NAT_TYPE_UNKNOWN_NAT;
136 155
137 /* is it a NAT? */ 156 /* is it a NAT? */
138 157
139 ifc.ifc_len = sizeof(buffer); 158 ifc.ifc_len = sizeof(buffer);
140 ifc.ifc_req = (struct ifreq *) buffer; 159 ifc.ifc_req = (struct ifreq *) buffer;
150 /* we only care about ipv4 interfaces */ 169 /* we only care about ipv4 interfaces */
151 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 170 sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
152 if(sinptr->sin_addr.s_addr == in.s_addr) { 171 if(sinptr->sin_addr.s_addr == in.s_addr) {
153 /* no NAT */ 172 /* no NAT */
154 gaim_debug_info("stun", "no nat"); 173 gaim_debug_info("stun", "no nat");
155 nattype.type = 0; 174 nattype.type = GAIM_STUN_NAT_TYPE_PUBLIC_IP;
156 } 175 }
157 } 176 }
158 } 177 }
159 gaim_timeout_remove(timeout); 178 gaim_timeout_remove(timeout);
160 179
164 return; 183 return;
165 } else if(test == 2) { 184 } else if(test == 2) {
166 do_callbacks(); 185 do_callbacks();
167 gaim_input_remove(incb); 186 gaim_input_remove(incb);
168 gaim_timeout_remove(timeout); 187 gaim_timeout_remove(timeout);
169 nattype.type = 2; 188 nattype.type = GAIM_STUN_NAT_TYPE_FULL_CONE;
170 } 189 }
171 } 190 }
172 191
173 static void hbn_cb(GSList *hosts, gpointer edata, const char *error_message) { 192 static void hbn_cb(GSList *hosts, gpointer edata, const char *error_message) {
174 static struct stun_header data; 193 static struct stun_header data;
176 195
177 if(!hosts) return; 196 if(!hosts) return;
178 if(!hosts->data) return; 197 if(!hosts->data) return;
179 198
180 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 199 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
181 nattype.status = 0; 200 nattype.status = GAIM_STUN_STATUS_UNKNOWN;
182 do_callbacks(); 201 do_callbacks();
183 return; 202 return;
184 } 203 }
185 204
186 addr.sin_family = AF_INET; 205 addr.sin_family = AF_INET;
188 addr.sin_addr.s_addr = INADDR_ANY; 207 addr.sin_addr.s_addr = INADDR_ANY;
189 while( ((ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) < 0 ) && ntohs(addr.sin_port) < 12208) { 208 while( ((ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) < 0 ) && ntohs(addr.sin_port) < 12208) {
190 addr.sin_port = htons(ntohs(addr.sin_port)+1); 209 addr.sin_port = htons(ntohs(addr.sin_port)+1);
191 } 210 }
192 if( ret < 0 ) { 211 if( ret < 0 ) {
193 nattype.status = 0; 212 nattype.status = GAIM_STUN_STATUS_UNKNOWN;
194 do_callbacks(); 213 do_callbacks();
195 return; 214 return;
196 } 215 }
197 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL); 216 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL);
198 217
212 data.transid[0] = rand(); 231 data.transid[0] = rand();
213 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); 232 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m');
214 data.transid[2] = rand(); 233 data.transid[2] = rand();
215 data.transid[3] = rand(); 234 data.transid[3] = rand();
216 235
217 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) { 236 if(sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) {
218 nattype.status = 0; 237 nattype.status = GAIM_STUN_STATUS_UNKNOWN;
219 do_callbacks(); 238 do_callbacks();
220 return; 239 return;
221 } 240 }
222 test = 1; 241 test = 1;
223 packet = &data; 242 packet = &data;
224 packetsize = sizeof(struct stun_header); 243 packetsize = sizeof(struct stun_header);
225 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); 244 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL);
226 } 245 }
227 246
228 static void do_test1(struct srv_response *resp, int results, gpointer sdata) { 247 static void do_test1(GaimSrvResponse *resp, int results, gpointer sdata) {
229 const char *servername = sdata; 248 const char *servername = sdata;
230 int port = 3478; 249 int port = 3478;
231 250
232 if(results) { 251 if(results) {
233 servername = resp[0].hostname; 252 servername = resp[0].hostname;
237 256
238 gaim_gethostbyname_async(servername, port, hbn_cb, NULL); 257 gaim_gethostbyname_async(servername, port, hbn_cb, NULL);
239 g_free(resp); 258 g_free(resp);
240 } 259 }
241 260
242 struct stun_nattype *gaim_stun_discover(StunCallback cb) { 261 GaimStunNatDiscovery *gaim_stun_discover(StunCallback cb) {
243 const char *servername = gaim_prefs_get_string("/core/network/stun_server"); 262 const char *servername = gaim_prefs_get_string("/core/network/stun_server");
244 263
245 gaim_debug_info("stun", "using server %s\n", servername); 264 gaim_debug_info("stun", "using server %s\n", servername);
246 if(nattype.status == 1) { /* currently discovering */ 265
247 if(cb) callbacks = g_slist_append(callbacks, cb); 266 if(nattype.status == GAIM_STUN_STATUS_DISCOVERING) {
267 if(cb)
268 callbacks = g_slist_append(callbacks, cb);
248 return NULL; 269 return NULL;
249 } 270 }
250 if(nattype.status != -1) { /* already discovered */ 271
251 if(cb) cb(&nattype); 272 if(nattype.status != GAIM_STUN_STATUS_UNDISCOVERED) {
273 if(cb)
274 cb(&nattype);
252 return &nattype; 275 return &nattype;
253 } 276 }
254 277
255 if(!servername || (strlen(servername)<2)) { 278 if(!servername || (strlen(servername) < 2)) {
256 nattype.status = 0; 279 nattype.status = GAIM_STUN_STATUS_UNKNOWN;
257 if(cb) cb(&nattype); 280 if(cb)
281 cb(&nattype);
258 return &nattype; 282 return &nattype;
259 } 283 }
260 callbacks = g_slist_append(callbacks, cb); 284 callbacks = g_slist_append(callbacks, cb);
261 gaim_srv_resolve("stun","udp",servername, do_test1, 285 gaim_srv_resolve("stun", "udp", servername, do_test1,
262 (gpointer) servername); 286 (gpointer) servername);
263 return &nattype; 287 return &nattype;
264 } 288 }
265 289
266 void gaim_stun_init() { 290 void gaim_stun_init() {

mercurial