When I try to bind my socket I need to specify the address family in the addrinfo/sockaddr-structure I pass in to the call to bind(), or one will get an winsock error 10047 (Address family not supported by protocol family.)
What if I created a socket elswhere not knowing its address family...
How could I get the address family for that socket, so i can bind it?
getsockname only works for bound sockets :/...
I don´t want to force the caller of my function to pass the address family to my functions, especially if she/he/it uses AF_UNSPEC/PF_UNSPEC when creating her/his socket
(e.g. SOCKET sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); )
Since I am using Winsock I did search the MSDN for a short while and found WSADuplicateSocket.
WSAPROTOCOL_INFO proto;
WSADuplicateSocket(Socket, GetCurrentProcessId(), &proto);
SocketAF = proto.iAddressFamily;
Works fine for windows machines...
Related
I'm looking at the udp client example here:
http://www.linuxhowtos.org/data/6/client_udp.c
snippet:
/* UDP client in the internet domain */
struct sockaddr_in server, from;
//...snipped
sock= socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) error("socket");
server.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
if (hp==0) error("Unknown host");
bcopy((char *)hp->h_addr,
(char *)&server.sin_addr,
hp->h_length);
server.sin_port = htons(atoi(argv[2]));
length=sizeof(struct sockaddr_in);
//... snipped
n=sendto(sock,buffer,
strlen(buffer),0,(const struct sockaddr *)&server,length);
if (n < 0) error("Sendto");
n = recvfrom(sock,buffer,256,0,(struct sockaddr *)&from, &length);
if (n < 0) error("recvfrom");
//... snipped
I'm trying to understand how it knows where to receive the message from. I know when sendto is called an available port is chosen and that is embedded in the udp message and the server application can read that and reply to it. How does the client code know to receive a message on that port?
This answer: https://stackoverflow.com/a/48245273/2748602 indicates there is kind of an implicit bind when the sendto function is called. How does it work? Is it in fact a bind with a random available port number that is as permanent as if I had called bind or something else? It seems there's some aspect of permanence. Just interested in a little more detail.
There is an implicit bind if the socket is unbound since all packets have to carry both a source port. So the API assumes that if you didn't care enough about the port to bind your socket beforehand, then it can just bind the socket to a random port. And while unfortunately I don't know the implementation details of sendto, I can offer some official documentation.
For Linux, from the udp man page:
When a UDP socket is created, its local and remote addresses are
unspecified. Datagrams can be sent immediately using sendto(2) or
sendmsg(2) with a valid destination address as an argument. When
connect(2) is called on the socket, the default destination
address is set and datagrams can now be sent using send(2) or write(2)
without specifying a destination address. It is still possible to
send to other destinations by passing an address to sendto(2) or
sendmsg(2). In order to receive packets, the socket can be bound to a
local address first by using bind(2). *Otherwise, the socket layer
will automatically assign a free local port out of the range defined
by /proc/sys/net/ipv4/ip_local_port_range and bind the socket to
INADDR_ANY.
For Windows, a snippet from the documentation for Winsock 2's sendto:
If the socket is unbound, unique values are assigned to the local
association by the system, and the socket is then marked as bound. If
the socket is connected, the getsockname function can be used to
determine the local IP address and port associated with the socket.
... there is kind of an implicit bind when the sendto function is called. How does it work? Is it in fact a bind with a random available port number that is as permanent as if I had called bind or something else?
man ip(7):
ip_local_port_range (since Linux 2.2)
This file contains two integers that define the default local
port range allocated to sockets that are not explicitly bound
to a port number—that is, the range used for ephemeral ports.
An ephemeral port is allocated to a socket in the following
circumstances:
* the port number in a socket address is specified as 0 when calling bind(2);
* listen(2) is called on a stream socket that was not previously bound;
* connect(2) was called on a socket that was not previously bound;
* sendto(2) is called on a datagram socket that was not previously bound.
I'm in the process of writing a project for college involving writing a chat client and server using POSIX sockets and C++.
The clients are supposed to converse with each other using P2P, such as each client has his own open UDP socket through which he sends and recieves messages from/to other clients.
My problem is 2-fold:
My UDPSocket class constructor seems to be ignoring the port number completely, binding to port 65535 regardless of the parameter.
The port is binding to IP 255.255.255.255 rather than my own IP (10.0.0.3), or at least that's what i get when I call getpeername.
To the best of my knowledge passing INADDR_ANY should bind to my local address, and passing port number 0 should make the OS choose a free port, what am I doing wrong?
This is the constructor of my UDPSocket class:
UDPSocket::UDPSocket(int port){
socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
// clear the s_in struct
bzero((char *) &in, sizeof(in)); /* They say you must do this */
//sets the sin address
in.sin_family = (short)AF_INET;
in.sin_addr.s_addr = htonl(INADDR_ANY); /* WILDCARD */
in.sin_port = htons((u_short)port);
fsize = sizeof(from);
//bind the socket on the specified address
if(bind(socket_fd, (struct sockaddr *)&in, sizeof(in))<0){
perror ("Error naming channel");
}
}
This is the initialization:
m_Socket = new UDPSocket(0);
And this is the method I use to retrieve the binded address: (UDPSocket inherits Socket)
std::string Socket::GetSocketAddress()
{
struct sockaddr_in addr;
int len = sizeof(addr);
getpeername(socket_fd, (struct sockaddr*)&addr, (socklen_t*)&len);
char ipAddressBuffer[50];
memset(ipAddressBuffer, 0, sizeof(ipAddressBuffer));
sprintf(ipAddressBuffer, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
return ipAddressBuffer;
}
Any help would be greatly appreciated,
Avi.
You're using getpeername , which gives you the remote address of a connected socket. If you check the return value of getpeername(), it should indicate failure.
You need to use getsockname() instead of getpeername() to get the address of your local socket
You need to check that getsockname() succeeds.
Note that your socket is bound to the special 0.0.0.0 address, which means "all local interfaces", so that's what getsockname() will also return.
Answering the more general question "How to set up peer-to-peer communications with UDP":
With UDP sockets, while you can use connect, you generally don't want to, as that restricts you to a single peer per socket. Instead, you want to use a single unconnected UDP socket in each peer with the sendto and recvfrom system calls to send and receive packets with a different address for each packet.
The sendto function takes a packet and a peer address to send it to, while the recvfrom function returns a packet and the peer address it came from. With a single socket, there's no need to multiplexing with select or poll -- you just call recvfrom to get the next packet from any source. When you get a packet, you also get the peer address to send packets (back) to.
On startup, your peer will create a single socket and bind it to INADDR_ANY (allowing it to receive packets on any interface or broadcast address on the machine) and either the specific port assigned to you program or port 0 (allowing the OS to pick any unused port). In the latter case, you'll need to use getsockname to get the port and report it to the user. Once the socket is set up, the peer program can sendto any peer it knows about, or recvfrom any peer at all (including those it does not yet know about).
So the only tricky part is bootstrapping -- getting the first packet(s) flowing so that peers can recieve them and figure out their peer addresses to talk to. One method is specifying peer addresses on the command line when you start each peer. You'll start the first one with no arguments (as it has no peers -- yet). It will just recvfrom (after socket setup) to get packets from peers. Start the second with the address of the first as an argument. It sends a packet (or several) to the first peer, which will then know about the new peer as soon as it gets the first packet. Now start a third client with the addresses of the first two on the command line...
Suppose I have a simple winsock server that has a listening socket, and then when a connection is accepted, it stores the socket in an array of sockets (to allow multiple connections).
How can I get the IP address of a specific connection? Is it stored in the socket handle?
As long, as the socket stays connected, you can get both own socket address and peer one.
getsockname will give you local name (i.e. from your side of a pipe)
getpeername will give you peer name (i.e. distant side of a pipe)
This information is available only when the socket is opened/connected, so it is good to to store it somewhere if it can be used after peer disconnects.
Yes it is stored in the socketaddr_in struct, you can extract it using:
SOCKADDR_IN client_info = {0};
int addrsize = sizeof(client_info);
// get it during the accept call
SOCKET client_sock = accept(serv, (struct sockaddr*)&client_info, &addrsize);
// or get it from the socket itself at any time
getpeername(client_sock, &client_info, sizeof(client_info));
char *ip = inet_ntoa(client_info.sin_addr);
printf("%s", ip);
I'm working on this project where the source and destination ports are specified for sending a message via a UDP socket in C++. I've got the TCP portion of the project working fine, but I don't understand how to specify both the source and destination ports when setting this up.
The way I would know how to do it is the "receiver" sets up a recvfrom() call, with the port that the "sender" will also use in the sendto() command... but it would need to be the same port.
So, given that I need port x on the "receiver" to talk to port y on the "sender", how would I do that?
Thanks
You can define a source port when you call bind on the sender side. For instance:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { /*error*/}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(source_port); // here
int res = bind(sockfd,(struct sockaddr*)&sin, sizeof(sin));
if (res < 0) { /*error*/}
And the destination port goes into the sockaddr parameter passed to sendto.
If this is one-to-one mapping, i.e. one source talks to one destination, then simply bind(2) the local port and connect(2) to the remote IP and port (contrary to common misconception you can connect UDP sockets). Do that on both sides (with appropriate remote and local IPs/ports of course), and now you can just use recv(2) and send(2) without explicit addressing.
If one side needs to wait for the other to send the first packet, then extract source address/port received with recvfrom(2), and then connect(2) to it.
If, on the other hand, one side acts as a multi-client server, then do same bind(2)/connect(2) dance on the client, but only do bind(2) to local port and then use recvfrom(2)/sendto(2) on the server.
If you need simultaneous duplex communication, then you should use sockets in blocking mode -- fcntl(...O_NONBLOCK...), and use select() to determine if your socket is writable or readable or both. Here is a nice example on how this can be done http://www.lowtek.com/sockets/select.html
I am hooking WSASend, and WSARecv in C++ using the same method I've used to hook the client's WSASend and WSARecv functions. In the client I am able to get the IP, Port, and Socket from the SOCKET structure passed by WSASend/WSARecv; however, for the server when I try to use getpeername or getsockname() they both return the error 10057 (Socket not connected)...
I'm fairly sure that the hook is correct on the server, since it prints the bytes successfully, and I'm also sure the socket SHOULD be valid seeing how client and server establish a successful connection.
Is there a way to resolve this problem by any other alternative methods? I've been looking around the internet to find a solution, but I haven't seen anyone with the same problem.
I've tried this:
sockaddr *address = new sockaddr;
int peer_len;
getpeername(s, address, &peer_len);
int err = WSAGetLastError();
if(err==0)
{
char *Str = inet_ntoa(((sockaddr_in*)address)->sin_addr);
printf("[%s", Str);
printf(":%d]",ntohs(((sockaddr_in*)address)->sin_port));
}
else
{
printf("Error %i\n",err);
}
(Using both getpeername and getsockname)Both result in the same socket not connected error.
I'm planning on using the packets the C++ dll gets and forward the information to the C# dll since it'll be easier to manage on that (for me anyways), but I'd need to distinguish each packet with it's socket id.
You can only do that on the connected socket, i.e. the one returned from the accept() call, not on the listening "server" socket.