C: Server/client socket program - Client error connecting - sockets

I'm new to networking and trying to create a simple client, server socket program in C, where arguments determine whether the program should run as a client or server. I did this by using simple if statements (if a flag is given, run as server, else run as client), but I'm not sure how to test this. I run my code with the argument to be a server in one terminal (on localhost and port number 3000 for example), and open another terminal and run the code with the argument to be a client (also on localhost and the same port).
The expected result is to see the client prompt the user for a message (if connected successfully), and send that message to the server, which prints out the message, however, I don't get the prompt on the client terminal to enter a message.
(I got the code for server and client behavior from one of many websites online, but they separate the client.c and server.c, whereas I want to combine both into one .c program)
Here's my code below, the error is triggered by
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
in the client section of the code.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n, i, server = 0; // 1 = server, 0 = client
// check if server or client
for (i = 0; i<argc; i++) {
if (strcmp(argv[i], "-l") == 0)
server = 1;
}
// client
if (server == 0) {
struct hostent *server;
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"FOUR*** ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return 0;
}
// server
if (server == 1) {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
return 0;
}
}
Here's the exact error output:
In one terminal window, I run the program as a server first:
$ ./socketz -l localhost 2003
Then in another terminal window, I run the program as a client:
$ ./socketz localhost 2003
ERROR connecting: Connection refused

The reason you can't connect is because your server process is not listening on port 2003. In particular, on this line:
serv_addr.sin_port = htons(portno);
The value of portno is zero, which causes the value of serv_addr.sin_port to also be zero, which accept() interprets as meaning that it should just pick an available TCP port to bind to.
The root of the problem is here:
portno = atoi(argv[1]);
... that line assigns a value to portno based on the first argument you entered when running the program, but you entered this:
./a.out -l localhost 2003
So the first argument is "-l", which is a non-number so it will cause atoi() to return 0. I think what you intended was portno = atoi(argv[3]); instead.

Related

How are socket timeouts enforced in linux

I'm trying to better understand how socket timeouts and keep-alive work in linux. This is the current snippet of code I'm using.
import socket
def set_keepalive_linux(sock, after_idle_sec=1, interval_sec=3, max_fails=5):
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle_sec)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval_sec)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
set_keepalive_linux(s)
s.connect(("www.python.org" , 80))
s.recv(1024)
Now, running netstat I see the timer set for this connection which makes sense.
tcp 0 0 myhost:randomport 199.232.44.223:http ESTABLISHED 81658/python3 keepalive (0.88/0/0)
Now, if I replace this code with
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
s.connect(("www.python.org" , 80))
s.recv(1024)
I'm unable to see any timer set (I understand that the timer in netstat -o is specifically for keepalive/retransmission so off is the expected result on rerunning netstat but is it maintained elsewhere?). So my question would be, are socket timeouts expected to be implemented by the application and the kernel has nothing to do with it?
[[Edit 1]]
Seems like this is as expected for python. I've hacked together a C program from various parts of stackoverflow that does roughly the same. Would like to see if there's some way I can access the timeout information somewhere for this
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(void)
{
int socket_desc;
struct sockaddr_in server_addr;
char server_message[2000], client_message[2000];
// Clean buffers:
memset(server_message,'\0',sizeof(server_message));
memset(client_message,'\0',sizeof(client_message));
// Create socket:
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if(socket_desc < 0){
printf("Unable to create socket\n");
return -1;
}
printf("Socket created successfully\n");
// Set port and IP the same as server-side:
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(80);
server_addr.sin_addr.s_addr = inet_addr("199.232.44.223");
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if (setsockopt (socket_desc, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof timeout) < 0)
error("setsockopt failed\n");
if (setsockopt (socket_desc, SOL_SOCKET, SO_SNDTIMEO, &timeout,
sizeof timeout) < 0)
error("setsockopt failed\n");
// Send connection request to server:
if(connect(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
printf("Unable to connect\n");
return -1;
}
printf("Connected with server successfully\n");
// Receive the server's response:
if(recv(socket_desc, server_message, sizeof(server_message), 0) < 0){
printf("Error while receiving server's msg\n");
return -1;
}
printf("Server's response: %s\n",server_message);
// Close the socket:
close(socket_desc);
return 0;
}

Raw socket not receiving UDP packet

I wrote an application using raw sockets that creates a UDP packet and sends to a destination. The application is working fine and I even saw the packet sent using Wireshark. Now, I want that packet to be captured by another application on the destination system. I want to be able to access the UDP header on the destination system. So, I created a receiver using raw sockets on dest system. But, I'm not able to receive the packet to my application. I'm able to capture the packet using SOCK_DGRAM socket, but not with raw socket.
I remember reading that raw sockets doesn't have the concept of ports. Can anyone explain me exactly what's going on the dest system, how the demultiplexing at transport layer works and how the protocol field of ip header effects the transport layer functionality?
Sender code:
int main(void){
char message[] = "This is something very useful";
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if(sockfd < 0){
perror("Error creating socket");
exit(1);
}
struct sockaddr_in this, other;
this.sin_family = AF_INET;
other.sin_family = AF_INET;
this.sin_port = htons(9000);
other.sin_port = htons(8000);
this.sin_addr.s_addr = INADDR_ANY;
other.sin_addr.s_addr = inet_addr("127.0.0.1");
if(bind(sockfd, (struct sockaddr *)&this, sizeof(this)) < 0){
printf("Bind failed\n");
exit(1);
}
char packet[64];
memset(packet, 0, 64);
struct udphdr *udph = (struct udphdr *) packet;
strcpy(packet + sizeof(struct udphdr), message);
udph->uh_sport = htons(8080);
udph->uh_dport = htons(8000);
udph->uh_ulen = htons(sizeof(struct udphdr) + sizeof(message));
udph->uh_sum = 0;
if(sendto(sockfd, packet, sizeof(struct udphdr) + sizeof(message), 0, (struct sockaddr *) &other, sizeof(other)) < 0)
perror("Error");
else
printf("Packet sent successfully\n");
close(sockfd);
return 0;
}
Receiver code:
int main(void){
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
char message[64];
if(sockfd < 0){
perror("Error creating socket");
exit(1);
}
struct sockaddr_in this;
this.sin_family = AF_INET;
this.sin_port = htons(8000);
this.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (struct sockaddr *)&this, sizeof(this)) < 0){
printf("Bind failed\n");
exit(1);
}
if(recv(sockfd, message, 64, 0) < 0){
perror("Error");
exit(1);
}
printf("\n\n%s\n\n", message);
close(sockfd);
return 0;
}

