Binding a port for client tcp socket - c

I have a problem about 'binging a local port for a client tcp socket'.
The code is as below:
void tcpv4_cli_connect(const char *srvhost, in_port_t srvport,
const char *clihost, in_port_t cliport)
{
struct sockaddr_in srvaddr, cliaddr;
struct in_addr inaddr;
int sockfd;
bzero(&srvaddr, sizeof(srvaddr));
inet_aton(srvhost, &inaddr);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr = inaddr;
srvaddr.sin_port = htons(srvport);
bzero(&cliaddr, sizeof(cliaddr));
inet_aton(clihost, &inaddr);
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr = inaddr;
cliaddr.sin_port = htons(cliport);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));
if (connect(sockfd, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) != 0)
perror("Something Wrong");
return;
}
int main(int argc, char *argv[])
{
// Wrong for "220.181.111.86", but ok for "127.0.0.1"
tcpv4_cli_connect("220.181.111.86", 80, "127.0.0.1", 40888);
return 0;
}
When I do tcpv4_cli_connect("220.181.111.86", 80, "127.0.0.1", 40888) in main function, (220.181.111.86 is an address on Internet), an error will show up: Something Wrong: Invalid argument.
And if I comment bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) in the code, things will be fine and a random port is used for client socket.
But it is alright when I do tcpv4_cli_connect("127.0.0.1", 80, "127.0.0.1", 40888) whether or not binding a port to client socket.
What does Invalid argument mean for a connect operation? I wonder if it is only allowed to bind a specific port for the client to connect to local address? Clients can only use random port to connect to a external server?
Is there someting I misunderstood?
/br
Ruan

When you bind() to 127.0.0.1 (INADDR_LOOPBACK), you are binding to a loopback interface that does not have access to the outside world, only to itself, so you cannot connect() to any IP other than 127.0.0.1. If you want to bind() to a local interface when you connect() to an outside server, you have to bind to the actual IP of an interface that is connected to a network that can reach that server.
If all you want to do is bind() to a specific port, but allow the OS to pick an appropriate interface for you, then bind to 0.0.0.0 (INADDR_ANY) instead.

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

UDP Client shows 'UDP Connected' while no UDP Server running on localhost

What is wrong with the following function ??
It should throw an error as I have no UDP server running on localhost.
int openUdpSocket(int port) {
int sock,sin_size;
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
struct hostent *host;
host= (struct hostent *) gethostbyname((char *)"127.0.0.1");
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
sin_size = sizeof(struct sockaddr);
Now the Following part causing trouble : -
int error = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(error < 0){
printf("Connection error\n");
exit(-1);
}
if (verbose)
printf("UDP connected\n");
return sock;
}
Output:
udit#mylaptop:~/Desktop/benchmark$ ./a.out
UDP connected
Note that I have created a similar function for TCP and the same thing is working fine with TCP that means when no TCP Server running it shows connection error and when TCP Server running then TCP Connected
The UDP Client mentioned above needs to receive response in form of some status codes in future. SO, Do I need to use bind() function here ??
You need to lookup what connect() does for a SOCK_DGRAM socket. It doesn't imply the existence of a peer. It only establishes an inbound and outbound IP address filter. See man 2 connect.
for UDP communication you need to use Sendto and Receivefrom functions,
bind and connect are not required for UDP communication.
try to search about this two functions and use them. :)

What Is The Purpose Of A sockaddr_in In This Program?

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.

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