Qt 5.5 not binding to port - linux

I have some code which worked fine in Qt 5.9 under Windows but is causing issues with Qt 5.5 under Linux.
It's basically contacting an echo server to detect whether a device is on the network and it starts by setting up a UDP sender and receiver, after which it sends a packet and checks that it comes back.
The problematic bit seems to be in binding the receiving socket:
// Create the two sockets.
m_sendSocket = new QUdpSocket(this);
m_recvSocket = new QUdpSocket(this);
// Connect sending socket to other end.
m_sendSocket->connectToHost(QHostAddress(host), 43837);
// Bind receiving socket so it will receive any response.
bool x = m_recvSocket->bind(m_sendSocket->localPort());
std::cout << x << " " << m_sendSocket->localPort() << std::endl;
It creates the two sockets (outgoing and incoming) then attempts to bind the outgoing socket's local port to the incoming socket's receiving port (so the response can be picked up).
This works fine under the Windows environment but the bind is failing under Linux. Since all it returns is a boolean value, I'm at a loss as to why it's failing.
Thinking it may be the default binding mode for the platform, I also tried explicitly setting that so that Linux would match Windows:
bool x = m_recvSocket->bind(m_sendSocket->localPort(), QAbstractSocket::ShareAddress);
But that didn't help.
The local port for the sender socket seems okay, I've seen values like 38349, 58597, and 37433.
Does anyone know why this might be failing, or whether Qt makes more information available somewhere as to why it's failing, or whether there's a better way to do this (that won't fail)?

You can get further information from the socket by accessing m_recvSocket->errorString(). In your case, modify the cout line to be:
std::cout << x
<< " " << m_sendSocket->localPort()
<< " " << m_recvSocket->errorString().toStdString()
<< std::endl;
What you'll see is something along the lines of "address already in use" because, as you realise, Windows and Linux have different default binding modes - the former is a more sharing OS whereas the latter appears to be vindictive and possessive (a).
So the sending socket has effectively locked up the local port it's using when calling connectToHost(), meaning the receiving socket cannot bind to it.
The way to solve this is to have the sending socket bind explicitly with the sharing option before connecting to the host. This can be done with:
m_sendSocket = new QUdpSocket(this);
m_recvSocket = new QUdpSocket(this);
m_sendSocket->bind(0, QAbstractSocket::ShareAddress);
m_sendSocket->connectToHost(QHostAddress(host), 43837);
bool x = m_recvSocket->bind(m_sendSocket->localPort(), QAbstractSocket::ShareAddress);
std::cout << x
<< " " << m_sendSocket->localPort()
<< " " << m_recvSocket->errorString().toStdString()
<< std::endl;
That results in the output:
1 47334 Unknown error
on my system, the error text can be ignored since the return value of bind was true (the initial 1 on the output line).
(a) Pax ducks for cover :-)

Related

std::map insert thread safe in c++11?

