Set hostname using winsock? - c++

I've just started using winsock, and it seems like it's only making a server on the local machine by default, rather than accepting external connections (from other computers on the system). I'm looking for the C++ equivalent of socket.bind(("192.168.0.112", 1024)) in Python (rather than "localhost")

If you want to bind to all adapters, which is the most common thing to do for accepting connections from both localhost and remote addresses, then this is all you really have to do:
sock = socket(AF_INET, SOCK_STREAM, 0); // SOCK_STREAM==TCP. Use SOCK_DGRAM if you want UDP
sockaddr_in addr = {}; // ={} is zero-init. Since INADDR_ANY is 0, it implicitly sets this as well
addr.sin_family = AF_INET;
addr.sin_port = htons(1024); // port 1024 in network byte order
int result = bind(sock, (sockaddr*)&addr, sizeof(addr));

Related

Can a UDP multicast socket be configured so that write() can be called rather than sendto()?

I am writing a C++ multicasting application on Linux Ubuntu.
In my C++ multicast sender class I do this:
uint16_t port = 5678;
const char* group = "239.128.128.128";
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(group);
addr.sin_port = htons(port);
const char* buf = "Hi there";
size_t bytes_to_write = 8;
size_t bytes_sent = sendto(fd, buf, bytes_to_write, 0, (struct sockaddr*) &addr, sizeof(addr));
Is there any way to configure the file descriptor so that I can call write() rather than sendto()? I would have thought there would be a setsockopt option or similar to do this?
Yes.
Per the documentation man 7 udp
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.
and, for generality, the POSIX spec for connect says
If the initiating socket is not connection-mode, then connect() shall set the socket's peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions.
It's always worth checking the documentation for these, things, it isn't that impenetrable. FWIW I couldn't remember immediately whether you need connect() or bind() for this, and it took me a few seconds to find out.

Does the code in a C++ winsock 2 application have to change when using a global IP address?

