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);
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,
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;
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));
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,
- 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,
+ uint32 local_port,
+ SilcClientEntry client_entry,
+ const char *filepath,
+ uint32 *session_id)
{
SilcClientFtpSession session;
SilcBuffer keyagr, ftp;
char *filename, *path;
+ int fd;
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) &&
+ 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->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;
+ session->port = 0;
+ } 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));
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
session->listener = silc_net_create_server(0, session->hostname);
if (session->listener < 0) {
SILC_LOG_DEBUG(("Could not create listener"));
+ 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);
}
/* 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
silc_dlist_add(conn->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);