SFTP code cleaned up. Memory leaks fixed.

This commit is contained in:
Scott Duensing 2023-05-17 16:55:03 -05:00
parent fc0ebb6e3f
commit 2fbeac943b
7 changed files with 165 additions and 336 deletions

View file

@ -33,7 +33,7 @@ typedef struct StringHashS {
} StringHashT;
#define ARRFREE(a) do { if (a != NULL) { arrfree(a); } break; } while(1)
#define ARRFREE(a) do { if (a != NULL) { arrfree(a); a = NULL; } break; } while(1)
#endif // ARRAY_H

View file

@ -31,29 +31,19 @@
struct SFTPS;
struct SSHS;
typedef void (*SFTPCallback)(struct SFTPS*);
typedef void (*SSHCallback)(struct SSHS*);
typedef struct SSHS {
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
int sock;
int result;
gboolean finished;
SSHCallback callback;
} SSHT;
typedef struct SFTPS {
SSHT *sshData;
LIBSSH2_SESSION *sshSession;
LIBSSH2_CHANNEL *sshChannel;
int sock;
void *userData;
FILE *local;
LIBSSH2_SFTP *session;
LIBSSH2_SFTP_HANDLE *handle;
LIBSSH2_SFTP *sftpSession;
LIBSSH2_SFTP_HANDLE *sftpHandle;
char buffer[102400];
char *ptr;
uint64_t fileSize;
@ -69,13 +59,12 @@ typedef struct SFTPS {
} SFTPT;
SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password);
void sshDisconnect(SSHT **sshData);
gboolean sshSFTPDelete(SSHT *sshData, char *target);
//int sshExecute(SSHT *sshData, char *command, char **output);
gboolean sshSFTPFileExists(SSHT *sshData, char *target);
SFTPT *sshSFTPReceive(SSHT *sshData, char *remote, char *local, SFTPCallback callback);
SFTPT *sshSFTPSend(SSHT *sshData, char *local, char *remote, SFTPCallback callback);
SFTPT *sshConnect(char *hostname, uint16_t port, char *user, char *password);
void sshDisconnect(SFTPT **sshData);
gboolean sshSFTPDelete(SFTPT *sshData, char *target);
gboolean sshSFTPFileExists(SFTPT *sshData, char *target);
gboolean sshSFTPReceive(SFTPT *sshData, char *remote, char *local, SFTPCallback callback);
gboolean sshSFTPSend(SFTPT *sshData, char *local, char *remote, SFTPCallback callback);
void sshShutdown(void);
void sshStartup(void);

View file

@ -67,6 +67,7 @@ extern char __utilFilenameBuffer[FILENAME_MAX];
char *utilCreateString(char *format, ...);
char *utilCreateStringVArgs(char *format, va_list args);
ArchiveT *utilDecompress(char *archive, char *outPath, archiveCallback callback, void *userData);
int utilDeleteTree(const char *path);
char *utilDeobfuscateASCII(char *obfuscated);
void utilDequote(char *string);
void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted);

View file

