+Fri Nov 2 18:52:08 EST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Do not process packet for disconnected socket connection.
+ Affected file lib/silccore/silcpacket.c.
+
+ * Process the DISCONNECT packet through scheduler in the
+ client library. Affected file lib/silcclient/client.c.
+
Thu Nov 1 22:10:07 EST 2001 Pekka Riikonen <priikone@silcnet.org>
* Defined to WHOIS command reply the sending of fingerprint
Commands:
- SEND <filepath> <nickname>
+ SEND <filepath> <nickname> [<local IP> [<local port>]]
Sends file transfer request to <nickname>. This
makes the <filepath> available to <nickname>.
- RECEIVE [<nickname>]
+ If the <local IP> is provided then the key exchange
+ protocol listener will be bound to that address. If
+ <local port> is defined it is bound to that port.
+ If they are not defined then the local IP address
+ of your machine is used to bind the listener. If that
+ fails then the <nickname> is assumed to provide the
+ listener. If you do not know whether you need to
+ provide <local IP> or not, do not provide it.
+
+ RECEIVE [<nickname>]
Accepts the file transfer request and starts
the file transfer session. If the <nickname> is
omitted the last received request is used.
- CLOSE [<nickname>]
+ CLOSE [<nickname>]
Closes the file transfer session, or rejects
file transfer request. If this command is given
/* SYNTAX: PING */
/* SYNTAX: SCONNECT <server> [<port>] */
/* SYNTAX: USERS <channel> */
-/* SYNTAX: FILE SEND <filepath> <nickname> */
+/* SYNTAX: FILE SEND <filepath> <nickname> [<local IP> [<local port>]] */
/* SYNTAX: FILE RECEIVE [<nickname>] */
/* SYNTAX: FILE CLOSE [<nickname>] */
/* SYNTAX: FILE */
uint32 *argv_lens, *argv_types;
int type = 0;
FtpSession ftp;
+ char *local_ip = NULL;
+ uint32 local_port = 0;
if (!server || !IS_SILC_SERVER(server) || !server->connected)
cmd_return_error(CMDERR_NOT_CONNECTED);
/* Now parse all arguments */
tmp = g_strconcat("FILE", " ", data, NULL);
- silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 4);
+ silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 6);
g_free(tmp);
if (argc == 1)
client_entry = entrys[0];
silc_free(entrys);
+ if (argc >= 5)
+ local_ip = argv[4];
+ if (argc >= 6)
+ local_port = atoi(argv[5]);
+
ftp = silc_calloc(1, sizeof(*ftp));
ftp->session_id =
silc_client_file_send(silc_client, conn, silc_client_file_monitor,
- server, client_entry, argv[2]);
+ server, local_ip, local_port,
+ client_entry, argv[2]);
printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
SILCTXT_FILE_SEND, client_entry->nickname,
tmp = silc_net_create_server(server->config->listen_port->port,
server->config->listen_port->listener_ip);
- if (tmp < 0)
+ if (tmp < 0) {
+ SILC_LOG_ERROR(("Could not create server listener: %s on %d",
+ server->config->listen_port->listener_ip,
+ server->config->listen_port->port));
goto err0;
+ }
sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
sock[sock_count] = tmp;
SilcPacketContext *packet = parser_context->packet;
SilcPacketType ret;
- if (conn && conn->hmac_receive)
+ if (conn && conn->hmac_receive && conn->sock == sock)
conn->psn_receive = parser_context->packet->sequence + 1;
/* Parse the packet immediately */
{
int del = FALSE;
+ SILC_LOG_DEBUG(("Start"));
+
if (!sock || (sock && conn->sock == sock))
del = TRUE;
if (!sock)
silc_socket_free(sock);
}
+/* Called when we receive disconnection packet from server. This
+ closes our end properly and displays the reason of the disconnection
+ on the screen. */
+
+SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
+{
+ SilcClient client = (SilcClient)context;
+ SilcSocketConnection sock;
+
+ SILC_CLIENT_GET_SOCK(client, fd, sock);
+ if (sock == NULL)
+ return;
+
+ silc_client_close_connection(client, sock, sock->user_data);
+}
+
/* Called when we receive disconnection packet from server. This
closes our end properly and displays the reason of the disconnection
on the screen. */
silc_free(msg);
SILC_SET_DISCONNECTED(sock);
- silc_client_close_connection(client, sock, sock->user_data);
+
+ /* Close connection through scheduler. */
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_disconnected_by_server_later,
+ client, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
/* Received error message from server. Display it on the screen.
ctx->ske->prop->group,
ctx->responder);
- /* If we are the SFTP client then start the SFTP session and retrieve
- the info about the file available for download. */
if (!session->server) {
+ /* If we are the SFTP client then start the SFTP session and retrieve
+ the info about the file available for download. */
session->sftp = silc_sftp_client_start(conn->sock,
silc_client_ftp_send_packet,
session,
silc_client_ftp_version, session);
+ } else {
+ /* Start SFTP server */
+ session->sftp = silc_sftp_server_start(conn->sock,
+ silc_client_ftp_send_packet,
+ session, session->fs);
+
+ /* Monitor transmission */
+ silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ,
+ silc_client_ftp_monitor, session);
}
/* Set this as active session */
conn->sock->port = silc_net_get_remote_port(sock);
session->sock = silc_socket_dup(conn->sock);
- /* Allocate the SFTP */
- if (session->server) {
- session->sftp = silc_sftp_server_start(conn->sock,
- silc_client_ftp_send_packet,
- session, session->fs);
-
- /* Monitor transmission */
- silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ,
- silc_client_ftp_monitor, session);
- }
-
/* Allocate internal context for key exchange protocol. This is
sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
SilcClientConnection conn,
SilcClientFileMonitor monitor,
void *monitor_context,
+ const char *local_ip,
+ uint32 local_port,
SilcClientEntry client_entry,
const char *filepath)
{
session->filesize = silc_file_size(filepath);
+ /* Create the listener for incoming key exchange protocol. */
+ if (local_ip)
+ session->hostname = strdup(local_ip);
+ else
+ session->hostname = silc_net_localip();
+ session->listener = silc_net_create_server(local_port, session->hostname);
+ if (session->listener < 0) {
+ /* Could not create listener. Do the second best thing; send empty
+ key agreement packet and let the remote client provide the point
+ for the key exchange. */
+ SILC_LOG_DEBUG(("Could not create listener"));
+ silc_free(session->hostname);
+ session->hostname = NULL;
+ } else {
+ /* Listener ready */
+ 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(NULL, 0);
+ 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));
session->listener = silc_net_create_server(0, session->hostname);
if (session->listener < 0) {
SILC_LOG_DEBUG(("Could not create listener"));
+ client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Cannot create listener on %s: %s",
+ session->hostname, strerror(errno));
return SILC_CLIENT_FILE_ERROR;
}
session->port = silc_net_get_local_port(session->listener);
* file indicated by the `filepath' is being transmitted to the remote
* client indicated by the `client_entry', already.
*
+ * If the `local_ip' is provided then this will try to bind the
+ * listener for key exchange protocol to that IP. If `local_port' is
+ * non-zero that port is used. If `local_ip' is NULL then this will
+ * automatically attempt to bind it to local IP address of the machine.
+ * If that fails then this does not bind to any address and port, and
+ * assume that the remote client will provide the listener for the
+ * key exchange protocol.
+ *
* 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
SilcClientConnection conn,
SilcClientFileMonitor monitor,
void *monitor_context,
+ const char *local_ip,
+ uint32 local_port,
SilcClientEntry client_entry,
const char *filepath);
{
SilcPacketParserContext *parse_ctx;
int packetlen, paddedlen, mac_len = 0;
- int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
bool cont = TRUE;
+
+ /* Do not process for disconnected connection */
+ if (SILC_IS_DISCONNECTED(sock))
+ return;
if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
return;
paddedlen + mac_len);
SILC_LOG_HEXDUMP(("Incoming packet (%d) (%dB decrypted), len %d",
- sequence - 1, block_len, paddedlen + mac_len),
+ sequence - 1, SILC_PACKET_MIN_HEADER_LEN,
+ paddedlen + mac_len),
sock->inbuf->data, paddedlen + mac_len);
/* Check whether this is normal or special packet */
if (!dest)
return NULL;
- SILC_GET32_LSB(ip.s_addr, dest->h_addr_list[0]);
+ memcpy(&ip.s_addr, dest->h_addr_list[0], 4);
ips = inet_ntoa(ip);
return strdup(ips);
/* Bind the server socket */
rval = bind(sock, (struct sockaddr *)&server, sizeof(server));
if (rval < 0) {
- SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno)));
+ SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
return -1;
}