📄 nut-request.c
字号:
/* * nut-request.c - gnutella requests implementations * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: nut-request.c,v 1.14 2001/08/01 10:16:23 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_GNUTELLA#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <string.h>#ifndef __MINGW32__# include <sys/types.h># include <sys/socket.h># include <netinet/in.h># include <arpa/inet.h>#endif#ifdef __MINGW32__# include <winsock2.h>#endif#include "libserveez.h"#include "gnutella.h"#include "nut-core.h"#include "nut-transfer.h"#include "nut-hostlist.h"#include "nut-request.h"/* * This routine will be called when a search reply occurs. Here we * can check if the reply was created by a packet we sent ourselves. */intnut_reply (svz_socket_t *sock, nut_header_t *hdr, svz_uint8_t *packet){ nut_config_t *cfg = sock->cfg; svz_socket_t *xsock; nut_packet_t *pkt; nut_record_t *record; nut_client_t *client = sock->data; char *p, *end, *file; int n; svz_uint8_t *id; nut_reply_t *reply; reply = nut_get_reply (packet); nut_host_catcher (sock, reply->ip, reply->port); pkt = (nut_packet_t *) svz_hash_get (cfg->packet, (char *) hdr->id); /* check client guid at the end of the packet */ id = packet + hdr->length - NUT_GUID_SIZE; if (id < packet + SIZEOF_NUT_REPLY) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "nut: dropping invalid query hit\n");#endif client->dropped++; return -1; } /* is that query hit (reply) an answer to my own request ? */ if (pkt != NULL) { xsock = pkt->sock; p = (char *) packet + SIZEOF_NUT_REPLY; end = (char *) packet + hdr->length - NUT_GUID_SIZE; memcpy (reply->id, id, NUT_GUID_SIZE);#if 0 printf ("records : %d\n", reply->records); printf ("port : %u\n", ntohs (reply->port)); printf ("ip : %s\n", svz_inet_ntoa (reply->ip)); printf ("speed : %u kbit/s\n", reply->speed); printf ("guid : %s\n", nut_print_guid (reply->id));#endif /* 0 */ /* process only if the connection has a minimum speed */ if (reply->speed < cfg->min_speed) return 0; /* go through all query hit records */ for (n = 0; n < reply->records && p < end; n++) { record = nut_get_record ((svz_uint8_t *) p); p += SIZEOF_NUT_RECORD; file = p; /* check if the reply is valid */ while (p < end && *p) p++; if (p == end || *(p + 1)) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "nut: invalid query hit payload\n");#endif client->dropped++; return -1; } p += 2; nut_canonize_file (file);#if 0 printf ("record %d\n", n + 1); printf ("file index : %u\n", record->index); printf ("file size : %u\n", record->size); printf ("file : %s\n", file);#endif /* startup transfer if possible */ if (cfg->dnloads < cfg->max_dnloads) { nut_init_transfer (sock, reply, record, file); } } } /* save the reply id to the reply hash for routing push requests */ else { svz_hash_put (cfg->reply, (char *) id, sock); } return 0;}/* * This is the callback for push requests. */intnut_push_request (svz_socket_t *sock, nut_header_t *hdr, svz_uint8_t *packet){ nut_config_t *cfg = sock->cfg; nut_client_t *client = sock->data; svz_socket_t *xsock; nut_push_t *push; nut_file_t *entry; svz_uint8_t *header; push = nut_get_push (packet); /* is the guid of this push request in the reply hash ? */ if ((xsock = (svz_socket_t *) svz_hash_get (cfg->reply, (char *) push->id)) != NULL) { header = nut_put_header (hdr); if (svz_sock_write (xsock, (char *) header, SIZEOF_NUT_HEADER) == -1 || svz_sock_write (xsock, (char *) packet, SIZEOF_NUT_PUSH) == -1) { svz_sock_schedule_for_shutdown (xsock); return -1; } } /* push request for ourselves ? */ else if (!memcmp (cfg->guid, push->id, NUT_GUID_SIZE)) {#if 0 printf ("push request for us\n" "file index : %u\n", push->index); printf ("ip : %s\n", svz_inet_ntoa (push->ip)); printf ("port : %u\n", htons (push->port));#endif /* find requested file in database */ if (cfg->uploads <= cfg->max_uploads && (entry = nut_get_database (cfg, NULL, push->index)) != NULL) { /* try to connect to given host */ if ((xsock = svz_tcp_connect (push->ip, push->port)) != NULL) { svz_log (LOG_NOTICE, "nut: connecting %s:%u\n", svz_inet_ntoa (push->ip), ntohs (push->port)); xsock->userflags |= NUT_FLAG_UPLOAD; xsock->cfg = cfg; svz_sock_setparent (xsock, svz_sock_getparent (sock)); /* * we are not sure about the format of this line, but two * of the reviewed clients (gtk_gnutella and gnutella itself) * use it as is */ if (svz_sock_printf (xsock, NUT_GIVE "%d:%s/%s\n\n", entry->index, nut_text_guid (cfg->guid), entry->file) == -1) { svz_sock_schedule_for_shutdown (xsock); return -1; } xsock->check_request = nut_check_upload; xsock->idle_func = nut_connect_timeout; xsock->idle_counter = NUT_CONNECT_TIMEOUT; } } } /* drop this push request */ else {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "nut: dropping push request\n");#endif client->dropped++; return -1; } return 0;}/* * This is called whenever there was a search query received. */intnut_query (svz_socket_t *sock, nut_header_t *hdr, svz_uint8_t *packet){ nut_config_t *cfg = sock->cfg; nut_reply_t reply; nut_record_t record; nut_query_t *query; nut_file_t *entry; svz_uint8_t *file, *p, *buffer = NULL; unsigned n, len = 0, size; struct sockaddr_in *addr = NULL; svz_portcfg_t *port; /* shall we reply to this query ? */ query = nut_get_query (packet); if (query->speed > cfg->speed) return -1; /* check validity of search request */ p = file = packet + SIZEOF_NUT_QUERY; len = SIZEOF_NUT_QUERY; while (*p++ && len < hdr->length) len++; if (len >= hdr->length && *file) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "nut: invalid query payload\n");#endif return -1; } /* create new gnutella header */ hdr->function = NUT_SEARCH_ACK; hdr->ttl = hdr->hop; hdr->hop = 0; /* go through database and build the record array */ for (size = 0, n = 0, entry = NULL; n < 256 && (int) n < cfg->search_limit;) { if ((entry = nut_find_database (cfg, entry, (char *) file)) != NULL) { len = strlen (entry->file) + 2; size += SIZEOF_NUT_RECORD + len; buffer = svz_realloc (buffer, size); p = buffer + size - len; memcpy (p, entry->file, len - 1); p += len - 1; *p = '\0'; p = buffer + size - len - SIZEOF_NUT_RECORD; record.index = entry->index; record.size = entry->size; memcpy (p, nut_put_record (&record), SIZEOF_NUT_RECORD); n++; } else break; } /* no files found in database */ if (!n) return 0; /* create gnutella search reply packet */ reply.records = (svz_uint8_t) n; if ((port = svz_sock_portcfg (sock)) != NULL) addr = svz_portcfg_addr (port); reply.ip = cfg->ip ? cfg->ip : addr ? addr->sin_addr.s_addr : sock->local_addr; reply.port = (unsigned short) (cfg->port ? cfg->port : addr ? addr->sin_port : sock->local_port); reply.speed = (unsigned short) cfg->speed; /* save packet length */ hdr->length = SIZEOF_NUT_REPLY + size + NUT_GUID_SIZE; /* send header, reply, array of records and guid */ if (svz_sock_write (sock, (char *) nut_put_header (hdr), SIZEOF_NUT_HEADER) == -1 || svz_sock_write (sock, (char *) nut_put_reply (&reply), SIZEOF_NUT_REPLY) == -1 || svz_sock_write (sock, (char *) buffer, size) == -1 || svz_sock_write (sock, (char *) cfg->guid, NUT_GUID_SIZE) == -1) { svz_free (buffer); return -1; } svz_free (buffer); return 0;}/* * This routine will be called when some gnutella server sent a * ping reply. */intnut_pong (svz_socket_t *sock, nut_header_t *hdr, svz_uint8_t *packet){ nut_config_t *cfg = sock->cfg; svz_socket_t *xsock; nut_packet_t *pkt; nut_pong_t *reply; nut_client_t *client = sock->data; /* put to host catcher hash */ reply = nut_get_pong (packet); nut_host_catcher (sock, reply->ip, reply->port); pkt = (nut_packet_t *) svz_hash_get (cfg->packet, (char *) hdr->id); /* is this a reply to my own gnutella packet ? */ if (pkt != NULL) { xsock = pkt->sock;#if 0 printf ("port : %u\n", ntohs (reply->port)); printf ("ip : %s\n", svz_inet_ntoa (reply->ip)); printf ("files : %u\n", reply->files); printf ("size : %u kb\n", reply->size);#endif /* update statistics */ cfg->nodes++; client->nodes++; if (reply->files && reply->size) { cfg->files += reply->files; cfg->size += reply->size; client->files += reply->files; client->size += reply->size; } } return 0;}/* * This callback is called if a ping request was received. We just * reply with our own configuration. */intnut_ping (svz_socket_t *sock, nut_header_t *hdr, svz_uint8_t *null){ nut_config_t *cfg = sock->cfg; nut_pong_t reply; svz_uint8_t *header, *pong; struct sockaddr_in *addr = NULL; svz_portcfg_t *port = NULL; /* create new gnutella packets */ hdr->function = NUT_PING_ACK; hdr->length = SIZEOF_NUT_PONG; hdr->ttl = hdr->hop; hdr->hop = 0; if ((port = svz_sock_portcfg (sock)) != NULL) addr = svz_portcfg_addr (port); reply.ip = cfg->ip ? cfg->ip : addr ? addr->sin_addr.s_addr : sock->local_addr; reply.port = (unsigned short) (cfg->port ? cfg->port : addr ? addr->sin_port : sock->local_port); reply.files = cfg->db_files; reply.size = cfg->db_size / 1024; header = nut_put_header (hdr); pong = nut_put_pong (&reply); /* try sending this packet */ if (svz_sock_write (sock, (char *) header, SIZEOF_NUT_HEADER) == -1 || svz_sock_write (sock, (char *) pong, SIZEOF_NUT_PONG) == -1) { svz_sock_schedule_for_shutdown (sock); return -1; } return 0;}#else /* ENABLE_GNUTELLA */int nut_request_dummy; /* Shut compiler warnings up. */#endif /* not ENABLE_GNUTELLA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -