socket has assigned server port 0 after sendbase C UDP - c

I'm writing a client-server application via udp.
I did these steps:
memset((void *)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(serverport);
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0)
err_func("Error in inet_pton()\n");
...
if( (socketfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_func("Error in socket()");
...
if(sendto(socketfd,&pckt, sizeof(pckt), 0, (struct sockaddr *)&servaddr,sizeof(servaddr)) == -1)
err_func("Error in sendto()\n");
...
struct sockaddr_in addr;
socklen_t len;
if(getsockname(socketfd,(struct sockaddr *) &addr, &len) != 0)
err_func("Error in getsockname()\n");
printf("My port is %d\n", addr.sin_port);
Now my problem is that this code will print "My port is 0", but why? and how is it possible? (0 is a jolly that means "the SO will assign a port randomly that is not used", but after a sendto the SO has have assigned a port to my socket, or not ?)
The strange thing is that after 2 or 3 sendto, my code start to print a different value for addr.sin_port. Why doest it not work fine since the first sendto?
I need it bind a port because on server I create a process that execute connect with that client address and he will receive all packets from the client.
I tried to run a bind into the client before run the first sendto, but it seems like bind has no effect (probably I fill the struct sockaddr_in used in bind wrong? I don't know).
If you need I can post all the code from running main... I send the first packet early...

Related

C Server connect to Client

I'm trying to make a Server/Client with push notifications.
First of all the Client connects with Server and then Server saves IP address and port of the client. At some point server needs to connect with client to send a notification.
This is how Server saves Client IP address and port after the accept of the first connection:
char client_ip[INET_ADDRSTRLEN];
int port_c;
// Socket, ..., bind, listen, accept
// Gets Client IP address
struct sockaddr_in* pV4Addr = (struct sockaddr_in*)&cli_addr;
struct in_addr ipAddr = pV4Addr->sin_addr;
inet_ntop( AF_INET, &ipAddr, client_ip, INET_ADDRSTRLEN );
printf("Client ip: %s\n", client_ip);
// Gets Client Port Number
port_c = (int) ntohs(cli_addr.sin_port);
printf("Client port is: %d\n", (int) ntohs(cli_addr.sin_port));
// [ ... ]
// Time to send notification to client
bzero((char *) &cli_addr, sizeof(cli_addr));
// Setting IP address and port
cli_addr.sin_family = AF_INET;
bcopy(client_ip, (char *)&cli_addr.sin_addr.s_addr, strlen(client_ip));
cli_addr.sin_port = htons(port_c);
// Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Bind socket to the local address
if(bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0)
error("Error bind");
if (connect(sockfd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)) < 0)
error("ERROR connecting");
I get bind error: Can't assign requested address.
And I am not sure how to code Client after the first connection. It would be listening and accepting the connection but if I do in the Client's code
cli_addr.sin_family = AF_INET;
cli_addr.sin_addr.s_addr = INADDR_ANY;
cli_addr.sin_port = htons(port_client);
Will the IP address be the same as the first connection?
If someone has another solution or better, please share it.
You are trying to bind the server socket to a client IP. That cannot work. You can only bind a socket to a local address. You must use bind for incomming connections, not for outgoing ones.
If you want your server to respond to a request from the client, simply use the socket returned by accept(), then send() using this socket.
You server code should look like this:
SOCKET sock_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sock_local_addr;
memset(&sock_local_addr, 0, sizeof(sock_local_addr));
sock_local_addr.sin_family = AF_INET;
sock_local_addr.sin_port = htons(SERVER_PORT);
sock_local_addr.sin_addr.s_addr = INADDR_ANY;
bind(sock_server, (const struct sockaddr *)&sock_local_addr, sizeof(sock_local_addr)); // bind server socket to any network interface of the server
listen(sock_server, 10);
struct sockaddr_in client_addr;
SOCKLEN_T client_addr_size = sizeof(client_addr);
SOCKET sock_client = accept(sock_server, (struct sockaddr *)&client_addr, &client_addr_size); // accept incomming connection; this will block until a client connects
recv_size = recv(sock_client, buf_in, sizeof(buf_in), 0); // receive data from client
send(sock_client, buf_out, sizeof(buf_out), 0); // send data back to client (buf_out is buffer containing the data to be sent)
shutdown(sock_client, SHUT_RDWR); // shutdown connection with client

Source and destination port for UDP socket?

I'm learning C by writing a small application that sends a DNS query to a specified server. Here is an example of the network code:
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
This works fine as the query is succesfully sent, and a reply is recieved. However, by sniffing the traffic with Wireshark I can see the message: Destination unreachable (Port unreachable).
I found out that I can avoid this by calling bind() before sendto():
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
if(bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed\n");
}
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
Now the Destination unreachable (Port unreachable) message is gone, but the application has to be run with root privileges as it will bind to port 53.
Is it possible to modify the code so a random non-privileged source port is used instead?
Problem solved
The problem occured because of a stupid mistake. I had simply commented out recvfrom(). As I was sniffing the traffic while testing the application, I could see the response and error arrving at my computer, and mistakenly confused this as the application was receving. Because I don't know what the hell I'm doing, I started to mess around with bind() etc. and this avalanche of failure started.
For brevity I did not post all the code, but the issue had probably been solved instantly if had did that instead.
You can bind to port 0 to let the OS randomly pick one available for you (just like INADDR_ANY is 0). See https://stackoverflow.com/a/1077305/3543692
Also, binding to port 53 makes no sense. The 53 port is the port of the DNS server, not the DNS client. Think if all the DNS clients on your computer use 53 for DNS client port, then only one DNS request to a server can be proceeded concurrently. Typically, all clients (both TCP/UDP) use random unused ports assigned by OS.

C unix domain sockets, recvfrom() doesn't set struct sockaddr* src_addr

I'm writing an application that listens for UDP packets over a unix domain socket. Consider the following code block.
int sockfd;
struct sockaddr_un servaddr;
sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
if(sockfd < 0)
{
perror("socket() failed");
}
unlink(port);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, port);
if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind() failed");
close(sockfd);
}
int n;
struct sockaddr_un cliaddr;
socklen_t len = sizeof(cliaddr);
discovery_msgs client_message;
bzero(&client_message, sizeof(client_message));
// Wait for a message to be received
n = recvfrom(sock_fd, &client_message, sizeof(client_message), 0,
(struct sockaddr *) &cliaddr, &len);
// At this point n = 560, client_message is filled with the expected data
//len = 0 and cliaddr has no information about the client that sent the data
Now the type of client_message isn't really important, I'm receiving a UDP packet and client_message contains all of the data I expect. The problem begins when I look at cliaddr and len after calling recvfrom. cliaddr is not modified by recvfrom like it normally is with normal network TCP/UDP and len is set to 0 after the call(which means recvfrom wrote no data to &cliaddr). I need the information in cliaddr to be populated with the unix domain path so I can send a response.
What am I doing wrong?
The solution is binding the socket on the client side when using Unix domain sockets. Otherwise the transient pathname created for sending the UDP packet immediately disappears after sendto(), which explains why the client's address information is not available on the server side.
See Stevens Network Programming page 419 or see this for an example client implementation that solves this issue: libpix.org/unp/unixdgcli01_8c_source.html
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_un cliaddr, servaddr;
sockfd = Socket(AF_LOCAL, SOCK_DGRAM, 0);
bzero(&cliaddr, sizeof(cliaddr)); /* bind an address for us */
cliaddr.sun_family = AF_LOCAL;
strcpy(cliaddr.sun_path, tmpnam(NULL));
Bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
bzero(&servaddr, sizeof(servaddr)); /* fill in server's address */
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXDG_PATH);
dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
exit(0);
}
Note: unp.h defines Bind() which is simply bind() with some error checking(commonly used throughout Stevens Network Programming). In the same manner, (SA *) is the equivalent to (struct sockaddr *).

