How to find a socket's local port number? (Windows C++) - c++

I'm new to Windows networking, and I am trying to find out which PORT number my socket is bound to (C++, Windows 7, Visual Studio 2010 Professional). It is a UDP socket, and from what I understand, using the following initial setup should bind it to a random available port/address:
sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = 0; //randomly selected port
int result = bind(clientSock, (sockaddr*)&local, sizeof(local));
//result is always 0
As far as using this method, it works for sending data or binding it to a specific port (replacing the 0 with a desired port number). What I need is to bind it randomly, and then find out which port it was bound to afterwards. Is there any way I can do this? It seems that the "local" struct contains "0.0.0.0" as the IP address and "0" as the PORT number.
Thanks for any and all help! I appreciate it.

Use getsockname. For example:
struct sockaddr_in sin;
int addrlen = sizeof(sin);
if(getsockname(clientSock, (struct sockaddr *)&sin, &addrlen) == 0 &&
sin.sin_family == AF_INET &&
addrlen == sizeof(sin))
{
int local_port = ntohs(sin.sin_port);
}
else
; // handle error
This also works for *nix-based systems, but note that some systems define the third argument of getsockname to be of type socklen_t* instead of int*, so you might get warnings about pointers differing in signedness if you're writing cross-platform code.

Related

Cannot Bind Socket to Port in Both IPv4 and IPv6

I am new to socket programming, and was working on some scratch code to get a better feel for it, when I hit a snag. Any guidance on what I am doing wrong would be much appreciated!
I am trying to write a simple program that binds and listens on a user specified port and sends a "Hello" message to any connection. For kicks, I figured I would just listen on the same port for all IPv4 and IPv6 addresses. Here is a code snippet:
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ( getaddrinfo(NULL, argv[1], &hints, &res) != 0 ) {
printf("getaddrinfo failed!\n");
return 1;
}
for ( addrinfo* p = res; p != NULL; p = p->ai_next ) {
inet_ntop(p->ai_family, get_addr_ptr(p->ai_addr), ipstr, sizeof ipstr);
printf("Found IP: %s\n",ipstr);
printf("\tGetting socket...\t");
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if ( sockfd == -1 ) {
perror("\t\tError");
continue;
}
printf("OK\n");
printf("\tBind Socket to Port...\t");
if ( bind(sockfd, p->ai_addr, p->ai_addrlen) == -1 ) {
perror("\t\tError");
close(sockfd);
continue;
}
printf("OK\n");
printf("\tListen on socket...\t");
if ( listen(sockfd, BACKLOG) == -1 ){
perror("\t\tError");
continue;
}
printf("OK\n");
}
freeaddrinfo(res);
while (1) {/* accept connections */}
When I run the code, I get this output:
$ ./simpleServer 8080
Found IP: 0.0.0.0
Getting socket... OK
Bind Socket to Port... OK
Listen on socket... OK
Found IP: ::
Getting socket... OK
Bind Socket to Port...
Error: Address already in use
However, if I look at netstat when the program is running, I don't see any conflicting port tied to ::, or any other IPv6 address for that matter.
I played a little bit more with this, and found that I can bind to the port with just IPv4 or just IPv6, but not both, which I don't understand. I have created two socket, with the following ai_addr's:
Family: AF_INET Address Info: 0.0.0.0:8008
Family: AF_INET6 Address Info: :::8080
I feel like I am probably missing something fundamental, but I cant see it.
Thanks!
The problem you're facing is probably that you're using Dual-Stack mode.
At least on Linux (Others have it often disabled e.g. FreeBSD) specifying
:: as address yields in binding to * as netstat or ss would put it.
This means, it accepts both IPv6 and IPv4 Addresses.
Though the IPv4 ones get mapped to ::ffff:<your normal ipv4 address>.
So I'm guessing the same problem occurred to you.
You could use IPV6_V6ONLY socket option if af_family == AF_INET6 to not allow this behaviour.
IPV6_V6ONLY (since Linux 2.4.21 and 2.6)
If this flag is set to true (nonzero), then the socket is restricted to sending and receiving IPv6 packets only. In this case, an IPv4 and an IPv6 application can bind to a single port at the same time.
If this flag is set to false (zero), then the socket can be used to send and receive packets to and from an IPv6 address or an IPv4-mapped IPv6 address.
The argument is a pointer to a boolean value in an integer.
The default value for this flag is defined by the contents of the file /proc/sys/net/ipv6/bindv6only. The default value for that file is 0 (false).
Taken from man 7 ipv6
Please note that you're overriding your previously created/binded/listened socket.
Also use gai_strerror to get a meaningful error from the return value
of getaddrinfo.

