What Is The Purpose Of A sockaddr_in In This Program? - c

For one of my classes I have to program a server and a client, and we were given some sample code to work with. Here is the snippet I am confused about:
main()
{
int sock, sock_current, cc, fromlen, tolen; /*sd is the socket */
int addrlen;
struct sockaddr_in sin;
struct sockaddr_in pin;
/* get an internet domain socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
/* complete the socket structure */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(PORT);
/* bind the socket to the port number */
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
perror("bind");
exit(1);
}
I think that the purpose of the sockaddr_in struct sin is to store a local IP address to associate with sock when it gets bound. Am I correct on that? If I am correct, how does this snippet of code accomplish that? I don't get it:
/* complete the socket structure */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(PORT);

The bind function assigns a local protocol address to a socket. The purpose of sin here is to tell bind which local address to assign.
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; //it's an IPv4 address
sin.sin_addr.s_addr = INADDR_ANY; //wildcard IP address
sin.sin_port = htons(PORT); //bind to this port number

In addition to what Yu said (which is all correct), if you don't call bind before calling listen() (which is likely right after the snippet you posted), it will listen on a random TCP port (because you opened an IPv4 TCP socket when you called socket()).
This is actually useful sometimes -- I have an app that broadcasts the port it runs on over the LAN for clients to find it, so it doesn't matter what port it's on.
Also, you can bind before you call connect(), if you want, to force what port or interface the outgoing connection will be made on, but this is also uncommon.

Related

Invalid argument to connect()

I'm trying to write code to setup a client socket that can send/receive messages from a server. Here's what I have:
// Create the socket
int s = socket(AF_INET, SOCK_STREAM, 0); // TODO: error checking
// Setup the client and server addresses
struct sockaddr_in cli_addr;
memset(&cli_addr, 0, sizeof(cli_addr));
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(7654);
cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(11111);
serv_addr.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");
// Bind the socket to the client address (so we can receive messsages)
if (bind(s, (struct sockaddr*)&cli_addr, sizeof(cli_addr)) == -1) {
perror("bind failed");
exit(errno);
}
// Connect the socket to the server address (so we can send messages)
if (connect(s, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
perror("connect failed");
exit(errno);
}
When I run this, I'm getting the error connect failed: Invalid argument. I don't see what I'm doing incorrectly here, though.
cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
...
serv_addr.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");
You'll bind the socket to localhost (127.0.0.1) but then you connect to an address which likely is not localhost. There is no way such a TCP with a fully internal IP address (i.e. not accessible from outside the machine) to an IP address of a different system can be created, hence "Invalid argument".
It is unclear what you are trying to achieve with the bind in the first place so it might be the best to just remove it. In this case it will automatically pick a local IP and port which can be used in a connection to the given destination IP.

Not receiving multicast data using code which works on another machine

We receive multicast data to two machines- Prod and Dev. The below code worked on Prod, but has never worked on Dev (even though the boxes should be set up identically). However, when I run
tshark -i <interface> -c 50
on Dev packets are being received from the same multicast address and port as Prod.
I have posted the code below. The program reaches the log line "Listening for packets" but then appears to simply block on recvfrom().
I would like to clarify I am not doing anything daft. Is there anything else I can check to see what's happening with the packets? I cannot speak with our vendor yet because they will simply run tshark and say the problem must be with our code.
std::string address("1.2.3.4"); // Not real address
const char *group = address.c_str();
int port = 26477;
_sock = socket(AF_INET, SOCK_DGRAM, 0);
assert(_sock >= 0);
u_int yes = 1;
int result = setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
assert(result >= 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
result = bind(_sock, (struct sockaddr *)&addr, sizeof(addr));
assert(result >= 0);
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
result = setsockopt(_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
assert(result >= 0);
LOG("Listening for packets...."); // CODE REACHES HERE
while (1)
{
socklen_t addrlen = sizeof(addr);
const size_t maxNumBytesToRead = MSGBUFSIZE - 1;
// I think code is just blocking here, waiting for packets
const int nbytes = recvfrom(_sock, msgbuf, maxNumBytesToRead, 0, (struct sockaddr *)&addr, &addrlen);
}
You're specifying INADDR_ANY as the interface to join the multicast group on. This means the system will choose a default interface. If your system has more than one active interface, it might not be the one you intended.
What's probably happening here is that your PROD machine happens to be joining on the desired interface, while the DEV machine is joining on a different interface.
Change mreq.imr_interface to contain the IP address of the network interface you want to bind to.

c - connect() does not return

I'm trying to build a c client that sends an html request message to a website, and then reads the response. Unfortunately, my connect() statement does not return.
Yes, I have seen this answer: connect() does not return
However, I do not want to set the socket to non-blocking, and then keep doing select() until I get a response, as I am only dealing with one request at a time.
int main() {
struct hostent *hp;
struct sockaddr_in serveraddr;
mySocket = socket(AF_INET, SOCK_STREAM, 0);
hp = gethostbyname("firefox.com"));
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)hp->h_addr_list[0], (char *)&serveraddr.sin_addr.s_addr, hp->h_length);
serveraddr.sin_port = htons(8080); // works up till here
connect(mySocket, (SA *) &serveraddr, sizeof(serveraddr)); // never returns
return 0;
}
Am I connecting correctly? I've gotten rid of the error checking in the above code.
Here is the output of "lsof -Pnl +M -i4" in terminal
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
proxy 8321 1000 3u IPv4 51542 0t0 TCP 10.0.2.15:42708->63.245.213.17:8080 (SYN_SENT)
Could this be a firewall issue? If so, how do I resolve it?
I should've been on port 80, not 8080, in the line:
serveraddr.sin_port = htons(8080); // no
serveraddr.sin_port = htons(80); // yes
Thanks for your help guys.

UDP Client Source port in C?

I am writing a UDP client and I need to mention the source port of my UDP packet in my data to send.
How my program can get the random port number generated by kernal which udp client is using to send data to voip server.
so
How can i specify a specific UDP source port before sending data.
I will be very very thankful. Please reply me as soon as possible. My project is stopped at this point.
Use bind to bind your socket to port 0, which will allow you to use getsockname to get the port. you can also bind your socket to a specific port, if you wish.
eg (assuming IPv4 socket, no error checking):
struct sockaddr_in sin = {};
socklen_t slen;
int sock;
short unsigned int port;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = 0;
bind(sock, (struct sockaddr *)&sin, sizeof(sin));
/* Now bound, get the address */
slen = sizeof(sin);
getsockname(sock, (struct sockaddr *)&sin, &slen);
port = ntohs(sin.sin_port);
Alternately, if you are communicating with a single server, you can use connect on your UDP socket (which also gives you the handy side effect of allowing you to use send instead of sendto, and making the UDP socket only accept datagrams from your "connected" peer), then use getsockname to obtain your local port/address. You may still choose to bind your socket prior to using connect.
eg:
struct sockaddr_in sin = {};
socklen_t slen;
int sock;
short unsigned int port;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* set sin to your target host... */
...
connect(sock, (struct sockaddr *)&sin, sizeof(sin));
/* now retrieve the address as before */
slen = sizeof(sin);
getsockname(sock, (struct sockaddr *)&sin, &slen);
port = ntohs(sin.sin_port);
You should bind(2) your socket to a port of your choosing. See also
man 7 ip and man 7 udp.

How to determine IP used by client connecting to INADDR_ANY listener socket in C

I have a network server application written in C, the listener is bound using INADDR_ANY so it can accept connections via any of the IP addresses of the host on which it is installed.
I need to determine which of the server's IP addresses the client used when establishing its connection - actually I just need to know whether they connected via the loopback address 127.0.0.1 or not.
Partial code sample as follows (I can post the whole thing if it helps):
static struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons(port);
bind(listener, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
listen(listener, CONNECTION_BACKLOG);
SOCKET socketfd;
static struct sockaddr_in clientAddress;
...
socketfd = accept(listener, (struct sockaddr *) &clientAddress, &length);
The solution to my specific problem (thanks to zildjohn01) in case anyone needs it, is shown below:
int isLocalConnection(int socket){
struct sockaddr_in sa;
int sa_len = sizeof(sa);
if (getsockname(socket, &sa, &sa_len) == -1) {
return 0;
}
// Local access means any IP in the 127.x.x.x range
return (sa.sin_addr.s_addr & 0xff) == 127;
}
You can use the getsockname function.
The getsockname() function retrieves the locally-bound name of the specified socket
From your code
socketfd = accept(listener, (struct sockaddr *) &clientAddress, &length);
Analyse the returned clientAddress. This is what you need.

Resources