Unable to get local host IP address from getsockname? - c++

I am able to get the port returned, but the IP is not. Should I be using something else other than getsockname? thx
if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) {
c.Format("Socket Error: %d", GetLastError());
tcpMESSAGE = 1;
break;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(4000); //port setting
server_addr.sin_addr.s_addr = INADDR_ANY;
if (::bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
c.Format("Bind Error: %d", GetLastError());
tcpMESSAGE = 1;
break;
}
if(1==1){
int len = sizeof server_addr;
if(::getsockname(sock,(struct sockaddr*)&server_addr,&len) == -1)
MessageBox("Error local host ip");
c.Format("local addr %s:%u\n errno: %d",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port), errno);
MessageBox(c);
}

You are binding to INADDR_ANY, but you have not connected the socket to a peer yet, so there is no IP for getsockname() to return. After a connection has been established via connect() or accept(), then getsockname() can return the specific IP that is being used for that connection. Binding alone is not enough, unless you bind to a specific IP, which you are not doing.

Related

LIBSSH2 C++ with dual stack IPv4 and IPv6

I am working on a C++ project that needs to establish a connection via SSH to a remote server and execute some commands and transfer files via SFTP. However, I need this application to work in dual stack mode (e.g., with IPv6 and IPv4) mode.
In the snippet below, my program initially receives an host-name, IPv6 or IPv4 address. In the IPv4 input the connection is successful. However, I am having strange problems in the IPv6 mode that I am noticing that the connection is established via socket and the SSH session fails to start.
Currently, I believe it could be something related to the inet_ntop() method. Please notice that remoteHost variable is an char* type and the remotePort is uint16_t type.
// Initialize some important variables
uint32_t hostaddr = 0, hostaddr6 = 0;
struct sockaddr_in sin = {};
struct sockaddr_in6 sinV6 = {};
int rc = 0, sock = 0, i = 0, auth_pw = 0;
// Here we will initialize our base class with username and password
this->username = usrName;
this->password = usrPassword;
// Firstly, we need to translate the hostname into an IPv4 or IPv6 address
struct addrinfo hints={}, *sAdrInfo = {};
char addrstr[100]={};
void *ptr= nullptr;
char addrParsed[50]={};
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
// Now we need to get some address info from the one supplied that remoteHost parameter
int errcode = getaddrinfo (remoteHost, nullptr, &hints, &sAdrInfo);
if (errcode != 0) {
SERVER_ERROR("[SSH] Error while getaddrinfo at SSHConnect() code %d", errno);
return -4;
}
inet_ntop(sAdrInfo->ai_family, sAdrInfo->ai_addr->sa_data, addrstr, 100);
// Here we need to determine if we are using IPv6 or IPv4
switch (sAdrInfo->ai_family) {
case AF_INET6:
ptr = &((struct sockaddr_in6 *) sAdrInfo->ai_addr)->sin6_addr;
break;
case AF_INET:
ptr = &((struct sockaddr_in *) sAdrInfo->ai_addr)->sin_addr;
break;
}
inet_ntop(sAdrInfo->ai_family, ptr, addrstr, 100);
sprintf(addrParsed, "%s", addrstr);
//This part is responsible for creating the socket and establishing the connection
// Now if we have an IPv4 based host
if (sAdrInfo->ai_family == AF_INET) {
this->hostaddr = inet_addr(addrParsed);
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
// Now we need to set these (address and port to our sockaddr_in variable sin)
sin.sin_port = htons(remotePort);
memcpy(&sin.sin_addr, &hostaddr, sizeof(hostaddr));
}
// Now if we have an IPv6 based host
else if (sAdrInfo->ai_family == AF_INET6) {
this->hostaddr6 = inet_addr(addrParsed);
sock = socket(AF_INET6, SOCK_STREAM, 0);
sin.sin_family = AF_INET6;
// Now we need to set these (address and port to our sockaddr_in variable sin)
sinV6.sin6_port = htons(remotePort);
memcpy(&sinV6.sin6_addr.s6_addr32, &hostaddr6, sizeof(this->hostaddr6));
}
// Now we need to connect to our socket :D
if (sAdrInfo->ai_family == AF_INET) {
int resCon = connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in));
if (resCon != 0){
SERVER_ERROR("[SSH] failed to connect with error code: %d!\n", errno);
return -1;
}
}
else if (sAdrInfo->ai_family == AF_INET6) {
int resCon = connect(sock, (struct sockaddr*)(&sinV6), sizeof(struct sockaddr_in6));
if (resCon != 0){
SERVER_ERROR("[SSH] failed to connect with error code: %d!\n", errno);
return -1;
}
}
// Free our result variables
freeaddrinfo(sAdrInfo);
// Create a session instance
session = libssh2_session_init();
if(!session) {
return -2;
}
/* Now to start the session. Here will trade welcome banners, exchange keys and setup crypto, compression,
* and MAC layers */
rc = libssh2_session_handshake(session, sock);
if(rc) {
SERVER_ERROR("Failure establishing SSH session: %d\n", rc);
return -3;
}
What is wrong with the implementation that is generating the "Failure establishing SSH session" message with IPv6 stack?
Best regards,

