5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "clientlibincludes.h"
22 #include "client_internal.h"
25 silc_client_connect_to_client(SilcClient client,
26 SilcClientConnection conn, int port,
27 char *host, void *context);
29 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx);
30 SILC_TASK_CALLBACK(silc_client_ftp_connected);
31 static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session,
34 /* File transmission session */
35 struct SilcClientFtpSessionStruct {
38 SilcClientConnection conn;
39 SilcClientEntry client_entry;
41 SilcSocketConnection sock;
47 SilcClientFileMonitor monitor;
48 void *monitor_context;
52 SilcSFTPFilesystem fs;
55 SilcSFTPHandle dir_handle;
56 SilcSFTPHandle read_handle;
62 void silc_client_ftp_free_sessions(SilcClient client,
63 SilcClientConnection conn)
65 if (conn->ftp_sessions) {
66 SilcClientFtpSession session;
67 silc_dlist_start(conn->ftp_sessions);
68 while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
69 session->sock->user_data = NULL;
70 silc_client_ftp_session_free(session);
72 silc_dlist_del(conn->ftp_sessions, session);
73 silc_dlist_uninit(conn->ftp_sessions);
77 void silc_client_ftp_session_free_client(SilcClientConnection conn,
78 SilcClientEntry client_entry)
80 SilcClientFtpSession session;
82 if (!conn->ftp_sessions)
86 silc_dlist_start(conn->ftp_sessions);
87 while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
88 if (session->client_entry == client_entry) {
89 session->sock->user_data = NULL;
90 silc_client_ftp_session_free(session);
96 /* SFTP packet send callback */
98 static void silc_client_ftp_send_packet(SilcSocketConnection sock,
99 SilcBuffer packet, void *context)
101 SilcClientFtpSession session = (SilcClientFtpSession)context;
102 SilcClient client = session->client;
105 SILC_LOG_DEBUG(("Start"));
107 buffer = silc_buffer_alloc(1 + packet->len);
108 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
109 silc_buffer_format(buffer,
111 SILC_STR_UI_XNSTRING(packet->data, packet->len),
114 /* Send the packet immediately */
115 silc_client_packet_send(client, sock, SILC_PACKET_FTP, NULL, 0, NULL, NULL,
116 buffer->data, buffer->len, TRUE);
118 silc_buffer_free(buffer);
121 /* SFTP monitor callback for SFTP server */
123 static void silc_client_ftp_monitor(SilcSFTP sftp,
124 SilcSFTPMonitors type,
125 const SilcSFTPMonitorData data,
128 SilcClientFtpSession session = (SilcClientFtpSession)context;
130 if (type == SILC_SFTP_MONITOR_READ) {
131 /* Call the monitor for application */
132 if (session->monitor)
133 (*session->monitor)(session->client, session->conn,
134 SILC_CLIENT_FILE_MONITOR_SEND,
135 data->offset, session->filesize,
136 session->client_entry, session->session_id,
137 session->filepath, session->monitor_context);
141 /* Returns the read data */
143 static void silc_client_ftp_data(SilcSFTP sftp,
144 SilcSFTPStatus status,
145 const unsigned char *data,
149 SilcClientFtpSession session = (SilcClientFtpSession)context;
151 SILC_LOG_DEBUG(("Start"));
153 if (status == SILC_SFTP_STATUS_EOF) {
155 /* Close the handle */
156 silc_sftp_close(sftp, session->read_handle, NULL, NULL);
157 session->read_handle = NULL;
159 /* Close the read file descriptor */
160 silc_file_close(session->fd);
164 if (status != SILC_SFTP_STATUS_OK) {
167 /* Close the handle */
168 silc_sftp_close(sftp, session->read_handle, NULL, NULL);
169 session->read_handle = NULL;
171 /* Close the read file descriptor */
172 silc_file_close(session->fd);
176 /* Read more, until EOF is received */
177 session->read_offset += data_len;
178 silc_sftp_read(sftp, session->read_handle, session->read_offset, 16384,
179 silc_client_ftp_data, session);
181 /* Call monitor callback */
182 if (session->monitor)
183 (*session->monitor)(session->client, session->conn,
184 SILC_CLIENT_FILE_MONITOR_RECEIVE,
185 session->read_offset, session->filesize,
186 session->client_entry, session->session_id,
187 session->filepath, session->monitor_context);
189 /* Write the read data */
190 silc_file_write(session->fd, data, data_len);
193 static void silc_client_ftp_open_handle(SilcSFTP sftp,
194 SilcSFTPStatus status,
195 SilcSFTPHandle handle,
198 SilcClientFtpSession session = (SilcClientFtpSession)context;
200 SILC_LOG_DEBUG(("Start"));
202 if (status != SILC_SFTP_STATUS_OK) {
207 /* Open the actual local file */
208 session->fd = silc_file_open(session->filepath, O_RDWR | O_CREAT);
209 if (session->fd < 0) {
214 session->read_handle = handle;
216 /* Now, start reading the file */
217 silc_sftp_read(sftp, session->read_handle, session->read_offset, 16384,
218 silc_client_ftp_data, session);
220 /* Call monitor callback */
221 if (session->monitor)
222 (*session->monitor)(session->client, session->conn,
223 SILC_CLIENT_FILE_MONITOR_RECEIVE,
224 session->read_offset, session->filesize,
225 session->client_entry, session->session_id,
226 session->filepath, session->monitor_context);
229 /* Returns the file name available for download. */
231 static void silc_client_ftp_readdir_name(SilcSFTP sftp,
232 SilcSFTPStatus status,
233 const SilcSFTPName name,
236 SilcClientFtpSession session = (SilcClientFtpSession)context;
237 SilcSFTPAttributesStruct attr;
239 SILC_LOG_DEBUG(("Start"));
241 if (status != SILC_SFTP_STATUS_OK) {
245 /* Now open the file */
246 memset(&attr, 0, sizeof(attr));
247 silc_sftp_open(sftp, name->filename[0], SILC_SFTP_FXF_READ, &attr,
248 silc_client_ftp_open_handle, session);
250 /* Save the important attributes */
251 session->filepath = strdup(name->filename[0]);
252 session->filesize = name->attrs[0]->size;
254 /* Close the directory handle */
255 silc_sftp_close(sftp, session->dir_handle, NULL, NULL);
256 session->dir_handle = NULL;
259 /* Returns the file handle after giving opendir command. */
261 static void silc_client_ftp_opendir_handle(SilcSFTP sftp,
262 SilcSFTPStatus status,
263 SilcSFTPHandle handle,
266 SilcClientFtpSession session = (SilcClientFtpSession)context;
268 SILC_LOG_DEBUG(("Start"));
270 if (status != SILC_SFTP_STATUS_OK) {
274 /* Now, read the directory */
275 silc_sftp_readdir(sftp, handle, silc_client_ftp_readdir_name, session);
276 session->dir_handle = handle;
279 /* SFTP version callback for SFTP client */
281 static void silc_client_ftp_version(SilcSFTP sftp,
282 SilcSFTPStatus status,
283 SilcSFTPVersion version,
286 SilcClientFtpSession session = (SilcClientFtpSession)context;
288 SILC_LOG_DEBUG(("Start"));
290 if (status != SILC_SFTP_STATUS_OK) {
294 /* The SFTP session is open, now retrieve the info about available file. */
295 silc_sftp_opendir(sftp, "", silc_client_ftp_opendir_handle, session);
298 /* This callback is called after the key agreement protocol has been
299 performed. This calls the final completion callback for the application. */
301 SILC_TASK_CALLBACK(silc_client_ftp_key_agreement_final)
303 SilcProtocol protocol = (SilcProtocol)context;
304 SilcClientKEInternalContext *ctx =
305 (SilcClientKEInternalContext *)protocol->context;
306 SilcClientFtpSession session = (SilcClientFtpSession)ctx->context;
307 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
309 SILC_LOG_DEBUG(("Start"));
311 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
312 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
313 /* Error occured during protocol */
314 silc_ske_free_key_material(ctx->keymat);
318 /* Set keys into use */
319 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
320 ctx->ske->prop->cipher,
321 ctx->ske->prop->pkcs,
322 ctx->ske->prop->hash,
323 ctx->ske->prop->hmac,
324 ctx->ske->prop->group,
327 /* If we are the SFTP client then start the SFTP session and retrieve
328 the info about the file available for download. */
329 if (!session->server) {
330 session->sftp = silc_sftp_client_start(conn->sock,
331 silc_client_ftp_send_packet,
333 silc_client_ftp_version, session);
336 /* Set this as active session */
337 conn->active_session = session;
340 silc_ske_free_key_material(ctx->keymat);
342 silc_ske_free(ctx->ske);
343 silc_free(ctx->dest_id);
344 ctx->sock->protocol = NULL;
345 silc_socket_free(ctx->sock);
347 silc_protocol_free(protocol);
350 static void silc_client_ftp_start_key_agreement(SilcClientFtpSession session,
353 SilcClient client = session->client;
354 SilcClientKEInternalContext *proto_ctx;
355 SilcProtocol protocol;
356 SilcClientConnection conn;
359 SILC_LOG_DEBUG(("Start"));
361 /* Add new connection for this session */
362 conn = silc_client_add_connection(client, session->hostname,
363 session->port, session);
365 /* Allocate new socket connection object */
366 silc_socket_alloc(sock, SILC_SOCKET_TYPE_CLIENT, (void *)conn, &conn->sock);
367 conn->sock->hostname = strdup(session->hostname);
368 conn->sock->port = silc_net_get_remote_port(sock);
369 session->sock = silc_socket_dup(conn->sock);
371 /* Allocate the SFTP */
372 if (session->server) {
373 session->sftp = silc_sftp_server_start(conn->sock,
374 silc_client_ftp_send_packet,
375 session, session->fs);
377 /* Monitor transmission */
378 silc_sftp_server_set_monitor(session->sftp, SILC_SFTP_MONITOR_READ,
379 silc_client_ftp_monitor, session);
382 /* Allocate internal context for key exchange protocol. This is
383 sent as context for the protocol. */
384 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
385 proto_ctx->client = client;
386 proto_ctx->sock = silc_socket_dup(conn->sock);
387 proto_ctx->rng = client->rng;
388 proto_ctx->responder = FALSE;
389 proto_ctx->context = session;
390 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
391 proto_ctx->verify = silc_client_protocol_ke_verify_key;
393 /* Perform key exchange protocol. */
394 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
395 &protocol, (void *)proto_ctx,
396 silc_client_ftp_key_agreement_final);
397 conn->sock->protocol = protocol;
399 /* Register the connection for network input and output. This sets
400 that scheduler will listen for incoming packets for this connection
401 and sets that outgoing packets may be sent to this connection as well.
402 However, this doesn't set the scheduler for outgoing traffic, it will
403 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
404 later when outgoing data is available. */
405 context = (void *)client;
406 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
408 /* Execute the protocol */
409 silc_protocol_execute(protocol, client->schedule, 0, 0);
412 SILC_TASK_CALLBACK(silc_client_ftp_connected)
414 SilcClientInternalConnectContext *ctx =
415 (SilcClientInternalConnectContext *)context;
416 SilcClient client = ctx->client;
417 SilcClientConnection conn = ctx->conn;
418 SilcClientFtpSession session = (SilcClientFtpSession)ctx->context;
419 int opt, opt_len = sizeof(opt);
421 SILC_LOG_DEBUG(("Start"));
423 /* Check the socket status as it might be in error */
424 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
426 if (ctx->tries < 2) {
427 /* Connection failed but lets try again */
428 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
429 "Could not connect to client %s: %s",
430 ctx->host, strerror(opt));
431 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
432 "Connecting to port %d of client %s resumed",
433 ctx->port, ctx->host);
435 /* Unregister old connection try */
436 silc_schedule_unset_listen_fd(client->schedule, fd);
437 silc_net_close_connection(fd);
438 silc_schedule_task_del(client->schedule, ctx->task);
441 silc_client_connect_to_client_internal(ctx);
444 /* Connection failed and we won't try anymore */
445 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
446 "Could not connect to client %s: %s",
447 ctx->host, strerror(opt));
448 silc_schedule_unset_listen_fd(client->schedule, fd);
449 silc_net_close_connection(fd);
450 silc_schedule_task_del(client->schedule, ctx->task);
452 silc_client_ftp_session_free(session);
457 silc_schedule_unset_listen_fd(client->schedule, fd);
458 silc_schedule_task_del(client->schedule, ctx->task);
460 /* Start the key agreement */
461 silc_client_ftp_start_key_agreement(session, fd);
465 silc_client_connect_to_client_internal(SilcClientInternalConnectContext *ctx)
469 /* Create connection to server asynchronously */
470 sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
474 /* Register task that will receive the async connect and will
476 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
477 silc_client_ftp_connected,
480 SILC_TASK_PRI_NORMAL);
481 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
489 silc_client_connect_to_client(SilcClient client,
490 SilcClientConnection conn, int port,
491 char *host, void *context)
493 SilcClientInternalConnectContext *ctx;
495 /* Allocate internal context for connection process. This is
496 needed as we are doing async connecting. */
497 ctx = silc_calloc(1, sizeof(*ctx));
498 ctx->client = client;
500 ctx->host = strdup(host);
503 ctx->context = context;
505 /* Do the actual connecting process */
506 return silc_client_connect_to_client_internal(ctx);
511 void silc_client_ftp_session_free(SilcClientFtpSession session)
513 SilcClientConnection conn;
515 silc_dlist_del(session->conn->ftp_sessions, session);
519 silc_sftp_server_shutdown(session->sftp);
521 silc_sftp_client_shutdown(session->sftp);
525 silc_sftp_fs_memory_free(session->fs);
527 if (session->listener) {
528 silc_schedule_unset_listen_fd(session->client->schedule,
530 silc_net_close_connection(session->listener);
534 silc_schedule_unset_listen_fd(session->client->schedule,
535 session->sock->sock);
536 silc_net_close_connection(session->sock->sock);
538 if (session->sock->user_data) {
539 conn = (SilcClientConnection)session->sock->user_data;
541 if (conn->active_session == session)
542 conn->active_session = NULL;
544 silc_client_close_connection(session->client, session->sock, conn);
546 silc_socket_free(session->sock);
550 silc_free(session->hostname);
551 silc_free(session->filepath);
555 SILC_TASK_CALLBACK(silc_client_ftp_process_key_agreement)
557 SilcClientFtpSession session = (SilcClientFtpSession)context;
558 SilcClient client = session->client;
559 SilcClientConnection conn;
560 SilcSocketConnection newsocket;
561 SilcClientKEInternalContext *proto_ctx;
564 SILC_LOG_DEBUG(("Start"));
566 sock = silc_net_accept_connection(session->listener);
572 /* Set socket options */
573 silc_net_set_socket_nonblock(sock);
574 silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
576 /* Allocate new socket connection object */
577 silc_socket_alloc(sock, SILC_SOCKET_TYPE_CLIENT, NULL, &newsocket);
579 /* Perform name and address lookups for the remote host. */
580 silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
581 if (!newsocket->hostname && !newsocket->ip) {
585 if (!newsocket->hostname)
586 newsocket->hostname = strdup(newsocket->ip);
587 newsocket->port = silc_net_get_remote_port(sock);
589 /* Add new connection for this session */
590 conn = silc_client_add_connection(client, newsocket->hostname,
591 newsocket->port, session);
592 conn->sock = newsocket;
593 conn->sock->user_data = conn;
594 session->sock = silc_socket_dup(conn->sock);
596 /* Allocate internal context for key exchange protocol. This is
597 sent as context for the protocol. */
598 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
599 proto_ctx->client = client;
600 proto_ctx->sock = silc_socket_dup(conn->sock);
601 proto_ctx->rng = client->rng;
602 proto_ctx->responder = TRUE;
603 proto_ctx->context = session;
604 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
605 proto_ctx->verify = silc_client_protocol_ke_verify_key;
607 /* Prepare the connection for key exchange protocol. We allocate the
608 protocol but will not start it yet. The connector will be the
609 initiator of the protocol thus we will wait for initiation from
610 there before we start the protocol. */
611 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
612 &newsocket->protocol, proto_ctx,
613 silc_client_ftp_key_agreement_final);
615 /* Register the connection for network input and output. This sets
616 that scheduler will listen for incoming packets for this connection
617 and sets that outgoing packets may be sent to this connection as well.
618 However, this doesn't set the scheduler for outgoing traffic, it
619 will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
620 later when outgoing data is available. */
621 context = (void *)client;
622 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
625 uint32 silc_client_file_send(SilcClient client,
626 SilcClientConnection conn,
627 SilcClientFileMonitor monitor,
628 void *monitor_context,
629 SilcClientEntry client_entry,
630 const char *filepath)
632 SilcClientFtpSession session;
633 SilcBuffer keyagr, ftp;
634 char *filename, *path;
636 SILC_LOG_DEBUG(("Start"));
638 /* Check for existing session for `filepath'. */
639 silc_dlist_start(conn->ftp_sessions);
640 while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
641 if (!strcmp(session->filepath, filepath) &&
642 session->client_entry == client_entry)
646 /* Add new session */
647 session = silc_calloc(1, sizeof(*session));
648 session->session_id = conn->next_session_id++;
649 session->client = client;
650 session->conn = conn;
651 session->client_entry = client_entry;
652 session->monitor = monitor;
653 session->monitor_context = monitor_context;
654 session->filepath = strdup(filepath);
655 session->server = TRUE;
656 silc_dlist_add(conn->ftp_sessions, session);
658 path = silc_calloc(strlen(filepath) + 8, sizeof(*path));
659 strcat(path, "file://");
660 strncat(path, filepath, strlen(filepath));
662 /* Allocate memory filesystem and put the file to it */
663 if (strrchr(path, '/'))
664 filename = strrchr(path, '/') + 1;
666 filename = (char *)path;
667 session->fs = silc_sftp_fs_memory_alloc(SILC_SFTP_FS_PERM_READ |
668 SILC_SFTP_FS_PERM_EXEC);
669 silc_sftp_fs_memory_add_file(session->fs, NULL, SILC_SFTP_FS_PERM_READ,
672 session->filesize = silc_file_size(filepath);
674 /* Send the key agreement inside FTP packet */
675 keyagr = silc_key_agreement_payload_encode(NULL, 0);
677 ftp = silc_buffer_alloc(1 + keyagr->len);
678 silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp));
679 silc_buffer_format(ftp,
681 SILC_STR_UI_XNSTRING(keyagr->data, keyagr->len),
683 silc_client_packet_send(client, conn->sock, SILC_PACKET_FTP,
684 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
685 ftp->data, ftp->len, FALSE);
687 silc_buffer_free(keyagr);
688 silc_buffer_free(ftp);
691 return session->session_id;
694 bool silc_client_file_receive(SilcClient client,
695 SilcClientConnection conn,
696 SilcClientFileMonitor monitor,
697 void *monitor_context,
698 SilcClientEntry client_entry,
701 SilcClientFtpSession session;
702 SilcBuffer keyagr, ftp;
704 SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
706 /* Get the session */
707 silc_dlist_start(conn->ftp_sessions);
708 while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
709 if (session->session_id == session_id) {
714 if (session == SILC_LIST_END) {
715 SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id));
719 /* See if we have this session running already */
720 if (session->sftp || session->listener) {
721 SILC_LOG_DEBUG(("Session already started"));
725 session->monitor = monitor;
726 session->monitor_context = monitor_context;
727 session->client_entry = client_entry;
728 session->conn = conn;
730 /* Add the listener for the key agreement */
731 session->hostname = silc_net_localip();
732 session->listener = silc_net_create_server(0, session->hostname);
733 if (session->listener < 0) {
735 SILC_LOG_DEBUG(("Could not create listener"));
738 session->port = silc_net_get_local_port(session->listener);
739 silc_schedule_task_add(client->schedule, session->listener,
740 silc_client_ftp_process_key_agreement, session,
741 0, 0, SILC_TASK_FD, SILC_TASK_PRI_NORMAL);
743 /* Send the key agreement inside FTP packet */
744 keyagr = silc_key_agreement_payload_encode(session->hostname, session->port);
746 ftp = silc_buffer_alloc(1 + keyagr->len);
747 silc_buffer_pull_tail(ftp, SILC_BUFFER_END(ftp));
748 silc_buffer_format(ftp,
750 SILC_STR_UI_XNSTRING(keyagr->data, keyagr->len),
752 silc_client_packet_send(client, conn->sock, SILC_PACKET_FTP,
753 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
754 ftp->data, ftp->len, FALSE);
756 silc_buffer_free(keyagr);
757 silc_buffer_free(ftp);
762 /* Closes FTP session */
764 bool silc_client_file_close(SilcClient client,
765 SilcClientConnection conn,
768 SilcClientFtpSession session;
770 SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
772 /* Get the session */
773 silc_dlist_start(conn->ftp_sessions);
774 while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
775 if (session->session_id == session_id) {
780 if (session == SILC_LIST_END) {
781 SILC_LOG_DEBUG(("Unknown session ID: %d\n", session_id));
785 silc_client_ftp_session_free(session);
790 /* Callback called after remote client information has been resolved.
791 This will try to find existing session for the client entry. If found
792 then continue with the key agreement protocol. If not then it means
793 this is a file transfer request and we let the application know. */
796 silc_client_ftp_resolve_cb(SilcClient client,
797 SilcClientConnection conn,
798 SilcClientEntry *clients,
799 uint32 clients_count,
802 SilcPacketContext *packet = (SilcPacketContext *)context;
803 SilcClientFtpSession session;
804 SilcKeyAgreementPayload payload;
805 SilcClientEntry client_entry;
810 SILC_LOG_DEBUG(("Start"));
815 client_entry = clients[0];
817 silc_dlist_start(conn->ftp_sessions);
818 while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
819 if (session->client_entry == client_entry)
823 /* Parse the key agreement payload */
824 payload = silc_key_agreement_payload_parse(packet->buffer);
828 hostname = silc_key_agreement_get_hostname(payload);
829 port = silc_key_agreement_get_port(payload);
831 if (session == SILC_LIST_END) {
832 /* No session found, create one and let the application know about
833 incomoing file transfer request. */
835 /* Add new session */
836 session = silc_calloc(1, sizeof(*session));
837 session->session_id = conn->next_session_id++;
838 session->client = client;
839 session->conn = conn;
840 silc_dlist_add(conn->ftp_sessions, session);
842 /* Let the application know */
843 client->ops->ftp(client, conn, client_entry,
844 session->session_id, hostname, port);
846 /* If hostname was provided we'll start the key exchange now. */
847 if (hostname && port) {
851 silc_key_agreement_payload_free(payload);
858 session->hostname = strdup(hostname);
859 session->port = port;
861 /* Session exists, continue with key agreement protocol. */
862 sock = silc_client_connect_to_client(client, conn, port, hostname,
868 silc_packet_context_free(packet);
871 /* Called when file transfer packet is received. This will parse the
872 packet and give it to the file transfer protocol. */
874 void silc_client_ftp(SilcClient client,
875 SilcSocketConnection sock,
876 SilcPacketContext *packet)
878 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
882 SILC_LOG_DEBUG(("Start"));
884 /* Parse the payload */
885 ret = silc_buffer_unformat(packet->buffer,
886 SILC_STR_UI_CHAR(&type),
891 /* We support only type number 1 (== SFTP) */
895 silc_buffer_pull(packet->buffer, 1);
897 /* If we have active FTP session then give the packet to the
898 protocol processor. */
899 if (conn->active_session) {
900 /* Give it to the SFTP */
901 if (conn->active_session->server)
902 silc_sftp_server_receive_process(conn->active_session->sftp, sock,
905 silc_sftp_client_receive_process(conn->active_session->sftp, sock,
908 /* We don't have active session, resolve the remote client information
909 and then try to find the correct session. */
910 SilcClientID *remote_id;
912 if (packet->src_id_type != SILC_ID_CLIENT)
915 remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
920 /* Resolve the client */
921 silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
922 silc_client_ftp_resolve_cb,
923 silc_packet_context_dup(packet));
924 silc_free(remote_id);