send_to returns EINVAL in udp

I am creating a simple file transfer application, but send_to is returning EINVAL when i am trying to send from server side to client, while both send_to and recv_from are working fine on the client side.
port_number, portno, hostname are passed as arguments.
Code to set up server:
portno=port_number;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)portno);
if (bind(sockfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
//getsockname(sockfd, (struct sockaddr *)&clientaddr, &clientlen);
cout<<"server port no"<<serveraddr.sin_port<<endl;
clientlen = sizeof(clientaddr);
Code to set up client:
hostname = name;
portno = port;
/* socket: create the socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* gethostbyname: get the server's DNS entry */
server = gethostbyname(hostname);
if (server == NULL)
{
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(-1);
}
/* build the server's Internet address */
memset((char *) &serveraddr,0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
serverlen = sizeof(serveraddr);
struct timeval tv;
tv.tv_sec = 1; // TIMEOUT IN SECONDS
tv.tv_usec = 0; // DEFAULT
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
printf("Cannot Set SO_RCVTIMEO for socket\n");
Command that is failing:
if(sendto (sockfd, ack, strlen(ack), 0,(struct sockaddr*)
&clientaddr,sizeof(clientaddr) < 0)
error("ERROR in sending hello_ACK");
where clientadddr is declared as struct sockaddr_in
EINVAL error is generated because of an invalid argument. So you should either initialize the clientaddr as you have done for serveraddr or if you are receiving a HELLO message earlier/ or any other message from the client you can pass clientaddr as an argument to that recvFrom call.
recvfrom(socketFileDescriptor, buffer, bufferSize,0,(struct sockaddr *) &clientaddr, &clientlen))
here the clientlen is sizeof(clientaddr) if you are writing in C.

systemd-activate socket activation for UDP daemons

I like using systemd-activate(8) for testing socket-activated daemons during development,
however, it seems it only listens for TCP connections:
% /usr/lib/systemd/systemd-activate -l 5700 ./prog
Listening on [::]:5700 as 3.
% netstat -nl |grep 5700
tcp6 0 0 :::5700 :::* LISTEN
I am using a program that handles datagrams (UDP). How can I make systemd-activate listen on a UDP port? Or is there a
simple way to do this using other tools, without going to the trouble of crafting and installing a systemd unit file?
This was recently added to systemd-activate: https://github.com/systemd/systemd/pull/2411, and will be part of systemd-229 when it is released.
I'm not sure that there is a way to do it with systemd-activate.
You may want to employ some .service unit file and a .socket unit file with dependencies. In a .socket unit you will describe ListenDatagram= option. See here for more details.
I ended up writing a simple C program to do this; code below (public domain).
The usage is:
./a.out <port-number> <prog> [<arg1> ...]
The program opens a UDP socket on <port-number>, sets the environment variables that systemd socket-activated daemons expect, then executes <prog> with whatever arguments follow.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char **argv) {
if (argc < 2) {
printf("no port specified\n");
return -1;
}
if (argc < 3) {
printf("no program specified\n");
return -1;
}
uint16_t port = htons((uint16_t) strtoul(argv[1], NULL, 10));
if (port == 0 || errno) {
printf("failed to parse port: %s\n", argv[1]);
return -1;
}
/* create datagram socket */
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
printf("failed to open socket; errno: %d\n", errno);
return -1;
}
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = port;
sa.sin_addr.s_addr = INADDR_ANY;
/* bind socket to port */
int r = bind(fd, (struct sockaddr *) &sa, sizeof(struct sockaddr_in));
if (r < 0) {
printf("bind failed; errno: %d\n", errno);
return -1;
}
/* execute subprocess */
setenv("LISTEN_FDS", "1", 0);
execvp(argv[2], argv + 2);
}

Not able to make connection to a server process located on different network using in C

I am trying to send messages between two system located on different network using C socket programming.
But when connect() system call initiated it is returning -1 so I am not able to connect to the server.
How can I get connect to a remote server located on different network or different machine. Same program is working when I am using client and server on local machine.
**Client code ----->**
int main(int argc, char *argv[]){
int sockfd,portno,n;
char buffer[256];
struct sockaddr_in serv_addr;
struct hostent *server;
if (argc<3)
error("error port number not provided");
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
error("error while creating socket ");
server =(struct hostent *)gethostbyname(argv[1]);
if(server == NULL){
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
//bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port=htons(portno);
if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
error("error while connecting..");
while(strncpy(buffer,"bye",3)!=0){
bzero(buffer,256);
printf("\nYou:");
fgets(buffer,255,stdin);
//n= write(sockfd,buffer,strlen(buffer));
n=send(sockfd,(char*)&buffer,strlen(buffer),0);
if(n<0)
printf("message not delivered\n");
bzero(buffer,256);
//n= read(sockfd,buffer,255);
n= recv(sockfd,buffer,255,0);
printf("\nfrd:%s",buffer);
}
close(sockfd);
}
**Server code -->**
int main(int argc, char *argv[]){
int sockfd,listenfd,portno,clilen,n;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
if (argc<2)
error("error port number not provided");
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
error("error while creating socket ");
bzero((char*) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof serv_addr)<0)
error("error while binding socket");
listen(sockfd`enter code here`,5);
clilen = sizeof(cli_addr);
if ((listenfd = accept(sockfd, (struct sockaddr*)&cli_addr,&clilen))<0)
error("error while initializing listening");
printf("listening for connections..");
while(strncmp(buffer,"bye",3)!=0){
bzero(buffer,256);
//n= read(listenfd,buffer,255);
n= recv(listenfd,buffer,255,0);
if(n<0)
error("no message");
printf("\nfrd:%s",buffer);
printf("\nyou:");
fgets(buffer,255,stdin);
//n= write(listenfd,buffer,sizeof buffer);
n=send(listenfd,(char*)&buffer,strlen(buffer),0);
if(n<0)
printf("message not sent");
}
close(sockfd);
}
All of client code is the same as that in the server.
server =(struct hostent *)gethostbyname(argv[1]);
if(server == NULL){
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
argv1 contains the name of a host on the Internet, e.g. hsembedded.blogspot.in ;)
The function:
struct hostent *gethostbyname(char *name)
Takes such a name as an argument and returns a pointer to a hostent containing information about that host. The field char *h_addr contains the IP address. If this structure is NULL, the system could not locate a host with this name.
The mechanism by which this function works is complex, often involves querying large databases all around the country.
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
This code sets the fields in serv_addr. Much of it is the same as in the server. However, because the field server->h_addr is a character string, we use the function:
void bcopy(char *s1, char *s2, int length)
which copies length bytes from s1 to s2.
the error is actually due to absence of #include<netdb.h> in client code.