I have very simple code in which multiple threads are trying to insert data in std::map and as per my understanding this should led to program crash because this is data race
std::map<long long,long long> k1map;
void Ktask()
{
for(int i=0;i<1000;i++)
{
long long random_variable = (std::rand())%1000;
std::cout << "Thread ID -> " << std::this_thread::get_id() << " with looping index " << i << std::endl;
k1map.insert(std::make_pair(random_variable, random_variable));
}
}
int main()
{
std::srand((int)std::time(0)); // use current time as seed for random generator
for (int i = 0; i < 1000; ++i)
{
std::thread t(Ktask);
std::cout << "Thread created " << t.get_id() << std::endl;
t.detach();
}
return 0;
}
However i ran it multiple time and there is no application crash and if run same code with pthread and c++03 application is crashing so I am wondering is there some change in c++11 that make map insert thread safe ?
No, std::map::insert is not thread-safe.
There are many reasons why your example may not crash. Your threads may be running in a serial fashion due to the system scheduler, or because they finish very quickly (1000 iterations isn't that much). Your map will fill up quickly (only having 1000 nodes) and therefore later insertions won't actually modify the structure and reduce possibility of crashes. Or perhaps the implementation you're using IS thread-safe.
For most standard library types, the only thread safety guarantee you get is that it is safe to use separate object instances in separate threads. That's it.
And std::map is not one of the exceptions to that rule. An implementation might offer you more of a guarantee, or you could just be getting lucky.
And when it comes to fixing threading bugs, there's only one kind of luck.

C++ - Corrupted String

I'm quite new to C++, but I'm used to some coding with R language. I started, a few weeks ago, to put together a small application that should copy and rename file pairs (.seq/.ab1). Result from a DNA sequencer analysis (renaming hundreds of them manually would be a real time waste, specially because we have lists with their new names).
Everything seemed to be fine, but the new files (those copied) appear with a "special character" in their names (right before the file type), it seeems like a space, but its not (I've replaced it with a space, and the file opened correctly). After deleting it the file can be oppened by its associated application, but with it, the aplication acusses the file to be corrupted.
The issue seems to come from the code related to ostringstream::str member function, but I honestly don't know how to fix it. I wonder if its not inserting a null character there, before I append the file type...
Here is the part of the code responsible. It gets the old and new names from a 2 column csv file, data separated by ";". Original data, and new (renamed files) data are kept in diferent directories, thats the reason I need to create a string with each file path inside a for loop. I intend to check old and new files content later, probably with memcmp. But first I need them to be correctly renamed.
I'm on a Ubuntu 14.04 (64 bit) machine with gcc 4.8.4 as compiler. I already excuse myself for the probably poor coding and bad english, I'm not a native speaker (writer, actually).
fNew.open(filename);
std::ostringstream oldSeqName (std::ostringstream::ate);
std::ostringstream newSeqName (std::ostringstream::ate);
std::ostringstream oldAb1Name (std::ostringstream::ate);
std::ostringstream newAb1Name (std::ostringstream::ate);
std::fstream log;
time_t now = time(0);
for (std::string nOld, nNew; getline(fNew, nOld, ';') && getline(fNew, nNew); )
{
std::cout << "Old Name: " << nOld << " -> New Name: " << nNew << std::endl;
// Keep a log of the name changes
log.open("NameChangesLog.txt", std::fstream::out | std::fstream::app);
log << ctime(&now) << " - " << "Old Name: " << nOld << " -> New Name: " << nNew << std::endl;
log.close();
// Create old seq files paths string
oldSeqName.str(nOld);
oldSeqName << ".seq";
std::string osn = "./Seq/" + oldSeqName.str();
// Create new seq files paths string
newSeqName.str(nNew);
newSeqName << ".seq";
std::string nsn = "./renamed/" + newSeqName.str();
std::ifstream ifseq(osn, std::ios::binary);
std::ofstream ofseq(nsn, std::ios::binary);
ofseq << ifseq.rdbuf();
ifseq.close();
ofseq.close();
// Create old ab1 files paths string
oldAb1Name.str(nOld);
oldAb1Name << ".ab1";
std::string oan = "./Seq/" + oldAb1Name.str();
// Create new abq files paths string
newAb1Name.str(nNew);
newAb1Name << ".ab1";
std::string nan = "./renamed/" + newAb1Name.str();
std::ifstream ifab1(oan, std::ios::binary);
std::ofstream ofab1(nan, std::ios::binary);
ofab1 << ifab1.rdbuf();
ifab1.close();
ofab1.close();
}
fNew.close();
Is the list file prepared on Windows machine? In that case it would have DOS line ending (\r\n) and is not well suited for getline on Unix. The character you see is likely \r. Make sure you use dos2unix utility before feeding the list file to your program
You probably forget to trim the values returned from getline, so they may still contain whitespace. Whitespace may be tricky to pick up by the application.

Reduce TCP maximum segment size (MSS) in Linux on a socket

In a special application in which our server needs to update firmware of low-on-resource sensor/tracking devices we encountered a problem in which sometimes data is lost in the
remote devices (clients) receiving packets of the new firmware. The connection is TCP/IP over
GPRS network. The devices use SIM900 GSM chip as a network interface.
The problems possibly come because of the device receiving too much data. We tried reducing the
traffic by sending packages more rarely but sometimes the error still occured.
We contacted the local retailer of the SIM900 chip who is also responsible for giving technical support and possibly contacting the chinese manufacturer (simcom) of the chip. They said that at first we should try to reduce the TCP MSS (Maximum Segment Size) of our connection.
In our server I did the following:
static int
create_master_socket(unsigned short master_port) {
static struct sockaddr_in master_address;
int master_socket = socket(AF_INET,SOCK_STREAM,0);
if(!master_socket) {
perror("socket");
throw runtime_error("Failed to create master socket.");
}
int tr=1;
if(setsockopt(master_socket,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int))==-1) {
perror("setsockopt");
throw runtime_error("Failed to set SO_REUSEADDR on master socket");
}
master_address.sin_family = AF_INET;
master_address.sin_addr.s_addr = INADDR_ANY;
master_address.sin_port = htons(master_port);
uint16_t tcp_maxseg;
socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
if(getsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len)) {
log_error << "Failed to get TCP_MAXSEG for master socket. Reason: " << errno;
perror("getsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
tcp_maxseg = 256;
if(setsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, tcp_maxseg_len)) {
log_error << "Failed to set TCP_MAXSEG for master socket. Reason: " << errno;
perror("setsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
if(getsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len)) {
log_error << "Failed to get TCP_MAXSEG for master socket. Reason: " << errno;
perror("getsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
if(bind(master_socket, (struct sockaddr*)&master_address,
sizeof(master_address))) {
perror("bind");
close(master_socket);
throw runtime_error("Failed to bind master_socket to port");
}
return master_socket;
}
Running the above code results in:
I0807 ... main.cpp:267] TCP_MAXSEG: 536
E0807 ... main.cpp:271] Failed to set TCP_MAXSEG for master socket. Reason: 22 setsockopt: Invalid argument
I0807 ... main.cpp:280] TCP_MAXSEG: 536
As you may see, the problem in the second line of the output: setsockopt returns "Invalid argument".
Why does this happen? I read about some constraints in setting TCP_MAXSEG but I did not encounter any report on such a behaviour as this.
Thanks,
Dennis
In addition to xaxxon's answer, just wanted to note my experience with trying to force my Linux to send only maximum TCP segments of a certain size (lower than what they normally are):
The easiest way I found to do so, was to use iptables:
sudo iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN --destination 1.1.1.1 -j TCPMSS --set-mss 200
This overwrites the remote incoming SYN/ACK packet on an outbound connection, and forces the MSS to a specific value.
Note1: You do not see this in wireshark, since wireshark capture before this happens.
Note 2: Iptables does not allow you to -increase- the MSS, just lower it
Alternatively, I also tried setting the socket option TCP_MAXSEG, like dennis had done. After taking the fix from xaxxon, this also worked.
Note: You should read the MSS value after the connection has been set up. Otherwise it returns the default value, which put me (and dennis) on the wrong track.
Now finally, I also ran into a number of other things:
I ran into TCP-offloading issues, where despite my MSS being set correctly, the frames being sent were still shown by wireshark as too big. You can disable this feature by : sudo ethtool -K eth0 tx off sg off tso off. This took me a long time to figure out.
TCP has lots of fancy things like MTU path discovery, which actually try to dynamically increase the MSS. Fun and cool, but confusing obviously. I did not have issues with it though in my tests
Hope this helps someone trying to do the same thing one day.
Unless otherwise noted, optval is a pointer to an int.
but you're using a u_int16. I don't see anything saying that this parameter isn't an int.
edit: Yeah, here is the source code and you can see:
637 if (optlen < sizeof(int))
638 return -EINVAL;

Why protocol buffer c++ library not reading binary objects properly

I created a binary file using a c++ program using protocol buffers. I had issues reading the binary file in my C# program, so I decided to write a small c++ program to test the reading.
My proto file is as follows
message TradeMessage {
required double timestamp = 1;
required string ric_code = 2;
required double price = 3;
required int64 size = 4;
required int64 AccumulatedVolume = 5;
}
When writing to protocol buffer, I first write the object type, then object length and the object itself.
coded_output->WriteLittleEndian32((int) ObjectType_Trade);
coded_output->WriteLittleEndian32(trade.ByteSize());
trade.SerializeToCodedStream(coded_output);
Now, when I am trying to read the same file in my c++ program i see strange behavior.
My reading code is as follows:
coded_input->ReadLittleEndian32(&objtype);
coded_input->ReadLittleEndian32(&objlen);
tMsg.ParseFromCodedStream(coded_input);
cout << "Expected Size = " << objlen << endl;
cout<<" Trade message received for: "<< tMsg.ric_code() << endl;
cout << "TradeMessage Size = " << tMsg.ByteSize() << endl;
In this case, i get following output
Expected Size = 33
Trade message received for: .CSAP0104
TradeMessage Size = 42
When I write to file, I write trade.ByteSize() as 33 bytes, but when I read the same object, the object ByteSize() is 42 bytes, which affects the rest of the data. I am not sure what is wrong in this. Please advice.
Regards,
Alok
This is guesswork, based on the above: when you use ParseFromCodedStream, you aren't actually limiting that to the objlen that you previously found; thus, if the stream contains any more data than this (i.e. that isn't the end of the file), the engine will try to keep reading to the EOF. You must cap the length to your expectation. I am not a C++ expert, so I can't offer direct guidance, but if this was C# (using protobuf-net):
objType = ProtoReader.DirectReadLittleEndianInt32(file);
len = ProtoReader.DirectReadLittleEndianInt32(file);
// assume GetObjectType returns typeof(TradeMessage) for our objType
Type type = GetObjectType(objType);
msg = RuntimeTypeModel.Default.Deserialize(file, null, type, len, null);
So apparently, i was doing a very silly mistake while creating the binary files. I did not open the file in binary mode when i wrote protobuf data to it causing it to add weird ascii characters in the middle. This caused an issue while reading the data using protobuf-net library. The issue is resolved here. Shouldn't have taken so long to resolve this.

