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;
}
Related
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.
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.
I have a functional server code with only TCP connection. Now I want the server to receive from UDP connection. I have used port 2000 for TCP & port 2001 for UDP. Here is a snippet of my code
struct timeval timeout; // timeout for select(), 1ms
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// TCP port setup
int sockfd; // listening socket descriptor
int newsockfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf_tcp[256]; // buffer for client data
char buf_copy_tcp[256];
int recv_bytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; // for setsockopt() SO_REUSEADDR
int i, k, rv_getaddrinfo, rv_setsockopt, rv_bind, rv_listen, rv_select;
struct addrinfo hints, *servinfo, *ptr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
rv_getaddrinfo = getaddrinfo(NULL, "2000", &hints, &servinfo);
for(ptr=servinfo; ptr!=NULL; ptr=ptr->ai_next)
{
sockfd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
rv_setsockopt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
rv_bind = bind(sockfd, ptr->ai_addr, ptr->ai_addrlen);
break;
}
if (ptr == NULL)
{
fprintf(stderr, "CLI Server error: failed to bind\n\r");
exit(2);
}
freeaddrinfo(servinfo); // all done with this
rv_listen = listen(sockfd, 10);
////////////////////////////////////////////////////////////////////////////////////////////////
// UDP port setup
int sockfd_udp; // listening socket descriptor
struct sockaddr_storage remoteaddr_udp; // client address
socklen_t addrlen_udp;
char buf_udp[256]; // buffer for client data
char buf_copy_udp[256];
int recv_bytes_udp;
char remoteIP_udp[INET6_ADDRSTRLEN];
int yes_udp=1; // for setsockopt() SO_REUSEADDR
int j, rv_getaddrinfo_udp, rv_setsockopt_udp, rv_bind_udp;
struct addrinfo hints_udp, *servinfo_udp, *ptr_udp;
memset(&hints_udp, 0, sizeof(hints_udp));
hints_udp.ai_family = AF_UNSPEC;
hints_udp.ai_socktype = SOCK_DGRAM;
hints_udp.ai_flags = AI_PASSIVE;
rv_getaddrinfo_udp = getaddrinfo(NULL, "2001", &hints_udp, &servinfo_udp);
for(ptr_udp=servinfo_udp; ptr_udp!=NULL; ptr_udp=ptr_udp->ai_next)
{
sockfd_udp = socket(ptr_udp->ai_family, ptr_udp->ai_socktype, ptr_udp->ai_protocol);
rv_setsockopt_udp = setsockopt(sockfd_udp, SOL_SOCKET, SO_REUSEADDR, &yes_udp, sizeof(int));
rv_bind_udp = bind(sockfd_udp, ptr_udp->ai_addr, ptr_udp->ai_addrlen);
break;
}
if (ptr_udp == NULL)
{
fprintf(stderr, "CLI UDP Server error: failed to bind\n\r");
exit(2);
}
freeaddrinfo(servinfo_udp); // all done with this
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// add the listener to the master set
FD_SET(sockfd, &master);
FD_SET(sockfd_udp, &master);
// keep track of the biggest file descriptor
if(sockfd > sockfd_udp)
fdmax = sockfd; // so far, it's this one
else
fdmax = sockfd_udp; // so far, it's this one
do
{
read_fds = master; // copy it
rv_select = select(fdmax+1, &read_fds, NULL, NULL, &timeout);
// run through the existing connections looking for data to read
for(i=0; i<=fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{ // we got one!!
if (i == sockfd)
{
// handle new connections
addrlen = sizeof(remoteaddr);
newsockfd = accept(sockfd, (struct sockaddr *)&remoteaddr, &addrlen);
FD_SET(newsockfd, &master); // add to master set
if (newsockfd > fdmax) // keep track of the max
fdmax = newsockfd;
inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN);
fprintf(stdout, "CLI Server: new connection from %s on socket %d\n\r", remoteIP, newsockfd);
}
else if (i == sockfd_udp)
{
// handle new udp connections
addrlen_udp = sizeof(remoteaddr_udp);
recv_bytes_udp = recvfrom(i, buf_udp, sizeof(buf_udp), 0, (struct sockaddr *)&remoteaddr_udp, &addrlen_udp);
inet_ntop(remoteaddr_udp.ss_family, get_in_addr((struct sockaddr*)&remoteaddr_udp), remoteIP_udp, INET6_ADDRSTRLEN);
for(j=0; j<=recv_bytes_udp; j++)
{
if( (buf_udp[k] == '\r') | (buf_udp[k] == '\n') )
buf_udp[k] = '\0';
}
fprintf(stdout, "CLI UDP Server: received %s from connection %s\n\r", buf_udp, remoteIP_udp);
}
else
{ // handle data from a client
if ((recv_bytes = recv(i, buf_tcp, sizeof(buf_tcp), 0)) <= 0)
{ // got error or connection closed by client
if (recv_bytes == 0) // connection closed
{
fprintf(stdout, "CLI Server: socket %d hung up\n\r", i);
}
else
{
perror("CLI Server error: recv");
exit(6);
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
}
else
{
for(k=0; k<=recv_bytes; k++)
{
if( (buf_tcp[k] == '\r') | (buf_tcp[k] == '\n') )
buf_tcp[k] = '\0';
}
fprintf(stdout, "CLI Server: received %s from socket %d\n\r", buf_tcp, i);
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} while(QUIT);
I am doing error checking at each stage but didn't include it in the snippet. When I compile & run this, I can connect to port 2000 but not to 2001, my Tera term terminal closes with connection refused message. Why is the client not able to connect to port 2001 (UDP socket) but connects to port 2000 (TCP socket). The server just responds to client messages until client enters QUIT.
I have modeled this code from Beej's Guide to Network Programming selectserver.c code.
The program that I wrote above was correct but my understanding of socket programming was not. It was a fluke that I managed to write correct code but thanks to #EJP for having an extended discussion in the comments to clear up my doubt.
My mistake was using Teraterm's TCP client to connect to a UDP server. Both communications are mutually exclusive & hence can't communicate with one another. So I had to use a UDP client. Netcat provides an option of UDP client using netcat -u <ip address> <port>. Then my UDP server was able to receive messages from UDP client.
Another mistake was confusing bind() with connect() in DATAGRAM sockets. A connected DGRAM is when I use connect on both server & client.
I thought the problem was with select(), as I wrongly thought that UDP & TCP sockets can't be used simultaneously in select(). But the above code is how you write a UDP/TCP server for multiple client.
Thanks again to Beej & #EJP
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.
I have a c program. it first tries to send UDP message to the loopback address, then read from the the loopback.
But first the sendto() function fails with the message "sendto fails: Invalid argument".
The code looks like:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int main(void)
{
struct sockaddr_in servaddr;
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
struct in_addr addr;
char dottedaddr[20];
inet_aton("127.0.0.1", &addr);
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = addr.s_addr;
servaddr.sin_port = htons(0);
struct sockaddr_in cliaddr;
inet_aton("192.168.2.12", &addr);
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = addr.s_addr;
cliaddr.sin_port = htons(5000);
if(bind(sockfd, (const struct sockaddr *)&cliaddr, sizeof(cliaddr)) == -1)
{
perror("bind failed");
exit(1);
}
char buf[] = {'h', 'i', ' ', 'i', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u', 0};
if( sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("sendto fails");
exit(2);
}
fd_set readFd;
FD_ZERO(&readFd);
FD_SET(sockfd, &readFd);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int ret = select(sockfd + 1, &readFd, NULL, NULL, &timeout);
if(ret > 0)
{
if(FD_ISSET(sockfd, &readFd))
{
char buf2[21];
struct sockaddr_in from;
int len = sizeof(from);
if(recvfrom(sockfd, buf2, sizeof(buf2), 0, (struct sockaddr *)&from, &len) == -1)
{
perror("recvfrom fails");
}
}
}
else if (ret == 0)
{
printf("select time out \n");
}
else
{
printf("select fails");
}
}
if i change the server port from 0 to 5000, then sendto() can succeed. What is the reason ?
The second question is, after the server port is changed to 5000, the select() cannot detect the socket is readable or not. It simply timeout. I think sockfd should be readable since i just send a message to the loopback address. Is there anything wrong with the code?
thank you!
if i change the server port from 0 to 5000, then sendto() can succeed. What is the reason ?
UDP required packets to have specific source and destination port greater that zero. The only case when you can use zero port is the bind call; in that case socket will be bind on some free non-zero port and future packets from that sockets will use that number as src port.
You always should specify non-zero destination port as a param of sendto() for udp packets.
I think sockfd should be readable since i just send a message to the loopback address.
I am not sure, but it looks like you don't listen loopback. When you bind, you bind only on 192.168.2.12 network interface. You should use INADDR_ANY to bind on all interfaces, including loopback.