📄 downloads.c
字号:
/*-*-linux-c-*-*/#include <stdlib.h>#include <time.h> #include <fcntl.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <gtk/gtk.h>#include "newtella.h"#include "connection.h"#include "gui.h"#include "gnutella.h"#include "hosts.h"#include "downloads.h"#include "http.h"#include "file.h"/* General functions for Download connections */int download_write(gpointer gdata, gint s, GdkInputCondition cond){ struct newtella_connection *dcon = (struct newtella_connection *)gdata; struct gpacket *packet; gint r; if (cond == GDK_INPUT_EXCEPTION) { download_stop(dcon, "Failed at sending HTTP headers"); return -1; } if (g_list_length(dcon->queue)) { packet = (struct gpacket *) g_list_last(dcon->queue)->data; r = send(dcon->s, packet->data, packet->len, 0); if (r != packet->len) download_stop(dcon, "Failed at sending HTTP headers"); dcon->queue = g_list_remove(dcon->queue, packet); newtella_free(packet->data); newtella_free(packet); gdk_input_remove(dcon->write_tag); } return 1;}int download_read(gpointer gdata, gint s, GdkInputCondition cond){ struct newtella_connection *dcon = (struct newtella_connection *)gdata; struct http_header *http; gchar *save_file; gchar servent_info[1024]; gint bytes_to_read, bytes_readed, http_skip, http_size; if (cond == GDK_INPUT_EXCEPTION) { download_stop(dcon, "Failed to read!"); return -1; } bytes_to_read = bytes_avail(dcon->s); if (!bytes_to_read) { if (dcon->total_handled == dcon->fi->size) dcon->state = GS_COMPLETE; else { dcon->state = GS_FAILED; download_stop(dcon, "Failed to read!"); return -1; } gui_update_download(dcon); return -1; } dcon->b = dcon->buffer + dcon->buffer_len; bytes_readed = con_recv_packet(dcon, bytes_to_read); if (bytes_readed != bytes_to_read) { download_stop(dcon, "Failed to read!"); return -1; } dcon->buffer_len += bytes_readed; if (dcon->hs_sent) { write(dcon->fi->des, dcon->buffer, bytes_readed); dcon->total_handled += bytes_readed; con_reset_buffer(dcon); gui_update_download(dcon); } else { /* parse the http headers */ do { http_size = http_header_size(dcon->buffer); if (!http_size) break; http = newtella_malloc(http_size); if (!memcmp("GIV", dcon->buffer, 3)) { con_reset_buffer(dcon); http->func = HTTP_GET; http->user_agent = GNEWTELLIUM; http->connection = "Keep-Alive"; http->file_name = dcon->fi->file_name; http->file_index = dcon->fi->index; http->range_start = 0; dcon->write_tag = gdk_input_add(dcon->s, GDK_INPUT_WRITE | GDK_INPUT_EXCEPTION, (GdkInputFunction) download_write, (gpointer)dcon); con_send_packet(dcon, http_header_build(http), strlen(http_header_build(http)), 0); return 1; } //g_print("***Got Response: %s\n", dcon->buffer); http = http_header_parse(dcon->buffer); /* GUI update */ if (http->user_agent) { gint row; g_snprintf(servent_info, sizeof(servent_info), "%s:%d (%s)", ip2str(dcon->fi->ip), dcon->fi->port, http->user_agent); row = gtk_clist_find_row_from_data(GTK_CLIST(download_list), (gpointer) dcon); gtk_clist_set_text(GTK_CLIST(download_list), row, 4, servent_info); } if (http->valid && (http->code == 200 || http->code == 206)) { save_file = newtella_malloc(strlen(gl_options->download_dir)+ strlen(dcon->fi->file_name)+1); strcpy(save_file, gl_options->download_dir); strcat(save_file, dcon->fi->file_name); if (!http->range_start) dcon->fi->des = open(save_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); else { gui_update_download_status(dcon, "Resuming"); dcon->fi->des = open(save_file, O_WRONLY, 0644); lseek(dcon->fi->des, http->range_start, SEEK_SET); } newtella_free(save_file); /* cut the HTTP header */ http_skip = bytes_readed - http_size; write(dcon->fi->des, dcon->buffer+http_size, http_skip); dcon->total_handled = http->range_start - http_skip; con_reset_buffer(dcon); dcon->hs_sent = 1; dcon->state = GS_CONNECTED; } else { switch (http->code) { case 404: dcon->state = GS_NOTFOUND; break; case 503: dcon->state = GS_BUSY; break; default: dcon->state = GS_FAILED; break; } download_stop(dcon, NULL); break; } } while (!dcon->hs_sent); } return 1;}int download_accept(gpointer data, gint source, GdkInputCondition cond){ struct sockaddr_in addr; size_t len; struct newtella_connection *dcon = data; int rval = accept(dcon->s, (struct sockaddr *) &addr, &len); if (rval == -1) printf("Can't accept\n"); dcon->s = rval; gdk_input_remove(dcon->read_tag); dcon->read_tag = gdk_input_add(dcon->s, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, (GdkInputFunction) download_read, (gpointer)dcon); return 1;}int download_add(struct file_found *download_file){ struct newtella_connection *dcon = newtella_malloc(sizeof(struct newtella_connection)); gint resume; /* copy the file info */ dcon->fi = newtella_malloc(sizeof *(dcon->fi)); *(dcon->fi) = *download_file; dcon->ip = gl_my_host_info->ip; con_zero_stats(dcon); con_init_queue(dcon); dcon->hs_sent = 0; if (gl_options->dcons == 1) gl_down_con = g_list_append(NULL, dcon); else gl_down_con = g_list_append(gl_down_con, dcon); gui_add_download(dcon); resume = file_get_size(dcon->fi->file_name, gl_options->download_dir); download_start(dcon, resume); return 1;}void download_resume(struct newtella_connection *dcon){ gint resume; dcon->state = GS_RESUME; gui_update_download_status(dcon, "Trying to resume..."); con_reset_buffer(dcon); con_zero_stats(dcon); con_init_queue(dcon); dcon->hs_sent = 0; resume = file_get_size(dcon->fi->file_name, gl_options->download_dir); download_start(dcon, resume);}int download_start(struct newtella_connection *dcon, gint resume){ struct sockaddr_in gnode, addr; size_t option; struct http_header *http = newtella_malloc(sizeof(struct http_header)); if (!dcon->fi->push) { /* direct connection */ dcon->state = GS_WAITINGCONNECT; dcon->s = newtella_force_connect(dcon->fi->ip, dcon->fi->port); if (dcon->s == -1) { perror("connect"); dcon->state = GS_FAILED; return (-1); } setsockopt(dcon->s, SOL_SOCKET, SO_KEEPALIVE, (void *) &option, sizeof(option)); setsockopt(dcon->s, SOL_SOCKET, SO_REUSEADDR, (void *) &option, sizeof(option)); dcon->read_tag = gdk_input_add(dcon->s, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, (GdkInputFunction) download_read, (gpointer)dcon); dcon->write_tag = gdk_input_add(dcon->s, GDK_INPUT_WRITE | GDK_INPUT_EXCEPTION, (GdkInputFunction) download_write, (gpointer)dcon); http->func = HTTP_GET; http->user_agent = GNEWTELLIUM; http->connection = "Keep-Alive"; http->file_name = dcon->fi->file_name; http->file_index = dcon->fi->index; http->range_start = resume; http->range_end = dcon->fi->size; //g_print("***Sending %s\n", http_header_build(http)); con_send_packet(dcon, http_header_build(http), strlen(http_header_build(http)), 0); } else { /* firewall - send a push */ dcon->state = GS_WAITINGPUSH; gui_update_download(dcon); dcon->s = socket(AF_INET, SOCK_STREAM, 0); if (fcntl(dcon->s, F_SETFL, O_NONBLOCK) == -1) { perror("fcntl"); exit(EXIT_FAILURE); } gnode.sin_family = AF_INET; gnode.sin_addr.s_addr = htonl(INADDR_ANY); gnode.sin_port = htons(0); bind(dcon->s, (struct sockaddr *)&gnode, sizeof(gnode)); if (listen(dcon->s, 1) == -1) printf("Can't listen\n"); /* get the port number */ option = sizeof(struct sockaddr_in); if (getsockname(dcon->s, (struct sockaddr *) &addr, &option) == -1) printf("Can't getsockname\n"); dcon->port = ntohs(addr.sin_port); gnutella_send_push(dcon); dcon->read_tag = gdk_input_add(dcon->s, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, (GdkInputFunction) download_accept, (gpointer) dcon); } /* update time */ dcon->last_time = time((time_t)NULL); return 1;}int download_stop(struct newtella_connection *dcon, const gchar *reason){ if (dcon->read_tag) gdk_input_remove(dcon->read_tag); close(dcon->s); /* close the downloaded file */ if (dcon->fi->des) close(dcon->fi->des); gui_update_download(dcon); if (reason) gui_update_download_status(dcon, reason); dcon->state = GS_STOPPED; return 1;}int download_kill(struct newtella_connection *dcon){ if (dcon->state != GS_STOPPED) download_stop(dcon, "Killed"); gl_down_con = g_list_remove(gl_down_con, dcon); gui_remove_download(dcon); newtella_free(dcon->fi); newtella_free(dcon); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -