Mercurial > pidgin
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 } |