Sometimes, the asio::tcp::socket object gets closed automatically before calling shutdown/close - sockets

Once in 5 times, I get this "Bad file descriptor"error when I am attempting to shutdown or close the asio::ip::tcp::socket object. The following is the function to close the acceptor and socket.
void close_server()
{
acceptor_instance.close(error_code);
if (error_code)
{
std::cerr << "close_server(): acceptor::close()" << "Error: " << error_code.message() << std::endl;
}
if(socket_instance.is_open())
{
socket_instance.shutdown(asio::ip::tcp::socket::shutdown_both, error_code);
if (error_code)
{
std::cerr << "close_server(): socket::close()" << "Error: " << error_code.message() << std::endl;
}
socket_instance.close(error_code);
if (error_code)
{
std::cerr << "close_server(): socket::close()" << "Error: " << error_code.message() << std::endl;
}
}
else
{
std::cerr << "close_server(): socket_instance is already CLOSED" << std::endl;
}
}
Sometimes the socket_intance.is_open() fails. Attempting to call the socket.shutdown() or socket.close() without checking if the socket is open, gives "Bad file descriptor" error, that means the socket was already closed.
How to identify the cause?
How to know when it was closed?

Related

Connection closed while trying to POST

I am new at QT and I am trying to establish REST service (GET and POST) for my application. Meanwhile GET demand works fine, I can not execute POST demand (as result I got from server reply: Connection closed error). Do you have any suggestions what is wrong?
Constructor:
{
net_acc_manager = new QNetworkAccessManager(this);
connect(net_acc_manager, &QNetworkAccessManager::finished,this, &MyApp::httpFinished);
}
POST, response I get: Failed, error code #2. Server error explanation: Connection closed
void MyApp::Post_demand()
{
QUrl url = QUrl("http://192.168.2.1/od/6040/00");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QByteArray postdata="0000";
net_acc_manager->post(request,postdata);
qCDebug(log_hal) << Q_FUNC_INFO << "Request POST posted" << full_url.toString();
}
GET, that part works fine, output: Http post finished successfully.
void MyApp::Get_demand()
{
QUrl url = QUrl("http://192.168.2.1/od/6040/00");
reply=net_acc_manager->get(QNetworkRequest(QUrl("http://192.168.2.1/od/6040/00")));
qCDebug(log_hal) << Q_FUNC_INFO << "Request GET posted" << full_url.toString();
}
HttpFinished function
void MyApp::httpFinished(QNetworkReply *n_reply)
{
qCDebug(log_hal) << Q_FUNC_INFO << "Http request finished. Status code:" << n_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (n_reply->error()) {
qCCritical(log_hal) << Q_FUNC_INFO << "Status code:" << n_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qCCritical(log_hal) << Q_FUNC_INFO <<
QString("Failed, error code: #%1; Server error explanation: %2")
.arg(QString::number(n_reply->error())
, n_reply->errorString().replace(QRegExp("\%20"), " ")).toLatin1().data();
n_reply->deleteLater();
n_reply = Q_NULLPTR;
emit failed();
return;
}
qCDebug(log_hal) << QString("Http post finished successfully. Reply Text: %1\nElapsed time: %2 ms")
.arg(QString(n_reply->readAll()), QString::number(timer->elapsed())).toLatin1().data();
//dummy read, to clear buffer
n_reply->readAll();
n_reply->deleteLater();
n_reply = Q_NULLPTR;
emit finished();
}
after all, I have found the problem and solution. It appeared that the problem was at posting string at POST demand.
The line from POST function:
QByteArray postdata="0000";
Should actually be:
QByteArray postdata("\"0000\"");
Thanks anyway.

connecting to questDB with libpqxx