How to detect USB device disconnect under Linux/Qt/C++

I'm writing a system (X-Platform Windows/Linux) that talks to a custom device using an FTDI USB chip. I use their D2XX driver for device open/close/read/write. So far, so good.
I need to know when the device is disconnected so the program can respond gracefully. At present, under Windows the application receives a sudden unexpected close. Under Linux, when the device is disconnected, there is a sgementation fault.
I have found informaiton under Windows about listening for the WM_DEVICECHANGE message. However, I have not found how to detect this event under Windows. There is information for the device driver level interacting with the kernel. However, I can't figure out how to do this at an application level. The FTDI driver does not offer any such service.
The system is written using the Qt framework with C++. The device driver is FTDI's D2XX driver.
Can anyone point me in the right direction?
Thanks so much in advance!
Judy
You'll probably want to use HAL (freedesktop.org's Hardware Abstraction Layer).
In the future you will probably want to use DeviceKit. It is a project fix the many problems with HAL. It hasn't been adopted by all major distros yet though (I think just Fedora), so you probably don't want to use it right now.
Edit: As Jeach said, you can use udev also. I wouldn't suggest this, as it is much lower level, and harder to program, but if latency is very important, this might be the best option.
Although what I'm about to tell you won't directly answer your question, it may give you a hint as to your next move.
I use udev rules configured in '/etc/udev/rules.d/' which run various scripts. When a USB device gets connected/disconnected I run a script which sends a HUP signal to my binary. Since my requirements can handle a bit of lag it works perfectly fine for me.
But my point is that maybe there is a udev library you can link to and register events programmatically (instead of scripts).
Hope it helps... good luck!
I recently had a project which involved reading via an FTDI chip. I also tried using libftdi but found out that it is much simpler to use /dev/ttyUSB* for reading and writing. This way, you can use QFile('/dev/ttyUSB*') to write and read. You can also check if the device actually exists and it won't segfault. Of course, this is not a very 'Platform independent' way. To get a platform independent method, you can use a Serial library for Qt.
You obviously have to write different implementations for the different operating systems unless you want to create a thread to continuously run:
FT_ListDevices(&numDevs, nullptr, FT_LIST_NUMBER_ONLY);
and enumerate the devices if numDevs changed compared to previous checks.
If you are like me and don't really like to do that sort of continuous polling on your USB devices then you will have to target your specific operating system.
Here's a link to some sample code from FTDI:
http://www.ftdichip.com/Support/SoftwareExamples/CodeExamples/VC.htm
Example 7 shows how to detect the USB insertion and removal on windows:
http://www.ftdichip.com/Support/Documents/AppNotes/AN_152_Detecting_USB_%20Device_Insertion_and_Removal.pdf
On Linux I can personally recommend using udev.
This code is for enumerating the devices:
#include <sys/types.h>
#include <dirent.h>
#include <cstdlib>
#include <libudev.h>
#include <fcntl.h>
struct udev *udev = udev_new();
if (!udev) {
cout << "Can't create udev" <<endl;
}
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "usb");
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry *dev_list_entry, *devices = udev_enumerate_get_list_entry(enumerate);
struct udev_device *dev;
udev_list_entry_foreach(dev_list_entry, devices) {
const char *path;
path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(udev, path);
if( udev_device_get_devnode(dev) != nullptr ){
string vendor = (std::string) udev_device_get_sysattr_value(dev, "idVendor");
string product = (std::string) udev_device_get_sysattr_value(dev, "idProduct");
string description = (std::string)udev_device_get_sysattr_value(dev, "product");
cout << vendor << product << description << endl;
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
This code I put in a separate thread that waits to receive an insertion or a removal event
struct udev_device *dev;
struct udev_monitor *mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL);
udev_monitor_enable_receiving(mon);
int fd = udev_monitor_get_fd(mon);
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1){
debugError("Can't get flags for fd");
}
flags &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
while( _running ){
cout << "waiting for udev" << endl;
dev = udev_monitor_receive_device(mon);
if (dev && udev_device_get_devnode(dev) != nullptr ) {
string action = (std::string)udev_device_get_action(dev);
if( action == "add" ){
cout << "do something with your device... " << endl;
} else {
string path = (std::string)udev_device_get_devnode(dev);
for( auto device : _DevicesList ){
if( device.getPath() == path ){
_DevicesList.erase(iter);
cout << "Erased Device from list" << endl;
break;
}
}
}
udev_device_unref(dev);
}
}
udev_monitor_unref(mon);
some of the functions and variables are obviously not defined when you copy/paste this code.
I keep a list of detected devices to check the path and other information like the location ID of the inserted device. I need the location ID later to FT_OpenEx via FT_OPEN_BY_LOCATION. To get the location id I read the contents of the following files:
string getFileContent(string file ){
string content = "";
ifstream readfile( file );
if( readfile.is_open() ){
getline(readfile, content );
readfile.close();
}
return content;
}
string usbdirectory = "/sys/bus/usb/devices";
string dev1content = getFileContent(usbdirectory+"/usb"+udev_device_get_sysattr_value(dev, "busnum" )+"/dev");
int dev1num = std::atoi(dev1content.substr(dev1content.find_first_of(":")+1).c_str());
string dev2content = (std::string)udev_device_get_sysattr_value(dev, "dev");
int dev2num = std::atoi(dev2content.substr(dev2content.find_first_of(":")+1).c_str());
int locationid = dev1num+dev2num+257;
I can't guarantee that the locationid is correct but it seemed to work for me until now.
Don't forget that you have two problems here :
Detecting device insertion / removal
Properly terminating your application.
The first problem has been adressed by Zifre.
But the second problem remains : your Linux app should not be segfaulting when the device is removed, and I think the two problems are unrelated : if the device is removed in the middle of a write or read system call, then those system call will return with an error before you get any notification, and this should not segfault your app.

Resources