Reading from UDP socket over WiFi always timeout

I have a piece of code that send a UDP broadcast to scan for device on our local network. It works fine when im plugged via ethernet, but it doesnt when im connected via WiFi.
Is there something different to do to connect in UDP when using WiFi?
You can find the code im using below. When using WiFi, select always return 0
struct sockaddr_in addr;
//Create socket
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
perror("socket");
exit(1);
}
/* set up destination address */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(48620);
addr.sin_addr.s_addr = inet_addr("192.168.3.255");
//TRYING TO BIND, NOT WORKING
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
int a = WSAGetLastError(); //ERROR 10049
perror("bind"); //Says NO ERROR
}
//allow broadcast
int broadcast = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(broadcast)) == -1)
exit(1);
if (sendto(fd, (const char *)&request, sizeof(request), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("sendto");
exit(1);
}
do
{
FD_ZERO(&rdFs);
FD_SET(fd, &rdFs);
lTimeout.tv_sec = 1;
lTimeout.tv_usec = 000000;
lSelRet = select(fd, (fd_set*)&rdFs, NULL, NULL, &lTimeout);
if (lSelRet > 0 && FD_ISSET(fd, &rdFs))
{
addrFromSize = sizeof(addrFrom);
lResult = recvfrom(fd, bufferIn, sizeof(bufferIn), 0, (struct sockaddr *) &addrFrom, &addrFromSize);
//Treat result
}
} while (lSelRet > 0);
Note : Even using WiFi, i can estalbish a TCP connection and communicate with the device, its just the UDP broadcast that doesnt work
Note2: currently testing on windows, but I will port it to Linux after
Edit : added the SO_BROADCAST as advised by Remy
Finally got it working, it was a code issue, not a router issue.
The issue was a misuse of the bind function, I needed to use my IP and not the broadcast IP.
/* set up destination address */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(48620);
addr.sin_addr.s_addr = inet_addr("192.168.3.134"); //<== Windows : My IP, not the broadcast IP
addr.sin_addr.s_addr = INADDR_ANY; //Linux
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
perror("bind");
}
EDIT : strangely enough, in windows you must bind to the ip sending the request, and on linux you must bind to INADDR_ANY.

Writing Client and Server, UDP

I'm trying to write a simple client and server using UDP.
I can send data from the client to the server, and the server recieves it well, but when I send the data from the server to the client, it doesnt work at all...
(It doesnt detect anything, and is stuck on recvfrom function..
Here is my Server code :
SOCKET ServerOn()
{
SOCKET ListenSocket;
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
exit(0);
}
// Create a SOCKET for listening for
// incoming connection requests.
ListenSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ListenSocket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("0.0.0.0");
service.sin_port = htons(2583);
if (bind(ListenSocket,(SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR)
{
closesocket(ListenSocket);
WSACleanup();
exit(2);
}
return ListenSocket;
}
In this function, I'm initializing the server on port 2583.
Here is my other code in the server :
int size = sizeof(service);
char *data = new char[500];
recvfrom(s,data, 500, NULL, (SOCKADDR*)&service, &size); // Getting a new connection
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("10.0.0.1");
service.sin_port = htons(2583);
int addrSize = sizeof(service);
if (sendto(s, "123", 3, NULL, (struct sockaddr*)&service, addrSize) != 3)
printf("%d", WSAGetLastError()); // Print error if did not send successfully
"10.0.0.1" is the IP of the Client (I made sure it is)...
I didnt found a way to get the IP automaticly from the socket, so I'm just putting it right away for now...
Here is my client code :
SOCKET ConnectToServer()
{
//----------------------
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
return NULL;
}
//----------------------
// Create a SOCKET for connecting to server
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ConnectSocket == INVALID_SOCKET)
{
WSACleanup();
return NULL;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(Default_IP.c_str()); // IP
clientService.sin_port = htons(Default_Port); // Port
//----------------------
// Connect to server.
iResult = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService)); // Connecting
while (iResult == SOCKET_ERROR) // ERROR, could not connect. keep trying
{
iResult = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService)); // Connecting
}
return ConnectSocket;
}
In this code, I'm connecting to the client.
and here is the rest of the client code :
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("10.0.0.1");
service.sin_port = htons(2583);
s = ConnectToServer();
sendto(s, "123", 3, NULL, (struct sockaddr*)&service, addrSize);
while(true)
{
result = recvfrom(s, (char*)waveIn, NUMPTS * sizeof(short int), NULL, (struct sockaddr *)&service, &addrSize);
if (result > 0)
{
std::cout << "New Data!" << std::endl;
}
else
printf("%d\n", WSAGetLastError());
}
the sendto function in the client does work, and the server recieves it, though when the server tries to send data back to the client, it recieves nothing, and it is stuck on the recvfrom function.
What am I doing wrong?
P.S - I'm running both client and server from the same computer, which means both has the same IP adress ("10.0.0.1"), but it allways worked for me when using sockets with TCP, so I've did it here too.
though, I did try use this code with 2 different computers, and I still had the same error...
Thanks!
When the server calls recvfrom(), it reports the IP:Port that the data came from. You need to send your reply back to that same IP:Port, eg:
sockaddr_in service;
int size = sizeof(service);
char data[500];
int len = recvfrom(s, data, 500, NULL, (SOCKADDR*)&service, &size);
if (len == -1)
printf("recv failed: %d", WSAGetLastError()); // Print error if did not recv successfully
else
{
if (sendto(s, "123", 3, NULL, (struct sockaddr*)&service, size) == -1)
printf("send failed: %d", WSAGetLastError()); // Print error if did not send successfully
}

