comparison src/stun.c @ 11336:7d7dd22215ec

[gaim-migrate @ 13549] STUN NAT discovery from gaim_network_get_public_ip committer: Tailor Script <tailor@pidgin.im>
author Thomas Butter <tbutter>
date Wed, 24 Aug 2005 20:45:20 +0000
parents dd1a5969b2e5
children 97028c1c69e9
comparison
equal deleted inserted replaced
11335:59aa7080eb2d 11336:7d7dd22215ec
1 /** 1 /**
2 * @file stun.c STUN (RFC3489) Implementation 2 * @file stun.c STUN (RFC3489) Implementation
3 * @ingroup core 3 * @ingroup core
4 * 4 *
5 * gaim 5 * gaim
6 *
7 * STUN implementation inspired by jstun [http://jstun.javawi.de/]
6 * 8 *
7 * Gaim is the legal property of its developers, whose names are too numerous 9 * Gaim is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this 10 * to list here. Please refer to the COPYRIGHT file distributed with this
9 * source distribution. 11 * source distribution.
10 * 12 *
43 static gint transid[4]; 45 static gint transid[4];
44 46
45 static GSList *callbacks = 0; 47 static GSList *callbacks = 0;
46 static int fd = -1; 48 static int fd = -1;
47 gint incb = -1; 49 gint incb = -1;
50 gint timeout = -1;
48 51
49 static void do_callbacks() { 52 static void do_callbacks() {
50 while(callbacks) { 53 while(callbacks) {
51 StunCallback cb = callbacks->data; 54 StunCallback cb = callbacks->data;
52 cb(&nattype); 55 if(cb)
56 cb(&nattype);
53 callbacks = g_slist_remove(callbacks, cb); 57 callbacks = g_slist_remove(callbacks, cb);
54 } 58 }
55 } 59 }
56 60
57 static void reply_cb(gpointer data, gint source, GaimInputCondition cond) { 61 static void reply_cb(gpointer data, gint source, GaimInputCondition cond) {
58 char buffer[10240]; 62 char buffer[1024];
59 char *tmp; 63 char *tmp;
60 int len; 64 int len;
61 struct in_addr in; 65 struct in_addr in;
62 struct stun_attrib *attrib; 66 struct stun_attrib *attrib;
63 struct stun_header *hdr; 67 struct stun_header *hdr;
64 struct ifconf ifc; 68 struct ifconf ifc;
65 struct ifreq *ifr; 69 struct ifreq *ifr;
66 struct sockaddr_in *sinptr; 70 struct sockaddr_in *sinptr;
67 71
68 len = recv(source, buffer, 10240, 0); 72 len = recv(source, buffer, 1024, 0);
69 73
70 hdr = (struct stun_header*)buffer; 74 hdr = (struct stun_header*)buffer;
71 if(hdr->transid[0]!=transid[0] || hdr->transid[1]!=transid[1] || hdr->transid[2]!=transid[2] || hdr->transid[3]!=transid[3]) { // wrong transaction 75 if(hdr->transid[0]!=transid[0] || hdr->transid[1]!=transid[1] || hdr->transid[2]!=transid[2] || hdr->transid[3]!=transid[3]) { // wrong transaction
72 gaim_debug_info("simple", "got wrong transid\n"); 76 gaim_debug_info("simple", "got wrong transid\n");
73 return; 77 return;
110 } 114 }
111 } 115 }
112 } 116 }
113 117
114 do_callbacks(); 118 do_callbacks();
119 gaim_timeout_remove(timeout);
115 gaim_input_remove(incb); 120 gaim_input_remove(incb);
116 } 121 }
117 122
123 static gboolean timeoutfunc(void *blah) {
124 /* remove input */
125 gaim_input_remove(incb);
126
127 /* set unknown */
128 nattype.status = 0;
129
130 /* callbacks */
131 do_callbacks();
132
133 return FALSE;
134 }
135
136
118 struct stun_nattype *gaim_stun_discover(StunCallback cb) { 137 struct stun_nattype *gaim_stun_discover(StunCallback cb) {
119 struct sockaddr_in addr; 138 struct sockaddr_in addr;
120 struct stun_header data; 139 struct stun_header data;
121 int ret = 0; 140 int ret = 0;
122 const char *ip = gaim_prefs_get_string("/core/network/stun_ip"); 141 const char *ip = gaim_prefs_get_string("/core/network/stun_ip");
123 int port = gaim_prefs_get_int("/core/network/stun_port"); 142 int port = gaim_prefs_get_int("/core/network/stun_port");
143
144 if(!ip || !port) {
145 nattype.status = 0;
146 if(cb) cb(&nattype);
147 return &nattype;
148 }
124 149
125 if(nattype.status == 1) { // currently discovering 150 if(nattype.status == 1) { // currently discovering
126 callbacks = g_slist_append(callbacks, cb); 151 if(cb) callbacks = g_slist_append(callbacks, cb);
127 return NULL; 152 return NULL;
128 } 153 }
129 if(nattype.status == 2 || nattype.status == 0) { // already discovered 154 if(nattype.status != -1) { // already discovered
130 cb(&nattype); 155 if(cb) cb(&nattype);
131 return &nattype; 156 return &nattype;
132 } 157 }
133
134 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 158 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
135 nattype.status = 0; 159 nattype.status = 0;
136 cb(&nattype); 160 if(cb) cb(&nattype);
137 return &nattype; 161 return &nattype;
138 } 162 }
139 163
140 addr.sin_family = AF_INET; 164 addr.sin_family = AF_INET;
141 addr.sin_port = htons(12108); 165 addr.sin_port = htons(12108);
143 while( ((ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) < 0 ) && ntohs(addr.sin_port) < 12208) { 167 while( ((ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) < 0 ) && ntohs(addr.sin_port) < 12208) {
144 addr.sin_port = htons(ntohs(addr.sin_port)+1); 168 addr.sin_port = htons(ntohs(addr.sin_port)+1);
145 } 169 }
146 if( ret < 0 ) { 170 if( ret < 0 ) {
147 nattype.status = 0; 171 nattype.status = 0;
148 cb(&nattype); 172 if(cb) cb(&nattype);
149 return &nattype; 173 return &nattype;
150 } 174 }
151 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL); 175 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL);
152 176
153 if(port == 0 || ip == NULL || ip[0] == '\0') return NULL; 177 if(port == 0 || ip == NULL || ip[0] == '\0') return NULL;
163 transid[2] = data.transid[2] = rand(); 187 transid[2] = data.transid[2] = rand();
164 transid[3] = data.transid[3] = rand(); 188 transid[3] = data.transid[3] = rand();
165 189
166 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) { 190 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) {
167 nattype.status = 0; 191 nattype.status = 0;
168 cb(&nattype); 192 if(cb) cb(&nattype);
169 return &nattype; 193 return &nattype;
170 } 194 }
195 if(cb) callbacks = g_slist_append(callbacks, cb);
196 timeout = gaim_timeout_add(2000, (GSourceFunc)timeoutfunc, NULL);
171 return NULL; 197 return NULL;
172 } 198 }