Howto implement SFTP with Qt/QNetworkAccessManager (C++) - c++

I'm new to Qt and I would like to implement FTP and SFTP support for my software.
As I googled I discovered that there doesn't exist a sftp library for Qt but it should be possible with QNetworkAccessManager.
I tried then to discover on how to build a custom protocol or something like that but didn't figure out how to do it.
Does someone know how I could do that?
Thanks,
Michael

There is no support for SFTP in Qt SDK but Qt Creator implements SFTP.
I have isolated the library that contains SSH and SFTP and I have created a new project named QSsh in Github. The aim of the project is to provide SSH and SFTP support for any Qt Application.
I have written an example on how to upload a file using SFTP. Take a look at examples/SecureUploader/
I hope it might be helpful

You need a custom implementation for each protocol. But we can create a class like QHttp which will do that. There are several protocols that has similar semantic, but not all. So, if you want write it, tell me and I help you.

There's no current SSH wrapper implementation in the Qt SDK. You have 3 choices here:
Roll your own custom SSH/SFTP client implementation using the IETF RFC and standard drafts like RFC4253. This might not be what you're looking for.
Use any of the ssh implementation libraries like openssh/libssh directly or writing your own Qt/C++ wrapper for future-reuse. Any reasonably decent project with ssh needs usually links to a an already established ssh library and uses it programatically. Like Qt Creator does, if you dig inside it long enough you'll find what user Paglian mentioned earlier. Relying on a library is less risky and more future-proof then rolling your own.
Use openssh tooling at the command line interface directly, using QProcess just like you'd use it at the shell. This is is the fastest method if you're working on a proof-of-concept project and don't need any complex ftp operations, as it might get a bit difficult to devise a robust wrapper around the CLI tooling.

