How to check incomingConnection for valid IP before starting QTcpSocket in separate thread
-
I see your confusion. The qintptr is not really a pointer, but a pointer-sized integer value. Pointer-sized integers (or INTPTRs) are commonly used to pass native handle values of various objects of the underlying operating system. For example, on Windows a file (or socket) handle is defined as the WINAPI type HANDLE which is in turn defined as void pointer. On Linux and unixes a file or socket handle (more commonly called a 'file descriptor' on unix platforms) is defined as a simple int. Qt hides this underlying platform details and uses a qintptr type to pass native handle values. Such type is guaranteed to be able to represent both int values as well as pointer values.
The documentation on "QTcpServer::incomingConnection()":http://qt-project.org/doc/qt-5.0/qtnetwork/qtcpserver.html#incomingConnection tells us that the socketDescriptor argument is the native socket descriptor for the accepted connection.
Bottom line: the socketDescriptor is not a pointer to some object, it is a value that you can use directly in any native calls, including getpeername(). You will probably get a warning about casting to a smaller/different type, but you can safely ignore that, or add an explicit (int) cast.
-
martin_ky, thanks for your hints. After ours of head ache I looked up the internet for the getpeername() method you mentioned and finally found a Windows site where these socket basics are explained. Hope I´ll find way through this now.
BTW working on a Win-OS hopefully will not kick me out of the decent part of mankind in the eyes of the rest of the world.
-
Unless it was clear from my last post and from the Qt documentation: the qintptr IS the native socket descriptor of the incoming connection.
Your incomingConnection() implementation can use it like this:
@void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
sockaddr nativeAddress;
int sz = sizeof nativeAddress;
getpeername(socketDescriptor, &nativeAddress, &sz);
QHostAddress address(&nativeAddress);
qDebug() << "Peer address is:" << address.toString();//TODO: decide what to do with the incoming connection
}
@On Windows, don't forget to include WinSock2.h and link the Ws2_32.lib
-
Following the hints of your last post I had found the Win-Socket stuff on the internet and after some hours of head scratching came to a similar code, which did not work. Now I copied your snippet (thanks!) into my code. For reasons I cannot conceive of, it does not work for me either:
@void TcpServerThreaded::incomingConnection(qintptr socketDescriptor){
sockaddr nativeAddress;
int sz = sizeof nativeAddress;
if(getpeername(socketDescriptor, &nativeAddress, &sz)== SOCKET_ERROR){
emit annotation(new QString("there is only little hope\n"));
}else{
QHostAddress address(&nativeAddress);
emit annotation(new QString(address.toString()));
}
...
}
@
Compiles without errors, but guess what annotation I get... -
For the fun of it, I tried to compile it both on Qt 5.0.2 and Qt 4.8.3 (Windows, MSVC).
On 4.8.3 works OK. But on 5.0.2 I'm getting the following error:
- getpeername() returns -1 (SOCKET_ERROR)
- WSAGetLastError() returns 10014 (WSAEFAULT)
I have absolutely no idea why it works on Qt 4 and not on Qt 5 :(
-
I will try to find out a little more about it. Try and error etc.. Nevertheless great hints you gave me. Thanks again.
-
You're welcome. It seems to me, that something changed between Qt 4 -> Qt 5, which makes this approach unusable on Windows.
Perhaps somebody from the Qt developers could look at this more closely?
-
Found a solution, however did not yet understand fully why it works:
the ERRORCODE from WSAGetLastError() 10014 means something like address(-size) error.
(See http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx)
So I assumed there must be something going wrong in the header file with the selection of the proper structure to use. Then I just increased the value of @ int sz = sizeof nativeAddress;@, which is being passed as a parameter to getpeername().
After having added 12 to sz, all of a sudden it worked.
Thanks to all again and especially to martin_ky. -
Ok, I figured this out (I was curious :). Bbbill, you're on the right track with the size of the sockaddr sturcture. This struct simply is not big enough to hold IPv6 addresses.
Do not just blindly increase the passed size of the address structure, or you will most certainly corrupt your stack. Instead sockaddr, use the sockaddr_storage struct, which is large enough to contain also IPv6 addresses. More light on this in "this thread.":http://stackoverflow.com/questions/8835322/api-using-sockaddr-storage
The difference between Qt 4 and 5 which I was talking about was in my QTcpServer::listen(QHostAddress::Any) call:
- QHostAddress::Any in Qt 4 means "listen on all IPv4 interfaces".
- but in Qt 5 "listen on all IPv4 and all IPv6 interfaces".
Therefore I was getting IPv6 connections when compiled with Qt 5, but not in Qt 4. If you don't want to use IPv6 and save some trouble, just make your QTcpServer listen only on QHostAddress::AnyIPv4. In this case, my original code works perfectly.
-
Yes, your recommendation makes sense. I changed my code for "sockaddr_storage". Have to use a cast in getpeername() now. Nasty but sure much more reliable than my tweeking with magic numbers.
Also I had to initialise the winsocket-dll by WSAStartup()-call prior to using native methods, otherwise it would not work. As I would like to leverage my programm to ip6 capability, I'll stick with this more general approach and go on learning to get it running. Thanks a lot.