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,