My code is based on the book "Network Programming for Microsoft Windows Second Edition", which can be found online as a PDF.
My code for the server application is:
#include <iostream>
#include <winsock2.h>
int main(void)
{
WSADATA wsaData;
SOCKET ReceivingSocket;
SOCKADDR_IN ReceiverAddr;
int Port = 5150;
char buffer;
SOCKADDR_IN SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
WSAStartup(MAKEWORD(2,2), &wsaData);
ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(Port);
ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr));
recvfrom(ReceivingSocket, &buffer, 1, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
std::cout << buffer << std::endl;
buffer = 'b';
sendto(ReceivingSocket, &buffer, 1, 0, (SOCKADDR*)&SenderAddr, SenderAddrSize);
std::cin.get();
closesocket(ReceivingSocket);
WSACleanup();
}
And for the client application is:
#include <winsock2.h>
#include <iostream>
int main()
{
WSADATA wsaData;
SOCKET SendingSocket;
SOCKADDR_IN ReceiverAddr;
SOCKADDR_IN ex;
int Port = 5150;
char buffer = 'a';
WSAStartup(MAKEWORD(2,2), &wsaData);
SendingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(Port);
ReceiverAddr.sin_addr.s_addr = inet_addr("-->insert ip here<--");
sendto(SendingSocket, &buffer, 1, 0, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr));
int len = sizeof (ex);
recvfrom(SendingSocket, &buffer, 1, 0, (SOCKADDR*)&ex, &len);
std::cout << buffer << std::endl;
std::cin.get();
closesocket(SendingSocket);
WSACleanup();
}
When I insert a local IP, the code works perfectly fine - the applications detect each other and exchange buffers. But when I insert my global IP, the applications don't detect each other. Is it a problem with the code, or something I have to change when using a global IP, or something wrong with my network settings?
To clarify:
When I said about "inserting IP address", I meant writing it instead of "-->insert ip here<--".
By local IP, I meant my computer's local IP address, checked in the console using the ipconfig command.
By global IP, I meant the global IP of my router, which I checked on myglobalip.com, and I forwarded port 5150 to my local IP address.
This might be a bit off topic, but if it's something wrong with network settings, I would appreciate if you could give a link to a good tutorial because I couldn't find one that worked.
Nice code. Nice and simple. All I had to do was cut and paste (and add #pragma comment (lib, "ws2_32.lib")).
Are the client and the server both running on your LAN? If so, my tests indicate that they won't be able to talk to each other via your router's external IP address. This is because the router doesn't loop back packets sent out through its ADSL / VDSL port (why would it?) so they just disappear into the ether. I tried enabling both the DMZ and port forwarding on my router (at minimum, you need one or the other) but no dice, which was what I was expecting.
So to test this, you will need the help of a friend with a router of his own. Let's suppose he is running the client. You will then need to put your server machine into your router's DMZ or (better, because it's safer) set up port forwarding for UDP port 5150 on your router to the server machine. In either case, give that machine a static IP address on your LAN else it might move. Then you have a chance of seeing this work.
Our friends over at superuser have this to say about sending UDP packets via [routers implementing] NAT (which is what you will have there) and getting an answer back:
IF Machine A sends [a UDP] frame from the same source port as the destination port ("Port N"), and IF the NAT is able to preserve that source port (i.e. it's configured to preserve source ports when possible, and that source port is not in use), THEN you can expect a reply to "Port N" to get back to Machine A.
But the problem currently is that nothing is listening. Certainly not your server program.

C++: Classic communication exercise between server and client

Good day.
As a computer science student, learning low-level C programming, i'm stucked in the "classic" practice exercise of writting a server-client communicating program.
The goal is to develop a server component which receives a command from a remote client component, and execute it as a local shell command; then, the command's output is send again to the client. Pretty simple.
My code send the command from the client, the server succesfully receive it, execute it and captures the output. But at this point, when the sayd server tries to reply with that output to the client ... something goes wrong and the client receives nothing. No clue if the problem is in the server part, or in the client counterpart.
Any idea? Thanks in advance!
Server:
struct sockaddr_in srvaddr, cliaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
int sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
srvaddr.sin_port = htons(42000);
bind(sk, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
recvfrom(sk, recepcion, sizeof(recepcion), 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr));
// [...] Portion of code with a Pipe pointing to a Fork which runs the command...
// And here is where, maybe, the communication is lost:
sendto(sk, recepcion, sizeof(recepcion), 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr));
Client:
struct sockaddr_in srvaddr, cliaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
int sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
cliaddr.sin_port = htons(42001);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
srvaddr.sin_port = htons(42000);
// [...] Some other code catching the command from the argument paramenters:
sendto(sk, comando, strlen(comando), 0, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
// And here's where the server reply should be, but theres nothing:
recvfrom(sk, buff, sizeof(buff), 0, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
Say i print all the traces with:
fprintf(stderr, "");
So, loosing the terminal's focus due to forking should not be an issue.
Bye and thanks!
The problem is most likely the recvfrom call. If you check the manual page you will see that the source-address length is a pointer. I don't know how you managed to get it to compile without errors or warnings.
You need to initialize the size to the actual size of the socket-address structure, pass a pointer to it, and the recvfrom function will fill in the actual size:
socklen_t cliaddrlen = sizeof(cliaddr);
recvfrom(sk, recepcion, sizeof(recepcion), 0,
(struct sockaddr *) &cliaddr, &cliaddrlen);
Oh, and I do assume you check for errors in your actual code?

How to find a socket's local port number? (Windows 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.

Reopen connected datagram socket

I have a connection protocol that has been defined by our customer. Data are sent between two linux computers using UDP and TCP protocols. The IP addresses and ports are fixed on startup.
We are sending messages at 200 Hz and I have been using connect to save some time on the transmissions.
My problem is that if there is a communication error, I need to tear down the connections and reinitialise.
I have a problem with one of the UDP connections as it will not rebind to the required address and returns errno 22.
The code I am using is something like:
int
doConnect(int& sock, int local_port, char *local_ip, int remote_port, char *remote_ip)
{
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(local_port);
inet_pton(local_ip,&addr.sin_addr.s_addr);
if (0 > bind(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Bind Error errno = %d\n", errno);
return ERR_BIND;
}
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(remote_port);
inet_pton(remote_ip,&addr.sin_addr.s_addr);
if (0 > connect(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Connect Error errno = %d\n", errno);
return ERR_CONNECT;
}
return ERR_OK;
}
The way that this is used is like this:
int s1(-1), s2(-1);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
When an error occurs
close(s1);
close(s2);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
Here the local address is 172.17.21.3 and I am connecting to 172.17.21.1. s1 listens to a broadcast message.
s1 successfully reconnects to the remote machine, but s2 fails with error 22 from the call to bind.
I have tried explicitly calling bind and connect to an AF_UNSPEC address immediately before I close the socket. This doesn't solve the problem.
Are there any options that I should be using?
Perhaps you could try:
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
I also suggest you double check that you're not passing the same socket to the two consecutive doConnect() calls (as errno 22 = EINVAL, which in the case of bind() appears to mean that the socket is already bound to an address).
The underlying socket layer might hold the port & IP address still open, even after your call to close. Try some of the following:
do a sleep(10) (or more) between the close and the call to doConnect again
configure the sockets using setsockopt with the SO_LINGER set to off
This actually happens more commonly with TCP connections, but I see no reason UDP can't have this problem as well.