Start a service in a LAN; the unknow server address case - c++

This questions are a new attempt to solve a previous question "How to get a list of all valid ip address in a local network using Javascript?" (see How to get a list of all valid ip address in a local network using Javascript? )
In order to avoid the need of test millions of addresses, I wonder if it would be possible following scenario (in this case, forget the JavaScriipt constraint of the initial post, and suppose a more general language, say C++ and a I/O library like Boost Asio):
a) A server "S" wakeup in a LAN to provide some service, say listening in port X, and get a random address (i.e A1 = 192.168.1.35).
b) A client "C", that need the service, wakeup in the same LAN, an get other random address (say A2 = 192.168.1.40).
"C" does not know the "S" address to get the service. So, two questions:
1.- Can "S" and "C" know for themselves its own addresses (A1 and A2)?
2.- Can "C" send a broadcast request to the LAN in the given port X? Some as "Here P2, some one in X?"
Obviously, if "S" is listening in the given port, and can get the message, them can in turn broadcast its own direction; so if "C" is listening, can get the server's address.

Related to my first question, after some digging, the answer is Yes.
See "Winsock Programer's FAQ".
If in Windows, as is my case for the server, there are a complete API named "IP Helper" http://msdn.microsoft.com/en-us/library/aa366073%28VS.85%29.aspx that can serve as well.
Related to the second question, I will try the quick and dirty method exposed, and hope be back with some result.

Related

QtRO - class qremoteobjects - how can connect 2 and more remote peers beetwen TCP

I was build example simpleswitch with registry node in Qt5.9. It's work fine, but when i replace QUrl("local.registry") and QUrl("local.replica") in definition QRemoteObjectRegistryHost and QRemoteObjectHost to QUrl("tcp://localhost:9999") or "tcp://127.0.0.1:9999", or paste current host address to defniton... i have error after run app...
qt.remoteobjects: Listen failed for URL: QUrl("tcp://127.0.0.1:9999")
qt.remoteobjects: QAbstractSocket::AddressInUseError
qt.remoteobjects: Could not create ClientIoDevice for client. Invalid url/scheme provided? QUrl("")
The valid value, use instead of QUrl("local.registry"):
QUrl("tcp://192.168.0.3:-1");
The valid value, use instead of QUrl("local.replica"):
QUrl("tcp://192.168.0.3:9999");
The IP address 192.168.0.3 - used for example (it value valid for my workstation in our office network) in your case IP address can contain other digits.
If Qt is indicating that 'the address is in use' then that is likely the source of the problem, literally the socket at IP:PORT is being used. You may check your development environment to see if you have multiple processes running of the same app - this is often the case and it leads to a collision of address spaces. We see this error in our environment consistently, and the root cause is simply as stated: 'the address is in use'.

Bind a socket to a specific interface with unknown Ip

