I have an application where a user can dynamically configure TCP connections between remote processes. I'd like to make sure the user input is valid, by providing them with a QComboBox that is pre-populated with all the valid hostnames on their network. Is there a way to find the list of hostnames using Qt?
If possible I'd like to do this on both windows and linux.
This can be achieved using Qt classes, but you'll also need to use system tools to gather the hostname information, and those tools are different between linux and windows. That said, with a simple preprocessor switch, we can use QProcess to call the right one, and pull the hostnames out of the result using a QRegExp:
// find valid hostnames
QStringList hostnames;
QRegExp hostnameRx("\\\\\\\\(.*)");
QProcess cmd(this);
#ifdef _WIN32
cmd.start("cmd.exe");
cmd.write("net view\r\n");
cmd.write("exit\r\n");
#else
cmd.start("smbtree", QStringList() << "--no-pass");
#endif // _WIN32
cmd.waitForFinished();
while (!cmd.atEnd())
{
QString line = cmd.readLine();
hostnameRx.indexIn(line);
if (!hostnameRx.cap(1).trimmed().isEmpty())
{
hostnames << hostnameRx.cap(1).trimmed();
}
}
The regex strips the begining '\\' returned by both net view and smbtree, because QTcpSocket connections take hostnames without it.
Obviously, the QStringListcan be used to populate a QComboBox:
QComboBox* box = new QComboBox(this);
box->insertItems(0, hostnames);
NOTE: net view and smbtree are only going to show computers with accessible shares. You can try nmap for a more complete list of live hosts, but you're going to need to run as root and you'll still probably hit a lot of firewall issues.
Related
I'm writing a gui for an net address etc. calculator. All the coding is done but now i want to have a button that will get your computer's ip address. I was looking for a solution and saw various posts on stackoverflow but none of them work for me...
Edit: this piece of code worked for me
QTcpSocket socket;
socket.connectToHost("8.8.8.8", 53);
if (socket.waitForConnected()) {
QString text = socket.localAddress().toString();
ui->ipAddress->setText(text);
} else {
QMessageBox msg;
msg.setText("Couldn't connect to the DNS server! No internet connection...");
msg.setWindowTitle("No internet connection");
msg.setIcon(QMessageBox::Critical);
msg.exec();
}```
I think the class you are looking for is the QNetworkInterface class.
From the man page:
The QNetworkInterface class provides a listing of the host's IP
addresses and network interfaces.
For example, calling QNetworkInterface::allAddresses() is a quick way to get a list of all the IP addresses on your machine. As for which one is the "public IP address", that's not a well-defined concept. On most modern consumer setups, it's arguable that there is no public IP address, as consumer PCs are typically hidden behind a NAT layer, and as such the only public IP address is on the network router, not on the user's computer itself.
You can use QHostInfo for this purpose. Ex;
auto list = QHostInfo::fromName(QHostInfo::localHostName()).addresses();
I am using following code snippet in my current project to get ip address. And it is working fine both on Desktop Linux and Embedded Linux. device is network interface name like "wlan0", "eth0" etc. It returns QNetworkAddressEntry which contains both ip and netmask. Use ip() function get ip address. Usually the first address entry is non-virtual one, so that's why am getting the first one.
const QNetworkInterface& networkInterface = QNetworkInterface::interfaceFromName(device);
if (networkInterface.isValid())
{
const QList<QNetworkAddressEntry>& addressEntries = networkInterface.addressEntries();
if (!addressEntries.isEmpty())
return addressEntries.front();
}
return QNetworkAddressEntry(); // could not found, invalid adress entry
Don't forget to add QT += network to your pro file.
Using QNetworkAccessManager, you can tap this free REST api: https://www.ipify.org/
That supports various options, such as returning the results in json. If you simply get that url, it will respond with the ip address you are most likely hoping to get back, in a raw format (i.e. a naked string).
I know that it is possible to change the network adapter in windows using the netsh command in console. but I need to do this in Qt using C++. I have tried to use QProcess to call netsh but command prompt needs admin right. also there is space in my adapter name that make it also not easy to run. Is there any library in Qt capable of changing Network adapter name without using QProcess and calling windows commands in it?
Update 1:
When I run the program with admin right and set the \" for having " inside of my string I can change the adapter name, using QProcess and netsh command.
QProcess p;
QString pi_network = "original adapter name";
p.start("netsh interface set interface name = \""+pi_network+"\" newname = \"MyAdapter\"");
I will post it as an answer, because it might help someone (as MrEricSir said in the comments).
you can use netsh command, but be aware that you should run your program with administrator right in windows.
QProcess p;
QString pi_network = "original adapter name";
p.start("netsh interface set interface name = \""+pi_network+"\" newname = \"new network adapter name\"");
p.waitForFinished();
p.close();
I wrote C++ program running on 2 cluster nodes which should add \ remove a virtual IP from the network card on each node (following some logic I've wrote..).
For that, I use EnableStatic method of the Win32_NetworkAdapterConfiguration class (https://msdn.microsoft.com/en-us/library/aa390383(v=vs.85).aspx).
On that program I have 2 buttons, "Release VIP" and "Acquire VIP".
I use RDP to connect these nodes (using the permanent IP, not the VIP).
For Release VIP I call: EnableStatic({ "1.1.1.5" }, { "255.255.0.0" });
For Acquire VIP I call: EnableStatic({ "1.1.1.5", "1.1.1.80" }, { "255.255.0.0", "255.255.0.0" });
(For this example 1.1.1.80 is the VIP)
When I did it on Windows 2012 everything worked fine and I was able to add \ remove the virtual IP.
Now, on Windows 2016, my RDP is losing connection for 2-3 seconds as a result of the change in the VIP on the network card (both add and remove..).
I know that in this API documentation Microsoft wrote that RDP should lose connection but I wonder:
Why it didn't happened in Windows 2012?
Did they made any change?
Maybe I do something wrong?
And more important:
Does it have other effect except the RDP losing connection that I should know of??
Is there a better API to use?
Thanks a lot!
It seems that c++ drivers doesn't accept mongodb connection uri format.
There's no documentation on how i should create connection string, any guess?
I need to connect to a replica set with 3 servers, and set readPreference options.
Create a connection to a replica set in MongoDB C++ client
Until the problems explained in #acm's answer are resolved, I have found a workaround to the bad Connection Strings of the C++ driver. You can create a DBClientReplicaSet using a vector of hosts and ports this way:
//First create a vector of hosts
//( you can ignore port numbers if yours are default)
vector<HostAndPort> hosts;
hosts.push_back(mongo::HostAndPort("YourHost1.com:portNumber1"));
hosts.push_back(mongo::HostAndPort("YourHost2.com:portNumber2"));
hosts.push_back(mongo::HostAndPort("YourHost3.com:portNumber3"));
//Then create a Replica Set DB Client:
mongo::DBClientReplicaSet connection("YourReplicaSetName",hosts,0);
//Connect to it now:
connection.connect();
//Authenticate to the database(s) if needed
std::string errmsg;
connection.auth("DB1Name","UserForDB1","pass1",errmsg);
connection.auth("DB2Name","UserForDB2","pass2",errmsg);
Now, you can use insert, update, etc. just as you did with DBClientConnection. For a quick fix, you can replace your references to DBClientConnection with DBClientBase (which is a parent to both DBClientConnection and DBClientReplicaSet)
Last pitfall: if you are using getLastError(), you must use it with the aimed database name like this:
connection.getLastError(std::string("DBName"));
cause otherwise it will always return "command failed: must log in" as described in this JIRA ticket.
Set the read preferences for every request
You have two ways to do that:
SlaveOK option
It lets your read queries be directed to secondary servers.
It takes place in the query options, which are at the end of the parameters of DBClientReplicaSet.query(). The options are listed in Mongo's official documentation
The one you would look for is mongo::QueryOption_SlaveOk, which will allow you to have reads made on secondary instances.
This is how you should call query();
connection.query("Database.Collection",
QUERY("_id" << id),
n,
m,
BSON("SomeField" << 1),
QueryOption_SlaveOk);
where n is the number of documents to return (0 if you don't want any limit), m the number to skip (defaults to 0), the next field is your projection and the last your query option.
To use several query option, you can use bitwise or | like this :
connection.query("Database.Collection",
QUERY("_id" << id),
n,
m,
BSON("SomeField" << 1),
QueryOption_SlaveOk | QueryOption_NoCursorTimeout | QueryOption_Exhaust);
Query::readPref option
The Query object has a readPref method which sets read preferences for a special query. It should be called for each query.
You can pass different arguments for more control. They are listed here.
So here's what you should do (I did not test that one cause I can't right now but it should work just fine)
/* you should pass an array for the tags. Not sure if this is required.
Anyway, let's create an empty array using the builder. */
BSONArrayBuilder bab;
/* if any, add your tags here */
connection.query("Database.Collection",
QUERY("_id" << id).readPref(ReadPreference_SecondaryPreferred, bab.arr()),
n,
m,
BSON("SomeField" << 1),
QueryOption_NoCursorTimeout | QueryOption_Exhaust);
Note: if any readPref option is used, it should override the slaveOk option.
Hope this helped.
Please see the connection string documentation for details on the connection string format.
(code links below are to 2.2.3 files)
To use a connection string with the C++ driver, you should use the ConnectionString class. You first call the ConnectionString::parse static method with a connection string to obtain a ConnectionString object. You then call ConnectionString::connect to obtain a DBClientBase object which you can then use to send queries.
As for read preference, at the moment I do not see a way to set the read preference in the connection string for the C++ driver, which would preclude a per-connection setting.
However, the implementation of DBClientBase returned by calling ConnectionString::parse with a string that identifies a replica set will return you an instance of DBClientReplicaSet. That class honors $readPreference in queries, so you can set your read preference on a per-query basis.
Since the current C++ drivers still do not accept the standard mongodb connection URIs, I've opened a ticket:
https://jira.mongodb.org/browse/CXX-2
Please vote for it to help get this fixed.
it seems like you can set read Preference before send a read request by call "readPref" method of your Query object. I'v not found a way to set read Preference on mongo collection object yet.
How can I check if I have a internet connection or live internet connection using C++?
C++ has no builtin functions for this, you will need to resort to system APIs. An easiest and obvious way is to create a socket and try to connect it to some known IP or check if DNS is working.
Some useful links:
http://msdn.microsoft.com/en-us/library/ms740673(VS.85).aspx (Windows Sockets)
http://www.tenouk.com/cnlinuxsockettutorials.html (Linux/Unix sockets)
The easiest way is to try to connect to a known outside IP address. If it fails in Windows, the connect function will return SOCKET_ERROR, and WSAGetLastError will usually return WSAEHOSTUNREACH (meaning the packet couldn't be sent to the host). In Linux, you'll get back a -1, and errno will be ENETUNREACH.
For starters you can subscribe to the ISensIntf to check if you have a valid network connection. (Let me know if you need help in this. Its painful to register for the events etc.).
After that, you can use Api's like IsNetworkAlive, InternetGetConnectedStateEx or the InternetCheckConnection to check connectivity to the internet etc.
If your using C# or VB, then first Add a reference to
Microsoft.VisualBasic.Code.
Microsoft.VisualBasic.Devices.Network network = new Microsoft.VisualBasic.Devices.Network();
network.NetworkAvailabilityChanged += new Microsoft.VisualBasic.Devices.NetworkAvailableEventHandler(network_NetworkAvailabilityChanged);
...
private static void network_NetworkAvailabilityChanged(object sender, Microsoft.VisualBasic.Devices.NetworkAvailableEventArgs e)
{
if (e.IsNetworkAvailable)
{
//network is connected.. do something..
}
else
{
//network isnt connected.. do something else.
}
Hope this helps