*/
/* $Id$ */
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
#include "client_internal.h"
static int
/* File transmission session */
struct SilcClientFtpSessionStruct {
- uint32 session_id;
+ SilcUInt32 session_id;
SilcClient client;
SilcClientConnection conn;
SilcClientEntry client_entry;
SilcBuffer packet;
char *hostname;
- uint16 port;
+ SilcUInt16 port;
int listener;
SilcClientFileMonitor monitor;
void *monitor_context;
char *filepath;
+ char *path;
SilcSFTP sftp;
SilcSFTPFilesystem fs;
SilcSFTPHandle dir_handle;
SilcSFTPHandle read_handle;
- uint64 filesize;
- uint64 read_offset;
+ SilcUInt64 filesize;
+ SilcUInt64 read_offset;
int fd;
};
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);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to client %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->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);
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));
+ client->internal->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);
(void *)ctx, 0, 0,
SILC_TASK_FD,
SILC_TASK_PRI_NORMAL);
- silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
+ silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
+ FALSE);
ctx->sock = sock;
return sock;
}
/* 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)
+static void silc_client_ftp_send_packet(SilcBuffer packet, void *context)
{
SilcClientFtpSession session = (SilcClientFtpSession)context;
SilcClient client = session->client;
SILC_STR_END);
/* Send the packet immediately */
- silc_client_packet_send(client, sock, SILC_PACKET_FTP, NULL, 0, NULL, NULL,
- session->packet->data, session->packet->len, TRUE);
+ silc_client_packet_send(client, session->sock, SILC_PACKET_FTP, NULL,
+ 0, NULL, NULL, session->packet->data,
+ session->packet->len, TRUE);
/* Clear buffer */
session->packet->data = session->packet->tail = session->packet->head;
static void silc_client_ftp_data(SilcSFTP sftp,
SilcSFTPStatus status,
const unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
void *context)
{
SilcClientFtpSession session = (SilcClientFtpSession)context;
/* Read more, until EOF is received */
session->read_offset += data_len;
- silc_sftp_read(sftp, session->read_handle, session->read_offset, 64512,
+ silc_sftp_read(sftp, session->read_handle, session->read_offset,
+ SILC_PACKET_MAX_LEN - 1024,
silc_client_ftp_data, session);
/* Call monitor callback */
void *context)
{
SilcClientFtpSession session = (SilcClientFtpSession)context;
+ char path[512];
SILC_LOG_DEBUG(("Start"));
}
/* Open the actual local file */
- session->fd = silc_file_open(session->filepath,
- O_RDWR | O_CREAT | O_EXCL);
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path) - 1, "%s%s", session->path ?
+ session->path : "", session->filepath);
+ session->fd = silc_file_open(path, O_RDWR | O_CREAT | O_EXCL);
if (session->fd < 0) {
/* Call monitor callback */
- session->client->ops->say(session->client, session->conn,
- SILC_CLIENT_MESSAGE_ERROR,
- "File `%s' open failed: %s", session->filepath,
- strerror(errno));
+ session->client->internal->ops->say(session->client, session->conn,
+ SILC_CLIENT_MESSAGE_ERROR,
+ "File `%s' open failed: %s",
+ session->filepath,
+ strerror(errno));
if (session->monitor)
(*session->monitor)(session->client, session->conn,
session->read_handle = handle;
/* Now, start reading the file */
- silc_sftp_read(sftp, session->read_handle, session->read_offset, 64512,
+ silc_sftp_read(sftp, session->read_handle, session->read_offset,
+ SILC_PACKET_MAX_LEN - 1024,
silc_client_ftp_data, session);
/* Call monitor callback */
silc_sftp_open(sftp, name->filename[0], SILC_SFTP_FXF_READ, &attr,
silc_client_ftp_open_handle, session);
- /* Save the important attributes */
+ /* Save the important attributes like filename and file size */
session->filepath = strdup(name->filename[0]);
session->filesize = name->attrs[0]->size;
if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Call monitor callback */
+ if (session->monitor)
+ (*session->monitor)(session->client, session->conn,
+ SILC_CLIENT_FILE_MONITOR_ERROR,
+ SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED, 0, 0,
+ session->client_entry, session->session_id,
+ session->filepath, session->monitor_context);
+
/* Error occured during protocol */
silc_ske_free_key_material(ctx->keymat);
goto out;
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);
+ session->sftp = silc_sftp_client_start(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->sftp = silc_sftp_server_start(silc_client_ftp_send_packet,
session, session->fs);
/* Monitor transmission */
}
/* Set this as active session */
- conn->active_session = session;
+ conn->internal->active_session = session;
out:
silc_ske_free_key_material(ctx->keymat);
NULL, session->monitor_context);
/* Add new connection for this session */
- conn = silc_client_add_connection(client, session->hostname,
+ conn = silc_client_add_connection(client, NULL, session->hostname,
session->port, session);
/* Allocate new socket connection object */
NULL, session->monitor_context);
/* Add new connection for this session */
- conn = silc_client_add_connection(client, newsocket->hostname,
+ conn = silc_client_add_connection(client, NULL, newsocket->hostname,
newsocket->port, session);
conn->sock = newsocket;
conn->sock->user_data = conn;
void silc_client_ftp_free_sessions(SilcClient client,
SilcClientConnection conn)
{
- if (conn->ftp_sessions) {
+ if (conn->internal->ftp_sessions) {
SilcClientFtpSession session;
- silc_dlist_start(conn->ftp_sessions);
- while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
if (session->sock)
session->sock->user_data = NULL;
silc_client_ftp_session_free(session);
}
- silc_dlist_del(conn->ftp_sessions, session);
- silc_dlist_uninit(conn->ftp_sessions);
+ silc_dlist_del(conn->internal->ftp_sessions, session);
}
}
{
SilcClientFtpSession session;
- if (!conn->ftp_sessions)
+ if (!conn->internal->ftp_sessions)
return;
/* Get the session */
- silc_dlist_start(conn->ftp_sessions);
- while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
if (session->client_entry == client_entry) {
if (session->sock)
session->sock->user_data = NULL;
SILC_LOG_DEBUG(("Free session"));
- silc_dlist_del(session->conn->ftp_sessions, session);
+ if (session->conn && session->conn->internal->ftp_sessions)
+ silc_dlist_del(session->conn->internal->ftp_sessions, session);
+
+ if (session->conn && session->conn->internal->active_session == session)
+ session->conn->internal->active_session = NULL;
if (session->sftp) {
if (session->server)
if (session->sock->user_data) {
conn = (SilcClientConnection)session->sock->user_data;
- if (conn->active_session == session)
- conn->active_session = NULL;
+ if (conn->internal->active_session == session)
+ conn->internal->active_session = NULL;
- silc_client_close_connection(session->client, session->sock, conn);
+ silc_client_close_connection_real(session->client, session->sock, conn);
} else {
silc_socket_free(session->sock);
}
silc_free(session->hostname);
silc_free(session->filepath);
+ silc_free(session->path);
+ memset(session, 'F', sizeof(*session));
silc_free(session);
}
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,
- void *monitor_context,
- const char *local_ip,
- uint32 local_port,
- SilcClientEntry client_entry,
- const char *filepath)
+ transmission of the file. */
+
+SilcClientFileError
+silc_client_file_send(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientFileMonitor monitor,
+ void *monitor_context,
+ const char *local_ip,
+ SilcUInt32 local_port,
+ SilcClientEntry client_entry,
+ const char *filepath,
+ SilcUInt32 *session_id)
{
SilcClientFtpSession session;
SilcBuffer keyagr, ftp;
char *filename, *path;
+ int fd;
+
+ assert(client && conn && client_entry);
SILC_LOG_DEBUG(("Start"));
/* Check for existing session for `filepath'. */
- silc_dlist_start(conn->ftp_sessions);
- while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
- if (!strcmp(session->filepath, filepath) &&
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
+ if (session->filepath && !strcmp(session->filepath, filepath) &&
session->client_entry == client_entry)
- return 0;
+ return SILC_CLIENT_FILE_ALREADY_STARTED;
}
+ /* See whether the file exists, and can be opened in generally speaking */
+ fd = silc_file_open(filepath, O_RDONLY);
+ if (fd < 0)
+ return SILC_CLIENT_FILE_NO_SUCH_FILE;
+ silc_file_close(fd);
+
/* Add new session */
session = silc_calloc(1, sizeof(*session));
- session->session_id = ++conn->next_session_id;
+ session->session_id = ++conn->internal->next_session_id;
session->client = client;
session->conn = conn;
session->client_entry = client_entry;
session->monitor_context = monitor_context;
session->filepath = strdup(filepath);
session->server = TRUE;
- silc_dlist_add(conn->ftp_sessions, session);
+ silc_dlist_add(conn->internal->ftp_sessions, session);
- path = silc_calloc(strlen(filepath) + 8, sizeof(*path));
- strcat(path, "file://");
- strncat(path, filepath, strlen(filepath));
+ path = silc_calloc(strlen(filepath) + 9, sizeof(*path));
+ silc_strncat(path, strlen(filepath) + 9, "file://", 7);
+ silc_strncat(path, strlen(filepath) + 9, filepath, strlen(filepath));
/* Allocate memory filesystem and put the file to it */
if (strrchr(path, '/'))
SILC_LOG_DEBUG(("Could not create listener"));
silc_free(session->hostname);
session->hostname = NULL;
+ session->port = 0;
} else {
/* Listener ready */
session->port = silc_net_get_local_port(session->listener);
silc_buffer_free(ftp);
silc_free(path);
- return session->session_id;
+ if (session_id)
+ *session_id = session->session_id;
+
+ return SILC_CLIENT_FILE_OK;
}
/* Receives a file from a client indicated by the `client_entry'. The
SilcClientConnection conn,
SilcClientFileMonitor monitor,
void *monitor_context,
- uint32 session_id)
+ const char *path,
+ SilcUInt32 session_id)
{
SilcClientFtpSession session;
SilcBuffer keyagr, ftp;
+ assert(client && conn);
+
SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
/* Get the session */
- silc_dlist_start(conn->ftp_sessions);
- while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
if (session->session_id == session_id) {
break;
}
session->monitor = monitor;
session->monitor_context = monitor_context;
session->conn = conn;
+ session->path = path ? strdup(path) : NULL;
/* 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
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));
+ client->internal->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);
SilcClientFileError silc_client_file_close(SilcClient client,
SilcClientConnection conn,
- uint32 session_id)
+ SilcUInt32 session_id)
{
SilcClientFtpSession session;
+ assert(client && conn);
+
SILC_LOG_DEBUG(("Start, Session ID: %d", session_id));
/* Get the session */
- silc_dlist_start(conn->ftp_sessions);
- while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
if (session->session_id == session_id) {
break;
}
static void silc_client_ftp_resolve_cb(SilcClient client,
SilcClientConnection conn,
SilcClientEntry *clients,
- uint32 clients_count,
+ SilcUInt32 clients_count,
void *context)
{
SilcPacketContext *packet = (SilcPacketContext *)context;
SilcKeyAgreementPayload payload = NULL;
SilcClientEntry client_entry;
char *hostname;
- uint16 port;
+ SilcUInt16 port;
SILC_LOG_DEBUG(("Start"));
client_entry = clients[0];
- silc_dlist_start(conn->ftp_sessions);
- while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) {
- if (session->client_entry == client_entry)
+ silc_dlist_start(conn->internal->ftp_sessions);
+ while ((session = silc_dlist_get(conn->internal->ftp_sessions))
+ != SILC_LIST_END) {
+ if (session->client_entry == client_entry && !session->server)
break;
}
/* Parse the key agreement payload */
- payload = silc_key_agreement_payload_parse(packet->buffer);
+ payload = silc_key_agreement_payload_parse(packet->buffer->data,
+ packet->buffer->len);
if (!payload)
goto out;
hostname = silc_key_agreement_get_hostname(payload);
port = silc_key_agreement_get_port(payload);
+ if (!hostname)
+ port = 0;
+ if (!port)
+ hostname = NULL;
if (session == SILC_LIST_END || (!hostname && !port)) {
/* No session found, create one and let the application know about
/* Add new session */
session = silc_calloc(1, sizeof(*session));
- session->session_id = ++conn->next_session_id;
+ session->session_id = ++conn->internal->next_session_id;
session->client = client;
session->conn = conn;
session->client_entry = client_entry;
- silc_dlist_add(conn->ftp_sessions, session);
+ silc_dlist_add(conn->internal->ftp_sessions, session);
/* Let the application know */
- client->ops->ftp(client, conn, client_entry,
- session->session_id, hostname, port);
+ client->internal->ops->ftp(client, conn, client_entry,
+ session->session_id, hostname, port);
if (hostname && port) {
session->hostname = strdup(hostname);
SilcPacketContext *packet)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- uint8 type;
+ SilcUInt8 type;
int ret;
SILC_LOG_DEBUG(("Start"));
/* If we have active FTP session then give the packet directly to the
protocol processor. */
- if (conn->active_session) {
+ if (conn->internal->active_session) {
/* Give it to the SFTP */
- if (conn->active_session->server)
- silc_sftp_server_receive_process(conn->active_session->sftp, sock,
- packet);
+ if (conn->internal->active_session->server)
+ silc_sftp_server_receive_process(conn->internal->active_session->sftp,
+ sock, packet);
else
- silc_sftp_client_receive_process(conn->active_session->sftp, sock,
- packet);
+ silc_sftp_client_receive_process(conn->internal->active_session->sftp,
+ sock, packet);
} else {
/* We don't have active session, resolve the remote client information
and then try to find the correct session. */
/* Resolve the client */
silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
- silc_client_ftp_resolve_cb,
+ NULL, silc_client_ftp_resolve_cb,
silc_packet_context_dup(packet));
silc_free(remote_id);
}