Im having an issue connecting to QuestDB with libpqxx, i can establish a connection using the postgresql client as per the instructions here:
https://questdb.io/docs/guidePSQL
however, when i go to connect to QuestDB, using my simple program, that is more-or-less a slightly modified version of the standard "get me started" program:
https://github.com/jtv/libpqxx
#include <iostream>
#include <pqxx/pqxx>
int main(){
try
{
pqxx::connection C(
"user=admin "
"hostaddr=127.0.0.1 "
"password=quest "
"dbname=qdb"
"port=8812 ");
std::cout << "Connected to " << C.dbname() << std::endl;
pqxx::work W{C};
pqxx::result R{W.exec("SELECT name FROM employee")};
std::cout << "Found " << R.size() << "employees:\n";
for (auto row: R)
std::cout << row[0].c_str() << '\n';
std::cout << "Doubling all employees' salaries...\n";
W.exec0("UPDATE employee SET salary = salary*2");
std::cout << "Making changes definite: ";
W.commit();
std::cout << "OK.\n";
}
catch (std::exception const &e)
{
std::cerr << e.what() << '\n';
return 1;
}
return 0;
}
.. i get an error:
could not connect to server: Connection refused
Is the server running on host "127.0.0.1" and accepting
TCP/IP connections on port 5432?
what also complicates things possibly, is i cannot find anywhere pg_hba.conf ,are these even still a thing in version 10 of postgresql? i have /usr/lib/postgresql/10 but no config files.. and ive also searched the machine.. nothing found. any help would be much appreciated.
thankyou
The official documentation for libpqxx states that:
The connection string consists of attribute=value pairs separated by spaces, e.g. "user=john password=1x2y3z4". reference
Your connection string is:
pqxx::connection C(
"user=admin "
"hostaddr=127.0.0.1 "
"password=quest "
"dbname=qdb"
"port=8812 ");
You are missing a space after qdb, so the correct connection string is:
pqxx::connection C(
"user=admin "
"hostaddr=127.0.0.1 "
"password=quest "
"dbname=qdb "
"port=8812 ");
I just tried it and it works fine for me.
On a second hand, the following SQL statement:
W.exec0("UPDATE employee SET salary = salary*2");
Will not work, UPDATE is not supported yet by QuestDB. You can find more details about SQL support on the official documentation, here.

How can i send and recv multiple files size in one socket c++?

i'm trying to develop a client/server application to share files..
1- Client send file size
2- Client send file data (name + content)
3- Server recv file size
4- Server recv file data (name + content)
I have my code that is working good for one file, and i'm asking how to edit it so i can send and receive size of multiple files ?
Can anyone help Plz !!!
Client code :
cout << "[Client] Sending files name to the Server... " << endl ;
int i=0;
while(i<files_vector.size()){
/************ Read & Send filename *************/
string filename = files_vector[i].getFullNameFile();
string test = filename+"&&";
size_t nameLen = strlen(test.c_str());
if(filename == "." || filename == "..")
continue;
string path_file = cf.pathSrcFiles+filename;
std::ifstream infile(path_file, std::ifstream::binary);
int32_t sizef = files_vector[i].getTaille();
/*** Send file size to server ***/
char fsize[256];
sprintf(fsize, "%d", nameLen+sizef);
if(send(sock, fsize, sizeof(fsize),0) < 0){
perror("Error sending file size\n");
exit(1);
}
/**** Send file data ****/
char content_file[sizef];
bzero(content_file, sizef);
infile.read(content_file,sizef);
string concat = test+string(content_file);
char file[sizef];
strcpy(file, concat.c_str());
cout << "content : " << file << endl;
cout << "size : " << nameLen+sizef << endl;
if(send(sock, file, nameLen+sizef, 0) < 0)
{
cout << stderr << "ERROR: Failed to send file" << filename << "
(error no = " << errno << ")" << endl;
break;
}
bzero(content_file, sizef);
infile.close();
cout << "Ok File " << filename << " from Client was Sent!\n" << endl;
i++;
}
Server code :
char csize[256];
int rc;
int32_t fsize;
/** Receive file size **/
if(rc = recv(sock, csize, 256, 0)) < 0){
cout << "Error receiving file size" << endl;
exit(1);
}
csize[rc] = '\0';
fsize = atoi(csize);
int n = 0;
int bytes_read = 0;
char* file;
file = new char[fsize];
memset(file, 0, fsize);
/** Receive file data **/
while((n = recv(sock, file+bytes_read, fsize-bytes_read, 0) > 0) &&
(bytes_read < fsize)){
cout << "content : " << file << endl;
bytes_read += n;
memset(file, 0, fsize);
}
delete[] file;

How fix strange syntax problem when using execute function?