I have a host with two interfaces. In my specific case I am trying to join a multicast group using boost::asio::ip::multicast::join_group which appears to only work if i use the constructor that includes the local address. However i do not know in advance the ip address of the local interface connected to the remote host that will do the multicasting. I do however know that it will be eth1. Of course, i could make it configurable but that seems like introducing a useless opportunity to misconfigure, seeing how the same address would have to be configured for the interface and my application.
Ideally there would be a glaringly obvious way to create a boost::asio::endpoint or boost::asio::address from an interface instead of an address that i somehow missed. Alternatively i would of course be just as happy with any other way to deduce an interfaces Ip that works both, with and without a DHCP-Server supplying the Ip.
Is there a proper way to do either or should i just trust users to never fumble with the configuration?
To make sure that this is not completely a XY Problem, here is the code i used while testing to join a multicast group:
m_socket.open(boost_ip::udp::v4());
m_socket.bind(boost_ip::udp::endpoint(boost_ip::udp::v4(), listeningPort));
m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
m_socket.set_option(boost::asio::ip::multicast::join_group(
boost::asio::ip::address::from_string("225.x.x.10").to_v4(), // remote
boost::asio::ip::address::from_string("192.x.x.3").to_v4())); // local
This does work but when i discard the last line to not be dependent on the current local address (that might be changed in deployment), i no longer receive any packets.
Multicast uses the IGMP protocol to form a multicast group. Since IGMP operates on the network layer, it requires the local ip address of the end-point that is joining the multicast group.
The application should wait for an event indicating an ip address has been assigned to the ethernet interface and then call the join_group method to join the multicast group.
I came up with an answer to my question myself. This works for me but I will leave the question open in case anyone has a more straightforward solution.
I settled with using <ifaddrs.h> to just find my current ip for the interface and use that to join the multicast group. This is the code i ended up with to determine my ip:
#include <ifaddrs.h>
#include <boost/asio.hpp>
#include <cstring>
std::string getInterfaceAddress(const std::string & interfaceName)
{
ifaddrs* firstNetIf = 0;
getifaddrs(&firstNetIf);
ifaddrs* netIf = 0;
for(netIf = firstNetIf; netIf != 0; netIf = netIf->ifa_next)
{
if(netIf->ifa_addr->sa_family == AF_INET && std::strncmp(netIf->ifa_name, interfaceName.c_str(), interfaceName.length()) == 0)
{
break;
}
}
unsigned long address =
netIf != 0 ? reinterpret_cast<sockaddr_in*>(netIf->ifa_addr)->sin_addr.s_addr : 0;
if(firstNetIf != 0)
{
freeifaddrs(firstNetIf);
}
return boost::asio::ip::address_v4(htonl(address)).to_string();
}
Of course in my case i could compare with "eth1" and return the boost::asio::ip::address directly but it turns out that this code can be used at one other place as well this way.

ZeroMQs router-dealer pattern. How to handle client address?

I use the router-dealer pattern from 0MQ. Now I want to store the client's address. I know that the first message from the client is the address, IP + portno I guess. Or rather recv() from the router socket puts the address in front of a received packet. But how do I handle this address, e.g. printing out or storing it for further outgoing messages? What type is it?
Here's the Guide explanation on this: http://zguide.zeromq.org/page:all#The-Request-Reply-Mechanisms
The ROUTER manages a set of connections, and keeps an 'identity' for each connection, which is a random number, like a handle. It tells you this identity on each message, as a first frame. It's a binary value, so you can't print it as-is.
The DEALER can override the ROUTER's internal identity by telling it, "use this ID" at connection time. That's what the zmq_setsockopt ZMQ_IDENTITY option does. We use this when nodes have some unique, often string, ID that has some meaning to the application.
the first part of the message is the identity of the sender (dealer) what you can set on the dealer side, with the zmq_setsockopt function (before connecting to the router). it's a maximum 255 char long string. if you don't set it, there will be some random unique thing, starting with #0 char.
so it's not the ip+port of your dealer by default, but you can put there that info if you like.

Get socket's IP address before accepting connection C++