getpeername() won't return a correct port but it returns a correct address of remote host socket language C

I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.

C: Issues binding an open port to a socket

I'm working on an assignment that deals with binding an available port to a TCP socket. Initially, when I wrote my server code, I set a predefined port for the system to listen on, and this worked perfectly. However, upon converting my code to bind to an open port and print the port being used, I am unable to connect to the server via telnet.
I came across another interesting anomaly when I converted my code back to using a predefined port. Once again, the server worked as expected on the predefined port, however, the port that it reported to be using was different than what I had assigned it.
This first code snippet creates a socket and uses a predefined port (32000).
/*Create TCP socket with a predefined port*/
listener = socket(AF_INET, SOCK_STREAM, 0);
if(listener == -1) {
perror("Create socket");
exit(1);
}/*End if*/
bzero(&servaddr, sizeof(servaddr));/*Set serraddr to 0's*/
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);/*Any of this host's interfaces is OK.*/
servaddr.sin_port = htons(32000);
bind(listener, (struct sockaddr *)&servaddr, sizeof(servaddr));
length = sizeof(servaddr);
/*getsockname(listener, (struct sockaddr *)&servaddr, &length);/*Find out port number*/
printf("RSTREAM:: assigned port number %d\n", servaddr.sin_port);
This second code snippet uses an available port. I tried setting servaddr.sin_port to 0 because I read that doing so signifies that the system is to provide an available port. I also tried commenting this line out just for the heck of it, but the results were the same.
/*Create TCP socket with an open port*/
listener = socket(AF_INET, SOCK_STREAM, 0);
if(listener == -1) {
perror("Create socket");
exit(1);
}/*End if*/
bzero(&servaddr, sizeof(servaddr));/*Set serraddr to 0's*/
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);/*Any of this host's interfaces is OK.*/
servaddr.sin_port = htons(0);/*bind() will provide unique port.*/
bind(listener, (struct sockaddr *)&servaddr, sizeof(servaddr));
length = sizeof(servaddr);
getsockname(listener, (struct sockaddr *)&servaddr, &length);/*Find out port number*/
printf("RSTREAM:: assigned port number %d\n", servaddr.sin_port);
You need to print the converted port number, i.e. you need to do ntohs(3):
printf("RSTREAM:: assigned port number %d\n", ntohs(servaddr.sin_port));

Resources