From b3c198997d2adb79fb3c2e48cba9d0511badd9f0 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 28 Oct 2001 20:53:55 +0000 Subject: [PATCH] updates. --- CHANGES | 3 + Makefile.am.pre | 14 +- TODO | 7 - apps/irssi/docs/help/in/file.in | 34 + .../irssi/src/fe-common/silc/module-formats.c | 9 +- .../irssi/src/fe-common/silc/module-formats.h | 3 + apps/irssi/src/silc/core/silc-core.c | 2 +- apps/irssi/src/silc/core/silc-servers.c | 182 +++-- apps/irssi/src/silc/core/silc-servers.h | 6 + apps/silcd/server.c | 9 +- includes/Makefile.am | 2 +- lib/silcclient/Makefile.am | 2 + lib/silcclient/client.c | 67 +- lib/silcclient/client_ftp.c | 635 +++++++++++------- lib/silcclient/client_prvmsg.c | 13 +- lib/silcclient/silcapi.h | 60 +- lib/silccore/Makefile.am | 2 + lib/silccore/silcpacket.c | 18 +- lib/silccrypt/Makefile.am | 2 + lib/silccrypt/silcrng.c | 37 +- lib/silccrypt/silcrng.h | 1 + lib/silcmath/Makefile.am | 2 + lib/silcsftp/Makefile.am | 2 + lib/silcsim/Makefile.am | 2 + lib/silcske/Makefile.am | 2 + lib/silcutil/Makefile.am | 2 + lib/silcutil/silcbufutil.h | 3 + lib/silcutil/unix/silcunixsockconn.c | 4 +- 28 files changed, 722 insertions(+), 403 deletions(-) create mode 100644 apps/irssi/docs/help/in/file.in diff --git a/CHANGES b/CHANGES index 28f84fd8..77fa1102 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,9 @@ Sun Oct 28 18:46:27 EST 2001 Pekka Riikonen now in server, to optimize packet processing. Affected file silcd/server.c. + * Include files are installed now only in Toolkit distribution + if make install is given. Affected files: all Makefile.am's. + Thu Oct 25 22:44:06 EDT 2001 Pekka Riikonen * Assure that silc_client_notify_by_server_resolve does not diff --git a/Makefile.am.pre b/Makefile.am.pre index 5be670a0..5c0696c5 100644 --- a/Makefile.am.pre +++ b/Makefile.am.pre @@ -37,11 +37,11 @@ EXTRA_DIST = CHANGES CREDITS $(SILC_EXTRA_DIST) # Installing of SILC into the system # -etcdir = $(silc_etcdir) -modulesdir = $(silc_modulesdir) -helpdir = $(silc_helpdir) -docdir = $(silc_docdir) -logsdir = $(silc_logsdir) +etcdir = $(DESTDIR)$(silc_etcdir) +modulesdir = $(DESTDIR)$(silc_modulesdir) +helpdir = $(DESTDIR)$(silc_helpdir) +docdir = $(DESTDIR)$(silc_docdir) +logsdir = $(DESTDIR)$(silc_logsdir) install-dirs: -mkdir -p $(etcdir) @@ -81,4 +81,8 @@ etc-install: $(etcdir)/silc.conf; \ fi +if SILC_DIST_CLIENT +install-data-hook: install-dirs sim-install doc-install etc-install +else install-data-hook: install-dirs generate-server-key sim-install doc-install etc-install +endif diff --git a/TODO b/TODO index eab9ad3a..dd3db5c9 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,6 @@ TODO/bugs in Irssi SILC client ============================== - o Add the SFTP support. - o /NAMES kees showing things wrong after JOIN and after ppl has left channel. @@ -40,8 +38,6 @@ TODO/bugs in Irssi SILC client TODO/bugs In SILC Client Library ================================ - o Add the SFTP support. - o JOIN command's argument handling is buggy. See the XXX in the code. @@ -122,9 +118,6 @@ TODO/bugs In SILC Server TODO/bugs In SILC Libraries =========================== - o Add some silc_rng_get_byte_fast that read directly from /dev/urandom. - That can be used for padding generation. The current is too slow. - o Compression routines are missing. The protocol supports packet compression thus it must be implemented. SILC Comp API must be defined. zlib package is already included into the lib dir (in CVS, diff --git a/apps/irssi/docs/help/in/file.in b/apps/irssi/docs/help/in/file.in new file mode 100644 index 00000000..a7a07ee5 --- /dev/null +++ b/apps/irssi/docs/help/in/file.in @@ -0,0 +1,34 @@ + +@SYNTAX:file@ + +This command is used to tranfer files between clients. +The actual file transfer stream is sent outside SILC network +peer to peer between the clients. Before the file transfer +begins the SILC Key Exchange protocol is performed between +the two clients to exchange key material. This key material +is then used to secure the file transfer stream between the +clients. + +The currently active file transfer sessions can be seen by +giving the FILE command without arguments. + +Commands: + + SEND + + Sends file transfer request to . This + makes the available to . + + RECEIVE [] + + Accepts the file transfer request and starts + the file transfer session. If the is + omitted the last received request is used. + + CLOSE [] + + Closes the file transfer session, or rejects + file transfer request. If this command is given + during the file transfer process it will be cancelled. + + diff --git a/apps/irssi/src/fe-common/silc/module-formats.c b/apps/irssi/src/fe-common/silc/module-formats.c index 19ae4cb3..6ccbbe88 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.c +++ b/apps/irssi/src/fe-common/silc/module-formats.c @@ -121,16 +121,19 @@ FORMAT_REC fecommon_silc_formats[] = { { "file_send", "File transfer request sent to {nick $0} for $1", 2, { 0, 0 } }, { "file_transmit", "Transmitting file {hilight $0} [$1kB] to {nick $2}", 3, { 0, 0, 0 } }, - { "file_transmitted", "Transmitted file {hilight $0} [$1kB] to {nick $2} [{hilight $3kB/s}]", 4, { 0, 0, 0, 0 } }, + { "file_transmitted", "Transmitted file {hilight $0} [$1kB] to {nick $2} [{hilight $3kB/s}]", 4, { 0, 0, 0, 3 } }, { "file_receive", "Receiving file {hilight $0} [$1kB] from {nick $2}", 3, { 0, 0 } }, - { "file_received", "Received file {hilight $0} [$1kB] from {nick $2} [{hilight $3kB/s}]", 4, { 0, 0 } }, + { "file_received", "Received file {hilight $0} [$1kB] from {nick $2} [{hilight $3kB/s}]", 4, { 0, 0, 0, 3 } }, { "file_request", "File transfer request from {nick $0}", 1, { 0 } }, { "file_request_host", "File transfer request from {nick $0} [$1 port $2]", 3, { 0, 0, 0 } }, { "file_key_exchange", "Negotiating keys for file transfer with {nick $0}", 1, { 0 } }, { "file_na", "No file transfers available", 0 }, { "file_client_na", "No file transfer offered by {nick $0}", 1, { 0 } }, { "file_show_header", "File transfers", 0 }, - { "file_show_line", " $0 $1 ($2)", 3, { 0, 0, 0 } }, + { "file_show_line", " $0 $1: $2kB of $3kB ($4%%) - $5kB/s - $6", 7, { 0, 0, 1, 1, 1, 3, 0 } }, + { "file_already_started", "File transfer already started with {nick $0}", 1, { 0 } }, + { "file_error", "Error during file transfer with {nick $0}", 1, { 0 } }, + { "file_close", "File transfer closed with {nick $0}", 1, { 0 } }, { NULL, NULL, 0 } }; diff --git a/apps/irssi/src/fe-common/silc/module-formats.h b/apps/irssi/src/fe-common/silc/module-formats.h index 89726a55..a7bb8ad8 100644 --- a/apps/irssi/src/fe-common/silc/module-formats.h +++ b/apps/irssi/src/fe-common/silc/module-formats.h @@ -124,6 +124,9 @@ enum { SILCTXT_FILE_CLIENT_NA, SILCTXT_FILE_SHOW_HEADER, SILCTXT_FILE_SHOW_LINE, + SILCTXT_FILE_ALREADY_STARTED, + SILCTXT_FILE_ERROR, + SILCTXT_FILE_CLOSED, }; extern FORMAT_REC fecommon_silc_formats[]; diff --git a/apps/irssi/src/silc/core/silc-core.c b/apps/irssi/src/silc/core/silc-core.c index 9936826d..1a833661 100644 --- a/apps/irssi/src/silc/core/silc-core.c +++ b/apps/irssi/src/silc/core/silc-core.c @@ -353,7 +353,7 @@ void silc_core_init_finish(void) silc_channels_init(); silc_queries_init(); - idletag = g_timeout_add(50, (GSourceFunc) my_silc_scheduler, NULL); + idletag = g_timeout_add(5, (GSourceFunc) my_silc_scheduler, NULL); } /* Deinit SILC. Called from src/fe-text/silc.c */ diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index e20a2d4b..e63578f0 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -308,10 +308,10 @@ char *silc_server_get_channels(SILC_SERVER_REC *server) /* SYNTAX: PING */ /* SYNTAX: SCONNECT [] */ /* SYNTAX: USERS */ -/* SYNTAX: FILE SEND */ +/* SYNTAX: FILE SEND */ /* SYNTAX: FILE RECEIVE [] */ /* SYNTAX: FILE CLOSE [] */ -/* SYNTAX: FILE SHOW */ +/* SYNTAX: FILE */ void silc_command_exec(SILC_SERVER_REC *server, const char *command, const char *args) @@ -439,47 +439,80 @@ static void silc_client_file_monitor(SilcClient client, if (ftp->client_entry == client_entry) { ftp->session_id = session_id; - if (!ftp->filepath) + if (!ftp->filepath && filepath) ftp->filepath = strdup(filepath); break; } } + if (ftp == SILC_LIST_END) + return; + + if (status == SILC_CLIENT_FILE_MONITOR_ERROR) { + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_ERROR, client_entry->nickname); + silc_schedule_task_add(silc_client->schedule, 0, + silc_client_file_close_later, ftp, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + if (ftp == server->current_session) + server->current_session = NULL; + silc_dlist_del(server->ftp_sessions, ftp); + } + + if (status == SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT) { + printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, + SILCTXT_FILE_KEY_EXCHANGE, client_entry->nickname); + } + if (status == SILC_CLIENT_FILE_MONITOR_SEND) { - if (offset == 0) + if (offset == 0) { printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_FILE_TRANSMIT, filepath, fsize, client_entry->nickname); + ftp->starttime = time(NULL); + } if (offset == filesize) { printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_FILE_TRANSMITTED, filepath, fsize, - client_entry->nickname, "1024"); - if (ftp != SILC_LIST_END) { - silc_schedule_task_add(silc_client->schedule, 0, - silc_client_file_close_later, ftp, - 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); - silc_dlist_del(server->ftp_sessions, ftp); - } + client_entry->nickname, ftp->kps); + silc_schedule_task_add(silc_client->schedule, 0, + silc_client_file_close_later, ftp, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + if (ftp == server->current_session) + server->current_session = NULL; + silc_dlist_del(server->ftp_sessions, ftp); } } if (status == SILC_CLIENT_FILE_MONITOR_RECEIVE) { - if (offset == 0) + if (offset == 0) { printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_FILE_RECEIVE, filepath, fsize, client_entry->nickname); + ftp->starttime = time(NULL); + } + if (offset == filesize) { printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, SILCTXT_FILE_RECEIVED, filepath, fsize, - client_entry->nickname, "1024"); - if (ftp != SILC_LIST_END) { - silc_schedule_task_add(silc_client->schedule, 0, - silc_client_file_close_later, ftp, - 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); - silc_dlist_del(server->ftp_sessions, ftp); - } + client_entry->nickname, ftp->kps); + silc_schedule_task_add(silc_client->schedule, 0, + silc_client_file_close_later, ftp, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + if (ftp == server->current_session) + server->current_session = NULL; + silc_dlist_del(server->ftp_sessions, ftp); } } + + /* Save some transmission data */ + if (offset && filesize) { + ftp->percent = ((double)offset / (double)filesize) * (double)100.0; + ftp->kps = (double)((offset / (double)(time(NULL) - ftp->starttime)) + + 1023) / (double)1024; + ftp->offset = offset; + ftp->filesize = filesize; + } } typedef struct { @@ -519,12 +552,13 @@ static void command_file(const char *data, SILC_SERVER_REC *server, { SilcClientConnection conn; SilcClientEntry *entrys, client_entry; + SilcClientFileError ret; uint32 entry_count; char *nickname = NULL, *tmp; unsigned char **argv; uint32 argc; uint32 *argv_lens, *argv_types; - int type; + int type = 0; FtpSession ftp; if (!server || !IS_SILC_SERVER(server) || !server->connected) @@ -533,22 +567,21 @@ static void command_file(const char *data, SILC_SERVER_REC *server, conn = server->conn; /* Now parse all arguments */ - tmp = g_strconcat("KEY", " ", data, NULL); + tmp = g_strconcat("FILE", " ", data, NULL); silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 4); g_free(tmp); - if (argc < 2) - cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); - - type = 0; - if (!strcasecmp(argv[1], "send")) - type = 1; - if (!strcasecmp(argv[1], "receive")) - type = 2; - if (!strcasecmp(argv[1], "close")) - type = 3; - if (!strcasecmp(argv[1], "show")) + if (argc == 1) type = 4; + + if (argc >= 2) { + if (!strcasecmp(argv[1], "send")) + type = 1; + if (!strcasecmp(argv[1], "receive")) + type = 2; + if (!strcasecmp(argv[1], "close")) + type = 3; + } if (type == 0) cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); @@ -628,13 +661,20 @@ static void command_file(const char *data, SILC_SERVER_REC *server, goto out; } - if (!silc_client_file_receive(silc_client, conn, - silc_client_file_monitor, server, - server->current_session->client_entry, - server->current_session->session_id)) - printformat_module("fe-common/silc", server, NULL, - MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, - server->current_session->client_entry->nickname); + ret = silc_client_file_receive(silc_client, conn, + silc_client_file_monitor, server, + server->current_session->client_entry, + server->current_session->session_id); + if (ret != SILC_CLIENT_FILE_OK) { + if (ret == SILC_CLIENT_FILE_ALREADY_STARTED) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED, + server->current_session->client_entry->nickname); + else + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + server->current_session->client_entry->nickname); + } goto out; } @@ -642,13 +682,20 @@ static void command_file(const char *data, SILC_SERVER_REC *server, silc_dlist_start(server->ftp_sessions); while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { if (ftp->client_entry == client_entry) { - if (!silc_client_file_receive(silc_client, conn, - silc_client_file_monitor, server, - ftp->client_entry, - ftp->session_id)) - printformat_module("fe-common/silc", server, NULL, - MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, - server->current_session->client_entry->nickname); + ret = silc_client_file_receive(silc_client, conn, + silc_client_file_monitor, server, + ftp->client_entry, + ftp->session_id); + if (ret != SILC_CLIENT_FILE_OK) { + if (ret == SILC_CLIENT_FILE_ALREADY_STARTED) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED, + client_entry->nickname); + else + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + client_entry->nickname); + } break; } } @@ -692,22 +739,44 @@ static void command_file(const char *data, SILC_SERVER_REC *server, goto out; } - if (!silc_client_file_close(silc_client, conn, - server->current_session->session_id)) + ret = silc_client_file_close(silc_client, conn, + server->current_session->session_id); + if (ret != SILC_CLIENT_FILE_OK) { + if (ret == SILC_CLIENT_FILE_ALREADY_STARTED) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED, + server->current_session->client_entry->nickname); + else + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + server->current_session->client_entry->nickname); + } else { printformat_module("fe-common/silc", server, NULL, - MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + MSGLEVEL_CRAP, SILCTXT_FILE_CLOSED, server->current_session->client_entry->nickname); - + } goto out; } silc_dlist_start(server->ftp_sessions); while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) { if (ftp->client_entry == client_entry) { - if (!silc_client_file_close(silc_client, conn, ftp->session_id)) + ret = silc_client_file_close(silc_client, conn, ftp->session_id); + if (ret != SILC_CLIENT_FILE_OK) { + if (ret == SILC_CLIENT_FILE_ALREADY_STARTED) + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_ALREADY_STARTED, + client_entry->nickname); + else + printformat_module("fe-common/silc", server, NULL, + MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, + client_entry->nickname); + } else { printformat_module("fe-common/silc", server, NULL, - MSGLEVEL_CRAP, SILCTXT_FILE_CLIENT_NA, - server->current_session->client_entry->nickname); + MSGLEVEL_CRAP, SILCTXT_FILE_CLOSED, + client_entry->nickname); + } + silc_dlist_del(server->ftp_sessions, ftp); silc_free(ftp->filepath); silc_free(ftp); @@ -739,8 +808,11 @@ static void command_file(const char *data, SILC_SERVER_REC *server, printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_LINE, ftp->client_entry->nickname, - ftp->filepath ? ftp->filepath : "[unknown]", - ftp->send ? "send" : "receive"); + ftp->send ? "send" : "receive", + (uint32)(ftp->offset + 1023) / 1024, + (uint32)(ftp->filesize + 1023) / 1024, + ftp->percent, ftp->kps, + ftp->filepath ? ftp->filepath : "[N/A]"); } break; diff --git a/apps/irssi/src/silc/core/silc-servers.h b/apps/irssi/src/silc/core/silc-servers.h index a790fa39..7add2f55 100644 --- a/apps/irssi/src/silc/core/silc-servers.h +++ b/apps/irssi/src/silc/core/silc-servers.h @@ -27,6 +27,12 @@ typedef struct { uint32 session_id; char *filepath; bool send; + + long starttime; /* Start time of transfer */ + double kps; /* Kilos per second */ + uint64 offset; /* Current offset */ + uint64 filesize; /* Total file size */ + uint32 percent; /* Percent of current transmission */ } *FtpSession; #define STRUCT_SERVER_CONNECT_REC SILC_SERVER_CONNECT_REC diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 8f2c8d83..a735140a 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1697,12 +1697,9 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context, break; case SILC_SOCKET_TYPE_SERVER: case SILC_SOCKET_TYPE_ROUTER: - /* Packets from servers are parsed as soon as possible */ - silc_schedule_task_add(server->schedule, sock->sock, - silc_server_packet_parse_real, - (void *)parser_context, 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); + /* Packets from servers are parsed immediately */ + silc_server_packet_parse_real(server->schedule, 0, sock->sock, + parser_context); break; default: return TRUE; diff --git a/includes/Makefile.am b/includes/Makefile.am index a5fb029f..cd5ecd16 100644 --- a/includes/Makefile.am +++ b/includes/Makefile.am @@ -32,4 +32,4 @@ include_HEADERS = \ endif EXTRA_DIST = \ - silcdefs.h.in + silcdefs.h.in *.h diff --git a/lib/silcclient/Makefile.am b/lib/silcclient/Makefile.am index b9b36334..29ab9c5a 100644 --- a/lib/silcclient/Makefile.am +++ b/lib/silcclient/Makefile.am @@ -32,6 +32,7 @@ libsilcclient_a_SOURCES = \ idlist.c \ protocol.c +if SILC_DIST_TOOLKIT include_HEADERS= \ client.h \ command.h \ @@ -39,6 +40,7 @@ include_HEADERS= \ idlist.h \ protocol.h \ silcapi.h +endif EXTRA_DIST = *.h diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 3e0032f6..8c950acb 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -26,7 +26,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start); SILC_TASK_CALLBACK(silc_client_connect_to_server_second); SILC_TASK_CALLBACK(silc_client_connect_to_server_final); -SILC_TASK_CALLBACK(silc_client_packet_parse_real); SILC_TASK_CALLBACK(silc_client_rekey_callback); SILC_TASK_CALLBACK(silc_client_rekey_final); @@ -767,37 +766,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process) } } -/* Parses whole packet, received earlier. */ - -SILC_TASK_CALLBACK(silc_client_packet_parse_real) -{ - SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context; - SilcClient client = (SilcClient)parse_ctx->context; - SilcPacketContext *packet = parse_ctx->packet; - SilcSocketConnection sock = parse_ctx->sock; - SilcClientConnection conn = (SilcClientConnection)sock->user_data; - int ret; - - SILC_LOG_DEBUG(("Start")); - - /* Parse the packet */ - if (parse_ctx->normal) - ret = silc_packet_parse(packet, conn->receive_key); - else - ret = silc_packet_parse_special(packet, conn->receive_key); - - if (ret == SILC_PACKET_NONE) - goto out; - - /* Parse the incoming packet type */ - silc_client_packet_parse_type(client, sock, packet); - - out: - /* silc_buffer_clear(sock->inbuf); */ - silc_packet_context_free(packet); - silc_free(parse_ctx); -} - /* Parser callback called by silc_packet_receive_process. Thie merely registers timeout that will handle the actual parsing when appropriate. */ @@ -807,10 +775,24 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context, SilcClient client = (SilcClient)context; SilcSocketConnection sock = parser_context->sock; SilcClientConnection conn = (SilcClientConnection)sock->user_data; + SilcPacketContext *packet = parser_context->packet; + SilcPacketType ret; if (conn && conn->hmac_receive) conn->psn_receive = parser_context->packet->sequence + 1; + /* Parse the packet immediately */ + if (parser_context->normal) + ret = silc_packet_parse(packet, conn->receive_key); + else + ret = silc_packet_parse_special(packet, conn->receive_key); + + if (ret == SILC_PACKET_NONE) { + silc_packet_context_free(packet); + silc_free(parser_context); + return FALSE; + } + /* If protocol for this connection is key exchange or rekey then we'll process all packets synchronously, since there might be packets in queue that we are not able to decrypt without first processing the @@ -818,11 +800,14 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context, if (sock->protocol && sock->protocol->protocol && (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE || sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) { - silc_client_packet_parse_real(client->schedule, 0, sock->sock, - parser_context); + + /* Parse the incoming packet type */ + silc_client_packet_parse_type(client, sock, packet); + silc_packet_context_free(packet); + silc_free(parser_context); /* Reprocess the buffer since we'll return FALSE. This is because - the `conn->receive_key' might have become valid bu processing + the `conn->receive_key' might have become valid by processing the previous packet */ if (sock->type != SILC_SOCKET_TYPE_UNKNOWN) silc_packet_receive_process(sock, FALSE, conn->receive_key, @@ -831,16 +816,14 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context, else silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, silc_client_packet_parse, client); + return FALSE; } - /* Parse the packet */ - silc_schedule_task_add(client->schedule, sock->sock, - silc_client_packet_parse_real, - (void *)parser_context, 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); - + /* Parse the incoming packet type */ + silc_client_packet_parse_type(client, sock, packet); + silc_packet_context_free(packet); + silc_free(parser_context); return TRUE; } diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c index 5d554d37..9badcc72 100644 --- a/lib/silcclient/client_ftp.c +++ b/lib/silcclient/client_ftp.c @@ -39,6 +39,7 @@ struct SilcClientFtpSessionStruct { SilcClientEntry client_entry; SilcSocketConnection sock; + SilcBuffer packet; char *hostname; uint16 port; @@ -59,66 +60,137 @@ struct SilcClientFtpSessionStruct { int fd; }; -void silc_client_ftp_free_sessions(SilcClient client, - SilcClientConnection conn) +SILC_TASK_CALLBACK(silc_client_ftp_connected) { - if (conn->ftp_sessions) { - SilcClientFtpSession session; - silc_dlist_start(conn->ftp_sessions); - while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { - session->sock->user_data = NULL; + SilcClientInternalConnectContext *ctx = + (SilcClientInternalConnectContext *)context; + SilcClient client = ctx->client; + SilcClientConnection conn = ctx->conn; + SilcClientFtpSession session = (SilcClientFtpSession)ctx->context; + int opt, opt_len = sizeof(opt); + + SILC_LOG_DEBUG(("Start")); + + /* Check the socket status as it might be in error */ + silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len); + if (opt != 0) { + if (ctx->tries < 2) { + /* Connection failed but lets try again */ + client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Could not connect to client %s: %s", + ctx->host, strerror(opt)); + client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, + "Connecting to port %d of client %s resumed", + ctx->port, ctx->host); + + /* Unregister old connection try */ + silc_schedule_unset_listen_fd(client->schedule, fd); + silc_net_close_connection(fd); + silc_schedule_task_del(client->schedule, ctx->task); + + /* Try again */ + silc_client_connect_to_client_internal(ctx); + ctx->tries++; + } else { + /* Connection failed and we won't try anymore */ + client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Could not connect to client %s: %s", + ctx->host, strerror(opt)); + silc_schedule_unset_listen_fd(client->schedule, fd); + silc_net_close_connection(fd); + silc_schedule_task_del(client->schedule, ctx->task); + silc_free(ctx); silc_client_ftp_session_free(session); } - silc_dlist_del(conn->ftp_sessions, session); - silc_dlist_uninit(conn->ftp_sessions); + return; } + + silc_schedule_unset_listen_fd(client->schedule, fd); + silc_schedule_task_del(client->schedule, ctx->task); + + /* Start the key agreement */ + silc_client_ftp_start_key_agreement(session, fd); } -void silc_client_ftp_session_free_client(SilcClientConnection conn, - SilcClientEntry client_entry) +static int +silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx) { - SilcClientFtpSession session; + int sock; - if (!conn->ftp_sessions) - return; + /* Create connection to server asynchronously */ + sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host); + if (sock < 0) + return -1; - /* Get the session */ - silc_dlist_start(conn->ftp_sessions); - while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { - if (session->client_entry == client_entry) { - session->sock->user_data = NULL; - silc_client_ftp_session_free(session); - break; - } - } + /* Register task that will receive the async connect and will + read the result. */ + ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, + silc_client_ftp_connected, + (void *)ctx, 0, 0, + SILC_TASK_FD, + SILC_TASK_PRI_NORMAL); + silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE); + ctx->sock = sock; + return sock; } -/* SFTP packet send callback */ +static int +silc_client_connect_to_client(SilcClient client, + SilcClientConnection conn, int port, + char *host, void *context) +{ + SilcClientInternalConnectContext *ctx; + + /* Allocate internal context for connection process. This is + needed as we are doing async connecting. */ + ctx = silc_calloc(1, sizeof(*ctx)); + ctx->client = client; + ctx->conn = conn; + ctx->host = strdup(host); + ctx->port = port; + ctx->tries = 0; + ctx->context = context; + + /* Do the actual connecting process */ + return silc_client_connect_to_client_internal(ctx); +} + +/* SFTP packet send callback. This will use preallocated buffer to avoid + reallocation of outgoing data buffer everytime. */ static void silc_client_ftp_send_packet(SilcSocketConnection sock, SilcBuffer packet, void *context) { SilcClientFtpSession session = (SilcClientFtpSession)context; SilcClient client = session->client; - SilcBuffer buffer; SILC_LOG_DEBUG(("Start")); - buffer = silc_buffer_alloc(1 + packet->len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); - silc_buffer_format(buffer, + /* Allocate outgoing packet */ + if (!session->packet) + session->packet = silc_buffer_alloc(1 + packet->len); + + /* Enlarge outgoing packet if needed */ + if (session->packet->truelen < 1 + packet->len) + session->packet = silc_buffer_realloc(session->packet, 1 + packet->len); + + /* Encode packet */ + silc_buffer_pull_tail(session->packet, 1 + packet->len); + silc_buffer_format(session->packet, SILC_STR_UI_CHAR(1), SILC_STR_UI_XNSTRING(packet->data, packet->len), SILC_STR_END); /* Send the packet immediately */ silc_client_packet_send(client, sock, SILC_PACKET_FTP, NULL, 0, NULL, NULL, - buffer->data, buffer->len, TRUE); + session->packet->data, session->packet->len, TRUE); - silc_buffer_free(buffer); + silc_buffer_clear(session->packet); } -/* SFTP monitor callback for SFTP server */ +/* SFTP monitor callback for SFTP server. This reports the application + how the transmission is going along. This function is for the client + who made the file available for download. */ static void silc_client_ftp_monitor(SilcSFTP sftp, SilcSFTPMonitors type, @@ -138,7 +210,10 @@ static void silc_client_ftp_monitor(SilcSFTP sftp, } } -/* Returns the read data */ +/* Returns the read data. This is the downloader's function (client side) + to receive the read data and read more until EOF is received from + the other side. This will also monitor the transmission and notify + the application. */ static void silc_client_ftp_data(SilcSFTP sftp, SilcSFTPStatus status, @@ -151,6 +226,7 @@ static void silc_client_ftp_data(SilcSFTP sftp, SILC_LOG_DEBUG(("Start")); if (status == SILC_SFTP_STATUS_EOF) { + /* EOF received */ /* Close the handle */ silc_sftp_close(sftp, session->read_handle, NULL, NULL); @@ -162,7 +238,12 @@ static void silc_client_ftp_data(SilcSFTP sftp, } if (status != SILC_SFTP_STATUS_OK) { - /* XXX errror */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); /* Close the handle */ silc_sftp_close(sftp, session->read_handle, NULL, NULL); @@ -175,7 +256,7 @@ static void silc_client_ftp_data(SilcSFTP sftp, /* Read more, until EOF is received */ session->read_offset += data_len; - silc_sftp_read(sftp, session->read_handle, session->read_offset, 16384, + silc_sftp_read(sftp, session->read_handle, session->read_offset, 64512, silc_client_ftp_data, session); /* Call monitor callback */ @@ -186,10 +267,13 @@ static void silc_client_ftp_data(SilcSFTP sftp, session->client_entry, session->session_id, session->filepath, session->monitor_context); - /* Write the read data */ + /* Write the read data to the real file */ silc_file_write(session->fd, data, data_len); } +/* Returns handle for the opened file. This is the downloader's function. + This will begin reading the data from the file. */ + static void silc_client_ftp_open_handle(SilcSFTP sftp, SilcSFTPStatus status, SilcSFTPHandle handle, @@ -200,21 +284,31 @@ static void silc_client_ftp_open_handle(SilcSFTP sftp, SILC_LOG_DEBUG(("Start")); if (status != SILC_SFTP_STATUS_OK) { - /* XXX errror */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); return; } /* Open the actual local file */ session->fd = silc_file_open(session->filepath, O_RDWR | O_CREAT); if (session->fd < 0) { - /* XXX errror */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); return; } - session->read_handle = handle; + session->read_handle = handle; /* Now, start reading the file */ - silc_sftp_read(sftp, session->read_handle, session->read_offset, 16384, + silc_sftp_read(sftp, session->read_handle, session->read_offset, 64512, silc_client_ftp_data, session); /* Call monitor callback */ @@ -226,7 +320,8 @@ static void silc_client_ftp_open_handle(SilcSFTP sftp, session->filepath, session->monitor_context); } -/* Returns the file name available for download. */ +/* Returns the file name available for download. This is the downloader's + function. */ static void silc_client_ftp_readdir_name(SilcSFTP sftp, SilcSFTPStatus status, @@ -239,7 +334,13 @@ static void silc_client_ftp_readdir_name(SilcSFTP sftp, SILC_LOG_DEBUG(("Start")); if (status != SILC_SFTP_STATUS_OK) { - /* XXX errror */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); + return; } /* Now open the file */ @@ -256,7 +357,8 @@ static void silc_client_ftp_readdir_name(SilcSFTP sftp, session->dir_handle = NULL; } -/* Returns the file handle after giving opendir command. */ +/* Returns the file handle after giving opendir command. This is the + downloader's function. */ static void silc_client_ftp_opendir_handle(SilcSFTP sftp, SilcSFTPStatus status, @@ -268,7 +370,13 @@ static void silc_client_ftp_opendir_handle(SilcSFTP sftp, SILC_LOG_DEBUG(("Start")); if (status != SILC_SFTP_STATUS_OK) { - /* XXX errror */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); + return; } /* Now, read the directory */ @@ -276,7 +384,9 @@ static void silc_client_ftp_opendir_handle(SilcSFTP sftp, session->dir_handle = handle; } -/* SFTP version callback for SFTP client */ +/* SFTP version callback for SFTP client. This is the downloader's function + after initializing the SFTP connection to the remote client. This will + find out the filename available for download. */ static void silc_client_ftp_version(SilcSFTP sftp, SilcSFTPStatus status, @@ -288,7 +398,13 @@ static void silc_client_ftp_version(SilcSFTP sftp, SILC_LOG_DEBUG(("Start")); if (status != SILC_SFTP_STATUS_OK) { - /* XXX errror */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); + return; } /* The SFTP session is open, now retrieve the info about available file. */ @@ -347,6 +463,9 @@ SILC_TASK_CALLBACK(silc_client_ftp_key_agreement_final) silc_protocol_free(protocol); } +/* The downloader's function to start the key agreement protocol with the + remote client after we have connected to it. */ + static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session, int sock) { @@ -358,6 +477,13 @@ static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session, SILC_LOG_DEBUG(("Start")); + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT, 0, 0, + session->client_entry, session->session_id, + NULL, session->monitor_context); + /* Add new connection for this session */ conn = silc_client_add_connection(client, session->hostname, session->port, session); @@ -409,148 +535,9 @@ static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session, silc_protocol_execute(protocol, client->schedule, 0, 0); } -SILC_TASK_CALLBACK(silc_client_ftp_connected) -{ - SilcClientInternalConnectContext *ctx = - (SilcClientInternalConnectContext *)context; - SilcClient client = ctx->client; - SilcClientConnection conn = ctx->conn; - SilcClientFtpSession session = (SilcClientFtpSession)ctx->context; - int opt, opt_len = sizeof(opt); - - SILC_LOG_DEBUG(("Start")); - - /* Check the socket status as it might be in error */ - silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len); - if (opt != 0) { - if (ctx->tries < 2) { - /* Connection failed but lets try again */ - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, - "Could not connect to client %s: %s", - ctx->host, strerror(opt)); - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, - "Connecting to port %d of client %s resumed", - ctx->port, ctx->host); - - /* Unregister old connection try */ - silc_schedule_unset_listen_fd(client->schedule, fd); - silc_net_close_connection(fd); - silc_schedule_task_del(client->schedule, ctx->task); - - /* Try again */ - silc_client_connect_to_client_internal(ctx); - ctx->tries++; - } else { - /* Connection failed and we won't try anymore */ - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, - "Could not connect to client %s: %s", - ctx->host, strerror(opt)); - silc_schedule_unset_listen_fd(client->schedule, fd); - silc_net_close_connection(fd); - silc_schedule_task_del(client->schedule, ctx->task); - silc_free(ctx); - silc_client_ftp_session_free(session); - } - return; - } - - silc_schedule_unset_listen_fd(client->schedule, fd); - silc_schedule_task_del(client->schedule, ctx->task); - - /* Start the key agreement */ - silc_client_ftp_start_key_agreement(session, fd); -} - -static int -silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx) -{ - int sock; - - /* Create connection to server asynchronously */ - sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host); - if (sock < 0) - return -1; - - /* Register task that will receive the async connect and will - read the result. */ - ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, - silc_client_ftp_connected, - (void *)ctx, 0, 0, - SILC_TASK_FD, - SILC_TASK_PRI_NORMAL); - silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE); - - ctx->sock = sock; - - return sock; -} - -static int -silc_client_connect_to_client(SilcClient client, - SilcClientConnection conn, int port, - char *host, void *context) -{ - SilcClientInternalConnectContext *ctx; - - /* Allocate internal context for connection process. This is - needed as we are doing async connecting. */ - ctx = silc_calloc(1, sizeof(*ctx)); - ctx->client = client; - ctx->conn = conn; - ctx->host = strdup(host); - ctx->port = port; - ctx->tries = 0; - ctx->context = context; - - /* Do the actual connecting process */ - return silc_client_connect_to_client_internal(ctx); -} - -/* Free session */ - -void silc_client_ftp_session_free(SilcClientFtpSession session) -{ - SilcClientConnection conn; - - silc_dlist_del(session->conn->ftp_sessions, session); - - if (session->sftp) { - if (session->server) - silc_sftp_server_shutdown(session->sftp); - else - silc_sftp_client_shutdown(session->sftp); - } - - if (session->fs) - silc_sftp_fs_memory_free(session->fs); - - if (session->listener) { - silc_schedule_unset_listen_fd(session->client->schedule, - session->listener); - silc_net_close_connection(session->listener); - } - - if (session->sock) { - silc_schedule_unset_listen_fd(session->client->schedule, - session->sock->sock); - silc_net_close_connection(session->sock->sock); - - if (session->sock->user_data) { - conn = (SilcClientConnection)session->sock->user_data; - - if (conn->active_session == session) - conn->active_session = NULL; - - silc_client_close_connection(session->client, session->sock, conn); - } else { - silc_socket_free(session->sock); - } - } - - silc_free(session->hostname); - silc_free(session->filepath); - silc_free(session); -} +/* The remote client's (the client who made the file available for download) + function for accepting incoming connection. This will also start the + key agreement protocol with the other client. */ SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement) { @@ -565,7 +552,12 @@ SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement) sock = silc_net_accept_connection(session->listener); if (sock < 0) { - /* XXX error */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); return; } @@ -579,13 +571,25 @@ SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement) /* Perform name and address lookups for the remote host. */ silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip); if (!newsocket->hostname && !newsocket->ip) { - /* XXX error */ + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); return; } if (!newsocket->hostname) newsocket->hostname = strdup(newsocket->ip); newsocket->port = silc_net_get_remote_port(sock); + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT, 0, 0, + session->client_entry, session->session_id, + NULL, session->monitor_context); + /* Add new connection for this session */ conn = silc_client_add_connection(client, newsocket->hostname, newsocket->port, session); @@ -622,6 +626,111 @@ SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement) SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock); } +/* Free all file transfer sessions. */ + +void silc_client_ftp_free_sessions(SilcClient client, + SilcClientConnection conn) +{ + if (conn->ftp_sessions) { + SilcClientFtpSession session; + silc_dlist_start(conn->ftp_sessions); + while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { + session->sock->user_data = NULL; + silc_client_ftp_session_free(session); + } + silc_dlist_del(conn->ftp_sessions, session); + silc_dlist_uninit(conn->ftp_sessions); + } +} + +/* Free file transfer session by client entry. */ + +void silc_client_ftp_session_free_client(SilcClientConnection conn, + SilcClientEntry client_entry) +{ + SilcClientFtpSession session; + + if (!conn->ftp_sessions) + return; + + /* Get the session */ + silc_dlist_start(conn->ftp_sessions); + while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { + if (session->client_entry == client_entry) { + session->sock->user_data = NULL; + silc_client_ftp_session_free(session); + break; + } + } +} + +/* Free session resources. */ + +void silc_client_ftp_session_free(SilcClientFtpSession session) +{ + SilcClientConnection conn; + + SILC_LOG_DEBUG(("Free session")); + + silc_dlist_del(session->conn->ftp_sessions, session); + + if (session->sftp) { + if (session->server) + silc_sftp_server_shutdown(session->sftp); + else + silc_sftp_client_shutdown(session->sftp); + } + + if (session->fs) + silc_sftp_fs_memory_free(session->fs); + + /* Destroy listener */ + if (session->listener) { + silc_schedule_unset_listen_fd(session->client->schedule, + session->listener); + silc_net_close_connection(session->listener); + silc_schedule_task_del_by_fd(session->client->schedule, session->listener); + } + + /* Destroy session connection */ + if (session->sock) { + silc_schedule_unset_listen_fd(session->client->schedule, + session->sock->sock); + silc_net_close_connection(session->sock->sock); + + if (session->sock->user_data) { + conn = (SilcClientConnection)session->sock->user_data; + + if (conn->active_session == session) + conn->active_session = NULL; + + silc_client_close_connection(session->client, session->sock, conn); + } else { + silc_socket_free(session->sock); + } + } + + if (session->packet) + silc_buffer_free(session->packet); + + silc_free(session->hostname); + silc_free(session->filepath); + silc_free(session); +} + +/* Sends a file indicated by the `filepath' to the remote client + indicated by the `client_entry'. This will negotiate a secret key + with the remote client before actually starting the transmission of + the file. The `monitor' callback will be called to monitor the + transmission of the file. + + This returns a file session ID for the file transmission. It can + be used to close the session (and abort the file transmission) by + calling the silc_client_file_close function. The session ID is + also returned in the `monitor' callback. This returns 0 if the + file indicated by the `filepath' is being transmitted to the remote + client indicated by the `client_entry', already. */ + uint32 silc_client_file_send(SilcClient client, SilcClientConnection conn, SilcClientFileMonitor monitor, @@ -645,7 +754,7 @@ uint32 silc_client_file_send(SilcClient client, /* Add new session */ session = silc_calloc(1, sizeof(*session)); - session->session_id = conn->next_session_id++; + session->session_id = ++conn->next_session_id; session->client = client; session->conn = conn; session->client_entry = client_entry; @@ -691,12 +800,20 @@ uint32 silc_client_file_send(SilcClient client, return session->session_id; } -bool silc_client_file_receive(SilcClient client, - SilcClientConnection conn, - SilcClientFileMonitor monitor, - void *monitor_context, - SilcClientEntry client_entry, - uint32 session_id) +/* Receives a file from a client indicated by the `client_entry'. The + `session_id' indicates the file transmission session and it has been + received in the `ftp' client operation function. This will actually + perform the key agreement protocol with the remote client before + actually starting the file transmission. The `monitor' callback + will be called to monitor the transmission. */ + +SilcClientFileError +silc_client_file_receive(SilcClient client, + SilcClientConnection conn, + SilcClientFileMonitor monitor, + void *monitor_context, + SilcClientEntry client_entry, + uint32 session_id) { SilcClientFtpSession session; SilcBuffer keyagr, ftp; @@ -713,13 +830,13 @@ bool silc_client_file_receive(SilcClient client, if (session == SILC_LIST_END) { SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id)); - return FALSE; + return SILC_CLIENT_FILE_UNKNOWN_SESSION; } /* See if we have this session running already */ if (session->sftp || session->listener) { SILC_LOG_DEBUG(("Session already started")); - return FALSE; + return SILC_CLIENT_FILE_ALREADY_STARTED; } session->monitor = monitor; @@ -727,43 +844,55 @@ bool silc_client_file_receive(SilcClient client, session->client_entry = client_entry; session->conn = conn; - /* Add the listener for the key agreement */ - session->hostname = silc_net_localip(); - session->listener = silc_net_create_server(0, session->hostname); - if (session->listener < 0) { - /* XXX Error */ - SILC_LOG_DEBUG(("Could not create listener")); - return FALSE; + /* If the hostname and port already exists then the remote client did + provide the connection point to us and we won't create listener, but + create the connection ourselves. */ + if (session->hostname && session->port) { + if (silc_client_connect_to_client(client, conn, session->port, + session->hostname, session) < 0) + return SILC_CLIENT_FILE_ERROR; + } else { + /* Add the listener for the key agreement */ + session->hostname = silc_net_localip(); + session->listener = silc_net_create_server(0, session->hostname); + if (session->listener < 0) { + SILC_LOG_DEBUG(("Could not create listener")); + return SILC_CLIENT_FILE_ERROR; + } + session->port = silc_net_get_local_port(session->listener); + silc_schedule_task_add(client->schedule, session->listener, + silc_client_ftp_process_key_agreement, session, + 0, 0, SILC_TASK_FD, SILC_TASK_PRI_NORMAL); + + /* Send the key agreement inside FTP packet */ + keyagr = silc_key_agreement_payload_encode(session->hostname, + session->port); + ftp = silc_buffer_alloc(1 + keyagr->len); + silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp)); + silc_buffer_format(ftp, + SILC_STR_UI_CHAR(1), + SILC_STR_UI_XNSTRING(keyagr->data, keyagr->len), + SILC_STR_END); + silc_client_packet_send(client, conn->sock, SILC_PACKET_FTP, + client_entry->id, SILC_ID_CLIENT, NULL, NULL, + ftp->data, ftp->len, FALSE); + + silc_buffer_free(keyagr); + silc_buffer_free(ftp); } - session->port = silc_net_get_local_port(session->listener); - silc_schedule_task_add(client->schedule, session->listener, - silc_client_ftp_process_key_agreement, session, - 0, 0, SILC_TASK_FD, SILC_TASK_PRI_NORMAL); - - /* Send the key agreement inside FTP packet */ - keyagr = silc_key_agreement_payload_encode(session->hostname, session->port); - ftp = silc_buffer_alloc(1 + keyagr->len); - silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp)); - silc_buffer_format(ftp, - SILC_STR_UI_CHAR(1), - SILC_STR_UI_XNSTRING(keyagr->data, keyagr->len), - SILC_STR_END); - silc_client_packet_send(client, conn->sock, SILC_PACKET_FTP, - client_entry->id, SILC_ID_CLIENT, NULL, NULL, - ftp->data, ftp->len, FALSE); - - silc_buffer_free(keyagr); - silc_buffer_free(ftp); - - return TRUE; + return SILC_CLIENT_FILE_OK; } -/* Closes FTP session */ +/* Closes file transmission session indicated by the `session_id'. + If file transmission is being conducted it will be aborted + automatically. This function is also used to close the session + after successful file transmission. This function can be used + also to reject incoming file transmission request. */ -bool silc_client_file_close(SilcClient client, - SilcClientConnection conn, - uint32 session_id) +SilcClientFileError silc_client_file_close(SilcClient client, + SilcClientConnection conn, + uint32 session_id) { SilcClientFtpSession session; @@ -779,12 +908,12 @@ bool silc_client_file_close(SilcClient client, if (session == SILC_LIST_END) { SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id)); - return FALSE; + return SILC_CLIENT_FILE_UNKNOWN_SESSION; } silc_client_ftp_session_free(session); - return TRUE; + return SILC_CLIENT_FILE_OK; } /* Callback called after remote client information has been resolved. @@ -792,20 +921,18 @@ bool silc_client_file_close(SilcClient client, then continue with the key agreement protocol. If not then it means this is a file transfer request and we let the application know. */ -static void -silc_client_ftp_resolve_cb(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - uint32 clients_count, - void *context) +static void silc_client_ftp_resolve_cb(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + uint32 clients_count, + void *context) { SilcPacketContext *packet = (SilcPacketContext *)context; SilcClientFtpSession session; - SilcKeyAgreementPayload payload; + SilcKeyAgreementPayload payload = NULL; SilcClientEntry client_entry; char *hostname; uint16 port; - int sock; SILC_LOG_DEBUG(("Start")); @@ -830,11 +957,11 @@ silc_client_ftp_resolve_cb(SilcClient client, if (session == SILC_LIST_END) { /* No session found, create one and let the application know about - incomoing file transfer request. */ + incoming file transfer request. */ /* Add new session */ session = silc_calloc(1, sizeof(*session)); - session->session_id = conn->next_session_id++; + session->session_id = ++conn->next_session_id; session->client = client; session->conn = conn; silc_dlist_add(conn->ftp_sessions, session); @@ -843,12 +970,11 @@ silc_client_ftp_resolve_cb(SilcClient client, client->ops->ftp(client, conn, client_entry, session->session_id, hostname, port); - /* If hostname was provided we'll start the key exchange now. */ if (hostname && port) { - /* XXX */ + session->hostname = strdup(hostname); + session->port = port; } - - silc_key_agreement_payload_free(payload); + goto out; } @@ -859,12 +985,19 @@ silc_client_ftp_resolve_cb(SilcClient client, session->port = port; /* Session exists, continue with key agreement protocol. */ - sock = silc_client_connect_to_client(client, conn, port, hostname, - session); - if (sock < 0) - goto out; + if (silc_client_connect_to_client(client, conn, port, + hostname, session) < 0) { + /* Call monitor callback */ + if (session->monitor) + (*session->monitor)(session->client, session->conn, + SILC_CLIENT_FILE_MONITOR_ERROR, 0, 0, + session->client_entry, session->session_id, + session->filepath, session->monitor_context); + } out: + if (payload) + silc_key_agreement_payload_free(payload); silc_packet_context_free(packet); } @@ -894,7 +1027,7 @@ void silc_client_ftp(SilcClient client, silc_buffer_pull(packet->buffer, 1); - /* If we have active FTP session then give the packet to the + /* If we have active FTP session then give the packet directly to the protocol processor. */ if (conn->active_session) { /* Give it to the SFTP */ diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index a5c6d7d1..2f105427 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -166,6 +166,16 @@ void silc_client_private_message(SilcClient client, silc_hash_client_id_compare, NULL, &id_cache) || ((SilcClientEntry)id_cache->context)->nickname == NULL) { + + if (id_cache && id_cache->context) { + remote_client = (SilcClientEntry)id_cache->context; + if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) { + remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING; + goto out; + } + remote_client->status |= SILC_CLIENT_STATUS_RESOLVING; + } + /* Resolve the client info */ silc_client_get_client_by_id_resolve(client, conn, remote_id, silc_client_private_message_cb, @@ -208,8 +218,7 @@ void silc_client_private_message(SilcClient client, out: if (payload) silc_private_message_payload_free(payload); - if (remote_id) - silc_free(remote_id); + silc_free(remote_id); } /* Function that actually employes the received private message key */ diff --git a/lib/silcclient/silcapi.h b/lib/silcclient/silcapi.h index 7ee729e2..c09023f9 100644 --- a/lib/silcclient/silcapi.h +++ b/lib/silcclient/silcapi.h @@ -1767,13 +1767,22 @@ silc_client_request_authentication_method(SilcClient client, void *context); typedef enum { + SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT, SILC_CLIENT_FILE_MONITOR_SEND, SILC_CLIENT_FILE_MONITOR_RECEIVE, SILC_CLIENT_FILE_MONITOR_GET, SILC_CLIENT_FILE_MONITOR_PUT, SILC_CLIENT_FILE_MONITOR_CLOSE, + SILC_CLIENT_FILE_MONITOR_ERROR, } SilcClientMonitorStatus; +typedef enum { + SILC_CLIENT_FILE_OK, + SILC_CLIENT_FILE_ERROR, + SILC_CLIENT_FILE_UNKNOWN_SESSION, + SILC_CLIENT_FILE_ALREADY_STARTED, +} SilcClientFileError; + /****f* silcclient/SilcClientAPI/silc_client_file_receive * * SYNOPSIS @@ -1834,6 +1843,11 @@ typedef void (*SilcClientFileMonitor)(SilcClient client, * file indicated by the `filepath' is being transmitted to the remote * client indicated by the `client_entry', already. * + * If error will occur during the file transfer process the error + * status will be returned in the monitor callback. In this case + * the application must call silc_client_file_close to close the + * session. + * ***/ uint32 silc_client_file_send(SilcClient client, SilcClientConnection conn, @@ -1846,12 +1860,13 @@ uint32 silc_client_file_send(SilcClient client, * * SYNOPSIS * - * bool silc_client_file_receive(SilcClient client, - * SilcClientConnection conn, - * SilcClientFileMonitor monitor, - * void *monitor_context, - * SilcClientEntry client_entry, - * uint32 session_id); + * SilcClientFileError + * silc_client_file_receive(SilcClient client, + * SilcClientConnection conn, + * SilcClientFileMonitor monitor, + * void *monitor_context, + * SilcClientEntry client_entry, + * uint32 session_id); * * DESCRIPTION * @@ -1862,21 +1877,27 @@ uint32 silc_client_file_send(SilcClient client, * actually starting the file transmission. The `monitor' callback * will be called to monitor the transmission. * + * If error will occur during the file transfer process the error + * status will be returned in the monitor callback. In this case + * the application must call silc_client_file_close to close the + * session. + * ***/ -bool silc_client_file_receive(SilcClient client, - SilcClientConnection conn, - SilcClientFileMonitor monitor, - void *monitor_context, - SilcClientEntry client_entry, - uint32 session_id); +SilcClientFileError +silc_client_file_receive(SilcClient client, + SilcClientConnection conn, + SilcClientFileMonitor monitor, + void *monitor_context, + SilcClientEntry client_entry, + uint32 session_id); /****f* silcclient/SilcClientAPI/silc_client_file_close * * SYNOPSIS * - * bool silc_client_file_close(SilcClient client, - * SilcClientConnection conn, - * uint32 session_id); + * SilcClientFileError silc_client_file_close(SilcClient client, + * SilcClientConnection conn, + * uint32 session_id); * * DESCRIPTION * @@ -1884,12 +1905,11 @@ bool silc_client_file_receive(SilcClient client, * If file transmission is being conducted it will be aborted * automatically. This function is also used to close the session * after successful file transmission. This function can be used - * also to reject incoming file transmission request. Returns TRUE - * if the session was closed and FALSE if such session does not exist. + * also to reject incoming file transmission request. * ***/ -bool silc_client_file_close(SilcClient client, - SilcClientConnection conn, - uint32 session_id); +SilcClientFileError silc_client_file_close(SilcClient client, + SilcClientConnection conn, + uint32 session_id); #endif diff --git a/lib/silccore/Makefile.am b/lib/silccore/Makefile.am index f77b6c05..04e898cd 100644 --- a/lib/silccore/Makefile.am +++ b/lib/silccore/Makefile.am @@ -31,6 +31,7 @@ libsilccore_a_SOURCES = \ silcauth.c \ silcprivate.c +if SILC_DIST_TOOLKIT include_HEADERS = \ silcauth.h \ silcchannel.h \ @@ -42,6 +43,7 @@ include_HEADERS = \ silcpacket.h \ silcpayload.h \ silcprivate.h +endif EXTRA_DIST = *.h diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index 68cb566c..d05c0bd1 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -187,7 +187,8 @@ void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher) /* Get random padding */ #if 1 - for (i = 0; i < ctx->padlen; i++) tmppad[i] = silc_rng_global_get_byte(); + for (i = 0; i < ctx->padlen; i++) tmppad[i] = + silc_rng_global_get_byte_fast(); #else /* XXX: For testing - to be removed */ memset(tmppad, 65, sizeof(tmppad)); @@ -402,8 +403,16 @@ void silc_packet_receive_process(SilcSocketConnection sock, /* Decrypt rest of the packet */ if (cipher) - silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, - parse_ctx->packet->buffer, parse_ctx->normal); + if (silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, + parse_ctx->packet->buffer, + parse_ctx->normal) == -1) { + SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s]", + sock->hostname, sock->port, + (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : + sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : + sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : + "Router"))); + } /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */ @@ -445,9 +454,6 @@ static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer, /* Compare the HMAC's (buffer->tail has the packet's HMAC) */ if (memcmp(mac, buffer->tail, mac_len)) { SILC_LOG_ERROR(("MAC failed")); - - /* XXX Remove */ - assert(FALSE); return FALSE; } diff --git a/lib/silccrypt/Makefile.am b/lib/silccrypt/Makefile.am index e55cb151..cce35796 100644 --- a/lib/silccrypt/Makefile.am +++ b/lib/silccrypt/Makefile.am @@ -39,6 +39,7 @@ libsilccrypt_a_SOURCES = \ silcpkcs.c \ pkcs1.c +if SILC_DIST_TOOLKIT include_HEADERS = \ aes.h \ blowfish.h \ @@ -60,6 +61,7 @@ include_HEADERS = \ silcpkcs.h \ silcrng.h \ twofish.h +endif EXTRA_DIST = *.h diff --git a/lib/silccrypt/silcrng.c b/lib/silccrypt/silcrng.c index 67ee08fe..a52b4eea 100644 --- a/lib/silccrypt/silcrng.c +++ b/lib/silccrypt/silcrng.c @@ -116,6 +116,7 @@ typedef struct SilcRngObjectStruct { SilcHash sha1; uint8 threshhold; char *devrandom; + int fd_devurandom; } SilcRngObject; /* Allocates new RNG object. */ @@ -127,6 +128,7 @@ SilcRng silc_rng_alloc() SILC_LOG_DEBUG(("Allocating new RNG object")); new = silc_calloc(1, sizeof(*new)); + new->fd_devurandom = -1; memset(new->pool, 0, sizeof(new->pool)); memset(new->key, 0, sizeof(new->key)); @@ -147,6 +149,10 @@ void silc_rng_free(SilcRng rng) memset(rng->key, 0, sizeof(rng->key)); silc_hash_free(rng->sha1); silc_free(rng->devrandom); + + if (rng->fd_devurandom != -1) + close(rng->fd_devurandom); + silc_free(rng); } } @@ -278,7 +284,7 @@ static void silc_rng_get_medium_noise(SilcRng rng) static void silc_rng_get_hard_noise(SilcRng rng) { #ifndef SILC_WIN32 - char buf[32]; + unsigned char buf[32]; int fd, len, i; /* Get noise from /dev/[u]random if available */ @@ -310,7 +316,7 @@ static void silc_rng_get_hard_noise(SilcRng rng) static void silc_rng_exec_command(SilcRng rng, char *command) { #ifndef SILC_WIN32 - char buf[1024]; + unsigned char buf[1024]; FILE *fd; int i; int c; @@ -546,6 +552,33 @@ unsigned char silc_rng_global_get_byte() return global_rng ? silc_rng_get_byte(global_rng) : 0; } +/* Return random byte as fast as possible. Reads from /dev/urandom if + available. If not then return from normal RNG (not so fast). */ + +unsigned char silc_rng_global_get_byte_fast() +{ +#ifndef SILC_WIN32 + unsigned char buf[1]; + + if (!global_rng) + return 0; + + if (global_rng->fd_devurandom == -1) { + global_rng->fd_devurandom = open("/dev/urandom", O_RDONLY); + if (global_rng < 0) + return silc_rng_global_get_byte(); + fcntl(global_rng->fd_devurandom, F_SETFL, O_NONBLOCK); + } + + if (read(global_rng->fd_devurandom, buf, sizeof(buf)) < 0) + return silc_rng_global_get_byte(); + + return buf[0]; +#else + return silc_rng_global_get_byte(); +#endif +} + uint16 silc_rng_global_get_rn16() { return global_rng ? silc_rng_get_rn16(global_rng) : 0; diff --git a/lib/silccrypt/silcrng.h b/lib/silccrypt/silcrng.h index d8eacad2..ef52b03a 100644 --- a/lib/silccrypt/silcrng.h +++ b/lib/silccrypt/silcrng.h @@ -191,6 +191,7 @@ void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, uint32 len); int silc_rng_global_init(SilcRng rng); int silc_rng_global_uninit(); unsigned char silc_rng_global_get_byte(); +unsigned char silc_rng_global_get_byte_fast(); uint16 silc_rng_global_get_rn16(); uint32 silc_rng_global_get_rn32(); unsigned char *silc_rng_global_get_rn_string(uint32 len); diff --git a/lib/silcmath/Makefile.am b/lib/silcmath/Makefile.am index d4f5b7e2..d1e75ab6 100644 --- a/lib/silcmath/Makefile.am +++ b/lib/silcmath/Makefile.am @@ -38,11 +38,13 @@ libsilcmath_a_SOURCES = \ mpbin.c \ $(MP_SOURCE) +if SILC_DIST_TOOLKIT include_HEADERS = \ mp_gmp.h \ mp_mpi.h \ silcmath.h \ silcmp.h +endif EXTRA_DIST = *.h diff --git a/lib/silcsftp/Makefile.am b/lib/silcsftp/Makefile.am index 83cf39d3..e05612ea 100644 --- a/lib/silcsftp/Makefile.am +++ b/lib/silcsftp/Makefile.am @@ -26,8 +26,10 @@ libsilcsftp_a_SOURCES = \ sftp_util.c \ sftp_fs_memory.c +if SILC_DIST_TOOLKIT include_HEADERS = \ silcsftp.h +endif EXTRA_DIST = *.h tests diff --git a/lib/silcsim/Makefile.am b/lib/silcsim/Makefile.am index ad45d5be..fdb14dc5 100644 --- a/lib/silcsim/Makefile.am +++ b/lib/silcsim/Makefile.am @@ -75,7 +75,9 @@ $(SIM_HASH_OBJS): ../silccrypt/libsilccrypt.a CLEANFILES = $(SIM_MODULES_DIR)/*.sim.so +if SILC_DIST_TOOLKIT include_HEADERS = silcsim.h silcsimutil.h +endif EXTRA_DIST = *.h diff --git a/lib/silcske/Makefile.am b/lib/silcske/Makefile.am index 94dffa26..b233c42d 100644 --- a/lib/silcske/Makefile.am +++ b/lib/silcske/Makefile.am @@ -25,11 +25,13 @@ libsilcske_a_SOURCES = \ payload.c \ groups.c +if SILC_DIST_TOOLKIT include_HEADERS = \ groups.h \ payload.h \ silcske.h \ silcske_status.h +endif EXTRA_DIST = *.h diff --git a/lib/silcutil/Makefile.am b/lib/silcutil/Makefile.am index e2de4414..93cd4a3b 100644 --- a/lib/silcutil/Makefile.am +++ b/lib/silcutil/Makefile.am @@ -38,6 +38,7 @@ libsilcutil_a_SOURCES = \ silcsockconn.c \ silcprotocol.c +if SILC_DIST_TOOLKIT include_HEADERS = \ silcbuffer.h \ silcbuffmt.h \ @@ -53,6 +54,7 @@ include_HEADERS = \ silcprotocol.h \ silcthread.h \ silcutil.h +endif EXTRA_DIST = *.h diff --git a/lib/silcutil/silcbufutil.h b/lib/silcutil/silcbufutil.h index 1717d14b..7016b71e 100644 --- a/lib/silcutil/silcbufutil.h +++ b/lib/silcutil/silcbufutil.h @@ -82,6 +82,9 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, uint32 newsize) if (!sb) return silc_buffer_alloc(newsize); + if (newsize <= sb->truelen) + return sb; + sb_new = silc_buffer_alloc(newsize); silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new)); silc_buffer_put(sb_new, sb->head, sb->truelen); diff --git a/lib/silcutil/unix/silcunixsockconn.c b/lib/silcutil/unix/silcunixsockconn.c index 330bab2d..3120e8ef 100644 --- a/lib/silcutil/unix/silcunixsockconn.c +++ b/lib/silcutil/unix/silcunixsockconn.c @@ -45,7 +45,7 @@ int silc_socket_write(SilcSocketConnection sock) SILC_LOG_DEBUG(("Could not write immediately, will do it later")); return -2; } - SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno))); + SILC_LOG_DEBUG(("Cannot write to socket: %s", strerror(errno))); return -1; } @@ -80,7 +80,7 @@ int silc_socket_read(SilcSocketConnection sock) SILC_LOG_DEBUG(("Could not read immediately, will do it later")); return -2; } - SILC_LOG_ERROR(("Cannot read from socket: %d:%s", fd, strerror(errno))); + SILC_LOG_DEBUG(("Cannot read from socket: %d:%s", fd, strerror(errno))); return -1; } -- 2.24.0