Why is the addr variable type-converted? - c++

While surfing on the internet I've found a c++ example that sends GET-requests. The part of this code I couldn't grasp is why (see the section that's bold) the variable addr is type converted. I understand that the function only accepts a certain type. But why using a type and then converting it to another one?
#include <iostream>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
using namespace std;
int main()
{
int s, error;
struct sockaddr_in addr;
if((s = socket(AF_INET,SOCK_STREAM,0))<0)
{
cout<<"Error 01: creating socket failed!\n";
close(s);
return 1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
inet_aton("204.27.61.92",&addr.sin_addr);
error = connect(s,(sockaddr*)&addr,sizeof(addr));
if(error!=0)
{
cout<<"Error 02: conecting to server failed!\n";
close(s);
return 1;
}
char msg[] = "GET /beej/inet_ntoaman.html http/1.1\nHOST: retran.com\n\n";
char answ[1024];
//cin.getline(&msg[0],256);
send(s,msg,sizeof(msg),0);
while(recv(s,answ,1024,0)!=0)
cout<<answ<<endl;
close(s);
cin.getline(&msg[0],1);
return 0;
}

This is runtime polymorphism, C style.
sockaddr is effectively an abstract base class - it isn't specific to any concrete type of socket. However, each socket type requires type-specific information.
Since C doesn't have language support for polymorphism, the technique is to write a "derived" type which has the "base" type as it's first data member. This way they have the same address, and you can cast between them.
So, (sockaddr*)&addr is an upcast, yielding a pointer to a valid base-class subobject. When you pass this to an AF_INET socket, it will cast the pointer back to (sockaddr_in*) and recover your inet-specific data.
Equivalent C++ for reference, since it's slightly more expressive:
class SockAddr {
public:
virtual ~SockAddr();
enum Family { INET, UNIX, ... };
Family get_family() const { return family; }
protected:
explicit SockAddr(Family f) : family(f) {}
Family family;
};
class SockAddrInet: public SockAddr {
uint16_t port;
uint32_t addr;
public:
SockAddrInet(uint16_t port, uint32_t addr)
: SockAddr(SockAddr::INET), port(htons(port)), addr(addr)
{}
};
class SockAddrUnix: public SockAddr {
std::string path;
public:
explicit SockAddrInet(std::string path)
: SockAddr(SockAddr::UNIX), path(path) {}
};
void connect(Socket &s, SockAddr const &addr) {
switch (addr.get_family()) {
case SockAddr::INET:
connect_inet(s, dynamic_cast<SockAddrInet const&>(addr));
break;
case SockAddr::UNIX:
connect_unix(s, dynamic_cast<SockAddrUnix const&>(addr));
break;
}
}

It's a technique to have "subtypes" in C. There are various other sockaddr types (e.g. sockaddr_in6 for IPv6). The called function inspects the sin_family field to determine which kind of struct was passed in and handle it accordingly.

struct sockaddr {
u_short sa_family;
char sa_data[14];
};
We have to remember that the socket APIs can work with many different network protocols. Each protocol has a completely different format for how addresses work. This sockaddr structure is, therefore, a generic structure. It contains a place to put the identifying address family, along with a generic "data" field that the address can be placed in, regardless of the format of the address.
There is however the sockaddr_in structure:
struct sockaddr_in { /* socket address (internet) */
short sin_family; /* address family (AF_INET) */
u_short sin_port; /* port number */
struct in_addr sin_addr; /* IP address */
char sin_zero[8]; /* reserved - must be 0x00's */
};
which is designed specially for networking, IP address. This type can be safely type casted to sockaddr* because it is aligned to it.
This is what Richard Stevens says about it in his "UNIX Network Programming":
Generic Socket Address Structure
A socket address structures is always passed by reference when passed as an argument to
any socket functions. But any socket function that takes one of these pointers as an
argument must deal with socket address structures from any of the supported protocol
families.
A problem arises in how to declare the type of pointer that is passed. With ANSI C, the
solution is simple: void * is the generic pointer type. But, the socket functions predate ANSI C and the solution chosen in 1982 was to define a generic socket address structure in the <sys/socket.h> header (...)
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family; /* address family: AF_xxx value */
char sa_data[14]; /* protocol-specific address */
};
The socket functions are then defined as taking a pointer to the generic socket address
structure, as shown here in the ANSI C function prototype for the bind function:
int bind(int, struct sockaddr *, socklen_t);
This requires that any calls to these functions must cast the pointer to the protocol-specific socket address structure to be a pointer to a generic socket address structure. (...)
From the kernel's perspective, another reason for using pointers to generic socket address
structures as arguments is that the kernel must take the caller's pointer, cast it to a struct sockaddr *, and then look at the value of sa_family to determine the type of the structure.
But from an application programmer's perspective, it would be simpler if the pointer type was void *, omitting the need for the explicit cast.

Returning to the windows's connect function ::connect
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx
It requires sockaddr as a parameter type

Related

LWIP -- using option `SO_BINDTODEVICE` with `lwip_setsockopt()` returns error `ENODEV`

With LWIP, I usually set up my ethernet interface on my embedded device like this (not all argument definitions are specified here):
struct netif gnetif;
// Set up the ethernet interface on embedded device.
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
// Registers the default network interface.
netif_set_default(&gnetif);
// Make ethernet interface work.
if(netif_is_link_up(&gnetif)){
netif_set_up(&gnetif);
}
else{
netif_set_down(&gnetif);
}
When the interface is set up, I want to bind it to the device using this call to setsockopt():
lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
where:
s is my socket descriptor,
level is set to SOL_SOCKET,
optname is set to SO_BINDTODEVICE,
optval is a pointer to ifreq structure,
optlen is size of the ifreq structure (previous bullet).
This call successfully enters this switch statement and successfully interprets the SOL_SOCKET level and SO_BINDTODEVICE option to end up here.
But for some reason this call to netif_find() sets n to 0 and then I get an error ENODEV which means that there is no device. This is weird, because gnetif.name returns st and also optval which is ifreq structure has only one member ifr_name which looks like this in the debugger (just before the call):
So what am I doing wrong that I get the ENDOV error?

Convert IPv6 to IPv4 format in c++?

I am maintaining an old system which runs fine on IPv4 format and i found out that the listener did not trigger when the requestor is coming from IPv6. I have the following line of code
SOCKADDR_IN SocketAddr;
INT nBufferSize=sizeof(SocketAddr);
hConnectSocket=WSAAccept(m_hListenSocket,(SOCKADDR *)&SocketAddr,&nBufferSize,NULL,NULL);
if (hConnectSocket==INVALID_SOCKET) return false;
I also googled and i know i should be using SOCKADDR_IN6 for IPv6. Is it possible to convert SOCKADDR_IN6 to SOCKADDR_IN format so that the rest of the application will work?
Thanks.
You can't convert all IPv6 addresses to IPv4 - there are more IPv6 addresses than IPv4 addresses. The best way to tackle this issue is to update/upgrade your application so it understand and store IPv6 addresses. This thread might be useful.
I implemented some time ago a solution that can work with IPV4 and IPV6 addresses. I did even encapsulate that property from the outside world.
The rest of the program should only know about sockets. And if your code accepts an address in the IPV6 or IPV4 format does not really matter /after accepting).
The important point is that you need to specify the ai_family with AF_UNSPEC. Then it will handle both address families. And for the accept function, you can handover a parameter big enough to hold both address types.
I am not sure, but maybe that could help you.
Please see the following code snippet that I developed some years ago in C++98.
// The following structures are used in order to be independent from the internet address families
// e.g. IPV4 or IPV6. The basic original functions have been designed for IPV4 only.
// But now we are in the age of IPV6. And we need to have means to deal with both address types
// So we have one Data type, that can hold both IPV4 and IPV6 (because it has the length of the
// larger IPV6 address). The pointer of this structure can be casted to the original data type
// that the functions always expected.
// The first field in the structures denotes the IP Address Family
// This is the big storage that can hold either a IPV4 or a IPV6 address
typedef struct sockaddr_storage SocketAddressStorage;
// This Type can hold the length of the IP Address container
typedef socklen_t SocketAddressStorageLength;
// This type is the Socket Address that OS function expect. We will cast the pointer of the big
// data type to this one
typedef struct sockaddr SocketAddress;
// The next 2 are specific address containers for either IPV4 or IPV6.
// One of them will be a part of the big "struct sockaddr_storage"
typedef struct sockaddr_in SocketAddressInternetIPV4;
typedef struct sockaddr_in6 SocketAddressInternetIPV6;
// We use the big structure that can hold an IPV4 and IPV6 address
// because we do not know, who is contacting this node
SocketAddressStorage addressOfCommunicationPartner;
// Get the length of the above define data structure
SocketAddressStorageLength socketAddressStorageLength = sizeof(addressOfCommunicationPartner);
// Accept the connection request from a client
// handle is the filedescriptor bound to this node and listening for connection requests
// The function will return a new file descriptor for the connected socket. This is a specific socket
// for the just established connection. The handle will continue to listen for more connection requests
// So this is a factory. We are listening for connection requests and if we get one, we create a new
// file descriptor for the specific communication purposes
// The information of the foreign node will be put in the "addressOfCommunicationPartner"
// Accept the connection request from a client
//lint -e{740,929,1924}
const Handle connectionHandle = accept(handle, reinterpret_cast<SocketAddress *>(&addressOfCommunicationPartner), &socketAddressStorageLength);
// Check, if connection could be established and we have a valid file descriptor
if (connectionHandle > null<Handle>())
{
// Now we want to get the IP address of the partner. Can be IPv4 or IPv6
// The following old style C String can hold both IPv4 and IPv6 address strings
mchar ipAddressCString[INET6_ADDRSTRLEN+1];
// This is a pointer into the address structure of the communication partner
// It points either to sin_addr for IPv4 or sin6_addr for IPv6
const void *ipAddressPEitherV4orV6;
// This will contain the IP Version as a string
std::string ipVersion;
// Now check, what family, what type of IP adress we have
//lint -e{911,1960}
if (AF_INET == addressOfCommunicationPartner.ss_family)
{
// So, it is IPv4. Remember that
ipVersion = "IPv4";
// Get a pointer to the appropriate element of the struct, which contains IP address info. And this depending on the IP Family/Type
//lint --e{740,925,929} Yes indeed, an unusual pointer cast
ipAddressPEitherV4orV6 = static_cast<const void *>( &((reinterpret_cast<const SocketAddressInternetIPV4 *const>(&addressOfCommunicationPartner))->sin_addr) );
}
else
{
// It is IPv6. Remember that
ipVersion = "IPv6";
// Get a pointer to the appropriate element of the struct, which contains IP address info. And this depending on the IP Family/Type
//lint --e{740,925,929} Yes indeed, an unusual pointer cast
ipAddressPEitherV4orV6 = static_cast<const void *>( &((reinterpret_cast<const SocketAddressInternetIPV6 *const>(&addressOfCommunicationPartner))->sin6_addr) );
}
// Convert native IP address format to readable C-String
//lint -e{917,1960}
if (null<mchar *>() == inet_ntop(addressOfCommunicationPartner.ss_family, ipAddressPEitherV4orV6, ipAddressCString, sizeof(ipAddressCString)))
{
// If this did not work then we will not show any IP Address. We can live with that
ipAddressCString[0] = '\x0';
}
// Debug Output
{
static long i=1;
ui << "Connection accepted " << i << " " << ipVersion << " " << ipAddressCString << " " << machineNetworkAddressInfo.portNumberString << std::endl;
i++;
}
// So. The connection request was established. We gathered all information
// Create a new TCP connection
TcpConnectionBase *tcpConnectionBase =tcpConnectionFactory->createInstance(machineNetworkAddressInfo.portNumberString, connectionHandle);
// And put a pointer to it in our internal list of Tcp Connection
tcpConnection.push_back(tcpConnectionBase);
You may find the rest here

How do I replicate a C++ cast of Windows SOCKADDR_BTH to a SOCKADDR in Rust?

I am writing a Bluetooth utility on Windows in Rust, using winsock2 (but happy to use any other libraries) and have hit a roadblock. The following C++ sample from the Windows Bluetooth Connection Sample is what I am using as a reference:.
SOCKADDR_BTH SockAddrBthServer;
# code to set SockAddrBthServer vals in here
connect(LocalSocket, (struct sockaddr *) &SockAddrBthServer, sizeof(SOCKADDR_BTH));
The structs are defined like so:
typedef struct _SOCKADDR_BTH
{
USHORT addressFamily; // Always AF_BTH
BTH_ADDR btAddr; // Bluetooth device address
GUID serviceClassId; // [OPTIONAL] system will query SDP for port
ULONG port; // RFCOMM channel or L2CAP PSM
} SOCKADDR_BTH, *PSOCKADDR_BTH;
typedef struct sockaddr {
#if (_WIN32_WINNT < 0x0600)
u_short sa_family;
#else
ADDRESS_FAMILY sa_family; // Address family.
#endif //(_WIN32_WINNT < 0x0600)
CHAR sa_data[14]; // Up to 14 bytes of direct address.
} SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;
How do I replicate the (struct sockaddr *) &SockAddrBthServer cast from the connect line above in Rust? So far, I'm making use of the winapi, user32 and ws2_32 crates.
Here is the Rust version of the connect function from the ws2_32 crate.
pub unsafe extern "system" fn connect(s: SOCKET, name: *const SOCKADDR, namelen: c_int) -> c_int
You are overthinking the problem. If Windows says it's cool to cast a SOCKADDR_BTH pointer to a SOCKADDR pointer, then just do that. In Rust, you have to add one extra cast to leave the safe world of references and get to a raw pointer, then you can cast that to whatever you want:
use std::mem;
struct SomeErrorType;
fn example(LocalSocket: SOCKET) -> Result<SOCKADDR_BTH, SomeErrorType> {
unsafe {
let SockAddrBthServer: SOCKADDR_BTH = mem::uninitialized();
let retval = connect(
LocalSocket,
&SockAddrBthServer as *const SOCKADDR_BTH as *const SOCKADDR,
mem::size_of::<SOCKADDR_BTH>() as i32,
);
// PERFORM REAL ERROR CHECKING HERE
if retval == 42 {
Ok(SockAddrBthServer)
} else {
Err(SomeErrorType)
}
}
}
(Untested because I don't have a Windows machine handy)
Under the hood, this will only work as long as the initial members of SOCKADDR_BTH exactly match the members of SOCKADDR.

C++ socket client / server simple message sender

I'm new in the socket concept , when I tried to folow the tutorial , I can't folow this step
Tutorial :
sockaddr_in ip;
ip.sin_family = AF_INET;
ip.sin_port = htons(99999);
ip.sin_addr.s_addr = inet_addr("10.0.0.2");
The problem is I can't folow the ip.sin_addr.saddr , when I type in :
ip.sin.addr. the only member this one have is s_un , what am I suppose to do ?
ip.sin_addr is an in_addr struct. Depending on the platform you are coding for, in_addr has different members available. For instance, on Linux, it has a single member:
struct in_addr {
uint32_t s_addr;
};
Whereas on Windows, it has a union of three members:
struct in_addr {
union {
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
} S_un_b;
struct {
unsigned short s_w1,
s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
};
And then a precompiler #define macro maps s_addr to S_un.S_addr.
So, you can always use ip.sin_addr.s_addr in your code on all platforms, but it might resolve to different data members behind the scenes.

WSAEFAULT error when use getsockname function

I have a problem using getsockname function. I have this code:
struct sockaddr sa;
int sa_len;
sa_len = sizeof(sa);
if (getsockname(socketfd, &sa, &sa_len) != SOCKET_ERROR)
{
///
}
else
{
int error = WSAGetLastError();
//error here WSAEFAULT always
}
As you can see, i always have error when use getsockname function. Error - WSAEFAULT. But why? structure and structure size are right, why this happens?
WSAEFAULT desc:
The name or the namelen parameter is not a valid part of the user
address space, or the namelen parameter is too small.
p.s. Application is 64 bit
Thanks!
Your struct sockaddr is too small to accept the socket address. Either use an appropriately sized struct, such as struct sockaddr_in, or better yet, use a struct sockaddr_storage, which is guaranteed to be large enough to contain the address. Using a sockaddr_storage also allows you to easily support both IPv4 and IPv6 with minimal adjustments.
Edited code:
struct sockaddr_storage sa;
int sa_len;
sa_len = sizeof(sa);
if (getsockname(socketfd, (struct sockaddr *)&sa, &sa_len) != SOCKET_ERROR)
Instead of general struct sockaddr use the one specified for your protocol i.e. *struct sockaddr_in* for IPv4 address. See here for a complete example.