📄 newtella.c
字号:
/*-*-linux-c-*-*//* * gnewtellium - Newtella for Unix * Copyright (C) 2001 Elias Athanasopoulos * * This program 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 of the License, or * (at your option) any later version. * * This program 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 program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* These includes are needed in the specified order by the BSD family. It maybe better to add an #ifdef BSD or something here...*/#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <stdlib.h>#include <sys/time.h>#include <unistd.h>#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <time.h>#include <string.h>#include "global.h"#include "newtella.h"#include "gnutella.h"#include "gui.h"#include "config.h"#include "file.h"#include "uploads.h"#include "downloads.h"#include "hosts.h"#include "route.h"extern struct newtella_options *gl_options;extern int gl_server, gl_read_tag;extern struct host_info *gl_my_host_info;gchar *ip2str(guint32 ip){ /* taken from gtk-gnutella */ struct in_addr ia; ia.s_addr = g_htonl(ip); return inet_ntoa(ia);}guint32 str2ip(gchar *str){ /* taken from gtk-gnutella */ struct in_addr ia; gint r; r = inet_aton(str, &ia); if (r) return g_ntohl(ia.s_addr); return 0;}int is_mp3(gchar *str){ return (!g_strncasecmp(str+strlen(str)-4, ".mp3", 4));}int newtella_server(int port){ int rval, s; struct sockaddr_in server; size_t option; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("server socket"); return 0; } /* get rid of "bind: address already used" */ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &option, sizeof(option)); /* non blocked */ fcntl(s, F_SETFL, O_NONBLOCK); server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(port); rval = bind(s, (struct sockaddr *)&server, sizeof(server)); if (rval < 0) { perror("server bind"); return 0; } return s;}int newtella_init_server(guint16 port){ gl_server = newtella_server(port); if (!gl_server) return 0; if (listen(gl_server, 10) < 0) perror("server listen"); gl_read_tag = gdk_input_add(gl_server, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, (GdkInputFunction) newtella_welcome_client, NULL); return 1;}int newtella_kill_server(void){ /* try to kill server */ if (gl_server) { gdk_input_remove(gl_read_tag); close(gl_server); } return 1;}int newtella_guess_ip(gint s){ struct sockaddr_in servent; size_t len = sizeof(struct sockaddr_in); /* kludge: if our local IP is not in the Internet space, guess it using a random connection. */ getsockname(s, (struct sockaddr *) &servent, &len); if (!host_is_private(g_ntohl(servent.sin_addr.s_addr), gl_my_host_info->port)) gl_my_host_info->ip = g_ntohl(servent.sin_addr.s_addr); return 1;}int newtella_force_connect(guint32 ip, guint16 port){ struct sockaddr_in server; int s = socket(AF_INET, SOCK_STREAM, 0); fcntl(s, F_SETFL, O_NONBLOCK); server.sin_family = AF_INET; server.sin_port = g_htons(port); server.sin_addr.s_addr = g_htonl(ip); if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { if (errno != EINPROGRESS) { perror("connect (client)"); return (-1); } } return s;}int newtella_welcome_client(gpointer gdata, gint s, GdkInputCondition cond){ struct sockaddr_in addr; int sock, len = sizeof(struct sockaddr_in); struct newtella_connection *in_con; if (cond == GDK_INPUT_EXCEPTION) return -1; sock = accept(s, (struct sockaddr *) &addr, &len); if (sock == -1) return -1; /* make it non-block */ fcntl(sock, F_SETFL, O_NONBLOCK); /* create a new incoming connection */ in_con = newtella_malloc(sizeof(struct newtella_connection)); in_con->s = sock; in_con->ip = g_ntohl(addr.sin_addr.s_addr); in_con->port = g_ntohs(addr.sin_port); in_con->type = CT_INCOMING; con_zero_stats(in_con); con_init_queue(in_con); in_con->state = GS_HANDSHAKE; if (gl_options->cons == 1) gl_con = g_list_append(NULL, in_con); else gl_con = g_list_append(gl_con, in_con); gui_add_con_to_list(in_con); in_con->read_tag = gdk_input_add(in_con->s, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, (GdkInputFunction) newtella_read, (gpointer)in_con); in_con->write_tag = 0; /* update time */ in_con->last_time = time((time_t)NULL); return 1;}int newtella_handshake_sucks(char *buf, int len){ /* handshake/download/upload data */ if (!memcmp(buf, "GNUTELLA OK\n\n", strlen("GNUTELLA OK\n\n"))) return 0; if (!memcmp(buf, "GNUTELLA CONNECT/0.4\n\n", strlen("GNUTELLA CONNECT/0.4\n\n"))) return 0; if (!memcmp(buf, "GET /get/", strlen("GET /get/"))) return 0; if (!memcmp(buf, "GIV", strlen("GIV"))) return 0; return 1;}int newtella_packet_sucks(struct gnutella_header *gh){ if ((gh->length > MAX_PACKET_LENGTH) || (gh->length < 0)) goto bad; if (gh->ttl > GNUTELLA_MAX_TTL || gh->hops > GNUTELLA_MAX_HOPS || gh->ttl == 0) goto bad; /* length check */ switch (gh->f) { case GNUTELLA_INIT: if (gh->length != 0) goto bad; break; case GNUTELLA_INITRESPONSE:; if (gh->length != GN_PONG_SIZE) goto bad; break; case GNUTELLA_PUSHREQUEST: if (gh->length != GN_PUSH_SIZE) goto bad; break; case GNUTELLA_SEARCH: if (gh->length < (GN_QUERY_SIZE+1)) goto bad; if (gh->length > GNUTELLA_MAX_QUERY) goto bad; break; case GNUTELLA_SEARCHRESPONSE: break; default: /* ok, this is defenately a bad package */ goto bad; } return 0; bad: // g_print("Got a bad packet. Func: 0x%X Size: %d\n", gh->f, gh->length); return 1;}gint handle_connect(struct newtella_connection *con, gchar *buf){ struct squery *query; struct host_info *host; GSList *l; GList *iter; gint hosts_sent = 0; if (memcmp(buf, "GNUTELLA CONNECT/0.4\n\n", strlen("GNUTELLA CONNECT/0.4\n\n"))) return 0; con_send_packet(con, "GNUTELLA OK\n\n", strlen("GNUTELLA OK\n\n"), 0); /* if we are full on connections send some cached hosts and drop the new connection */ if (gl_options->connected >= gl_options->max_con) { iter = g_list_first(gl_hosts_in_cache); while (iter) { host = (struct host_info *) iter->data; gnutella_send_cached_host(con, host); hosts_sent++; if (hosts_sent > HOST_FEED) break; iter = iter->next; } con_mark(con, GS_HOSTFEED); return 1; } con_mark(con, GS_CONNECTED); /* send pending queries */ for (l = gl_queries; l; l = l->next) { query = (struct squery *) l->data; gnutella_send_query(query, con, 0); } return 1;}int handle_connect_response(struct newtella_connection *con, char *buf){ GSList *l; struct squery *query; if (memcmp(buf, "GNUTELLA OK\n\n", strlen("GNUTELLA OK\n\n"))) return 0; con_mark(con, GS_CONNECTED); if (gl_options->hosts_in_cache < HOST_CACHE_LOW_LIMIT) gnutella_send_ping(con, 0); else gnutella_send_ping(con, 1); /* send pending queries */ for (l = gl_queries; l; l = l->next) { query = (struct squery *) l->data; gnutella_send_query(query, con, 0); } return 1;}int handle_get_request(struct newtella_connection *con, char *buf){ if (memcmp(buf, "GET /get/", 8)) return 0; return 1;}int handle_push(struct newtella_connection *con, struct gnutella_header *gh, char *buf){ struct gnutella_push *gpush; struct message *rmsg, *msg; /* check if we have seen the ping */ if (route_msg_find(gh->guid, GNUTELLA_INIT, gh->length)) { con->total_received_dropped++; return GN_PUSH_SIZE; } else con->total_handled++; gpush = newtella_malloc(sizeof *gpush); GNUTELLA_PUSH_GRAB(gpush, buf) /* is it for us? */ if (guidcmp(gl_options->gl_guid, gpush->guid)) { upload_add(g_htonl(gpush->ip), gpush->port, gpush->index, gpush->guid); goto skip_routing; } /* route the push if we have seen the result set */ msg = route_msg_rs_find(gpush->guid); if (!msg) goto skip_routing; /* ok, we have to route it */ rmsg = newtella_malloc(sizeof *rmsg); rmsg->head = newtella_malloc(sizeof *(rmsg->head)); *(rmsg->head) = *gh; rmsg->length = GN_HEADER_SIZE + gh->length; rmsg->policy = RP_ONLY_TO; rmsg->con = msg->con; rmsg->time = time((time_t *)NULL); /* route msg */ route_msg_add(rmsg, buf); skip_routing: newtella_free(gpush); return GN_PUSH_SIZE;}int handle_init(struct newtella_connection *con, struct gnutella_header *gh){ struct message *rmsg; /* check if we have seen the ping */ if (route_msg_find(gh->guid, GNUTELLA_INIT, gh->length)) { con->total_received_dropped++; return 0; } else con->total_handled++; /* send the reply (pong) */ gnutella_send_pong(con, gh->guid, 7); /* remove packet from network if it has expired */ if (gh->ttl == 1) return 0; /* store the new ping */ rmsg = newtella_malloc(sizeof(struct message)); rmsg->head = newtella_malloc(sizeof *(rmsg->head)); *(rmsg->head) = *gh; rmsg->length = GN_HEADER_SIZE; rmsg->policy = RP_ALL_EXC; rmsg->con = con; rmsg->time = time((time_t *)NULL); /* route msg */ route_msg_add(rmsg, NULL); return 0;}int handle_init_response(struct newtella_connection *con, gchar *buf, struct gnutella_header *gh){ struct gnutella_pong_header *gpong; struct message *rmsg, *msg; /* check if we have seen the pong */ if (route_msg_find(gh->guid, GNUTELLA_INITRESPONSE, gh->length)) { con->total_received_dropped++; return GN_PONG_SIZE; } else con->total_handled++; /* add it in cache only if we are low on hosts */ if (gl_options->hosts_in_cache < gl_options->host_cache_length) { gpong = newtella_malloc(sizeof *gpong); GNUTELLA_PONG_GRAB(gpong, buf) host_add_in_cache(gpong); newtella_free(gpong); } /* remove packet from network if it has expired */ if (gh->ttl == 1) return GN_PONG_SIZE; /* check if we haven't seen the ping related to the pong */ msg = route_msg_find(gh->guid, GNUTELLA_INIT, gh->length); if (msg == NULL) return GN_PONG_SIZE; /* ok, we have to route it */ rmsg = newtella_malloc(sizeof *rmsg); rmsg->head = newtella_malloc(sizeof *(rmsg->head)); *(rmsg->head) = *gh; rmsg->length = GN_HEADER_SIZE + gh->length; rmsg->policy = RP_ONLY_TO; rmsg->con = msg->con; rmsg->time = time((time_t *)NULL); /* route msg */ route_msg_add(rmsg, buf); return GN_PONG_SIZE;}int handle_search(struct newtella_connection *con, struct gnutella_header *gh, gchar *buf){ struct gnutella_query_header *gquery; struct message *rmsg; GList *keywords, *iter, *found_hits; gint query_length; /* check if we have seen the query */ if (route_msg_find(gh->guid, GNUTELLA_SEARCH, gh->length)) { con->total_received_dropped++; return gh->length; } query_length = strlen(buf+2); if (query_length > GNUTELLA_MAX_QUERY) { con->total_bad_received++; return gh->length; } con->total_handled++; gquery = newtella_malloc(sizeof *gquery); GNUTELLA_QUERY_GRAB(gquery, buf); keywords = file_extract_keywords(gquery->name); if (keywords) { GList *l; iter = g_list_first(keywords); while (iter) { found_hits = file_scan_db((gchar *)iter->data); /* ok we have what he/she wants */ if (found_hits) { gnutella_send_query_response(con, found_hits, gh->guid); g_list_free(found_hits); } iter = iter->next; } /* clean up */ l = g_list_first(keywords); while (l) { newtella_free(l->data); l = l->next; } g_list_free(keywords); } /* remove packet from network if it has expired */ if (gh->ttl == 1) goto skip_query; /* store the new packet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -