Passing a QLocalSocket* to a method expecting a QIODevice* - qt

Perhaps I'm being over-ambitious, but I'm trying to write a server program which can accept connections over both QLocalSockets and QTcpSockets. The concept is to have a 'nexus' object with both a QLocalServer and QTcpServer listening for new connections:
Nexus::Nexus(QObject *parent)
: QObject(parent)
{
// Establish a QLocalServer to deal with local connection requests:
localServer = new QLocalServer;
connect(localServer, SIGNAL(newConnection()),
this, SLOT(newLocalConnection()));
localServer -> listen("CalculationServer");
// Establish a UDP socket to deal with discovery requests:
udpServer = new QUdpSocket(this);
udpServer -> bind(QHostAddress::Any, SERVER_DISCOVERY_PORT);
connect(udpServer, SIGNAL(readyRead()),
this, SLOT(beDiscovered()));
// Establish a QTcpServer to deal with remote connection requests:
tcpServer = new QTcpServer;
connect(tcpServer, SIGNAL(newConnection()),
this, SLOT(newTcpConnection()));
tcpServer -> listen(QHostAddress::Any, SERVER_COMMAND_PORT);
}
... and then separate slots which establish a server object, whose constructor takes a pointer to a QIODevice. In theory, this ought to work because both QLocalSocket and QTcpSocket inherit QIODevice. Here is the newLocalConnection slot, for example:
void Nexus::newLocalConnection()
{
// Create a new CalculationServer connected to the newly-created local socket:
serverList.append(new CalculationServer(localServer -> nextPendingConnection()));
// We don't allow more than one local connection, so stop listening on the server:
localServer -> close();
}
The problem is that this won't compile, giving an error:
error C2664:
'CalculationServer::CalculationServer(QIODevice
*,QObject *)' : cannot convert parameter 1 from 'QLocalSocket *' to
'QIODevice *' 1> Types pointed
to are unrelated; conversion requires
reinterpret_cast, C-style cast or
function-style cast
Now the types pointed to are clearly not unrelated, and elsewhere in my code I have no problems at all with actions like:
QLocalSocket *socket = new QLocalSocket;
QIODevice *server = new QIODevice;
server = socket;
... so can anyone tell me why the compiler has a problem with this? Is there a way that I can make the constructor accept the QLocalServer*? I suppose there is the nuclear option of getting the constructor to take a void pointer plus an extra variable to tell it what it's being sent, so it can then recast the void pointer to either a QLocalSocket or QTcpSocket, but I feel uncomfortable resorting to reinterpret_cast on what looks like it ought to be a straightforward bit of C++ polymorphism.
Regards,
Stephen.

The most likely reason is that you have forgotten to #include <QLocalSocket> in the source file where the error occurs.

Related

Ocaml / Async socket issue

I am quite new to OCaml and I am working on a small TCP client utility, using Async/Core.
The connection is opened using
Tcp.with_connection (Tcp.Where_to_connect.of_host_and_port { host = "localhost"; port = myPort })
I need to be able to accept keyboard input, as well as read input from the socket. I use the Deferred.any for this purpose.
Calling Reader.read reader buf on the socket results in `Eof, which is OK, but when the method (containing the Deferred.any code) is called recursively, I get an exception:
“unhandled exception in Async scheduler”
(“unhandled exception”
((monitor.ml.Error
(“can not read from reader” (reason “in use”)
.....
Reader.is_closed on the reader returns false.
How can I “monitor” the socket recursively without this exception?
Michael

Qt QUdpsocket audiostreaming

I am trying to clone the audio streaming model of QTCpsocket but now using QUdpsocket (virtual connection), though it looks like the code is being executed , nevertheless, effectively its not doing the job, I cant get streamed audio captured;
Main focus point is: is it possible to start a QAudioOutput with a QUDpsocket ???
Yet to clearly mention that this code works fine with a TCP socket!
Code snippet:
in server.h file
private:
QUdpSocket *socketUDP;
and in .CPP file
udpServer::udpServer(QObject *parent) : QObject(parent)
{
socketUDP = new QUdpSocket(this);
serverAddress = QHostAddress("192.168.1.8");
//socketUDP->bind(serverAddress, 1357);
socketUDP->bind(1357, QUdpSocket::ShareAddress);
socketUDP->open(QIODevice::ReadOnly);
connect(socketUDP, &QUdpSocket::readyRead, this, &udpServer::playStreamedAudio);
}
then the playstream() method:
void udpServer::playStreamedAudio() {
// set the QAudioFormat parameters of output audio device.
my_QAudioFormat = new QAudioFormat;
my_QAudioFormat->setSampleRate(48000);
my_QAudioFormat->setChannelCount(1);
my_QAudioFormat->setSampleSize(8);
my_QAudioFormat->setCodec("audio/pcm");
my_QAudioFormat->setByteOrder(QAudioFormat::LittleEndian);
my_QAudioFormat->setSampleType(QAudioFormat::UnSignedInt);
//
// get default audio output device
audiOutputDevice = QAudioDeviceInfo::defaultOutputDevice();
audiooutput = new QAudioOutput(audiOutputDevice,my_QAudioFormat, this);
// attach to socket!
qDebug() << "Playaing AudioStream";
socketUDP->open(QIODevice::ReadOnly);
audiooutput->start(socketUDP); // the Audio output device shall listen to server socket for audio
}
It turns out that UDP sockets may not suitability be interfaced as QioDevices... seems they are not intended to be, the packets are better be written to a file and then processed.

How to get QDBusConnection::connect() failure reason

I'm trying to connect to a D-Bus signal this way:
bool result = QDBusConnection::systemBus().connect(
"foo.bar", // service
"/foo/bar", // path
"foo.bar", // interface
"SignalSomething",
this,
SLOT(SignalSomethingSlot()));
if( !result )
{
// Why!?
}
QDBusConnection::connect() returns a boolean, how do I get extended error information? If a check QDBusConnection::lastError() it returns no useful information (as QDBusError::isValid() is false).
I had the same issue and it turned out that the slot I connected to had the wrong parameter types. They must match according to Qt's documentation and it looks like connect() verifies that, despite not explicitly mentioned.
Warning: The signal will only be delivered to the slot if the parameters match.
I suggest d-feet to list signals and check their parameter types. dbus-monitor does list signals, paths and such too, but not always the exact type of parameters.
One important observation though: I fixed the issue in my particular case by using different slot parameters than the actual signal has!
I wanted to connect to a com.ubuntu.Upstart0_6 signal mentioned here to detect when the screen in Ubuntu is locked/unlocked. dbusmonitor prints the following and d-feet shows parameters (String, Array of [String])
// dbusmonitor output
signal time=1529077633.579984 sender=:1.0 -> destination=(null destination) serial=809 path=/com/ubuntu/Upstart; interface=com.ubuntu.Upstart0_6; member=EventEmitted
string "desktop-unlock"
array [
]
Hence the signal should be of type
void screenLockChangedUbuntu(QString event, QVector<QString> args) // connect() -> false
This however made connect() return false. The solution was to remove the array parameter from the slot:
void screenLockChangedUbuntu(QString event) // works
I am aware that the array parameter was always empty, but I cannot explain why it only worked when removing it.
You could try these tricks:
1) Set QDBUS_DEBUG environment variable before running your application.
export QDBUS_DEBUG=1
2) Start dbus-monitor to see what's happening on the bus. You may need to set a global policy to be able to eavesdrop system bus depending on your distro.
Update:
Are you sure connecting to the system bus succeeded? If it fails you should probably check system.conf policy and possibly create own conf in system.d. This post might be helpful.
You could first connect to the system bus with QDBusConnection::connectToBus and check if it succeeded with QDBusConnection::isConnected. Only after that you try to connect to the signal and check if that succeeded.
QDBusConnection bus = QDBusConnection::connectToBus(QDBusConnection::systemBus, myConnectionName);
if (bus.isConnected())
{
if(!bus.connect( ... ))
{
// Connecting to signal failed
}
}
else
{
// Connecting to system bus failed
}

Qt TCP/IP socket connection check

I am writing Qt TCP/IP client. I want to check the connection state with server before send data to sever.
As far my knowledge I can do this by following methods
Use a bool 'ConnectionState', set this variable when connected with
sever and reset this variable on disconnected() signal. Now before
sending data to server (client->write()) check the value of this
variable.
use this 'client->state() == QTcpSocket::ConnectedState' way to check the connection state.
Which is good practice. Or any other method to this.
Thanks In advance.
QTCPSocket is derived from QAbstractSocket, which provides a state() function. This returns one of the following enums: -
enum SocketState { UnconnectedState, HostLookupState, ConnectingState, ConnectedState, ..., ListeningState }
So, assuming m_pSocket is a QTcpSocket, you would simply do this to check if it is connected:-
bool connected = (m_pSocket->state() == QTcpSocket::ConnectedState);
You could add a boolean and keep track of the state, but if a network error occurs you need to ensure that it is always in-sync with the actual connection state.
You can use errorOccurred signal and It's just enough for this signal define a slot in client. when an error occurs, a signal trigger and you can receive notify in slot function.
In client.h
/* define a slot for client */
public slots:
void errorOccurred(QAbstractSocket::SocketError error);
In client.c
/*client constructor*/
Client::Client(QObject *parent) {
/*some other code here*/
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
this, SLOT(errorOccurred(QAbstractSocket::SocketError)));
/*and maybe some other code here*/
}
and in client.c write implementation for errorOccurred:
void Client::errorOccurred(QAbstractSocket::SocketError error) {
qDebug() << "error in connection: " << socket->errorString();
}
OUTPUT:
error in connection: "Connection refused"

qdbus - can't connect to dbus signal with struct argument

I'm trying to connect to amarok d-bus signal StatusChange (reference: https://xmms2.org/wiki/MPRIS#StatusChange). Interface and struct is ok because I can connect to simple signal CapsChange(int) in same interface and can get status by GetStatus dbus method, so this marshall struct is ok:
struct AmarokStatus {
int st1;
int st2;
int st3;
int st4;
};
Q_DECLARE_METATYPE(AmarokStatus)
qDBusRegisterMetaType<AmarokStatus>();
But when call:
mInf = new QDBusInterface("org.mpris.MediaPlayer2.amarok", "/Player",
"org.freedesktop.MediaPlayer", QDBusConnection::sessionBus(),this);
connect(mInf, SIGNAL(StatusChange(AmarokStatus)), this, SLOT(statusChanged(AmarokStatus)));
connect(mInf, SIGNAL(CapsChange(int)), this, SLOT(capsChange(int)));
I got message:
Object::connect: No such signal
org::freedesktop::MediaPlayer::StatusChange(AmarokStatus)
I have tried with SIGNAL(StatusChange(struct)) and SIGNAL(StatusChange(QDbusargument)) and other types but same message
D-Feet is saying that definition of StatusChange is: StatusChange(Struct of (Int32, Int32, Int32, Int32)), same with dbus-monitor. And same problem with signal TrackChange(array of struct). So I'm definitely messing something with connect() method.
There are two options:
Ensure the emitter which implements QDBusAbstractInterface defines the signal you are connecting to. This solution is a bit cleaner.
or
Use QDBusConnection::connect to connect to an anonymous signal. This solution works in a pinch but in my experience can be particularly error-prone:
if (!QDBusConnection::systemBus().connect("org.mpris.MediaPlayer2.amarok", "/Player", "org.freedesktop.MediaPlayer", "StatusChange", this, SLOT(statusChanged(AmarokStatus)))) {
qWarning() << "Failed to connect";
}

Resources