I met an error when trying to use a function called execute to use one database. The information shows me that's about syntax, but I don't think so.
The following is my critical code and important information about the error.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'u' at line 1
#include <stdlib.h>
#include <iostream>
/*
Include directly the different
headers from cppconn/ and mysql_driver.h + mysql_util.h
(and mysql_connection.h). This will reduce your build time!
*/
#include<string>
#include "mysql_connection.h"
#include <mysql_driver.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
using namespace std;
using namespace sql;
int main()
{
try {
sql::mysql::MySQL_Driver driver;
cout<<" driver "<<endl;
sql::Connection *con = NULL;
cout<<" con"<<endl;
sql::Statement *stmt;
cout<<" stmt"<<endl;
sql::ResultSet *res;
cout<<" res"<<endl;
/* Create a connection */
//driver = sql::mysql::MySQL_Driver::MySQL_Driver();
SQLString ip_port("localhost:3306");
cout<<"some debug string"<<endl;
SQLString user("debian-sys-maint");
SQLString password("fTlykRye1LwttC8f");
con = driver.connect(ip_port, user, password);
assert(con!=NULL);
cout<<" root"<<endl;
/* Connect to the MySQL test database */
SQLString schema("account");
//con->setSchema(schema);
cout<<" table"<<endl;
stmt = con->createStatement();
cout<<" table*2"<<endl;
assert(stmt!=NULL);
SQLString db("use account");
stmt->execute(db);
res = stmt->executeQuery("SELECT * from user");
while (res->next()) {
cout << "\t... MySQL replies: ";
/* Access column data by alias or column name */
cout << res->getString("name") << endl;
cout << "\t... MySQL says it again: ";
/* Access column data by numeric offset, 1 is the first column */
cout << res->getString("password") << endl;
}
delete res;
delete stmt;
delete con;
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "(" << __FUNCTION__ << ") on line "<<endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
cout<<"\n";
}
cout << endl;
return EXIT_SUCCESS;
}
I was confused that why the information was not about the sentence "use account". Instead, it was about "u". Thanks very much.
USER is a reserved word/keyword in MySQL.
You should delimit your field names with backticks to avoid problems:
SELECT * FROM `user`

Why would connect() give intermittent EINVAL on port to FreeBSD?