I do this using libssh. Very straight forward.
https://api.libssh.org/stable/libssh_tutor_sftp.html
Don't forget to add your sftp server into known hosts in your system.
ssh-keyscan -H mysftpserver.com >> ~/.ssh/known_hosts
Example code:
#include "sftpuploader.h"
#include <QtDebug>
#include <QFileInfo>
#include <libssh/libssh.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <libssh/sftp.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <QFile>
int verify_knownhost(ssh_session session)
{
int state, hlen;
unsigned char *hash = NULL;
char *hexa;
char buf[10];
state = ssh_is_server_known(session);
hlen = ssh_get_pubkey_hash(session, &hash);
if (hlen < 0)
return -1;
switch (state)
{
case SSH_SERVER_KNOWN_OK:
break; /* ok */
case SSH_SERVER_KNOWN_CHANGED:
fprintf(stderr, "Host key for server changed: it is now:\n");
ssh_print_hexa("Public key hash", hash, hlen);
fprintf(stderr, "For security reasons, connection will be stopped\n");
free(hash);
return -1;
case SSH_SERVER_FOUND_OTHER:
fprintf(stderr, "The host key for this server was not found but an other"
"type of key exists.\n");
fprintf(stderr, "An attacker might change the default server key to"
"confuse your client into thinking the key does not exist\n");
free(hash);
return -1;
case SSH_SERVER_FILE_NOT_FOUND:
fprintf(stderr, "Could not find known host file.\n");
fprintf(stderr, "If you accept the host key here, the file will be"
"automatically created.\n");
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
case SSH_SERVER_NOT_KNOWN:
hexa = ssh_get_hexa(hash, hlen);
fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
fprintf(stderr, "Public key hash: %s\n", hexa);
free(hexa);
if (fgets(buf, sizeof(buf), stdin) == NULL)
{
free(hash);
return -1;
}
if (strncasecmp(buf, "yes", 3) != 0)
{
free(hash);
return -1;
}
if (ssh_write_knownhost(session) < 0)
{
fprintf(stderr, "Error %s\n", strerror(errno));
free(hash);
return -1;
}
break;
case SSH_SERVER_ERROR:
fprintf(stderr, "Error %s", ssh_get_error(session));
free(hash);
return -1;
}
free(hash);
return 0;
}
bool upload(const QString &localFile,
const QString &dest,
const QString &host,
const QString &username,
const QString &passwd)
{
bool retVal = false;
QFileInfo info(localFile);
m_localFilename = info.canonicalFilePath();
m_remoteFilename = dest + "/" + info.fileName();
int verbosity = SSH_LOG_PROTOCOL;
int port = 22;
int rc;
sftp_session sftp;
sftp_file file;
int access_type;
int nwritten;
QByteArray dataToWrite;
ssh_session my_ssh_session;
QFile myfile(m_localFilename);
if(!myfile.exists())
{
qDebug() << "SFTPUploader: File doesn't exist " << m_localFilename;
return retVal;
}
my_ssh_session = ssh_new();
if(my_ssh_session == NULL)
{
return retVal;
}
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host.toUtf8());
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
qDebug() << "SFTPUploader: Error connecting to localhost: " << ssh_get_error(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
else
{
qDebug() << "SFTPUploader: SSH connected";
}
// Verify the server's identity
// For the source code of verify_knowhost(), check previous example
if (verify_knownhost(my_ssh_session) < 0)
{
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
qDebug() << "SFTPUploader: verify_knownhost failed";
return retVal;
}
rc = ssh_userauth_password(my_ssh_session, username.toUtf8(), passwd.toUtf8());
if (rc != SSH_AUTH_SUCCESS)
{
qDebug() << "SFTPUploader: Error authenticating with password: " << ssh_get_error(my_ssh_session);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
else
{
qDebug() << "SFTPUploader: Authentication sucess";
}
sftp = sftp_new(my_ssh_session);
if (sftp == NULL)
{
qDebug() << "SFTPUploader: Error allocating SFTP session:" << ssh_get_error(my_ssh_session);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
qDebug() << "SFTPUploader: Error initializing SFTP session:", sftp_get_error(sftp);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
access_type = O_WRONLY | O_CREAT | O_TRUNC;
file = sftp_open(sftp, dest.toUtf8(), access_type, S_IRWXU);
if (file == NULL)
{
qDebug() << "SFTPUploader: Can't open file for writing:", ssh_get_error(my_ssh_session);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
if(myfile.open(QFile::ReadOnly))
{
dataToWrite = myfile.readAll();
}
nwritten = sftp_write(file, dataToWrite, dataToWrite.size());
if (nwritten != dataToWrite.size())
{
qDebug() << "SFTPUploader: Can't write data to file: ", ssh_get_error(my_ssh_session);
sftp_close(file);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
rc = sftp_close(file);
if (rc != SSH_OK)
{
qDebug() << "SFTPUploader: Can't close the written file:" << ssh_get_error(my_ssh_session);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
}
else
{
qDebug() << "SFTPUploader: Success";
retVal = true;
}
return retVal;
}

Related

SSH connection through C++ libssh refuses to connect

I am trying to create a simplified SSH connection between client and server with libssh library in C++. My code is as displayed below:
ssh_session session;
session = ssh_new();
if(session == NULL) {
cout << "Session cannot be created. Exiting.." << endl;
exit(EXIT_FAILURE);
}
int verbosity = SSH_LOG_FUNCTIONS;
ssh_options_set(session, SSH_OPTIONS_HOST, "127.0.0.1");
ssh_options_set(session, SSH_OPTIONS_PORT, "22");
ssh_options_set(session, SSH_OPTIONS_USER, "box")
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
int rc;
// ---- This is where it starts
rc = ssh_connect(session); // <--- CONNECTION IS CREATED, but THEN IT IS REFUSED BY SERVER!
if(rc != SSH_OK) {
cout << "rc != SSH_OK" << endl; // <--- GETS PRINTED AFTER REFUSAL OF CONNECTION
exit(EXIT_FAILURE); // <--- CODE EXITS HERE!
}
enum ssh_known_hosts_e state;
unsigned char *hash = NULL;
ssh_key srvpubkey = NULL;
size_t hashlen;
rc = ssh_get_server_publickey(session, &srvpubkey);
if(rc < 0) {
return -1;
}
rc = ssh_get_publickey_hash(srvpubkey, SSH_PUBLICKEY_HASH_SHA256, &hash, &hashlen);
ssh_key_free(srvpubkey);
if(rc < 0) {
cout << "Public Key Hash #ERROR" << endl;
return -1;
}
switch(state) {
case SSH_KNOWN_HOSTS_OK: {
// ok, no problem!
cout << "All good!" << endl;
break;
}
case SSH_KNOWN_HOSTS_CHANGED: {
ssh_clean_pubkey_hash(&hash);
cout << "Hash: " << hash << endl << "Length: " << hashlen << endl;
return -1;
}
case SSH_KNOWN_HOSTS_OTHER: {
ssh_clean_pubkey_hash(&hash);
return -1;
}
case SSH_KNOWN_HOSTS_NOT_FOUND: {
ssh_clean_pubkey_hash(&hash);
return -1;
}
case SSH_KNOWN_HOSTS_UNKNOWN: {
ssh_clean_pubkey_hash(&hash);
return -1;
}
case SSH_KNOWN_HOSTS_ERROR: {
ssh_clean_pubkey_hash(&hash);
return -1;
}
default: {
ssh_clean_pubkey_hash(&hash);
return -1;
}
}
ssh_clean_pubkey_hash(&hash);
ssh_disconnect(session);
ssh_free(session);
When executing this code, I am greeted with Connection Refused error. Please note that my SSH server is up and running, when I attempt to connect through my command terminal it is working OK. I am able to connect and do all I need, however when executed through this code; as previously stated, the connection is being refused. Any tips, hints or assistance is greatly appreciated.
PS. I've enabled maximum verbosity to learn more about the error but what I said is all that was provided. It gave no further information when debugging.
This has been solved. Thanks to tcpdump I was able to learn that the connection was being made to a different port. What immediately came to my attention then is to check how the port was being set and the mistake was right here:
ssh_options_set(session, SSH_OPTIONS_PORT, "22");
Fix:
int port = 22;
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
Because SSH_OPTIONS_PORT takes reference.

How to get OpenSSL BIO_do_connect() failure reason?

I'm using Ubuntu 18.04/gcc 7.3/OpenSSL 1.1.0g to make C++ app performing TLS/SSL connection with non-blocking BIO API.
When BIO_do_connect() fails connecting, e.g. if using wrong host name or port, there is no errors reported by OpenSSL. ERR_get_error() returns zero and ERR_print_errors_xx() doesn't print anything.
So the question is - how to get actual connection failure reason, e.g. 'Connection refused' or 'Host not resolved' etc?
Used code snippet below:
#include <cstdio>
#include <cstring>
#include <iostream>
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/ssl.h"
int main(int argc, char *argv[])
{
OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, nullptr);
std::cout << OpenSSL_version(OPENSSL_VERSION) << std::endl;
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
if (!ctx)
{
std::cerr << "Error creating SSL context:" << std::endl;
ERR_print_errors_fp(stderr);
return 1;
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
if(!SSL_CTX_load_verify_locations(ctx,
"/etc/ssl/certs/ca-certificates.crt",
nullptr))
{
std::cerr << "Error loading trust store into SSL context" << std::endl;
ERR_print_errors_fp(stderr);
return 1;
}
BIO* cbio = BIO_new_ssl_connect(ctx);
SSL* ssl = nullptr;
BIO_get_ssl(cbio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(cbio, "not_actually_existing_host.com:https");
BIO_set_nbio(cbio, 1);
std::cout << "Start connecting" << std::endl;
next:
if (BIO_do_connect(cbio) <= 0)
{
if (!BIO_should_retry(cbio))
{
std::cerr << "Error attempting to connect:" << std::endl;
ERR_print_errors_fp(stderr); // <---- PRINTS NOTHING!!!
BIO_free_all(cbio);
SSL_CTX_free(ctx);
return 1;
}
else goto next;
}
std::cout << "Connected OK" << std::endl;
BIO_free_all(cbio);
SSL_CTX_free(ctx);
return 0;
}
This approach finally works for me:
const auto sysErrorCode = errno;
const auto sslErrorCode = ERR_get_error();
std::string errorDescription;
if (sslErrorCode != 0) errorDescription = ERR_error_string(sslErrorCode, nullptr);
if (sysErrorCode != 0)
{
if (!errorDescription.empty()) errorDescription += '\n';
errorDescription += "System error, code=" + std::to_string(sysErrorCode);
errorDescription += ", ";
errorDescription += strerror(sysErrorCode);
}

Having Errors While Trying to Open a SQLite3 Database

I'm working in Visual Studio Community 2017, and what I'm trying to do is open and read the information of a database in C++.
#include <stdio.h>
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
#include "C:\Users\santiago.corso\Desktop\sqlite-amalgamation-3240000 (1)\sqlite-amalgamation-3240000\sqlite3.h"
bool find_employee(int _id)
{
bool found = false;
sqlite3* db;
sqlite3_stmt* stmt;
stringstream ss;
// create sql statement string
// if _id is not 0, search for id, otherwise print all IDs
if (_id) { ss << "select * from employees where id = " << _id << ";"; }
else { ss << "select * from employees;"; }
string sql(ss.str());
//the resulting sql statement
printf("sql: %s\n", sql.c_str());
//get link to database object
if (sqlite3_open("C:\ProgramData\PROISER\ISASPSUS\datastore\dsfile.db", &db) != SQLITE_OK) {
printf("ERROR: can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return found;
}
// compile sql statement to binary
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL) != SQLITE_OK) {
printf("ERROR: while compiling sql: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
sqlite3_finalize(stmt);
return found;
}
// execute sql statement, and while there are rows returned, print ID
int ret_code = 0;
while ((ret_code = sqlite3_step(stmt)) == SQLITE_ROW) {
printf("TEST: ID = %d\n", sqlite3_column_int(stmt, 0));
found = true;
}
if (ret_code != SQLITE_DONE) {
//this error handling could be done better, but it works
printf("ERROR: while performing sql: %s\n", sqlite3_errmsg(db));
printf("ret_code = %d\n", ret_code);
}
printf("entry %s\n", found ? "found" : "not found");
//release resources
sqlite3_finalize(stmt);
sqlite3_close(db);
return found;
}
The errors that are being returned are from the category Compiler Error C4129.
I cant reach a solution. If you could help me I would appreciate it.
I could correct above mistake by puting "\\" in all the parts of the path in sqlite3_open. Beside that, another error poped up about a entry point that must be defined, refering to
if (sqlite3_open("C:\ProgramData\PROISER\ISASPSUS\datastore\dsfile.db", &db) != SQLITE_OK) {
printf("ERROR: can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return found;`
Also what i want to know is if with this piece of code is enough for opening and reading the database. Im starting with sqlite3 and what i want to do next is exporting its content to an excel file.
Someone recommend me using the exact app for the cause that is native to sqlite3 and is like a cmd.However, i would rather build a script for this purpose instead of using a cmd.

Is QLocalSocket really used for namedpipes

According to th Qt documentation if we want to use named pipes on windows, we can use QLocalSocket.
I am writing a server and client program with Qt. If I try to use the WIN32 API to write some message in the pipe line, the Qt client does not show it. Also, if the client writes by using the WIN32 API again, the Qt server does not echo the message sent. Is QLocalSocket really recommended for named pipes?
This is the Win32 Server code
wcout << "Creating an instance of a named pipe..." << endl;
// Create a pipe to send data
HANDLE pipe = CreateNamedPipeW(
L"\\\\.\\pipe\\ServicePipe", // name of the pipe
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
PIPE_TYPE_BYTE, // send data as a byte stream
100, // only allow 1 instance of this pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE) {
wcout << "Failed to create outbound pipe instance.";
// look up error code here using GetLastError()
system("pause");
return 1;
}
wcout << "Waiting for a client to connect to the pipe..." << endl;
// This call blocks until a client process connects to the pipe
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result) {
wcout << "Failed to make connection on named pipe." << endl;
// look up error code here using GetLastError()
CloseHandle(pipe); // close the pipe
system("pause");
return 1;
}
wcout << "Sending data to pipe..." << endl;
// This call blocks until a client process reads all the data
wcout <<endl<<"Input your message: ";
wstring data=L"";
getline(wcin,data);
DWORD numBytesWritten = 0;
result = WriteFile(
pipe, // handle to our outbound pipe
data.c_str(), // data to send
wcslen(data.c_str()) * sizeof(wchar_t), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
);
if (result) {
wcout << "Number of bytes sent: " << numBytesWritten << endl;
} else {
wcout << "Failed to send data." << endl;
// look up error code here using GetLastError()
}
// Close the pipe (automatically disconnects client too)
CloseHandle(pipe);
wcout << "Done." << endl;
This is the Win32 Client side:
wcout << "Connecting to pipe..." << endl;
// Open the named pipe
// Most of these parameters aren't very relevant for pipes.
HANDLE pipe = CreateFileW(
L"\\\\.\\pipe\\ServicePipe",
GENERIC_READ, // only need read access
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (pipe == INVALID_HANDLE_VALUE) {
wcout << "Failed to connect to pipe." << endl;
// look up error code here using GetLastError()
system("pause");
return 1;
}
wcout << "Reading data from pipe..." << endl;
// The read operation will block until there is data to read
wchar_t buffer[128];
DWORD numBytesRead = 0;
BOOL result = ReadFile(
pipe,
buffer, // the data from the pipe will be put here
127 * sizeof(wchar_t), // number of bytes allocated
&numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);
if (result) {
buffer[numBytesRead / sizeof(wchar_t)] = '?'; // null terminate the string
wcout << "Number of bytes read: " << numBytesRead << endl;
wcout << "Message: " << buffer << endl;
} else {
wcout << "Failed to read data from the pipe." << endl;
}
// Close our pipe handle
CloseHandle(pipe);
wcout << "Done." << endl;
This is the Qt Server side
LocalSocketIpcServer::LocalSocketIpcServer(QString servername, QObject *parent)
:QObject(parent) {
m_server = new QLocalServer(this);
if (!m_server->listen(servername)) {
showMessage("Not able to start the Server");
}
connect(m_server, SIGNAL(newConnection()), this, SLOT(socket_new_connection()));
}
LocalSocketIpcServer::~LocalSocketIpcServer() {
}
void LocalSocketIpcServer::socket_new_connection() {
QLocalSocket *clientConnection = m_server->nextPendingConnection();
while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
clientConnection->waitForReadyRead();
//connect(clientConnection,SIGNAL(readyRead()),clientConnection,SLOT(rea));
connect(clientConnection, SIGNAL(disconnected()),clientConnection, SLOT(deleteLater()));
QDataStream in(clientConnection);
in.setVersion(QDataStream::Qt_5_1);
if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
return;
}
QString message;
in >> message;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
QString msg=+"Message recieved with content "+message+"\n";
out.setVersion(QDataStream::Qt_5_1);
out <<msg;
out.device()->seek(0);
clientConnection->write(block);
clientConnection->flush();
clientConnection->disconnectFromServer();
emit messageReceived(message);
}
void LocalSocketIpcServer::showMessage(QString msg)
{
QMessageBox m;
m.setText(msg);
m.exec();
}
LocalSocketIpcServer::FrmMain(QWidget *parent) :QMainWindow(parent),ui(new Ui::FrmMain)
{
ui->setupUi(this);
m_server = new LocalSocketIpcServer("\\\\.\\pipe\ServicePipe", this);
connect(m_server, SIGNAL(messageReceived(QString)), this, SLOT(messageReceived(QString)));
}
LocalSocketIpcServer::~FrmMain()
{
delete ui;
}
void LocalSocketIpcServer::messageReceived(QString message)
{
ui->textBrowser->append(message+"\n");
}
This is the Qt Client side
LocalSocketIpcClient::LocalSocketIpcClient(QString remoteServername, QObject *parent) :
QObject(parent) {
m_socket = new QLocalSocket(this);
m_serverName = remoteServername;
connect(m_socket, SIGNAL(connected()), this, SLOT(socket_connected()));
connect(m_socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
connect(m_socket, SIGNAL(readyRead()), this, SLOT(socket_readReady()));
connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)),
this, SLOT(socket_error(QLocalSocket::LocalSocketError)));
}
LocalSocketIpcClient::~LocalSocketIpcClient() {
m_socket->abort();
delete m_socket;
m_socket = NULL;
}
QString LocalSocketIpcClient::Read()
{
QDataStream in(this->m_socket);
in.setVersion(QDataStream::Qt_5_1);
if (m_socket->bytesAvailable() < (int)sizeof(quint16)) {
return "No data available";
}
QString message;
in >> message;
return message;
}
void LocalSocketIpcClient::send_MessageToServer(QString message) {
m_socket->abort();
m_message = message;
m_socket->connectToServer(m_serverName,QIODevice::ReadWrite);
}
void LocalSocketIpcClient::socket_connected(){
QByteArray block;
QDataStream out(&block, QIODevice::ReadWrite);
out.setVersion(QDataStream::Qt_5_1);
out << m_message;
out.device()->seek(0);
m_socket->write(block);
m_socket->flush();
}
void LocalSocketIpcClient::socket_disconnected() {
//showMessage("Client socket_disconnected");
}
void LocalSocketIpcClient::socket_readReady() {
//showMessage("Client socket read Ready");
QDataStream in(this->m_socket);
in.setVersion(QDataStream::Qt_5_1);
if (m_socket->bytesAvailable() < (int)sizeof(quint16)) {
return;
}
QString message;
in >> message;
emit RecievedDataFromServer(message);
}
void LocalSocketIpcClient::socket_error(QLocalSocket::LocalSocketError e) {
/*
QString errorMessage="Client socket_error:";
switch (e) {
case QLocalSocket::ConnectionRefusedError:
errorMessage+="The connection was refused by the peer (or timed out).";
break;
case QLocalSocket::PeerClosedError:
errorMessage+="The remote socket closed the connection. Note that the client socket (i.e., this socket) will be closed after the remote close notification has been sent.";
break;
case QLocalSocket::ServerNotFoundError:
errorMessage+="The local socket name was not found.";
break;
case QLocalSocket::SocketAccessError:
errorMessage+="The socket operation failed because the application lacked the required privileges.";
break;
case QLocalSocket::SocketResourceError:
errorMessage+="The local system ran out of resources (e.g., too many sockets).";
break;
case QLocalSocket::SocketTimeoutError:
errorMessage+="The socket operation timed out.";
break;
case QLocalSocket::DatagramTooLargeError:
errorMessage+="The datagram was larger than the operating system's limit (which can be as low as 8192 bytes).";
break;
case QLocalSocket::ConnectionError:
errorMessage+="An error occurred with the connection.";
break;
case QLocalSocket::UnsupportedSocketOperationError:
errorMessage+="The requested socket operation is not supported by the local operating system.";
break;
case QLocalSocket::UnknownSocketError:
errorMessage+="An unidentified error occurred.";
break;
default:
break;
}
showMessage(errorMessage);
*/
}
void LocalSocketIpcClient::showMessage(QString msg)
{
QMessageBox m;
m.setText(msg);
m.exec();
}
LocalSocketIpcClient::SingleMessageSend(QWidget *parent) :
QDialog(parent),
ui(new Ui::SingleMessageSend)
{
ui->setupUi(this);
client = new LocalSocketIpcClient("\\\\.\\pipe\ServicePipe", this);
connect(this->client,SIGNAL(RecievedDataFromServer(QString)),this,SLOT(UpdateGUI(QString)));
}
LocalSocketIpcClient::~SingleMessageSend()
{
delete ui;
}
void SingleMessageSend::on_pushButton_clicked()
{
QString msg=this->ui->lineEdit->text().trimmed();
client->send_MessageToServer(msg);
}
void SingleMessageSend::UpdateGUI(QString message)
{
ui->textEdit->insertPlainText(message+"\n");
}
void SingleMessageSend::on_pushButton_2_clicked()
{
ui->textEdit->insertPlainText(client->Read()+QString("\n"));
}
Without going through all of your code, I can answer this in the affirmative. Here is some code from a working app that writes from a Qt app to a named pipe in another Qt app (it restores another app which is minimized):
QLocalSocket ls;
ls.connectToServer("Restore Server", QIODevice::WriteOnly);
if (!ls.waitForConnected(5000))
{
qDebug(ls.errorString().toUtf8());
return false;
}
ls.write("raise");
if (!ls.waitForBytesWritten(5000))
{
qDebug(ls.errorString().toUtf8());
return false;
}
ls.disconnectFromServer();
The app to be restored sets things up thus:
localServer = new QLocalServer(this);
connect(localServer, SIGNAL(newConnection()), this,
SLOT(messageFromOtherInstance()));
localServer->listen("Restore Server");
When it comes time to read the message, I do it like this:
QLocalSocket *localSocket = localServer->nextPendingConnection();
if (!localSocket->waitForReadyRead(5000))
{
qDebug(localSocket->errorString().toLatin1());
return;
}
QByteArray byteArray = localSocket->readAll();
QString message = QString::fromUtf8(byteArray.constData());
if (message == "raise")
bringToTop(this);
It may well be that Qt named pipes and M$ named pipes are somehow incompatible. I suggest writing a M$ framework app to write to the M$ framework client, and a M$ framework app to read, to make sure they are both working right. Then, substitute a Qt app to read from the Qt server. If that doesn't work, it is some sort of framework incompatibility (although I expect they both interact with the OS properly). One thing to be sure of in situations like this is to make sure the processes don't block. That's why e.g. I make sure the read is ready before I read it. You might also have to flush the pipe after writing on the M$ side, although I didn't with Qt.
(Note that I have since found out that if a Print, Print Preview, Page Setup or browse for file dialog is open, it stops the Qt message loop, and the app will be unresponsive to messages like this. The Choose Font dialog, OTOH, doesn't block the parent app. Go figure.)

Upload Directory

How can I upload a directory using the FtpPutFile function or all the directory this is my code:
void FileSubmit(path ToUpload)
{
HINTERNET hInternet;
HINTERNET hFtpSession;
hInternet = InternetOpen(NULL,INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
if (hInternet == NULL) cout << ("No Internet Connection..\n");
else cout << ("Internet Connection Established\n");
hFtpSession = InternetConnect(hInternet,"host",INTERNET_DEFAULT_FTP_PORT, "user","pass", INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE,0 );
if (!hFtpSession) cout << ("Error in the FTP connection..\n");
else
{
cout <<("FTP Connection Established!\n");
FtpPutFile(hFtpSession, "D://test//*.doc", ToUpload.string().c_str(), FTP_TRANSFER_TYPE_ASCII, INTERNET_FLAG_PASSIVE);
if (!FtpPutFile(hFtpSession, "D://test//*.doc", ToUpload.string().c_str(), FTP_TRANSFER_TYPE_ASCII, INTERNET_FLAG_PASSIVE))
cout <<("File Transfer Failed..\n");
else cout << ("The file was sent..\n");
InternetCloseHandle(hFtpSession);
InternetCloseHandle(hInternet);
}
}
int main()
{
FileSubmit(destination);
return 0;
}
You can't 'upload' directories directly; you would need to create the directory with FtpCreateDirectory() then iterate over all the files in your local directory and call FtpPutFile() on each of them.
If you need a way of getting a list of files in a directory you can use Boost.Filesystem. Look for the directory_iterator and recursive_directory_iterator classes.