169 } |
169 } |
170 list = g_slist_sort(list, prioritycmp); |
170 list = g_slist_sort(list, prioritycmp); |
171 return list; |
171 return list; |
172 } |
172 } |
173 |
173 |
174 static gconstpointer newfrommessage(JingleContent *cn, GError **err) |
174 static GSList *get_our_candidates(guint16 port) |
175 { |
175 { |
176 JingleS5B *js5b; |
176 GSList *our_candidates = NULL, *entry; |
177 LmMessageNode *node = cn->transport, *node2; |
177 |
178 const gchar *modestr; |
178 for (entry = local_ips; entry; entry = entry->next) { |
179 |
179 LocalIP *lcand = (LocalIP *)entry->data; |
180 js5b = g_new0(JingleS5B, 1); |
|
181 modestr = lm_message_node_get_attribute(node, "mode"); |
|
182 js5b->mode = index_in_array(modestr, jingle_s5b_modes); |
|
183 js5b->sid = g_strdup(lm_message_node_get_attribute(node, "sid")); |
|
184 |
|
185 if (!js5b->sid) { |
|
186 g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING, |
|
187 "an attribute of the transport element is missing"); |
|
188 g_free(js5b); |
|
189 return NULL; |
|
190 } |
|
191 |
|
192 js5b->candidates = parse_candidates(node); |
|
193 |
|
194 return (gconstpointer) js5b; |
|
195 } |
|
196 |
|
197 static gconstpointer new(void) |
|
198 { |
|
199 JingleS5B *js5b = g_new0(JingleS5B, 1); |
|
200 GSList *entry; |
|
201 gint port; |
|
202 |
|
203 js5b->mode = JINGLE_S5B_TCP; |
|
204 js5b->sid = gen_random_sid(); |
|
205 port = settings_opt_get_int("jingle_s5b_dir"); |
|
206 if (port < 1024 && port > (guint16)~0) { |
|
207 port = g_random_int_range(1024, (guint16)~0); |
|
208 } |
|
209 |
|
210 for (entry = local_candidates; entry; entry = entry->next) { |
|
211 LocalCandidate *lcand = (LocalCandidate *)entry->data; |
|
212 S5BCandidate *cand = g_new0(S5BCandidate, 1); |
180 S5BCandidate *cand = g_new0(S5BCandidate, 1); |
213 cand->cid = gen_random_cid(); |
181 cand->cid = gen_random_cid(); |
214 cand->host = g_inet_address_to_string(lcand->address); |
182 cand->host = g_inet_address_to_string(lcand->address); |
215 cand->jid = g_strdup(lm_connection_get_jid(lconnection)); |
183 cand->jid = g_strdup(lm_connection_get_jid(lconnection)); |
216 cand->port = port; |
184 cand->port = port; |
217 cand->priority = lcand->priority; |
185 cand->priority = lcand->priority; |
218 |
186 |
219 js5b->ourcandidates = g_slist_prepend(js5b->ourcandidates, cand); |
187 our_candidates = g_slist_prepend(our_candidates, cand); |
220 } |
188 } |
|
189 our_candidates = g_slist_sort(our_candidates, prioritycmp); |
|
190 return our_candidates; |
|
191 } |
|
192 |
|
193 /** |
|
194 * @brief Get a port number by settings or randomly |
|
195 * @return A guint16 containing the port number |
|
196 * */ |
|
197 static guint16 get_port(void) |
|
198 { |
|
199 // TODO: find a way to make sure the port is not already used |
|
200 guint64 portstart, portend; |
|
201 guint16 port; |
|
202 const gchar *port_range = settings_opt_get("jingle_s5b_portrange"); |
|
203 |
|
204 if (port_range != NULL) { |
|
205 sscanf(port_range, "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &portstart, &portend); |
|
206 |
|
207 if ((portstart >= 1024 && portstart <= (guint16)~0) && |
|
208 (portend >= 1024 && portend <= (guint16)~0) && portstart <= portend) { |
|
209 port = g_random_int_range(portstart, portend); |
|
210 } else { |
|
211 scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Invalid port range specified"); |
|
212 port = g_random_int_range(1024, (guint16)~0); |
|
213 } |
|
214 } else { |
|
215 port = g_random_int_range(1024, (guint16)~0); |
|
216 } |
|
217 |
|
218 return port; |
|
219 } |
|
220 |
|
221 static gconstpointer newfrommessage(JingleContent *cn, GError **err) |
|
222 { |
|
223 JingleS5B *js5b; |
|
224 LmMessageNode *node = cn->transport; |
|
225 const gchar *modestr; |
|
226 |
|
227 js5b = g_new0(JingleS5B, 1); |
|
228 modestr = lm_message_node_get_attribute(node, "mode"); |
|
229 js5b->mode = index_in_array(modestr, jingle_s5b_modes); |
|
230 js5b->sid = g_strdup(lm_message_node_get_attribute(node, "sid")); |
|
231 |
|
232 if (!js5b->sid) { |
|
233 g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING, |
|
234 "an attribute of the transport element is missing"); |
|
235 g_free(js5b); |
|
236 return NULL; |
|
237 } |
|
238 |
|
239 js5b->candidates = parse_candidates(node); |
|
240 js5b->ourcandidates = get_our_candidates(get_port()); |
|
241 |
|
242 return (gconstpointer) js5b; |
|
243 } |
|
244 |
|
245 static gconstpointer new(void) |
|
246 { |
|
247 JingleS5B *js5b = g_new0(JingleS5B, 1); |
|
248 |
|
249 |
|
250 js5b->mode = JINGLE_S5B_TCP; |
|
251 js5b->sid = gen_random_sid(); |
|
252 // the user can manually specify a port range to use in for format: |
|
253 // portstart-portend |
|
254 |
|
255 |
|
256 js5b->ourcandidates = get_our_candidates(get_port()); |
|
257 |
221 return js5b; |
258 return js5b; |
222 } |
259 } |
223 |
260 |
224 static JingleHandleStatus |
261 static JingleHandleStatus |
225 handle_session_accept(JingleS5B *js5b, LmMessageNode *node, GError **err) |
262 handle_session_accept(JingleS5B *js5b, LmMessageNode *node, GError **err) |
336 |
373 |
337 /** |
374 /** |
338 * @brief Discover all IPs of this computer |
375 * @brief Discover all IPs of this computer |
339 * @return A linked list of GInetAddress |
376 * @return A linked list of GInetAddress |
340 */ |
377 */ |
341 static GSList *get_all_local_ips() { |
378 static GSList *get_all_local_ips(void) { |
342 GSList *addresses = NULL; |
379 GSList *addresses = NULL; |
343 GInetAddress *thisaddr; |
380 GInetAddress *thisaddr; |
344 GSocketFamily family; |
381 GSocketFamily family; |
345 struct ifaddrs *first, *ifaddr; |
382 struct ifaddrs *first, *ifaddr; |
346 struct sockaddr_in *native; |
383 struct sockaddr_in *native; |
347 struct sockaddr_in6 *native6; |
384 struct sockaddr_in6 *native6; |
348 const guint8 *addrdata; |
385 const guint8 *addrdata; |
349 guint16 ifacecounter = 0; // for lack of a better method |
386 guint16 ifacecounter = 0; // for lack of a better method |
350 LocalCandidate *candidate; |
387 LocalIP *candidate; |
351 |
388 |
352 gint rval = getifaddrs(&first); |
389 gint rval = getifaddrs(&first); |
353 if (!rval) |
390 if (!rval) |
354 return NULL; |
391 return NULL; |
355 |
392 |
407 static gchar *gen_random_cid(void) |
444 static gchar *gen_random_cid(void) |
408 { |
445 { |
409 return random_str(7); |
446 return random_str(7); |
410 } |
447 } |
411 |
448 |
|
449 static void free_localip(LocalIP *l) { |
|
450 g_object_unref(l->address); |
|
451 g_free(l); |
|
452 } |
|
453 |
412 static void jingle_socks5_init(void) |
454 static void jingle_socks5_init(void) |
413 { |
455 { |
414 g_type_init(); |
456 g_type_init(); |
415 jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs, |
457 jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs, |
416 JINGLE_TRANSPORT_STREAMING, |
458 JINGLE_TRANSPORT_STREAMING, |
417 JINGLE_TRANSPORT_PRIO_HIGH); |
459 JINGLE_TRANSPORT_PRIO_HIGH); |
418 xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5); |
460 xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5); |
419 local_candidates = get_all_local_ips(); |
461 local_ips = get_all_local_ips(); |
420 } |
462 } |
421 |
463 |
422 static void jingle_socks5_uninit(void) |
464 static void jingle_socks5_uninit(void) |
423 { |
465 { |
424 xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5); |
466 xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5); |
425 jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5); |
467 jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5); |
426 g_slist_foreach(local_candidates, (GFunc)g_object_unref, NULL); |
468 g_slist_foreach(local_ips, (GFunc)free_localip, NULL); |
427 } |
469 g_slist_free(local_ips); |
|
470 } |