comparison src/stun.c @ 11354:97028c1c69e9

[gaim-migrate @ 13573] added retries and nat type detection (#ifdef NOTYET since no one needs it at the moment) committer: Tailor Script <tailor@pidgin.im>
author Thomas Butter <tbutter>
date Sat, 27 Aug 2005 14:16:13 +0000
parents 7d7dd22215ec
children e1840eb860e7
comparison
equal deleted inserted replaced
11353:0f03b5492130 11354:97028c1c69e9
22 * 22 *
23 * You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software 24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * 26 *
27 * TODO: currently only detects if there is a NAT and not the type of NAT
28 */ 27 */
29 28
30 #include <sys/socket.h> 29 #include <sys/socket.h>
31 #include <ifaddrs.h> 30 #include <ifaddrs.h>
32 #include <net/if.h> 31 #include <net/if.h>
40 #include "stun.h" 39 #include "stun.h"
41 #include "prefs.h" 40 #include "prefs.h"
42 41
43 struct stun_nattype nattype = {-1, 0, "\0"}; 42 struct stun_nattype nattype = {-1, 0, "\0"};
44 43
45 static gint transid[4];
46
47 static GSList *callbacks = 0; 44 static GSList *callbacks = 0;
48 static int fd = -1; 45 static int fd = -1;
49 gint incb = -1; 46 static gint incb = -1;
50 gint timeout = -1; 47 static gint timeout = -1;
48 static struct stun_header *packet;
49 static int packetsize = 0;
50 static int test = 0;
51 static int retry = 0;
52 static struct sockaddr_in addr;
51 53
52 static void do_callbacks() { 54 static void do_callbacks() {
53 while(callbacks) { 55 while(callbacks) {
54 StunCallback cb = callbacks->data; 56 StunCallback cb = callbacks->data;
55 if(cb) 57 if(cb)
56 cb(&nattype); 58 cb(&nattype);
57 callbacks = g_slist_remove(callbacks, cb); 59 callbacks = g_slist_remove(callbacks, cb);
58 } 60 }
59 } 61 }
62
63 static gboolean timeoutfunc(void *blah) {
64 if(retry > 2) {
65 if(test == 2) nattype.type = 5;
66 /* remove input */
67 gaim_input_remove(incb);
68
69 /* set unknown */
70 nattype.status = 0;
71
72 /* callbacks */
73 do_callbacks();
74
75 return FALSE;
76 }
77 retry++;
78 sendto(fd, packet, packetsize, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
79 return TRUE;
80 }
81
82 #ifdef NOTYET
83 static void do_test2() {
84 struct stun_change data;
85 data.hdr.type = htons(0x0001);
86 data.hdr.len = 0;
87 data.hdr.transid[0] = rand();
88 data.hdr.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m');
89 data.hdr.transid[2] = rand();
90 data.hdr.transid[3] = rand(); data.attrib.type = htons(0x003);
91 data.attrib.len = htons(4);
92 data.value[3] = 6;
93 packet = (struct stun_header*)&data;
94 packetsize = sizeof(struct stun_change);
95 retry = 0;
96 test = 2;
97 sendto(fd, packet, packetsize, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
98 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL);
99 }
100 #endif
60 101
61 static void reply_cb(gpointer data, gint source, GaimInputCondition cond) { 102 static void reply_cb(gpointer data, gint source, GaimInputCondition cond) {
62 char buffer[1024]; 103 char buffer[1024];
63 char *tmp; 104 char *tmp;
64 int len; 105 int len;
70 struct sockaddr_in *sinptr; 111 struct sockaddr_in *sinptr;
71 112
72 len = recv(source, buffer, 1024, 0); 113 len = recv(source, buffer, 1024, 0);
73 114
74 hdr = (struct stun_header*)buffer; 115 hdr = (struct stun_header*)buffer;
75 if(hdr->transid[0]!=transid[0] || hdr->transid[1]!=transid[1] || hdr->transid[2]!=transid[2] || hdr->transid[3]!=transid[3]) { // wrong transaction 116 if(hdr->transid[0]!=packet->transid[0] || hdr->transid[1]!=packet->transid[1] || hdr->transid[2]!=packet->transid[2] || hdr->transid[3]!=packet->transid[3]) { // wrong transaction
76 gaim_debug_info("simple", "got wrong transid\n"); 117 gaim_debug_info("simple", "got wrong transid\n");
77 return; 118 return;
78 } 119 }
79 120 if(test==1) {
80 tmp = buffer + sizeof(struct stun_header); 121 tmp = buffer + sizeof(struct stun_header);
81 while(buffer+len > tmp) { 122 while(buffer+len > tmp) {
82 123
83 attrib = (struct stun_attrib*) tmp; 124 attrib = (struct stun_attrib*) tmp;
84 if(attrib->type == htons(0x0001) && attrib->len == htons(8)) { 125 if(attrib->type == htons(0x0001) && attrib->len == htons(8)) {
85 memcpy(&in.s_addr, tmp+sizeof(struct stun_attrib)+2+2, 4); 126 memcpy(&in.s_addr, tmp+sizeof(struct stun_attrib)+2+2, 4);
86 strcpy(nattype.publicip, inet_ntoa(in)); 127 strcpy(nattype.publicip, inet_ntoa(in));
128 }
129 tmp += sizeof(struct stun_attrib) + attrib->len;
87 } 130 }
88 tmp += sizeof(struct stun_attrib) + attrib->len; 131 gaim_debug_info("simple", "got public ip %s\n",nattype.publicip);
89 } 132 nattype.status = 2;
90 gaim_debug_info("simple", "got public ip %s\n",nattype.publicip); 133 nattype.type = 1;
91 nattype.status = 2; 134
92 nattype.type = 1; 135 // is it a NAT?
93 136
94 // is it a NAT? 137 ifc.ifc_len = sizeof(buffer);
95 138 ifc.ifc_req = (struct ifreq *) buffer;
96 ifc.ifc_len = sizeof(buffer); 139 ioctl(source, SIOCGIFCONF, &ifc);
97 ifc.ifc_req = (struct ifreq *) buffer; 140
98 ioctl(source, SIOCGIFCONF, &ifc); 141 tmp = buffer;
99 142 while(tmp < buffer + ifc.ifc_len) {
100 tmp = buffer; 143 ifr = (struct ifreq *) tmp;
101 while(tmp < buffer + ifc.ifc_len) { 144 len = sizeof(struct sockaddr);
102 ifr = (struct ifreq *) tmp; 145
103 len = sizeof(struct sockaddr); 146 tmp += sizeof(ifr->ifr_name) + len;
104 147
105 tmp += sizeof(ifr->ifr_name) + len; 148 if(ifr->ifr_addr.sa_family == AF_INET) {
106 149 // we only care about ipv4 interfaces
107 if(ifr->ifr_addr.sa_family == AF_INET) { 150 sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
108 // we only care about ipv4 interfaces 151 if(sinptr->sin_addr.s_addr == in.s_addr) {
109 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 152 // no NAT
110 if(sinptr->sin_addr.s_addr == in.s_addr) { 153 gaim_debug_info("simple","no nat");
111 // no NAT 154 nattype.type = 0;
112 gaim_debug_info("simple","no nat"); 155 }
113 nattype.type = 0;
114 } 156 }
115 } 157 }
116 } 158 gaim_timeout_remove(timeout);
117 159
118 do_callbacks(); 160 #ifdef NOTYET
119 gaim_timeout_remove(timeout); 161 do_test2();
120 gaim_input_remove(incb); 162 #endif
121 } 163 return;
122 164 } else if(test == 2) {
123 static gboolean timeoutfunc(void *blah) { 165 do_callbacks();
124 /* remove input */ 166 gaim_input_remove(incb);
125 gaim_input_remove(incb); 167 gaim_timeout_remove(timeout);
126 168 nattype.type = 2;
127 /* set unknown */ 169 }
128 nattype.status = 0; 170 }
129
130 /* callbacks */
131 do_callbacks();
132
133 return FALSE;
134 }
135
136 171
137 struct stun_nattype *gaim_stun_discover(StunCallback cb) { 172 struct stun_nattype *gaim_stun_discover(StunCallback cb) {
138 struct sockaddr_in addr; 173 static struct stun_header data;
139 struct stun_header data;
140 int ret = 0; 174 int ret = 0;
141 const char *ip = gaim_prefs_get_string("/core/network/stun_ip"); 175 const char *ip = gaim_prefs_get_string("/core/network/stun_ip");
142 int port = gaim_prefs_get_int("/core/network/stun_port"); 176 int port = gaim_prefs_get_int("/core/network/stun_port");
143 177
144 if(!ip || !port) { 178 if(!ip || !port) {
180 addr.sin_port = htons(port); 214 addr.sin_port = htons(port);
181 addr.sin_addr.s_addr = inet_addr(ip); 215 addr.sin_addr.s_addr = inet_addr(ip);
182 216
183 data.type = htons(0x0001); 217 data.type = htons(0x0001);
184 data.len = 0; 218 data.len = 0;
185 transid[0] = data.transid[0] = rand(); 219 data.transid[0] = rand();
186 transid[1] = data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); 220 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m');
187 transid[2] = data.transid[2] = rand(); 221 data.transid[2] = rand();
188 transid[3] = data.transid[3] = rand(); 222 data.transid[3] = rand();
189 223
190 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) { 224 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) {
191 nattype.status = 0; 225 nattype.status = 0;
192 if(cb) cb(&nattype); 226 if(cb) cb(&nattype);
193 return &nattype; 227 return &nattype;
194 } 228 }
229 test = 1;
230 packet = &data;
231 packetsize = sizeof(struct stun_header);
195 if(cb) callbacks = g_slist_append(callbacks, cb); 232 if(cb) callbacks = g_slist_append(callbacks, cb);
196 timeout = gaim_timeout_add(2000, (GSourceFunc)timeoutfunc, NULL); 233 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL);
197 return NULL; 234 return NULL;
198 } 235 }