IP_ADD_MEMBERSHIP on a socket, will the socket listen to unicast also?

Considering the code below,
I'm trying to bind a UDP socket for multicast.
I've bound it to a specific port, and set IP_ADD_MEMBERSHIP for the address to listen to.
My question: will the socket receive unicast UDP packets bound for that port? If so, how can I prevent it? I wish to only receive multicast.
int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
u_int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
{
perror("Reusing ADDR failed");
exit(1);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (source_iface.empty()
? htonl(INADDR_ANY)
: inet_addr(source_iface.c_str()));
if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group.c_str());
mreq.imr_interface.s_addr = (source_iface.empty()
? htonl(INADDR_ANY)
: inet_addr(source_iface.c_str()));
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
exit(1);
}
I believe you'll also need to bind on the particular multicast address on which you want to listen, and not just in the setsockopt call - the latter also being necessary to make sure that the network card and IGMP also do the right thing.
See also What does it mean to bind a multicast (UDP) socket?
Okay, I got my instance to work so I know what the problem was. The bind() has to occur against the multicast IP address:
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (group.empty()
? htonl(INADDR_ANY) // <-- this will work here but not below
: inet_addr(group.c_str()));
if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
The difference here is group instead of source_iface. Until I changed that, it would not receive broadcasted packets at all.

c++ winsock server-client remote connection

I am trying to create a simple app that exchanges messages between two remote computers.
With the "127.0.0.1" ip it works properly, waits for the client's confirm and connects to the client, but if I try a local "192.168.0.15" or my global ip with the same port, the server connects immediately to sth without waiting for the client.
Here's part of my server code:
char ip[20] = "127.0.0.1"; int port = 19385;
SOCKET sockListen, sockConnect;
SOCKADDR_IN address;
sockConnect = socket (AF_INET, SOCK_STREAM, NULL);
address.sin_addr.s_addr = inet_addr (ip);
address.sin_family = AF_INET;
address.sin_port = htons (port);
sockListen = socket (AF_INET, SOCK_STREAM, NULL);
bind (sockListen, (SOCKADDR*)&address, AddressSize);
listen (sockListen, SOMAXCONN);
sockConnect = accept (sockListen, (SOCKADDR*)&address, &AddressSize);
...
Please suggest how to fix the problem. thx
You are not supposed to initialize your sockConnect variable with socket() before calling accept(). accept() returns a new allocated socket handle that is already connected to a client. You are leaking the socket handle that socket() allocated.
You can only bind() to an IP that belongs to a NIC of the local machine that the app is running on. You cannot bind() to an external IP.
The code you have shown is not doing any error handling at all. You need to add that, eg:
int errCode;
SOCKET sockListen = socket (AF_INET, SOCK_STREAM, NULL);
if (sockListen == INVALID_SOCKET)
{
errCode = WSAGetLastError();
// ...
}
else
{
SOCKADDR_IN address = {0};
address.sin_addr.s_addr = inet_addr (ip);
address.sin_family = AF_INET;
address.sin_port = htons (port);
if (bind (sockListen, (SOCKADDR*)&address, sizeof(address)) == SOCKET_ERROR)
{
errCode = WSAGetLastError();
// ...
}
else
{
if (listen (sockListen, SOMAXCONN) == SOCKET_ERROR)
{
errCode = WSAGetLastError();
// ...
}
else
{
int addressSize;
SOCKET sockClient = accept (sockListen, (SOCKADDR*)&address, &addressSize);
if (sockClient == INVALID_SOCKET)
{
errCode = WSAGetLastError();
// ...
}
else
{
// ...
closesocket(sockClient);
}
}
}
closesocket(sockListen);
}