I have in my C++ application a failure that arose upon porting to 32 bit FreeBSD 8.1 from 32 bit Linux. I have a TCP socket connection which fails to connect. In the call to connect(), I got an error result with errno == EINVAL which the man page for connect() does not cover.
What does this error mean, which argument is invalid? The message just says: "Invalid argument".
Here are some details of the connection:
family: AF_INET
len: 16
port: 2357
addr: 10.34.49.13
It doesn't always fail though. The FreeBSD version only fails after letting the machine sit idle for several hours. But after failing once, it works reliably until you let it sit idle again for a prolonged period.
Here is some of the code:
void setSocketOptions(const int skt);
void buildAddr(sockaddr_in &addr, const std::string &ip,
const ushort port);
void deepBind(const int skt, const sockaddr_in &addr);
void
test(const std::string &localHost, const std::string &remoteHost,
const ushort localPort, const ushort remotePort,
sockaddr_in &localTCPAddr, sockaddr_in &remoteTCPAddr)
{
const int skt = socket(AF_INET, SOCK_STREAM, 0);
if (0 > skt) {
clog << "Failed to create socket: (errno " << errno
<< ") " << strerror(errno) << endl;
throw;
}
setSocketOptions(skt);
// Build the localIp address and bind it to the feedback socket. Although
// it's not traditional for a client to bind the sending socket to a the
// local address, we do it to prevent connect() from using an ephemeral port
// which (our site's firewall may block). Also build the remoteIp address.
buildAddr(localTCPAddr, localHost, localPort);
deepBind(skt, localTCPAddr);
buildAddr(remoteTCPAddr, remoteHost, remotePort);
clog << "Info: Command connect family: "
<< (remoteTCPAddr.sin_family == AF_INET ? "AF_INET" : "<unknown>")
<< " len: " << int(remoteTCPAddr.sin_len)
<< " port: " << ntohs(remoteTCPAddr.sin_port)
<< " addr: " << inet_ntoa(remoteTCPAddr.sin_addr) << endl;
if (0 > ::connect(skt, (sockaddr*)& remoteTCPAddr, sizeof(sockaddr_in)))) {
switch (errno) {
case EINVAL: {
int value = -1;
socklen_t len = sizeof(value);
getsockopt(skt, SOL_SOCKET, SO_ERROR, &value, &len);
cerr << "Error: Command connect failed on local port "
<< getLocFbPort()
<< " and remote port " << remotePort
<< " to remote host '" << remoteHost
<< "' family: "
<< (remoteTCPAddr.sin_family == AF_INET ? "AF_INET" : "<unknown>")
<< " len: " << int(remoteTCPAddr.sin_len)
<< " port: " << ntohs(remoteTCPAddr.sin_port)
<< " addr: " << inet_ntoa(remoteTCPAddr.sin_addr)
<< ": Invalid argument." << endl;
cerr << "\tgetsockopt => "
<< ((value != 0) ? strerror(value): "success") << endl;
throw;
}
default: {
cerr << "Error: Command connect failed on local port "
<< localPort << " and remote port " << remotePort
<< ": (errno " << errno << ") " << strerror(errno) << endl;
throw;
}
}
}
}
void
setSocketOptions(int skt)
{
// See page 192 of UNIX Network Programming: The Sockets Networking API
// Volume 1, Third Edition by W. Richard Stevens et. al. for info on using
// ::setsockopt().
// According to "Linux Socket Programming by Example" p. 319, we must call
// setsockopt w/ SO_REUSEADDR option BEFORE calling bind.
int so_reuseaddr = 1; // Enabled.
int reuseAddrResult
= ::setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr,
sizeof(so_reuseaddr));
if (reuseAddrResult != 0) {
cerr << "Failed to set reuse addr on socket.";
throw;
}
// For every two hours of inactivity, a keepalive occurs.
int so_keepalive = 1; // Enabled. See page 200 for info on SO_KEEPALIVE.
int keepAliveResult =
::setsockopt(skt, SOL_SOCKET, SO_KEEPALIVE, &so_keepalive,
sizeof(so_keepalive));
if (keepAliveResult != 0) {
cerr << "Failed to set keep alive on socket.";
throw;
}
struct linger so_linger;
so_linger.l_onoff = 1; // Turn linger option on.
so_linger.l_linger = 5; // Linger time in seconds. (See page 202)
int lingerResult
= ::setsockopt(skt, SOL_SOCKET, SO_LINGER, &so_linger,
sizeof(so_linger));
if (lingerResult != 0) {
cerr << "Failed to set linger on socket.";
throw;
}
// Disable the Nagel algorithm on the command channel. SOL_TCP is not
// defined on FreeBSD
#ifndef SOL_TCP
#define SOL_TCP (::getprotobyname("TCP")->p_proto)
#endif
unsigned int tcpNoDelay = 1;
int noDelayResult
= ::setsockopt(skt, SOL_TCP, TCP_NODELAY, &tcpNoDelay,
sizeof(tcpNoDelay));
if (noDelayResult != 0) {
cerr << "Failed to set tcp no delay on socket.";
throw;
}
}
void
buildAddr(sockaddr_in &addr, const std::string &ip, const ushort port)
{
memset(&addr, 0, sizeof(sockaddr_in)); // Clear all fields.
addr.sin_len = sizeof(sockaddr_in);
addr.sin_family = AF_INET; // Set the address family
addr.sin_port = htons(port); // Set the port.
if (0 == inet_aton(ip.c_str(), &addr.sin_addr)) {
cerr << "BuildAddr IP.";
throw;
}
};
void
deepBind(const int skt, const sockaddr_in &addr)
{
// Bind the requested port.
if (0 <= ::bind(skt, (sockaddr *)&addr, sizeof(addr))) {
return;
}
// If the port is already in use, wait up to 100 seconds.
int count = 0;
ushort port = ntohs(addr.sin_port);
while ((errno == EADDRINUSE) && (count < 10)) {
clog << "Waiting for port " << port << " to become available..."
<< endl;
::sleep(10);
++count;
if (0 <= ::bind(skt, (sockaddr*)&addr, sizeof(addr))) {
return;
}
}
cerr << "Error: failed to bind port.";
throw;
}
Here is example output when EINVAL (it doesn't always fail here, sometimes it succeeds and fails on the first packet sent over the socket getting scrambled):
Info: Command connect family: AF_INET len: 16 port: 2357 addr: 10.34.49.13
Error: Command connect failed on local port 2355 and remote port 2357 to remote host '10.34.49.13' family: AF_INET len: 16 port: 2357 addr: 10.34.49.13: Invalid argument.
getsockopt => success
I figured out what the issue was, I was first getting a ECONNREFUSED, which on Linux I can just retry the connect() after a short pause and all is well, but on FreeBSD, the following retry of connect() fails with EINVAL.
The solution is when ECONNREFUSED to back up further and instead start retrying back to beginning of test() definition above. With this change, the code now works properly.
It's interesting that the FreeBSD connect() manpage doesn't list EINVAL. A different BSD manpage states:
[EINVAL] An invalid argument was detected (e.g., address_len is
not valid for the address family, the specified
address family is invalid).
Based on the disparate documentation from the different BSD flavours floating around, I would venture that there may be undocumented return code possibilities in FreeBSD, see here for example.
My advice is to print out your address length and the sizeof and contents of your socket address structure before calling connect - this will hopefully assist you to find out what's wrong.
Beyond that, it's probably best if you show us the code you use to set up the connection. This includes the type used for the socket address (struct sockaddr, struct sockaddr_in, etc), the code which initialises it, and the actual call to connect. That'll make it a lot easier to assist.
What’s the local address? You’re silently ignoring errors from bind(2), which seems like not only bad form, but could be causing this issue to begin with!