paulo@0: /* paulo@0: * $Id: push.c,v 1.3 2004/03/24 06:36:12 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: #include "msg_handler.h" paulo@0: paulo@0: #include "gt_accept.h" paulo@0: #include "gt_share_file.h" paulo@0: #include "gt_share.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: typedef struct giv_connect paulo@0: { paulo@0: uint32_t index; paulo@0: char *filename; paulo@0: } giv_connect_t; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static giv_connect_t *giv_connect_alloc (uint32_t index, const char *filename) paulo@0: { paulo@0: giv_connect_t *giv; paulo@0: paulo@0: if (!(giv = malloc (sizeof(giv_connect_t)))) paulo@0: return NULL; paulo@0: paulo@0: if (filename) paulo@0: giv->filename = STRDUP (filename); paulo@0: else paulo@0: giv->filename = NULL; paulo@0: paulo@0: giv->index = index; paulo@0: paulo@0: return giv; paulo@0: } paulo@0: paulo@0: static void giv_connect_free (giv_connect_t *giv) paulo@0: { paulo@0: if (!giv) paulo@0: return; paulo@0: paulo@0: free (giv->filename); paulo@0: free (giv); paulo@0: } paulo@0: paulo@0: static char *giv_connect_str (giv_connect_t *giv) paulo@0: { paulo@0: String *s; paulo@0: paulo@0: if (!(s = string_new (NULL, 0, 0, TRUE))) paulo@0: return NULL; paulo@0: paulo@0: string_append (s, "GIV "); paulo@0: string_appendf (s, "%u:", giv->index); paulo@0: string_appendf (s, "%s/", gt_guid_str (GT_SELF_GUID)); paulo@0: paulo@0: if (giv->filename && !string_isempty (giv->filename)) paulo@0: string_append (s, giv->filename); paulo@0: paulo@0: string_append (s, "\n\n"); paulo@0: paulo@0: return string_free_keep (s); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static void handle_giv_connect (int fd, input_id id, TCPC *c, paulo@0: giv_connect_t *giv) paulo@0: { paulo@0: char *str; paulo@0: int ret; paulo@0: paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGFN (GT, "entered"); paulo@0: paulo@0: if (net_sock_error (fd)) paulo@0: { paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGFN (GT, "error connecting back: %s", GIFT_NETERROR ()); paulo@0: paulo@0: tcp_close (c); paulo@0: return; paulo@0: } paulo@0: paulo@0: /* restore the index */ paulo@0: c->udata = NULL; paulo@0: str = giv_connect_str (giv); paulo@0: paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGSOCK (GT, c, "sending GIV response: %s", str); paulo@0: paulo@0: ret = tcp_send (c, str, strlen (str)); paulo@0: free (str); paulo@0: paulo@0: if (ret <= 0) paulo@0: { paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGFN (GT, "error sending: %s", GIFT_NETERROR ()); paulo@0: paulo@0: tcp_close (c); paulo@0: return; paulo@0: } paulo@0: paulo@0: /* use this connection for something */ paulo@0: input_remove (id); paulo@0: input_add (c->fd, c, INPUT_READ, paulo@0: (InputCallback)gt_handshake_dispatch_incoming, TIMEOUT_DEF); paulo@0: } paulo@0: paulo@0: static void giv_connect (int fd, input_id id, TCPC *c) paulo@0: { paulo@0: giv_connect_t *giv; paulo@0: paulo@0: giv = c->udata; paulo@0: handle_giv_connect (fd, id, c, giv); paulo@0: paulo@0: giv_connect_free (giv); paulo@0: } paulo@0: paulo@0: static void gt_giv_request (GtNode *src, uint32_t index, in_addr_t ip, paulo@0: in_port_t port, uint8_t hops) paulo@0: { paulo@0: giv_connect_t *giv; paulo@0: char *filename = NULL; paulo@0: Share *share; paulo@0: GtShare *gt_share; paulo@0: TCPC *c; paulo@0: paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGFN (GT, "entered"); paulo@0: paulo@0: /* if the pushed IP address is local, forget about it */ paulo@0: if (gt_is_local_ip (ip, src->ip)) paulo@0: return; paulo@0: paulo@0: /* special case: if the node we got the giv from is local paulo@0: * and the giv is from them (hops=0), don't connect to the paulo@0: * external address but the internal */ paulo@0: if (hops == 0 && gt_is_local_ip (src->ip, ip)) paulo@0: ip = src->ip; paulo@0: paulo@0: /* paulo@0: * Look for the index in the local shared database, if it is found paulo@0: * keep track of the filename. paulo@0: */ paulo@0: if ((share = gt_share_local_lookup_by_index (index, NULL)) != NULL && paulo@0: (gt_share = share_get_udata (share, GT->name)) != NULL) paulo@0: { paulo@0: filename = gt_share->filename; paulo@0: } paulo@0: paulo@0: if (!(giv = giv_connect_alloc (index, filename))) paulo@0: return; paulo@0: paulo@0: if (!(c = tcp_open (ip, port, FALSE))) paulo@0: { paulo@0: giv_connect_free (giv); paulo@0: return; paulo@0: } paulo@0: paulo@0: c->udata = giv; paulo@0: paulo@0: input_add (c->fd, c, INPUT_WRITE, paulo@0: (InputCallback)giv_connect, TIMEOUT_DEF); paulo@0: } paulo@0: paulo@0: GT_MSG_HANDLER(gt_msg_push) paulo@0: { paulo@0: gt_guid_t *client_guid; paulo@0: uint32_t index; paulo@0: uint32_t ip; paulo@0: uint16_t port; paulo@0: uint8_t hops; paulo@0: paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGFN (GT, "entered"); paulo@0: paulo@0: client_guid = gt_packet_get_ustr (packet, 16); paulo@0: index = gt_packet_get_uint32 (packet); paulo@0: ip = gt_packet_get_ip (packet); paulo@0: port = gt_packet_get_port (packet); paulo@0: paulo@0: hops = gt_packet_hops (packet); paulo@0: paulo@0: if (MSG_DEBUG) paulo@0: { paulo@0: GT->DBGSOCK (GT, c, "client_guid=%s index=%d ip=%s port=%hu", paulo@0: gt_guid_str (client_guid), index, net_ip_str (ip), port); paulo@0: } paulo@0: paulo@0: if (gt_guid_cmp (client_guid, GT_SELF_GUID) == 0) paulo@0: { paulo@0: /* TODO: we should not respond if we get a lot of these */ paulo@0: gt_giv_request (GT_NODE(c), index, ip, port, hops); paulo@0: return; paulo@0: } paulo@0: paulo@0: #if 0 paulo@0: if ((dst_c = push_cache_lookup (client->guid))) paulo@0: gt_route_forward_packet (dst_c, packet); paulo@0: #endif paulo@0: }