C++ bind UDP Socket Address Family not suppoerted

Running a Linux system on a PowerPC Architecture which is connected via Ethernet to another Device obtaining a UDP connection (Package Based),
I try to setup a socket and bind it to my Port 8813. But whenever I enter a Port different from 0, Binding fails.
Here is the code:
int connector::initUDPSocket(){
struct hostent *server;
//Construct Socket
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}
;
sockaddr_in socketaddress;
socklen_t addrlen = sizeof(struct sockaddr_in); /* length of addresses */
udpsocket=socket(AF_INET,SOCK_DGRAM ,0);
if(udpsocket<=0)
{
printf("No Socket opened!");
return 1;
}
else
{
printf("ONE Socket opened!");
memset((char *) &socketaddress,0, sizeof(socketaddress));
socketaddress.sin_family = AF_INET;
socketaddress.sin_addr.s_addr=htonl(inet_addr("192.168.0.10"));//<=That's the external devices address;// htonl(inet_addr("192.168.0.1"));//<=That's my devices address;//htonl(INADDR_ANY);//INADDR_ANY;//
socketaddress.sin_port = htons(8813);//8813;//htonl(8813);//htons(0); //<=Only the last one works
int bind_result=bind(udpsocket,(struct sockaddr *)&socketaddress,sizeof(socketaddress));
if( bind_result == SOCKET_ERROR)
{
printf(LFL_CRI,"BIND failed! Error: %s",strerror(errno)); //Returns "BIND failed! Error: Address family not supported by protocol"
}
else
{
printf(LFL_CRI,"BIND worked!");
//Nun den Listener für den DatenStream aufsetzen.
char SockAddrBuffer[sizeof(struct sockaddr_storage)];
socklen_t SockAddrBufferSize = sizeof(SockAddrBuffer);
int numofbytes=recvfrom(udpsocket, udp_buffer, UDP_BUFFERSIZE, 0, (struct sockaddr *)SockAddrBuffer, &SockAddrBufferSize);
if (numofbytes >0)
{
printf("%i bytes received",numofbytes);
}
}
}
return 0;
}
}
What I found out so far:
Ping 192.168.0.10 is possible
Data seem not to be blocked by the firewall; iptables -nvL mentioned no dropped packages. I added a new rule for that, before this rule was applied, the number or dropped packages increased when the external device was connected.
Using a test tool on my Windows PC (simply debugging, if there's incoming traffic on a port; connecting the external device to it), I receive data; so, the external device definitely sends data
Binding to Port 0 works; the netstat -au mentions a tool listening on port 2, while the program is running
Error Message: BIND failed! Error: Address family not supported by protocol
So, 2 questions are open here:
What am I doing wrong?
What am I understanding wrong about "bind". What sense does it make to listen to "some random port assigned to my program by the system"? I mean, if I setup an http-Server, I want to listen to Port 80 and not to port "RANDOM". What is this good for?
You've redefined struct sockaddr_in in your code. If is in any way different from how the system defines it, any code that attempts to use this struct will not work properly.
You need to #include <netinet/in.h> to get the proper definition of this struct.

sendto() sends from the wrong source port

I'm currently working on a networking assignment. We intended the client to automatically get assigned an IP and port to a TCP socket, and bind an UDP socket to the same address and port as the TCP socket. This way, both UDP and TCP share the same IP and port.
I've checked several questions here and all of them seem to state that the source port depends on the address you specify on binding the socket, however, this doesn't seem to work.
This is the code on my client, where I bind the UDP socket:
sockaddr_in udpAddress;
udpAddress.sin_family = AF_INET;
udpAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
udpAddress.sin_port = htons(27015);
bind(udpSocket, (sockaddr*)&udpAddress, sizeof(udpAddress));
printf("[UDP] Bound to port %d\n", ntohs(udpAddress.sin_port));
printf("Error when binding: %d\n", WSAGetLastError());
char buffer[32];
sprintf(buffer, "TEST\n");
sendto(udpSocket, buffer, 7, 0, (sockaddr*)&serverAddress, sizeof(serverAddress));
When running the application, this prints the following:
[UDP] Bound to port 27015
Error when binding: 0
Error 0 implies that there is no error, so this should be fine.
However, when I check on the server console, I see the following print:
[UDP] 127.0.0.1:64910
Which is generated by the following code:
#if PLATFORM == PLATFORM_WINDOWS
typedef int socklen_t;
#endif
sockaddr_in from;
socklen_t fromLength = sizeof(from);
short messageSize = recvfrom(udpSocket, (char*)udpBuffer, udpBufferSize, 0, (sockaddr*)&from, &fromLength);
if (messageSize > 0)
{
unsigned int from_address = ntohl(from.sin_addr.s_addr);
unsigned int from_port = ntohs(from.sin_port);
printf("[UDP] %d.%d.%d.%d:%d\n", from_address >> 24, from_address >> 16 & 0xff, from_address >> 8 & 0xff, from_address & 0xff, from_port);
}
I really wonder why this port is invalid. Does anyone know what I'm doing wrong?
Also worth saying, it seems like every time I restart my application, the port increments, so I'm not even sure if this is my own fault. If I send a packet to the server using the program PacketSender, the port reported on the server is the same port reported by the program, but this port is assigned automatically, not chosen.
I have found the solution to my problem. When I tried to check for the return value of bind(), I kept getting prompted with an error. It turns out that for whatever reason, I was in the std namespace without explicitly stating this anywhere in my own code. After changing bind() to ::bind(), I was able to catch the return value and bind() did what I expected.

Function connect() return zero regardless whether it succeeded to connect or not

When I use connect() function on i7 computer it always returns zero regardless whether it succeeded to connect or not. I just don't have another application to connect to and it returns zero anyway (server's address 127.0.0.1).
When I run the same application on different computer it behaves correctly. So, what could be problem?
Thank you.
Edit Move from Answer below.
Code
struct hostent* pHostEntry;
pHostEntry = gethostbyname(host);
if(pHostEntry == NULL)
{
return 0;
}
struct in_addr* host_addr = (struct in_addr*) * pHostEntry->h_addr_list;
if(host_addr == NULL)
{
return 0;
}
long sockfd;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return 0;
}
memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = *host_addr;
serv_addr.sin_port = htons(port);
if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
{
CloseSocket();
sockfd = -1;
return 0;
}
Here it is. Here I always have zero. I, of course checked whether any other application listens om the same port. There is no one. Moreover, if I had one then I couldn't work if my server is on. But when my server is on I don't have any conflicts. i7 -> Intel(R( Core(TM) i7 CPU 930 # 2,80GHz 2.80 GHz I use this code for a while now. I have several computers with different OS and chips. Only this on (with OS Windows 7) has such a problem. I just wondering if someone has faced the same problem. Thank you
It's entirely possible that Windows 7 is returning an IP6 address for the remote server. I suggest you check the value of pHostEntry->h_addrtype.
This line is wrong:
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
On Unix, that works, because valid file descriptors tend to be small non-negative numbers. But according to the documentation for socket, -1 is the only error return code. Other negative numbers are not errors.
Now you're trying to run this code on Windows, and the assumption that descriptors are small non-negative numbers breaks.
The Windows documentation is very clear. socket returns INVALID_SOCKET in case of error, all other values indicate success.

Double UDP socket binding in Linux

In C++, when I run (red alert! pseudo-code)
bind(s1, <local address:port1234>)
bind(s2, <local address:port1234>)
on two different UDP sockets (s1 and s2 each created with a call to socket()) I get problems. In Linux (Ubuntu), the double binding seems to be fine. In Windows, however, the double binding fails, and the call to bind() the second time for the same address returns != 0.
I want to get the behavior I have on Windows on my Linux machine. Are there some settings I can work to get a "port busy" on Linux?
Please see bind and setsockopt. Unless you have invoked setsockopt with SO_REUSEADDR, then your invocation of bind with the same address should result in failure with EADDRINUSE.
That's not the behaviour I get on Linux. When I run the following test program, the second bind call fails with EADDRINUSE:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main()
{
int s1, s2;
struct sockaddr_in sa = {
.sin_family = AF_INET,
.sin_port = 0x5555,
.sin_addr.s_addr = INADDR_ANY };
s1 = socket(PF_INET, SOCK_DGRAM, 0);
s2 = socket(PF_INET, SOCK_DGRAM, 0);
if (bind(s1, (struct sockaddr *)&sa, sizeof sa) < 0)
perror("bind 1");
if (bind(s2, (struct sockaddr *)&sa, sizeof sa) < 0)
perror("bind 2");
return 0;
}
Are you sure about that? According to man 7 ip on my Linux box (fedora 9):
When a process wants to receive new incoming packets or connections, it should bind a socket to a local interface address using bind(2). Only one IP socket may be bound to any given local (address, port) pair.
There is no mention of an exception for UDP binding in either man 7 ip or man 7 udp. (This does not prove anything, but non-documented behaviour in something as basic as this is ... surprising.)