Mercurial > pidgin
comparison libpurple/protocols/jabber/si.c @ 23364:05802d915c13
Improve error handling for xmpp file transfers.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Sat, 14 Jun 2008 03:20:19 +0000 |
parents | 576528012cce |
children | 10382f1e1353 |
comparison
equal
deleted
inserted
replaced
23363:576528012cce | 23364:05802d915c13 |
---|---|
621 acceptfd = accept(source, NULL, 0); | 621 acceptfd = accept(source, NULL, 0); |
622 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) | 622 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) |
623 return; | 623 return; |
624 else if(acceptfd == -1) { | 624 else if(acceptfd == -1) { |
625 purple_debug_warning("jabber", "accept: %s\n", g_strerror(errno)); | 625 purple_debug_warning("jabber", "accept: %s\n", g_strerror(errno)); |
626 /* TODO: This should cancel the ft */ | 626 /* Don't cancel the ft - allow it to fall to the next streamhost.*/ |
627 return; | 627 return; |
628 } | 628 } |
629 | 629 |
630 purple_input_remove(xfer->watcher); | 630 purple_input_remove(xfer->watcher); |
631 close(source); | 631 close(source); |
657 if(!xfer->data) | 657 if(!xfer->data) |
658 return; | 658 return; |
659 | 659 |
660 jsx = xfer->data; | 660 jsx = xfer->data; |
661 | 661 |
662 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) | 662 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { |
663 return; | 663 if (type && !strcmp(type, "error")) |
664 purple_xfer_cancel_remote(xfer); | |
665 return; | |
666 } | |
664 | 667 |
665 if(!(from = xmlnode_get_attrib(packet, "from"))) | 668 if(!(from = xmlnode_get_attrib(packet, "from"))) |
666 return; | 669 return; |
667 | 670 |
668 if(!(query = xmlnode_get_child(packet, "query"))) | 671 if(!(query = xmlnode_get_child(packet, "query"))) |
716 { | 719 { |
717 PurpleXfer *xfer = data; | 720 PurpleXfer *xfer = data; |
718 JabberSIXfer *jsx; | 721 JabberSIXfer *jsx; |
719 JabberIq *iq; | 722 JabberIq *iq; |
720 xmlnode *query, *streamhost; | 723 xmlnode *query, *streamhost; |
721 char *jid, port[6]; | 724 const char *ft_proxies; |
722 const char *local_ip, *public_ip, *ft_proxies; | 725 char port[6]; |
723 GList *tmp; | 726 GList *tmp; |
724 JabberBytestreamsStreamhost *sh, *sh2; | 727 JabberBytestreamsStreamhost *sh, *sh2; |
728 int streamhost_count = 0; | |
725 | 729 |
726 jsx = xfer->data; | 730 jsx = xfer->data; |
727 jsx->listen_data = NULL; | 731 jsx->listen_data = NULL; |
728 | 732 |
733 /* I'm not sure under which conditions this can happen | |
734 * (it seems like it shouldn't be possible */ | |
729 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) { | 735 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) { |
730 purple_xfer_unref(xfer); | 736 purple_xfer_unref(xfer); |
731 return; | 737 return; |
732 } | 738 } |
733 | 739 |
734 purple_xfer_unref(xfer); | 740 purple_xfer_unref(xfer); |
735 | |
736 if (sock < 0) { | |
737 purple_xfer_cancel_local(xfer); | |
738 return; | |
739 } | |
740 | |
741 jsx->local_streamhost_fd = sock; | |
742 | 741 |
743 iq = jabber_iq_new_query(jsx->js, JABBER_IQ_SET, | 742 iq = jabber_iq_new_query(jsx->js, JABBER_IQ_SET, |
744 "http://jabber.org/protocol/bytestreams"); | 743 "http://jabber.org/protocol/bytestreams"); |
745 xmlnode_set_attrib(iq->node, "to", xfer->who); | 744 xmlnode_set_attrib(iq->node, "to", xfer->who); |
746 query = xmlnode_get_child(iq->node, "query"); | 745 query = xmlnode_get_child(iq->node, "query"); |
747 | 746 |
748 xmlnode_set_attrib(query, "sid", jsx->stream_id); | 747 xmlnode_set_attrib(query, "sid", jsx->stream_id); |
749 | 748 |
750 jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node, | 749 /* If we successfully started listening locally */ |
750 if (sock >= 0) { | |
751 gchar *jid; | |
752 const char *local_ip, *public_ip; | |
753 | |
754 jsx->local_streamhost_fd = sock; | |
755 | |
756 jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node, | |
751 jsx->js->user->domain, jsx->js->user->resource); | 757 jsx->js->user->domain, jsx->js->user->resource); |
752 xfer->local_port = purple_network_get_port_from_fd(sock); | 758 xfer->local_port = purple_network_get_port_from_fd(sock); |
753 g_snprintf(port, sizeof(port), "%hu", xfer->local_port); | 759 g_snprintf(port, sizeof(port), "%hu", xfer->local_port); |
754 | 760 |
755 /* TODO: Should there be an option to not use the local host as a ft proxy? | 761 /* Include the localhost's IP (for in-network transfers) */ |
756 * (to prevent revealing IP address, etc.) */ | 762 local_ip = purple_network_get_local_system_ip(jsx->js->fd); |
757 | 763 if (strcmp(local_ip, "0.0.0.0") != 0) { |
758 /* Include the localhost's IP (for in-network transfers) */ | 764 streamhost_count++; |
759 local_ip = purple_network_get_local_system_ip(jsx->js->fd); | 765 streamhost = xmlnode_new_child(query, "streamhost"); |
760 if (strcmp(local_ip, "0.0.0.0") != 0) | 766 xmlnode_set_attrib(streamhost, "jid", jid); |
761 { | 767 xmlnode_set_attrib(streamhost, "host", local_ip); |
762 streamhost = xmlnode_new_child(query, "streamhost"); | 768 xmlnode_set_attrib(streamhost, "port", port); |
763 xmlnode_set_attrib(streamhost, "jid", jid); | 769 } |
764 xmlnode_set_attrib(streamhost, "host", local_ip); | 770 |
765 xmlnode_set_attrib(streamhost, "port", port); | 771 /* Include the public IP (assuming that there is a port mapped somehow) */ |
766 } | 772 public_ip = purple_network_get_my_ip(jsx->js->fd); |
767 | 773 if (strcmp(public_ip, local_ip) != 0 && strcmp(public_ip, "0.0.0.0") != 0) { |
768 /* Include the public IP (assuming that there is a port mapped somehow) */ | 774 streamhost_count++; |
769 /* TODO: Check that it isn't the same as above and is a valid IP */ | 775 streamhost = xmlnode_new_child(query, "streamhost"); |
770 public_ip = purple_network_get_my_ip(jsx->js->fd); | 776 xmlnode_set_attrib(streamhost, "jid", jid); |
771 if (strcmp(public_ip, local_ip) != 0) | 777 xmlnode_set_attrib(streamhost, "host", public_ip); |
772 { | 778 xmlnode_set_attrib(streamhost, "port", port); |
773 streamhost = xmlnode_new_child(query, "streamhost"); | 779 } |
774 xmlnode_set_attrib(streamhost, "jid", jid); | 780 |
775 xmlnode_set_attrib(streamhost, "host", public_ip); | 781 g_free(jid); |
776 xmlnode_set_attrib(streamhost, "port", port); | 782 |
777 } | 783 /* The listener for the local proxy */ |
778 | 784 xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, |
779 g_free(jid); | 785 jabber_si_xfer_bytestreams_send_connected_cb, xfer); |
780 | 786 } |
781 /* The listener for the local proxy */ | |
782 xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, | |
783 jabber_si_xfer_bytestreams_send_connected_cb, xfer); | |
784 | 787 |
785 /* insert proxies here */ | 788 /* insert proxies here */ |
786 ft_proxies = purple_account_get_string(xfer->account, "ft_proxies", NULL); | 789 ft_proxies = purple_account_get_string(xfer->account, "ft_proxies", NULL); |
787 if (ft_proxies) { | 790 if (ft_proxies) { |
788 int i, portnum; | 791 int i, portnum; |
809 purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p\n", | 812 purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p\n", |
810 jsx, jsx->streamhosts, i, ft_proxy_list[i]); | 813 jsx, jsx->streamhosts, i, ft_proxy_list[i]); |
811 if(g_list_find_custom(jsx->streamhosts, ft_proxy_list[i], jabber_si_compare_jid) != NULL) | 814 if(g_list_find_custom(jsx->streamhosts, ft_proxy_list[i], jabber_si_compare_jid) != NULL) |
812 continue; | 815 continue; |
813 | 816 |
817 streamhost_count++; | |
814 streamhost = xmlnode_new_child(query, "streamhost"); | 818 streamhost = xmlnode_new_child(query, "streamhost"); |
815 xmlnode_set_attrib(streamhost, "jid", ft_proxy_list[i]); | 819 xmlnode_set_attrib(streamhost, "jid", ft_proxy_list[i]); |
816 xmlnode_set_attrib(streamhost, "host", ft_proxy_list[i]); | 820 xmlnode_set_attrib(streamhost, "host", ft_proxy_list[i]); |
817 xmlnode_set_attrib(streamhost, "port", port); | 821 xmlnode_set_attrib(streamhost, "port", port); |
818 | 822 |
838 purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and sh->jid %p", | 842 purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and sh->jid %p", |
839 jsx, jsx->streamhosts, sh->jid); | 843 jsx, jsx->streamhosts, sh->jid); |
840 if(g_list_find_custom(jsx->streamhosts, sh->jid, jabber_si_compare_jid) != NULL) | 844 if(g_list_find_custom(jsx->streamhosts, sh->jid, jabber_si_compare_jid) != NULL) |
841 continue; | 845 continue; |
842 | 846 |
847 streamhost_count++; | |
843 streamhost = xmlnode_new_child(query, "streamhost"); | 848 streamhost = xmlnode_new_child(query, "streamhost"); |
844 xmlnode_set_attrib(streamhost, "jid", sh->jid); | 849 xmlnode_set_attrib(streamhost, "jid", sh->jid); |
845 xmlnode_set_attrib(streamhost, "host", sh->host); | 850 xmlnode_set_attrib(streamhost, "host", sh->host); |
846 g_snprintf(port, sizeof(port), "%hu", sh->port); | 851 g_snprintf(port, sizeof(port), "%hu", sh->port); |
847 xmlnode_set_attrib(streamhost, "port", port); | 852 xmlnode_set_attrib(streamhost, "port", port); |
853 sh2->port = sh->port; | 858 sh2->port = sh->port; |
854 | 859 |
855 jsx->streamhosts = g_list_prepend(jsx->streamhosts, sh2); | 860 jsx->streamhosts = g_list_prepend(jsx->streamhosts, sh2); |
856 } | 861 } |
857 | 862 |
863 /* We have no way of transferring, cancel the transfer */ | |
864 if (streamhost_count == 0) { | |
865 jabber_iq_free(iq); | |
866 /* We should probably notify the target, but this really shouldn't ever happen */ | |
867 purple_xfer_cancel_local(xfer); | |
868 return; | |
869 } | |
870 | |
858 jabber_iq_set_callback(iq, jabber_si_connect_proxy_cb, xfer); | 871 jabber_iq_set_callback(iq, jabber_si_connect_proxy_cb, xfer); |
859 | 872 |
860 jabber_iq_send(iq); | 873 jabber_iq_send(iq); |
861 | 874 |
862 } | 875 } |
867 JabberSIXfer *jsx; | 880 JabberSIXfer *jsx; |
868 | 881 |
869 purple_xfer_ref(xfer); | 882 purple_xfer_ref(xfer); |
870 | 883 |
871 jsx = xfer->data; | 884 jsx = xfer->data; |
885 | |
886 /* TODO: Should there be an option to not use the local host as a ft proxy? | |
887 * (to prevent revealing IP address, etc.) */ | |
872 jsx->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM, | 888 jsx->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM, |
873 jabber_si_xfer_bytestreams_listen_cb, xfer); | 889 jabber_si_xfer_bytestreams_listen_cb, xfer); |
874 if (jsx->listen_data == NULL) { | 890 if (jsx->listen_data == NULL) { |
875 purple_xfer_unref(xfer); | 891 /* We couldn't open a local port. Perhaps we can use a proxy. */ |
876 /* XXX: couldn't open a port, we're fscked */ | 892 jabber_si_xfer_bytestreams_listen_cb(-1, xfer); |
877 purple_xfer_cancel_local(xfer); | |
878 return; | |
879 } | 893 } |
880 | 894 |
881 } | 895 } |
882 | 896 |
883 static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet, | 897 static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet, |