I need to get the IP address of a connection to see if it has already connected previously (checking against a list of ips, if it has connected previously but isnt connected anymore, it will say offline). (using nonblocking sockets)
How can I get the IP without first accepting it.
///
case FD_ACCEPT:
int W;
for(W = 0;W <= ListView_GetItemCount(GetDlgItem(HwND,IDC_IPLIST));W++){
So then im just gonna check the IP against the list view to see if it had connected before. If it has, I want to use the same socket number it was using last time.
This is how I'm accepting connections right now
case FD_ACCEPT:
while(Client[F] != NULL)
{
F++;
}
Client[F]=accept(wParam,(LPSOCKADDR)&ServAdr,&AdrLen);
break;
so to break it down...
I want to check incoming connections against an IP list of previous connections. This list will have the IP and whether its online/offline (connected/not connected). If it has connected before I want it to show Online when I accept the new connection, and use the same socket number it used last time instead of using a new one all together. If it hasn't I want it to be added to the list. (the list will have the socket number)
If this doesnt make much sense I'll try and clarify a bit more.
What you are asking for cannot be done with accept(). You do not have access to a connection's information until after it has been accepted and a new SOCKET handle allocated. To get the connection info pre-acceptance, you have to use the callback functionality of WSAAccept() instead.
Either way, there is no way to reuse an existing SOCKET handle for a new connection. Each accepted connection must have its own unique SOCKET handle. You can certainly associate the new connection from a previously-seen IP with an existing slot in your ListView, though.
If by socket number you mean the number returned by accept(), you can't rely on it's value at all. I mean, if the remote host disconnects and connects again the value returned by accept() will most probably be different. It does not make sense to rely on this number.
If by socket number you mean the position in your array, you can assign the value returned by accept() to temporary variable:
SOCKET tmpSock;
sockaddr_in tmpAddr;
int namelen;
typedef struct { /*...*/ } TClient;
TClient Client[MAX_CLIENTS];
/*...*/
tmpSock = accept(/*...*/);
namelen = sizeof(tmpAddr);
getpeername(tmpSock, (sockaddr*)&tmpAddr,&namelen);
/*...*/
//looking for tmpAddr.sin_addr in your list and calculating
//the list position - F
/*...*/
Client[F].Socket = tmpSock;
Client[F].IsConnected = true;
Client[F].Address = tmpAddr.sin_addr;
Have in mind that after the listen() call the OS kernel will accept all incoming connection to the port/local IP set by you. It means that the connect() of remote host will return successfully whether you call accept() or not (provided you have space in listen queue). Calling accept() will only allow you to interact with the socket. It will not change the connection state seen by the remote host.
I'm not sure the is possible nor an efficient specification to achieve what you want. I would either:
Accept any connection and then check the IP address, disconnecting connections which are not in the list
(This probably isn't suitable for you) Configure an upstream firewall, such that only allowed IP addresses are allowed through.
If you bind to a wildcard address (INADDR_ANY), then the IP address used for communication isn't determined until a connection comes in (it will be one from the interface the packets are passing through). The same listening socket can result in accepted connections on more than one IP address.
If you bind to a specific address, then you already know the address you bound to.

Is ->h_addr_list[0] the address I need?

I am working on implementing UpNP on C++, and I need to get the local internal IP address assigned by the router to make the sockets works. The address I need is the one that appears on routers where it shows the computers connected to the router and the local IP assigned to each computer. I am using this:
PHOSTENT Addr = NULL;
char Host[MAX_PATH];
if( gethostname(Host, sizeof(Host)) == 0 )
{
Address = gethostbyname( Host );
if( Address != NULL )
{
//*(struct in_addr *)Address->h_addr_list[0]) <- this is my address
}
}
This works fine on the computer I am testing, but that computer has only one network card, so I was wondering if maybe when a computer has more than one card or network device, Address->h_addr_list[0] may not be the one I need and it could be in another index of that array.
Will [0] always retrieve the IP assigned by the router?
(Assuming winsock here, as per previous question)
You shouldn't assume that the first address is the correct one (as there may be multiple interfaces, and more than one may be active)
I'd recommend enumerating addresses using either getaddrinfo with an empty pNodeName argument, or GetAdaptersAddresses.
Both of these return a linked lists with your system's registered addresses
... get the local internal IP address assigned by the router ...
Note that in some cases, the machine's IP address will be manually assigned, but the user will still want to use UPnP.
On Linux, it is suggested to use getaddrinfo(3) instead of gethostbyname(3), perhaps Winsocks has made a similar transition?
On Linux, it is common for /etc/hosts to have loopback entries also accessible by hostname; /etc/gai.conf can be used to configure the sort order of returned addresses, and possibly a loopback address will be returned. Does Winsock make it that easy for sysadmins to change the order of returned addresses?
Don't forget that a system may legitimately have multiple upstream routers: a laptop with an EV-DO or EDGE or similar cellular data connection and a wireless or wired Ethernet will have multiple IPs, multiple upstream routers, and the routing table will be consulted to figure out which one should be used to send each packet.
Can you use either (a) the address used by clients to contact you? (getsockname(2) will return the local address used on a specific socket.) (b) ask the user to select among the list of IP addresses, if there are several? Binding to N of M interfaces would be nice, so users can select which networks get the services and which networks are left alone.