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.
Related
i am working on a chat.
i can start my server and client on the same computer using the 127.0.0.1 ip address and can talk fine, but if I try using my own IP address in the client to connect to the server, it does not connect. If someone else also tries to do it, it doesn't work
i have portforwarded in my router like this:
external host: my ip
internal host: my internal ip i got with ipconfig (192.168.1.4)
internal port: 54444
external port: 54444
even then, I think I should still be able to connect to my IP address without a portforward since the server is hosted on 127.0.0.1/localhost, right?
this is my client code:
WSADATA wsa;
if (!WSAStartup(MAKEWORD(2, 2), &wsa))
{
printf("started server\n");
SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sock)
{
printf("created listen socket\n");
sockaddr_in addr;
addr.sin_family = AF_INET;
inet_pton(AF_INET, "92.83.235.216", &addr.sin_addr);
addr.sin_port = htons(54444);
if (!connect(listen_sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))
{
printf("connected to server\n");
char buffer[2048];
char input[2048];
for(;;)
{
printf("message: ");
scanf_s("%s", input);
if (send(listen_sock, input, strlen(input) + 1, 0))
{
printf("\nsent message \"%s\"", input);
}
memset(input, 0, sizeof(input));
printf("\n");
}
}
}
}
printf("%d\n", WSAGetLastError());
WSACleanup();
it stops after it shows "creating listen socket", right at the connect() call
Any ideas?
EDIT: server code is very jumbled because of me making it into a class to make it easier to use + adding a thread to handle multiple connections, but like I said it does work internall
only thing different in the server code besides the listen and accept calls is these rules i added:
char opt_val = 1;
setsockopt(this->m_listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));
setsockopt(this->m_listen_sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, sizeof(opt_val));
What you're describing sounds like your SYN packets are being dropped (SYN... no SYN/ACK or RST). You can use wireshark to see what is happening with the actual tcp connection (filter on port).
You might want to eliminate the server as a source of error by listening on localhost and connecting that way. You can verify it is listening on the correct address and port using netstat.
Otherwise, it would help if you posted your server code.
I have a short program to send UDP data to a local socket like so.
const char *i = "localhost";
const char *p = "8980";
struct addrinfo h;
struct addrinfo *res = 0;
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
if (getaddrinfo(i, p, &hints, &res) != 0)
{
printf("ERROR: getaddinfo\n");
}
int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd == -1)
{
printf("ERROR: socket\n");
freeaddrinfo(res);
}
if (sendto(fd, "hello", 5, 0, res->ai_addr, res->ai_addrlen) == -1)
{
printf("ERROR: Sending\n");
}
freeaddrinfo(res);
close(fd);
I have launched ncat in a different terminal window with ncat -ul localhost 8980 and I can see "hello" on it when I subsequently launch the above program. I can also perform repeated calls to sendto and see hello multiple times. The program terminates but I cannot see an additional "hello" message on ncat when I relaunch the sending program. Why is this?
I've also tried not calling close at the end of the program as well.
The issue is that every time you run your program it will send its data from a different port, and thus be seen as a different network endpoint. When ncat
first receives a packet, it will bind to the remote endpoint and stop listening for packets coming from any other endpoint.
You can work around this with ncat by using the -k option. Sadly, ncat's -k option can only be used with the -e or -c options when doing UDP. You can make it work with:
ncat -ulkc "cat > $(tty)" localhost 8980
It will still bind to each remote endpoint it gets anything from though, so there's a limit to the number of times it will work (default 100, configurable via the -m option).
It's a bit easier if you use nc instead. It's -k option works normally with -u:
nc -ulk localhost 8980
That will prevent nc from binding to the remote endpoint at all, so it doesn't have the same limit as ncat.
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.
I'm programming a server/client system using winsock2 and it works great when I connect the client to the server name or the server IPv6 address. However, when I use the server IPv4 address I get error "Connection refused" from the call to connect() in the client.
This error occurs with either my client or using telnet. However, I can successfully ping the server using either of the three name, IPv4 or IPv6.
I've tried this running both server and client on the same machine, on separate machines, and firewalls deactivated on all machines.
Here is an excerpt of my server initialization and listening code:
SOCKET sockfd = INVALID_SOCKET, in_socketID;
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
struct addrinfo *ip;
sockaddr_storage incoming_addr;
int addr_size;
int tmp_err;
const char *sPort = "20152";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
tmp_err = getaddrinfo(NULL, sPort, &hints, &servinfo);
if (tmp_err != 0)
throw exception("ERROR: getaddrinfo failed");
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL && sockfd == INVALID_SOCKET; p = p->ai_next)
{
ip = p;
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == INVALID_SOCKET)
{
cerr << "ERROR on socket(): " << WSAGetLastError() << endl;
} // end if
else if (bind(sockfd, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
{
cerr << "ERROR on bind(): " << WSAGetLastError() << endl;
closesocket(sockfd);
sockfd = INVALID_SOCKET;
} // end if
} // end for
if (sockfd == INVALID_SOCKET)
{
// looped off the end of the list with no successful bind
throw exception("ERROR: Failed to bind socket");
}
// clean up
if (servinfo)
freeaddrinfo(servinfo);
if (listen(sockfd, SOMAXCONN ) == SOCKET_ERROR)
throw exception("Listen failed");
while (true)
{
memset(&incoming_addr, 0, sizeof(incoming_addr));
addr_size = sizeof(incoming_addr);
in_socketID = accept(socketID, (sockaddr *)&incoming_addr, &addr_size);
// do stuff with incoming connection
}
This is my client code:
int sockfd = INVALID_SOCKET;
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
struct addrinfo *ip;
int tmp_err;
const char *sHost = "192.168.1.136";
const char *sPort = "20152";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // use TCP
tmp_err = getaddrinfo(sHost, // web address or ip to connect to
sPort, // port or protocol
&hints, // initialized hints structure
&servinfo); // return structure
if (tmp_err != 0)
throw exception("ERROR: getaddrinfo failed");
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL && sockfd == INVALID_SOCKET; p = p->ai_next)
{
ip = p;
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == INVALID_SOCKET)
{
cerr << "ERROR on socket(): " << WSAGetLastError() << endl;
//continue;
} // end if
else if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0)
{
cerr << "ERROR on connect(): " << WSAGetLastError() << endl;
closesocket(sockfd);
sockfd = INVALID_SOCKET;
//continue;
} // end if
} // end for
if (sockfd == INVALID_SOCKET)
throw exception("ERROR: Failed to connect");
// clean up
if (servinfo)
freeaddrinfo(servinfo);
// do stuff with new socket
I already read several similar questions in the site, but none answered this issue.
How can I connect also to the server IPv4 address? I need help, please.
Thanks.
EDIT:
From a suggestion given by user Sorayuki, I made some changes just to test if his theory was correct.
I was able to connect to the IPv4 by changing on the server
hints.ai_family = AF_UNSPEC;
to
hints.ai_family = AF_INET;
I knew it would obviously work, but when I do this, of course IPv6 doesn't work.
It appears user Sorayuki was right and my loop was connecting to IPv6.
It seems that there is no easy way to unify IPv6 and IPv4. Your socket must listen to either one or the other which makes the process really annoying.
According to the documentation, the old style to listen to both IPv4 and IPv6 is to create a socket for each and listen on both. This is for Windows Server 2003 and Windows XP SP1.
The preferred modern style (Windows Vista, 7 and 8) is to turn your socket into a dual socket and it will listen to both IPv4 and IPv6. However, your client must also be able to set up a dual socket, so, if your application is serving an old client, you are stuck with the old method.
Thanks!
This is because binding to an IPv6 address does not magically bind to an IPv4 address as well.
On Linux, by default binding to [::] will cause IPv6 and IPv4 to work (unless /proc/sys/net/ipv6/bindv6only is set to 1).
However, on Mac OS X and Windows, binding to [::] will only work for IPv6. You must also bind to an IPv4 address (or 0.0.0.0) for it to work.
Your logic described in your comment "loop through all the results and bind to the first we can" is precisely the problem here. You should both bind to [::] with the IPV6_V6ONLY flag (see setsockopt()) and 0.0.0.0.
Is it because that you bind your server socket to an IPv6 address?
in the "for" loop, IPv6 address appearing before IPv4 address seems to cause your server's socket listen on an IPv6 address.
So your server is not listening on any IPv4 address, cause all connection towards IPv4 address of server is refused.
Try to see all listening port is on which IP address with tool or some command (eg. netstat)
have you tried to run the server and client on the same machine?
this sounds like a firewall problem.
if you succeed connecting telnet / your application on the same machine you'll know this is the problem.
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.