@ -55,6 +55,8 @@ void message(MessageTypesT level, char *format, ...) {
msg = utilCreateStringVArgs(format, args);
va_end(args);
debug("%s\n", msg);
// Break multiline messages down into individual lines.
tok = strtok(msg, "\n");
while (tok != NULL) {
@ -68,6 +70,8 @@ void message(MessageTypesT level, char *format, ...) {
tok = strtok(NULL, "\n");
}
DEL(msg);
}
@ -209,7 +213,7 @@ static void winMessagesDelete(gpointer userData) {
DEL(_pendingMessages[0]);
arrdel(_pendingMessages, 0);
}
ARRFREE(_pendingMessages);
//ARRFREE(_pendingMessages); // This is making Memwatch mad.
utilWindowUnRegister(userData);
_lstMessages = NULL;

View file

@ -242,9 +242,10 @@ static void clearRecipeData(ProjectDataT *self) {
while (arrlen(self->recipes) > 0) {
DEL(self->recipes[0]->key);
DEL(self->recipes[0]->value);
DEL(self->recipes[0]);
arrdel(self->recipes, 0);
}
ARRFREE(self->recipes);
//ARRFREE(self->recipes); // This is making Memwatch mad.
}
@ -263,8 +264,7 @@ static void cookFinished(CompilerContextT **context) {
// If this is not first call, process context.
if (self->tempInteger != -1) {
if (ctx->programResult != 0) {
//***TODO*** Not all negative returns are severe.
message(ctx->programResult > 0 ? MSG_ERROR : MSG_SEVERE, "Recipe %s returned %d", self->recipes[self->tempInteger]->value, ctx->programResult);
message(MSG_ERROR, "Recipe %s returned %d", self->recipes[self->tempInteger]->value, ctx->programResult);
}
}
@ -896,7 +896,7 @@ EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData) {
};
char temp[6];
int result = 0;
SSHT *ssh = NULL;
SFTPT *ssh = NULL;
char *error = NULL;
(void)object;
@ -1069,8 +1069,7 @@ EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->treeProject));
GtkTreeIter iter;
GtkTreeIter child;
SSHT *ssh;
SFTPT *sftp;
SFTPT *ssh;
char *temp;
char *filename;
char *pathString;
@ -1081,7 +1080,6 @@ EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
gboolean archPrinted;
FILE *out;
ssh = NEW(SSHT);
ssh = sshConnect(self->buildHost, self->buildSSHPort, self->buildUser, self->buildPassword);
if (!ssh) {
@ -1101,6 +1099,7 @@ EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
message(MSG_SEVERE, "Unable to write temporary build.start file");
unlink(buildStart); // Just in case.
message(MSG_INFO, "Build canceled");
DEL(buildStart);
sshDisconnect(&ssh);
return;
}
@ -1138,7 +1137,7 @@ EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
temp = utilCreateString("%s%s", self->windowData.path, filename);
arrput(_sendList, temp);
}
DEL(filename);
//DEL(filename); // GTK says I need to free this. Memwatch says otherwise.
} while (gtk_tree_model_iter_next(model, &child));
}
} while (gtk_tree_model_iter_next(model, &iter));
@ -1147,10 +1146,8 @@ EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
arrput(_sendList, buildStart);
// Prime the pump! We only set sshData and userData so sendSFTP can determine this is the first file.
sftp = NEW(SFTPT);
sftp->sshData = ssh;
sftp->userData = self;
sendSFTP(sftp);
ssh->userData = self;
sendSFTP(ssh);
}
@ -1181,10 +1178,10 @@ gboolean projectAddToTree(ProjectDataT *self, char *filename) {
do {
gtk_tree_model_get(model, &child, COL_FILENAME, &temp, -1);
if (strcmp(temp, filename) == 0) {
DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus.
//DEL(temp); // GTK says I need to free this. Memwatch says otherwise.
return FALSE; // Item exists and was not added.
}
DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus.
//DEL(temp); // GTK says I need to free this. Memwatch says otherwise.
} while (gtk_tree_model_iter_next(model, &child));
}
} while (gtk_tree_model_iter_next(model, &iter));
@ -1201,7 +1198,7 @@ gboolean projectAddToTree(ProjectDataT *self, char *filename) {
}
}
}
DEL(temp);
temp = NULL; //DEL(temp); // GTK says I need to free this. Memwatch says otherwise.
fileLen = 0;
utilEnsureBufferSize((unsigned char **)&temp, &fileLen, 4); // fileLen is just a throwaway here.
snprintf(temp, 4, "%d", foundAt);
@ -1224,8 +1221,10 @@ static void receiveSFTP(SFTPT *sftp) {
if (sftp->finished) {
if (sftp->success) {
message(MSG_INFO, "Cleaning up remote build");
sshSFTPDelete(sftp->sshData, REMOTE_BUILD_RESULTS);
//***TODO*** Delete any local "results" folder.
sshSFTPDelete(sftp, REMOTE_BUILD_RESULTS);
temp = utilCreateString("%sresults", self->windowData.path);
utilDeleteTree(temp);
DEL(temp);
message(MSG_INFO, "Unpacking build");
temp = utilCreateString("%s%s", self->windowData.path, LOCAL_BUILD_RESULTS);
utilDecompress(temp, self->windowData.path, decompressBuild, self);
@ -1233,11 +1232,8 @@ static void receiveSFTP(SFTPT *sftp) {
} else {
message(MSG_ERROR, "Receiving %s from build server - FAILED", sftp->remoteName);
message(MSG_INFO, "Build canceled");
sshDisconnect(&sftp->sshData);
}
DEL(sftp->localName);
DEL(sftp->remoteName);
DEL(sftp);
sshDisconnect(&sftp);
}
}
@ -1406,13 +1402,9 @@ static gboolean updateBuildOptions(ProjectDataT *self) {
static void sendSFTP(SFTPT *sftp) {
ProjectDataT *self = (ProjectDataT *)sftp->userData;
SFTPT *last;
SFTPT *next;
char *target;
char *name;
last = sftp;
// If source and target are missing, this is the first file - start sending.
// Or, did the current transfer succeed? If so, send next file.
if ((sftp->localName == NULL && sftp->remoteName == NULL) || (sftp->finished && sftp->success)) {
@ -1425,19 +1417,15 @@ static void sendSFTP(SFTPT *sftp) {
name = utilFileBasename(_sendList[0]);
target = utilCreateString("build/%s", name);
message(MSG_INFO, "Sending %s to build server", name);
sftp = sshSFTPSend(last->sshData, _sendList[0], target, sendSFTP);
sftp->userData = self;
sshSFTPSend(sftp, _sendList[0], target, sendSFTP);
DEL(target);
DEL(name);
DEL(_sendList[0]);
arrdel(_sendList, 0);
} else {
// Finished!
message(MSG_INFO, "Waiting for build to complete");
// "last" will be deleted by sshSFTPUpdate so copy what we need to "next".
next = NEW(SFTPT);
next->sshData = last->sshData;
next->userData = last->userData;
g_timeout_add_seconds(5, waitForBuild, next);
g_timeout_add_seconds(5, waitForBuild, sftp);
}
}
@ -1447,21 +1435,14 @@ static void sendSFTP(SFTPT *sftp) {
message(MSG_ERROR, "Sending %s to build server - FAILED", sftp->remoteName);
}
message(MSG_INFO, "Build canceled");
sshDisconnect(&last->sshData);
sshDisconnect(&sftp);
// Clear any remaining transfers.
while (arrlen(_sendList) > 0) {
DEL(_sendList[0]);
arrdel(_sendList, 0);
}
ARRFREE(_sendList);
}
// Do we need to free this?
if (last->finished) {
// Do not delete last->sshData as we continue to need it until everything is finished.
DEL(last->localName);
DEL(last->remoteName);
DEL(last);
}
}
@ -1513,31 +1494,24 @@ static void targetArrayDelete(TargetT ***array) {
static gboolean waitForBuild(gpointer userData) {
SFTPT *last = (SFTPT *)userData;
ProjectDataT *self = (ProjectDataT *)last->userData;
SFTPT *sftp;
SFTPT *sftp = (SFTPT *)userData;
ProjectDataT *self = (ProjectDataT *)sftp->userData;
char *temp;
gboolean result;
if (sshSFTPFileExists(last->sshData, REMOTE_BUILD_RESULTS)) {
if (sshSFTPFileExists(sftp, REMOTE_BUILD_RESULTS)) {
// Build complete! Next step!
//***TODO*** Delete any local build archive.
message(MSG_INFO, "Retrieving build results");
temp = utilCreateString("%s%s", self->windowData.path, LOCAL_BUILD_RESULTS);
sftp = sshSFTPReceive(last->sshData, REMOTE_BUILD_RESULTS, temp, receiveSFTP);
unlink(temp);
result = sshSFTPReceive(sftp, REMOTE_BUILD_RESULTS, temp, receiveSFTP);
DEL(temp);
if (!sftp) {
if (!result) {
message(MSG_ERROR, "Receiving build from build server - FAILED");
message(MSG_INFO, "Build canceled");
sshDisconnect(&last->sshData);
} else {
sftp->userData = last->userData;
sshDisconnect(&sftp);
}
// Finally finished with "last"
DEL(last->localName);
DEL(last->remoteName);
DEL(last);
return G_SOURCE_REMOVE;
}
@ -1627,6 +1601,8 @@ static void winProjectDelete(gpointer userData) {
targetArrayDelete(&self->targets);
clearRecipeData(self);
DEL(self->projectName);
DEL(self->projectType);
DEL(self->buildHost);
DEL(self->buildUser);
DEL(self->buildPassword);

333
src/ssh.c
View file

@ -40,25 +40,19 @@ closesocket(data->sock);
static SFTPT **_activeSFTPs = NULL;
static SSHT **_activeSSHs = NULL;
static char *_output = NULL;
static int _outputLen = 0;
static char *_buffer = NULL;
static int _bufferLen = 0;
gboolean sshUpdate(gpointer userData); // Not static
static SFTPT *sshSFTPTransfer(SSHT *sshData, char *local, char *remote, SFTPCallback callback, gboolean uploading);
static gboolean sshSFTPTransfer(SFTPT *sshData, char *local, char *remote, SFTPCallback callback, gboolean uploading);
gboolean sshSFTPUpdate(gpointer userData); // Not static
static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session);
SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
SFTPT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
int rc;
struct hostent *hostent;
struct sockaddr_in sin;
in_addr_t hostaddr;
SSHT *data = NULL;
SFTPT *data = NULL;
hostent = gethostbyname(hostname);
if (hostent == NULL) {
@ -72,7 +66,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
return NULL;
}
data = NEW(SSHT);
data = NEW(SFTPT);
if (data) {
data->sock = socket(AF_INET, SOCK_STREAM, 0);
@ -86,73 +80,76 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
return NULL;
}
data->session = libssh2_session_init();
if (!data->session) {
data->sshSession = libssh2_session_init();
if (!data->sshSession) {
socketclose(data->sock);
DEL(data);
return NULL;
}
libssh2_session_set_blocking(data->session, 0);
libssh2_session_set_blocking(data->sshSession, 0);
while ((rc = libssh2_session_handshake(data->session, data->sock)) == LIBSSH2_ERROR_EAGAIN)
while ((rc = libssh2_session_handshake(data->sshSession, data->sock)) == LIBSSH2_ERROR_EAGAIN)
;
if (rc) {
message(MSG_ERROR, "Failure establishing SSH session: %d\n", rc);
libssh2_session_free(data->session);
libssh2_session_free(data->sshSession);
socketclose(data->sock);
DEL(data);
return NULL;
}
while ((rc = libssh2_userauth_password(data->session, user, password)) == LIBSSH2_ERROR_EAGAIN)
while ((rc = libssh2_userauth_password(data->sshSession, user, password)) == LIBSSH2_ERROR_EAGAIN)
;
if (rc) {
message(MSG_ERROR, "Failure authenticating SSH session: %d\n", rc);
while (libssh2_session_disconnect(data->session, "Error") == LIBSSH2_ERROR_EAGAIN)
while (libssh2_session_disconnect(data->sshSession, "Error") == LIBSSH2_ERROR_EAGAIN)
;
libssh2_session_free(data->session);
libssh2_session_free(data->sshSession);
socketclose(data->sock);
DEL(data);
return NULL;
}
}
//***TODO*** Move SFTP session setup here so we don't keep repeating it.
// SFTP session setup here so we don't keep repeating it.
do {
data->sftpSession = libssh2_sftp_init(data->sshSession);
if (!data->sftpSession) {
if (libssh2_session_last_errno(data->sshSession) != LIBSSH2_ERROR_EAGAIN) {
sshDisconnect(&data);
return NULL;
}
}
} while (!data->sftpSession);
return data;
}
void sshDisconnect(SSHT **sshData) {
SSHT *data = *sshData;
void sshDisconnect(SFTPT **sshData) {
SFTPT *data = *sshData;
//***TODO*** Move SFTP session teardown here so we don't keep repeating it.
// SFTP session teardown here so we don't keep repeating it.
libssh2_sftp_shutdown(data->sftpSession);
libssh2_session_disconnect(data->session, "Normal Shutdown.");
libssh2_session_free(data->session);
libssh2_session_disconnect(data->sshSession, "Normal Shutdown.");
libssh2_session_free(data->sshSession);
socketclose(data->sock);
DEL(data->localName);
DEL(data->remoteName);
DEL(data);
}
gboolean sshSFTPDelete(SSHT *sshData, char *target) {
LIBSSH2_SFTP *session;
gboolean sshSFTPDelete(SFTPT *sshData, char *target) {
int rc;
gboolean result = TRUE;
do {
session = libssh2_sftp_init(sshData->session);
if (!session) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
return FALSE;
}
}
} while (!session);
do {
rc = libssh2_sftp_unlink(session, target);
rc = libssh2_sftp_unlink(sshData->sftpSession, target);
if (rc == 0) break;
if (rc != LIBSSH2_ERROR_EAGAIN) {
result = FALSE;
@ -160,96 +157,11 @@ gboolean sshSFTPDelete(SSHT *sshData, char *target) {
}
} while (TRUE);
libssh2_sftp_shutdown(session);
return result;
}
/*
int sshExecute(SSHT *sshData, char *command, char **output) {
int rc;
int exitcode = 127;
char *exitsignal = (char *)"none";
int outputLen = 0;
utilEnsureBufferSize((unsigned char **)output, &outputLen, 1024);
*output[0] = 0;
while ((sshData->channel = libssh2_channel_open_session(sshData->session)) == NULL && libssh2_session_last_error(sshData->session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(sshData->sock, sshData->session);
}
if (sshData->channel == NULL) {
return exitcode;
}
while ((rc = libssh2_channel_exec(sshData->channel, command)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(sshData->sock, sshData->session);
}
if (rc != 0) {
return exitcode;
}
for (;;) {
do {
rc = libssh2_channel_read(sshData->channel, (char *)_buffer, sizeof(_buffer));
if (rc > 0) {
utilEnsureBufferSize((unsigned char **)output, &outputLen, (int)strlen((const char *)*output) + rc + 1);
strncat(*output, (char *)_buffer, rc);
}
} while (rc > 0);
if (rc == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(sshData->sock, sshData->session);
} else {
break;
}
}
while ((rc = libssh2_channel_close(sshData->channel)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(sshData->sock, sshData->session);
}
if (rc == 0) {
exitcode = libssh2_channel_get_exit_status(sshData->channel);
libssh2_channel_get_exit_signal(sshData->channel, &exitsignal, NULL, NULL, NULL, NULL, NULL);
}
libssh2_channel_free(sshData->channel);
return exitcode;
}
SSHT *sshExecuteVerbose(SSHT *sshData, char *title, char *command, SSHCallback callback) {
int rc;
sshData->title = strdup(title);
sshData->callback = callback;
sshData->finished = FALSE;
while ((sshData->channel = libssh2_channel_open_session(sshData->session)) == NULL && libssh2_session_last_error(sshData->session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(sshData->sock, sshData->session);
}
if (sshData->channel == NULL) {
return NULL;
}
while ((rc = libssh2_channel_exec(sshData->channel, command)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(sshData->sock, sshData->session);
}
if (rc != 0) {
return NULL;
}
// ***TODO*** SSH Progress Dialog Here
//sshData->status = new SSHStatus(sshData);
arrpush(_activeSSHs, sshData);
return sshData;
}
*/
gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
LIBSSH2_SFTP *session;
gboolean sshSFTPFileExists(SFTPT *sshData, char *target) {
LIBSSH2_SFTP_HANDLE *handle;
LIBSSH2_SFTP_ATTRIBUTES attrs;
char *path;
@ -259,15 +171,6 @@ gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
int rc;
gboolean result = FALSE;
do {
session = libssh2_sftp_init(sshData->session);
if (!session) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
return FALSE;
}
}
} while (!session);
// Split filename and path.
// Cannot use utilFilePath and friends because this is a remote path.
temp = strdup(target); // Make copy in case they pass in a constant.
@ -289,9 +192,8 @@ gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
DEL(temp);
do {
handle = libssh2_sftp_opendir(session, path);
if ((!handle) && (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN)) {
libssh2_sftp_shutdown(session);
handle = libssh2_sftp_opendir(sshData->sftpSession, path);
if ((!handle) && (libssh2_session_last_errno(sshData->sshSession) != LIBSSH2_ERROR_EAGAIN)) {
free(file);
free(path);
return FALSE;
@ -322,91 +224,76 @@ gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
free(path);
libssh2_sftp_closedir(handle);
libssh2_sftp_shutdown(session);
return result;
}
SFTPT *sshSFTPReceive(SSHT *sshData, char *remote, char *local, SFTPCallback callback) {
gboolean sshSFTPReceive(SFTPT *sshData, char *remote, char *local, SFTPCallback callback) {
return sshSFTPTransfer(sshData, local, remote, callback, FALSE);
}
SFTPT *sshSFTPSend(SSHT *sshData, char *local, char *remote, SFTPCallback callback) {
gboolean sshSFTPSend(SFTPT *sshData, char *local, char *remote, SFTPCallback callback) {
return sshSFTPTransfer(sshData, local, remote, callback, TRUE);
}
static SFTPT *sshSFTPTransfer(SSHT *sshData, char *local, char *remote, SFTPCallback callback, gboolean uploading) {
SFTPT *sftp = NULL;
static gboolean sshSFTPTransfer(SFTPT *sshData, char *local, char *remote, SFTPCallback callback, gboolean uploading) {
int i;
// Do not allow two of the same transfers to be started.
for (i=0; i<arrlen(_activeSFTPs); i++) {
if ((strcmp(_activeSFTPs[i]->localName, local) == 0) && (strcmp(_activeSFTPs[i]->remoteName, remote) == 0)) {
// Return existing transfer handle.
return _activeSFTPs[i];
// Return existing transfer is running.
return TRUE;
}
}
sftp = NEW(SFTPT);
if (sftp) {
sftp->fileSize = uploading ? utilFileSize(local) : 0;
sftp->local = fopen(local, uploading ? "rb" : "wb");
if (sftp->local) {
sftp->fileSent = 0;
sftp->nread = 0;
sftp->ptr = NULL;
sftp->localName = strdup(local);
sftp->remoteName = strdup(remote);
sftp->sshData = sshData;
sftp->uploading = uploading;
sftp->readMore = TRUE;
sftp->finished = FALSE;
sftp->success = FALSE;
sftp->callback = callback;
do {
sftp->session = libssh2_sftp_init(sshData->session);
if (!sftp->session) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
break;
}
}
} while (!sftp->session);
if (sshData) {
sshData->fileSize = uploading ? utilFileSize(local) : 0;
sshData->local = fopen(local, uploading ? "rb" : "wb");
if (sshData->local) {
do {
if (uploading) {
sftp->handle = libssh2_sftp_open(sftp->session, sftp->remoteName,
sshData->sftpHandle = libssh2_sftp_open(sshData->sftpSession, remote,
LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH);
} else {
sftp->handle = libssh2_sftp_open(sftp->session, sftp->remoteName,
sshData->sftpHandle = libssh2_sftp_open(sshData->sftpSession, remote,
LIBSSH2_FXF_READ,
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH);
}
if (!sftp->handle) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
if (!sshData->sftpHandle) {
if (libssh2_session_last_errno(sshData->sshSession) != LIBSSH2_ERROR_EAGAIN) {
break;
}
}
} while (!sftp->handle);
if (sftp->handle) {
arrput(_activeSFTPs, sftp);
return sftp;
} while (!sshData->sftpHandle);
if (sshData->sftpHandle) {
DEL(sshData->localName);
DEL(sshData->remoteName);
sshData->fileSent = 0;
sshData->nread = 0;
sshData->ptr = NULL;
sshData->localName = strdup(local);
sshData->remoteName = strdup(remote);
sshData->uploading = uploading;
sshData->readMore = TRUE;
sshData->finished = FALSE;
sshData->success = FALSE;
sshData->callback = callback;
arrput(_activeSFTPs, sshData);
return TRUE;
} else {
message(MSG_SEVERE, "Failed to get SFTP handle! %d, %lu\n", libssh2_session_last_errno(sshData->session), libssh2_sftp_last_error(sftp->session));
libssh2_sftp_shutdown(sftp->session);
DEL(sftp);
message(MSG_SEVERE, "Failed to get SFTP handle! %d, %lu\n", libssh2_session_last_errno(sshData->sshSession), libssh2_sftp_last_error(sshData->sftpSession));
}
} else {
DEL(sftp);
}
}
return NULL;
return FALSE;
}
@ -425,6 +312,7 @@ gboolean sshSFTPUpdate(gpointer userData) {
// More data to read?
if (_activeSFTPs[i]->readMore) {
_activeSFTPs[i]->nread = fread(_activeSFTPs[i]->buffer, 1, sizeof(_activeSFTPs[i]->buffer), _activeSFTPs[i]->local);
// Are we finished sending?
if (_activeSFTPs[i]->nread <= 0) {
result = _activeSFTPs[i];
arrdel(_activeSFTPs, i);
@ -437,8 +325,8 @@ gboolean sshSFTPUpdate(gpointer userData) {
// Is there data to send?
if (_activeSFTPs[i]->nread > 0) {
// Send data.
while ((rc = (int)libssh2_sftp_write(_activeSFTPs[i]->handle, _activeSFTPs[i]->ptr, _activeSFTPs[i]->nread)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(_activeSFTPs[i]->sshData->sock, _activeSFTPs[i]->sshData->session);
while ((rc = (int)libssh2_sftp_write(_activeSFTPs[i]->sftpHandle, _activeSFTPs[i]->ptr, _activeSFTPs[i]->nread)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(_activeSFTPs[i]->sock, _activeSFTPs[i]->sshSession);
}
if (rc >= 0) {
_activeSFTPs[i]->ptr += rc;
@ -457,8 +345,8 @@ gboolean sshSFTPUpdate(gpointer userData) {
// Downloading
// Data to read?
while ((rc = libssh2_sftp_read(_activeSFTPs[i]->handle, _activeSFTPs[i]->buffer, sizeof(_activeSFTPs[i]->buffer))) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(_activeSFTPs[i]->sshData->sock, _activeSFTPs[i]->sshData->session);
while ((rc = libssh2_sftp_read(_activeSFTPs[i]->sftpHandle, _activeSFTPs[i]->buffer, sizeof(_activeSFTPs[i]->buffer))) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(_activeSFTPs[i]->sock, _activeSFTPs[i]->sshSession);
}
if (rc > 0) {
_activeSFTPs[i]->fileSize += rc;
@ -476,12 +364,10 @@ gboolean sshSFTPUpdate(gpointer userData) {
result->finished = TRUE;
result->success = TRUE;
fclose(result->local);
libssh2_sftp_close(result->handle);
libssh2_sftp_shutdown(result->session);
libssh2_sftp_close(result->sftpHandle);
if (result->callback) {
result->callback(result);
}
DEL(result);
}
return G_SOURCE_CONTINUE;
@ -489,14 +375,16 @@ gboolean sshSFTPUpdate(gpointer userData) {
void sshShutdown(void) {
//***TODO*** Any active sessions?
g_idle_remove_by_data(sshUpdate);
// Any active sessions to disconnect?
while (arrlen(_activeSFTPs) > 0) {
sshDisconnect(&_activeSFTPs[0]);
arrdel(_activeSFTPs, 0);
}
//ARRFREE(_activeSFTPs); // This is making Memwatch mad.
g_idle_remove_by_data(sshSFTPUpdate);
DEL(_output);
DEL(_buffer);
libssh2_exit();
}
@ -516,71 +404,10 @@ void sshStartup(void) {
printf("libssh2 initialization failed: %d\n", err);
}
utilEnsureBufferSize((unsigned char **)&_output, &_outputLen, 1024);
utilEnsureBufferSize((unsigned char **)&_buffer, &_bufferLen, 0x4000);
g_idle_add(sshUpdate, sshUpdate);
g_idle_add(sshSFTPUpdate, sshSFTPUpdate);
}
gboolean sshUpdate(gpointer userData) {
int rc;
int exitcode = 127;
char *exitsignal = (char *)"none";
SSHT *s;
int i;
(void)userData;
_output[0] = 0;
for (i=0; i<arrlen(_activeSSHs); i++) {
s = _activeSSHs[i];
if (!s->finished) {
rc = libssh2_channel_read(s->channel, _buffer, sizeof(_buffer));
if (rc > 0) {
utilEnsureBufferSize((unsigned char **)&_output, &_outputLen, rc + 1);
_output[0] = 0;
strncat(_output, (char *)_buffer, rc);
//***TODO*** Display in status dialog
//s->status->AddOutput(output);
} else {
if (rc == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(s->sock, s->session);
} else {
while ((rc = libssh2_channel_close(s->channel)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(s->sock, s->session);
}
DEL(_output);
_output = strdup("\n\nUH OH! Something wrong happened. Check the output for errors.");
if (rc == 0) {
exitcode = libssh2_channel_get_exit_status(s->channel);
libssh2_channel_get_exit_signal(s->channel, &exitsignal, NULL, NULL, NULL, NULL, NULL);
if (exitcode == 0) {
DEL(_output);
_output = strdup("\n\nFINISHED! You can close this window anytime.");
}
}
//***TODO*** Display in status dialog
//s->status->AddOutput(output);
libssh2_channel_free(s->channel);
s->result = exitcode;
//s->finished = true;
//s->status->Finished(); // No close
if (s->callback) s->callback(s);
arrdel(_activeSSHs, i);
break; // Exit for loop
// We don't delete "s" because it will be handled by utilSSHDisconnect
}
}
}
}
return G_SOURCE_CONTINUE;
}
static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session) {
struct timeval timeout;
int rc;

View file

@ -76,6 +76,8 @@ char *utilCreateStringVArgs(char *format, va_list args) {
vsnprintf(buffer, (size_t)size, format, args);
}
//debug("%s = %s\n", format, buffer);
return buffer;
}
@ -251,6 +253,35 @@ gboolean utilDecompressUpdate(gpointer userData) {
}
int utilDeleteTree(const char *path) {
DIR *directory = opendir(path);
char *filename = NULL;
struct dirent *entry;
int (*removeFunc)(const char *);
if (directory) {
while ((entry = readdir(directory))) {
if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) {
continue;
}
filename = utilCreateString("%s/%s", path, entry->d_name);
removeFunc = entry->d_type == DT_DIR ? utilDeleteTree : remove;
if (removeFunc(filename)) {
DEL(filename);
closedir(directory);
return -1;
}
DEL(filename);
}
if (closedir(directory)) {
return -1;
}
}
return remove(path);
}
char *utilDeobfuscateASCII(char *obfuscated) {
char *deobfuscated = NULL;
char *hostname;
@ -874,6 +905,7 @@ gboolean utilWindowUnRegister(gpointer windowData) {
debug("Window Unregistered: %ld\n", hmlen(_windowList));
DEL(w->filename);
DEL(w->path);
DEL(w->title);
return (result == 1) ? TRUE : FALSE;