I have the following program where I am attempting to re-create ping. This works great when run in my macOS dev environment, but when running in my prod Linux environment the socket fails to get created. I can't figure out why. In addition, any way to resolve this so it works on Linux would be great.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* Calculate ICMP checksum */
uint16_t ip_checksum(void *icmp_header, int size_of_header){
unsigned short *buffer = icmp_header;
unsigned int sum = 0;
uint16_t result;
for(sum=0;size_of_header > 1; size_of_header -=2){
sum += *buffer++;
}
if(size_of_header == 1){
sum += *(unsigned char*)buffer;
}
sum = (sum >> 16) + (sum & 0xffff);
result = ~sum;
return result;
}
int main(int argc, char const *argv[]){
char ip[20]; /* Define variable to hold user entered IP address*/
const int icmp_size=8; /* Size of icmp header */
struct sockaddr_in toSendTo; /* Set sockaddr_in struct */
/* Create ICMP header */
struct icmp_header{
unsigned char icmph_type;
unsigned char icmph_code;
uint16_t icmph_checksum;
unsigned short int icmph_ident;
unsigned short int icmph_seqnum;
} icmp_header;
/* Get user to input IP address */
printf("Please enter an IP address: ");
fgets(ip, sizeof(ip), stdin);
/* Loop to send 3 pings requests */
for(int i = 0; i < 3; i++){
icmp_header.icmph_type = 8; /* Set ICMP type to 8 for sending ICMP request */
icmp_header.icmph_code = 0; /* Set ICMP code to 0 for sending ICMP request */
icmp_header.icmph_checksum = 0; /* Initializee checksum to 0 */
icmp_header.icmph_seqnum = i*20; /* Arbitrary sequence number */
icmp_header.icmph_ident = i+50; /* Arbitrary id */
icmp_header.icmph_checksum = ip_checksum(&icmp_header,icmp_size); /* Calculate checksum */
/* Set transport IP in sockaddr struct */
if (inet_addr(ip) == -1){
printf("Error, invalid IP address\n");
exit(1);
}else{
toSendTo.sin_addr.s_addr = inet_addr(ip);
}
/* Create socket */
int soc = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
/* Check if creation of socket throws an error */
if(soc == -1){
printf("Error creating socket\n");
exit(1);
}
/* Send ICMP ping request */
int send = sendto(soc, &icmp_header, icmp_size, 0, (struct sockaddr *)&toSendTo, sizeof(toSendTo));
/* Check if sending ICMP request throws an error */
if (send < 0){
printf("Error sending ping(%d).\n", i+1);
exit(1);
}else{
printf("\nICMP Echo Request(%d) sent to %s", i+1,ip);
}
unsigned int response_address_size; /* Variable for size of response packet */
char response_buffer[50]; /* Buffer for content of response */
struct sockaddr response_address; /* Struct to hold response address */
/* Struct to hold ICMP response header information */
typedef struct icmp_resp{
unsigned char icmph_type;
unsigned char icmph_code;
uint16_t icmph_checksum;
unsigned short int icmph_ident;
unsigned short int icmph_seqnum;
} icmp_r;
/* Receive ICMP response */
int resp = recvfrom(soc, response_buffer, sizeof(response_buffer), 0, &response_address, &response_address_size);
/* Check if receiving response throws an error */
if (resp < 0){
printf("Error receiving response (%d)\n",i+1);
exit(1);
}
icmp_r* echo_response;
echo_response = (icmp_r *)&response_buffer[20];
/* Determine if Destination Unreachable is response */
if(echo_response->icmph_type == 3 && echo_response->icmph_code == 0){
printf("Destination Unreachable...\n");
}else{
/* Print ICMP response information */
printf("ICMP Response(%d) : type=%d,code=%d,checksum=%x, ident=%d, seq=%d\n\n", i+1,
echo_response->icmph_type,
echo_response->icmph_code,
ntohs(echo_response->icmph_checksum),
echo_response->icmph_ident,
echo_response->icmph_seqnum);
}
/* Close Socket */
close(soc);
}
}
Here is my output when run in Linux:
Please enter an IP address: 8.8.8.8
Error creating socket
You have to set ping_group_range with sysctl like in the example below for specifying the groups who can create IPPROTO_ICMP sockets.
sysctl -w net.ipv4.ping_group_range="gid gid"
From the documentation:
ping_group_range (two integers; default: see below; since Linux
2.6.39)
Range of the group IDs (minimum and maximum group IDs,
inclusive) that are allowed to create ICMP Echo sockets.
The default is "1 0", which means no group is allowed to
create ICMP Echo sockets.
Edit
The socket type has to be SOCK_DGRAM instead of SOCK_RAW in int soc = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); and you also need to define toSendTo.sin_family = AF_INET;.
Related
I wrote a C program to implement Traceroute, because I need to get the ip path data efficiently. I hope when I ping an IP I could get all of the Ips between the src and dst IP. So I used TTL to get the Middle IPs, I suppose when I increase TTL one each time, I could get the middle Ips gradually. The code snippet as follows:
for(;ttl_val<20;ttl_val++){
setsockopt(ping_sockfd, SOL_IP, IP_TTL,&ttl_val, sizeof(ttl_val)
}
But when I use recvfrom to get the middle Ips, I found it was not correct, the middle Ips always change and they are different with the one I got with linux traceroute command.
The snippet code as follows:
struct sockaddr_in r_addr;
addr_len=sizeof(r_addr);
if ( recvfrom(ping_sockfd, &pckt, sizeof(pckt), 0,(struct sockaddr*)&r_addr, &addr_len) <= 0){
printf("\nPacket receive failed!\n");
}else{
if(!(pckt.hdr.type ==69 && pckt.hdr.code==0)){
printf("Error..Packet \n");
}else{
//THE MIDDLE IPs were not correct!!!!!!
printf("=%s\n", inet_ntoa(r_addr.sin_addr));
}
}
For example, my ip is 1.1.1.1, I'm going to ping the dest ip 5.5.5.5, the midway ips are: 2.2.2.2, 3.3.3.3, 4.4.4.4, i.e these are routes' ips in the path. I hope when I set TTL=1 I can get 2.2.2.2, when I set TTL=2 I can get 3.3.3.3, ect. I have no idea why my above doesn't work, When I set TTL the code return a random IP and not the real midway IP, because they are different from the Ips I got by linux traceroute command. My whole code as following please:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
// Define the Packet Constants
// ping packet size
#define PING_PKT_S 64
// Automatic port number
#define PORT_NO 0
// Automatic port number
#define PING_SLEEP_RATE 1000000
// Gives the timeout delay for receiving packets
// in seconds
#define RECV_TIMEOUT 1
// Define the Ping Loop
int pingloop=1;
// ping packet structure
struct ping_pkt{
struct icmphdr hdr;
char msg[PING_PKT_S-sizeof(struct icmphdr)];
};
// Calculating the Check Sum
unsigned short checksum(void *b, int len){
unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;
for ( sum = 0; len > 1; len -= 2 )
sum += *buf++;
if ( len == 1 )
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
int atoint(char s[]){
int i,n=0;
for(i=0;s[i]>='0' && s[i]<='9';i++){
n=10*n+(s[i]-'0');
}
return n;
}
// Interrupt handler
void intHandler(int dummy){
pingloop=0;
}
// Performs a DNS lookup
char *dns_lookup(char *addr_host, struct sockaddr_in *addr_con){
printf("\nResolving DNS..\n");
struct hostent *host_entity;
char *ip=(char*)malloc(NI_MAXHOST*sizeof(char));
int i;
if ((host_entity = gethostbyname(addr_host)) == NULL){
// No ip found for hostname
return NULL;
}
//filling up address structure
strcpy(ip, inet_ntoa(*(struct in_addr *)
host_entity->h_addr));
(*addr_con).sin_family = host_entity->h_addrtype;
(*addr_con).sin_port = htons (PORT_NO);
(*addr_con).sin_addr.s_addr = *(long*)host_entity->h_addr;
return ip;
}
// Resolves the reverse lookup of the hostname
char* reverse_dns_lookup(char *ip_addr){
struct sockaddr_in temp_addr;
socklen_t len;
char buf[NI_MAXHOST], *ret_buf;
temp_addr.sin_family = AF_INET;
temp_addr.sin_addr.s_addr = inet_addr(ip_addr);
len = sizeof(struct sockaddr_in);
if (getnameinfo((struct sockaddr *) &temp_addr, len, buf,
sizeof(buf), NULL, 0, NI_NAMEREQD)){
printf("Could not resolve reverse lookup of hostname\n");
return NULL;
}
ret_buf = (char*)malloc((strlen(buf) +1)*sizeof(char) );
strcpy(ret_buf, buf);
return ret_buf;
}
// make a ping request
void send_ping(int ping_sockfd, struct sockaddr_in *ping_addr,
char *ping_dom, char *ping_ip, char *rev_host, int ttl_val){
int msg_count=0, i, addr_len, flag=1,msg_received_count=0;
struct ping_pkt pckt;
struct timespec time_start, time_end, tfs, tfe;
long double rtt_msec=0, total_msec=0;
struct timeval tv_out;
tv_out.tv_sec = RECV_TIMEOUT;
tv_out.tv_usec = 0;
clock_gettime(CLOCK_MONOTONIC, &tfs);
// set socket options at ip to TTL and value to 64,
// change to what you want by setting ttl_val
if (setsockopt(ping_sockfd, SOL_IP, IP_TTL,&ttl_val, sizeof(ttl_val)) != 0){
printf("\nSetting socket options to TTL failed!\n");
return;
}else{
printf("\nSocket set to TTL..\n");
}
// setting timeout of recv setting
// setsockopt(ping_sockfd, SOL_SOCKET, SO_RCVTIMEO,(const char*)&tv_out, sizeof tv_out);
// send icmp packet in an infinite loop
while(pingloop){
// flag is whether packet was sent or not
flag=1;
//filling packet
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = getpid();
for ( i = 0; i < sizeof(pckt.msg)-1; i++ )
pckt.msg[i] = i+'0';
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = msg_count++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
usleep(PING_SLEEP_RATE);
//send packet
clock_gettime(CLOCK_MONOTONIC, &time_start);
if ( sendto(ping_sockfd, &pckt, sizeof(pckt), 0,
(struct sockaddr*) ping_addr,
sizeof(*ping_addr)) <= 0){
printf("\nPacket Sending Failed!\n");
flag=0;
}
struct sockaddr_in r_addr;
//receive packet
addr_len=sizeof(r_addr);
// struct sockaddr_in from;
if ( recvfrom(ping_sockfd, &pckt, sizeof(pckt), 0,(struct sockaddr*)&r_addr, &addr_len) <= 0 && msg_count>1){
printf("\nPacket receive failed!\n");
}else{
clock_gettime(CLOCK_MONOTONIC, &time_end);
double timeElapsed = ((double)(time_end.tv_nsec - time_start.tv_nsec))/1000000.0;
rtt_msec = (time_end.tv_sec-time_start.tv_sec) * 1000.0+ timeElapsed;
// if packet was not sent, don't receive
if(flag){
if(!(pckt.hdr.type ==69 && pckt.hdr.code==0)){
printf("Error..Packet received with ICMP type %d code %d\n", pckt.hdr.type, pckt.hdr.code);
}else{
printf("%d bytes from %s (h: %s) (%s) msg_seq=%d ttl=%d rtt = %Lf ms.\n", PING_PKT_S, ping_dom, rev_host,ping_ip, msg_count,ttl_val, rtt_msec);
printf("saddr = %d, %s: %d\n", r_addr.sin_family, inet_ntoa(r_addr.sin_addr), r_addr.sin_port);
msg_received_count++;
}
}
}
}
clock_gettime(CLOCK_MONOTONIC, &tfe);
double timeElapsed = ((double)(tfe.tv_nsec - tfs.tv_nsec))/1000000.0;
total_msec = (tfe.tv_sec-tfs.tv_sec)*1000.0 + timeElapsed;
printf("\n===%s ping statistics===\n", ping_ip);
printf("\n%d packets sent, %d packets received, %f percent packet loss. Total time: %Lf ms.\n\n", msg_count, msg_received_count, ((msg_count - msg_received_count)/msg_count) * 100.0, total_msec);
}
// Driver Code
int main(int argc, char *argv[]){
int sockfd;
char *ip_addr, *reverse_hostname;
struct sockaddr_in addr_con;
int addrlen = sizeof(addr_con);
char net_buf[NI_MAXHOST];
if(argc!=3){
printf("\nFormat %s <address> ttl \n", argv[0]);
return 0;
}
ip_addr = dns_lookup(argv[1], &addr_con);
if(ip_addr==NULL){
printf("\nDNS lookup failed! Could not resolve hostname!\n");
return 0;
}
reverse_hostname = reverse_dns_lookup(ip_addr);
printf("\nTrying to connect to '%s' IP: %s\n",argv[1], ip_addr);
printf("\nReverse Lookup domain: %s",reverse_hostname);
//socket()
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sockfd<0){
printf("\nSocket file descriptor not received!!\n");
return 0;
}else{
printf("\nSocket file descriptor %d received\n", sockfd);
}
signal(SIGINT, intHandler);//catching interrupt
int ttl = atoint(argv[2]);
//send pings continuously
send_ping(sockfd, &addr_con, reverse_hostname,ip_addr, argv[1],ttl);
return 0;
}
Your TTL works well. Use tcpdump -vn icmp to observe.
Your code results:
$ sudo ./test7 www.baidu.com 3
...
64 bytes from (null) (h: www.baidu.com) (104.193.88.123) msg_seq=25 ttl=3 rtt = 0.196290 ms.
saddr = 2, 162.151.78.85: 0
64 bytes from (null) (h: www.baidu.com) (104.193.88.123) msg_seq=26 ttl=3 rtt = 0.103414 ms.
saddr = 2, 162.151.78.85: 0
^C64 bytes from (null) (h: www.baidu.com) (104.193.88.123) msg_seq=27 ttl=3 rtt = 0.166377 ms.
saddr = 2, 162.151.78.85: 0
traceroute:
$ traceroute -n www.baidu.com
traceroute to www.baidu.com (104.193.88.123), 30 hops max, 60 byte packets
1 *.*.*.* 15.001 ms 15.138 ms 15.121 ms
2 *.*.*.* 14.828 ms 14.873 ms 15.047 ms
3 162.151.78.85 14.469 ms 14.941 ms 14.590 ms
...
However, on a noisy system (with other ICMP packets flying around) you are receiving also other packets. What you are missing is filtering receiving your own ICMP ID and desired ICMP type.
Without filtering, you will receive other undesired data (other ICMP) and you will need to discard (like you did with type 69 and code 0) AND recvfrom again. Linux examples of filtering:
struct sock_fprog filter;
// set filter with your ID
setsockopt(ping_sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof filter);
struct icmp_filter filter;
// set filter.data with ICMP types (bitmask)
setsockopt(ping_sockfd, SOL_RAW, ICMP_FILTER, &filter, sizeof filter);
This pertains to attempting to validate the return address in recvfrom() (the fifth argument to the function) in this UDP echo client:
While I can send data to the server and receive return communications correctly, I'm having trouble validating the return IP address when comparing the fromAddr.sin_addr and echoServAddr.sin_addr.
The goal here is to compare the address in the structure that was used in sendto() and the address in the structure returned from recvfrom() to validate the echo reply from the server indeed came from where the initial transmission from the client was sent (A rudimentary POC that there wasn't a Man In The Middle).
What should I be looking at in order to appropriately validate the return address as it is returned from recvfrom() matches the address transmitted to as referenced in the sendto() call?
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), sendto(), and recvfrom() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#define ECHOMAX 255 /* Longest string to echo */
void DieWithError(char *errorMessage); /* External error handling function */
int main(int argc, char *argv[])
{
int sock; /* Socket descriptor */
struct sockaddr_in echoServAddr; /* Echo server address */
struct sockaddr_in fromAddr; /* Source address of echo */
unsigned short echoServPort; /* Echo server port */
unsigned int fromSize; /* In-out of address size for recvfrom() */
char *servIP; /* IP address of server */
char *echoString; /* String to send to echo server */
char echoBuffer[ECHOMAX+1]; /* Buffer for receiving echoed string */
int echoStringLen; /* Length of string to echo */
int respStringLen; /* Length of received response */
// manage the command line arguments and errors
if ((argc < 3) || (argc > 4)) {
fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo Port>]\n",
argv[0]);
exit(1);
}
// load servIP
servIP = argv[1];
// load echoString
echoString = argv[2];
// check echoString and error if too long
echoStringLen = strlen(echoString);
if (!(echoStringLen <= 255)) {
DieWithError("BUFFER EXCEEDED ERROR");
}
// load port
if (argc == 4)
echoServPort = atoi(argv[3]);
else
echoServPort = 7;
// create the socket
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
DieWithError("SOCKET CREATION ERROR");
}
/* Construct the server address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet addr family */
echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */
echoServAddr.sin_port = htons(echoServPort); /* Server port */
// send the string
inet_pton(AF_INET, servIP, &echoServAddr.sin_addr);
if ((sendto(sock, echoString, strlen(echoString), 0, (struct sockaddr *)
&echoServAddr, sizeof(echoServAddr))) < 0) {
DieWithError("SEND ERROR");
}
// recieve a response
respStringLen = recvfrom(sock, echoBuffer, sizeof(echoBuffer), 0,
(struct sockaddr *) &fromAddr, &fromSize);
if (respStringLen < 0) {
DieWithError("RECV ERROR");
}
// print the message sent
printf("SENT FROM CLIENT: '%s'\n", echoString);
// print the message recieved
echoBuffer[respStringLen] = '\0';
printf("RECEIVED FROM SERVER: '%s'\n", echoBuffer);
// check if from the correct server
if ((struct sockaddr *) &echoServAddr.sin_addr != (struct sockaddr *) &fromAddr.sin_addr) {
DieWithError("INVALID RETURN ADDRESS");
}
// close the socket
close(sock);
// exit the program
exit(0);
}
If the source IP/port of the incoming packet is the same as the destation IP/port of the packet you sent, then the sin_addr and sin_port fields of echoServAddr and fromAddr should match.
This line of code however doesn't do that:
if ((struct sockaddr *) &echoServAddr.sin_addr != (struct sockaddr *) &fromAddr.sin_addr) {
This is comparing the address of echoServAddr.sin_addr against the address of fromAddr.sin_addr. Because these are two separate variables, this will always be false. You instead want:
if ((echoServAddr.sin_addr.s_addr != fromAddr.sin_addr.s_addr) ||
(echoServAddr.sin_port != fromAddr.sin_port))
My router.c file creates 2 sockets
the first is to bind to a port and answer clients
the second is to connect to an already bound port (by the server.c file)
and send messages to.
for some reason the sendto line return an Invalid argument error.
please help.
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
/* The Rounter represents through the server file(recv_udp.c).It transmitting from/to A(client) and C(another client)
by specific criteria (given in the assignment). */
int main(int argc, char *argv[])
{
/* Adding values that`ll be used for Q5*/
char serMsg [] = "Nice to hear from you,I am the server\n";
// char serMsg [] = "Good morning sun shine\n";
int serMsgLeng = strlen(serMsg)+1;
int error = -1;
char buff_A[200] = {'\0'};
char buff_C[200] = {'\0'};
// A value we get from the command prompt
float x;
float random, rand_num;
struct timeval tv;
tv.tv_sec = 3; /* 3 Seconds Time-out */
tv.tv_usec = 0;
/* Values that`ll receive for the socket I`ll open (as socket descriptor(an int) etc.) */
int socket_fd1,socket_fd2, cc, addrLenA, s_in2Size;
/* Randome number Raffled between the range of[0,1] */
double randNum;
/* Defining Structures for decleration of the server s_in= as serverAddr(local ip,and local port),
from_A = the address that the datagram was received from client A,
from_C-the address that the datagram was received from client C . */
struct sockaddr_in s_in1, s_in2;
// Defining Structures for handling the clients address(client A and client C)
// Client A address structure
struct sockaddr_in client_A_addr;
//Client C address structure
struct sockaddr_in client_C_addr;
x = atof(argv[1]);
// Creating UDPsocket-(it`s a system call)-the socket()function opens a local socket and saves it`s number in socket_fd value. */
socket_fd1 = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
socket_fd2 = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
/*set the socket options*/
setsockopt(socket_fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
setsockopt(socket_fd2, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
// Binary cleaning /
bzero((char *) &s_in1, sizeof(s_in1)); /* They say you must do this */
bzero((char *) &s_in2, sizeof(s_in2));
/* Configure settings in address struct
"s_in.sin_family"-set the address family to be "AF_INET
"s_in.sin_addr.s_addr"- the htonl function converts host's to network's long
"s_in.sin_port" -the htons function converts regular form port to binary form.*/
s_in1.sin_family = (short)AF_INET;//host byte order
s_in1.sin_addr.s_addr = htonl(INADDR_ANY); // WILDCARD //
s_in1.sin_port = htons(1337);
s_in2.sin_family = (short)AF_INET;//host byte order
s_in2.sin_addr.s_addr = inet_addr("172.17.0.15"); // WILDCARD //
s_in2.sin_port = htons(1338);
// printsin( &s_in, "RECV_UDP", "Local socket is:");
fflush(stdout);
/* The bind function assigns a local protocol address to a socket(and another system call).
The purpose of sin here is to tell bind which local address to assign.
bind method input:the sock_fd and the stuctur that handels the address and it`s length*/
bind(socket_fd1, (struct sockaddr *)&s_in1, sizeof(s_in1));
printf("After binding,waiting to hear from clients!\n");
addrLenA = sizeof(client_A_addr);
s_in2Size = sizeof(s_in2);
connect(socket_fd2, (struct sockaddr *) &s_in2, s_in2Size);
printf("After connect to server!\n");
// Keep listenning
for(;;) {
// Check from who we recive the message - if from cilent A
// Check for errors
//recfrom() returns the length of the message that it receives,so if the client message length that the method returns is
//equal to the message length of client A - we raffel a number between[0,1].
if( (cc = recvfrom(socket_fd1,&buff_A,sizeof(buff_A),0,(struct sockaddr*)&client_A_addr,&addrLenA))== error){
printf("No message for now, waiting...\n");
}
// For self-check ,no error occured
if (strlen(buff_A) > 0) {
printf("Client A says: %s\n", buff_A);
// Than raffel a randNum and decide what to do with it(send or delete it)
srand(time(NULL));
random = rand();
rand_num = random / RAND_MAX;
printf("rand_num: %f\n", rand_num);
printf("x: %f\n", x);
// Greater than X send it
if(rand_num > x) {
printf("Sending message From A to C\n");
// Pass the message to C
if(sendto(socket_fd2, &buff_A, sizeof(buff_A),0,(struct sockaddr*)&client_C_addr,sizeof(client_C_addr))== error){
printf("sendto()- Client C failes to send message\n");
printf("%s\n", strerror(errno));
exit(1);
}
} else {
// Drop the message
}
// Clearing the message buffer
memset(buff_A, '\0', sizeof buff_A);
}
} //end for
return 0;
}
You never fill in client_C_addr. You must tell sendto where to send the data, like:
client_C_addr.sin_family = AF_INET;
client_C_addr.sin_port = htons(port);
client_C_addr.sin_addr.s_addr = inet_addr("192.168.1.1");
I try to create a function to open a socket (i will have multiple socket in the future) called libf_build_udp_socket. But when it comes to bind i got the error cannot assign requested address and if i bypass this bind i got an error when sending a cmd.
If i don't use my function and integrate directly the code in my main, it works perfectly.
For the explanation i have a computer under linux that have to send cmd and received log from different equipment such as signal receiver...
Here is my full code, so maybe you will better understand my goals.
/* Standard Linux headers */
#include <stdio.h> //printf
#include <string.h> //memset
#include <stdlib.h> //exit(0);
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/times.h>
#include <unistd.h>
#include <errno.h>
/* DEFINE */
#define IP_RX "192.168.0.10" //notre IP=192.168.0.5
#define BUFFLEN 1024 //Max length of buffer
#define PORT_RX 3000 //The port on which to send data
unsigned short int libf_build_udp_socket(int * udp_socket, char * server_address, unsigned short int udp_port);
int main (void)
{
/*
** Definition of the local variables.
*/
//SOCKET
struct sockaddr_in addr_rx;
int serv_len_rx=sizeof(addr_rx);
int socket_fd_rx;
unsigned short int socketStatus; /* Socket return status */
//FD
fd_set readfds;
//BUFFER & CMD
char recepbuff[BUFFLEN];
char cmd[BUFFLEN], cmd_final[BUFFLEN];
//OTHER
int i, recv;
char choice;
int loop=1;
//TIMEOUT STRUCT
struct timeval tv;
tv.tv_sec=0; /*timeout de 0sec*/
tv.tv_usec=1000; //NE MARCHE PAS SI =0
/*
** Initialisation of the local variables.
*/
memset(recepbuff, '0' ,sizeof(recepbuff)); /*pareil que bzero*/
i=0;
/*
** Creating the socket
** call socket (it creates an endpoint for communication and
** returns the socket descriptor.
** To create an UDP socket here are the param
** The protocol family should be AF_INET
** The protocol type is SOCK_DGRAM
** The protocol should beset to default ie
** DEF_PROTOCOL wich is default so 0. );
*/
//OPENING AND SETTING SOCKET RX
socketStatus = libf_build_udp_socket(&socket_fd_rx, IP_RX, PORT_RX);
if (socketStatus>0)
{
printf("Could not create the socket, code error %d\n", socketStatus);
return 0;
}
/* Messaging*/
while(1)
{
printf ("\n//Boucle %d\n", i);
//clear the buffer by filling null, it might have previously received data
memset(recepbuff, '\0' ,sizeof(recepbuff));
loop=1;
//preparing cmd
printf("Enter command :");
fgets(cmd, sizeof(cmd) , stdin);
snprintf(cmd_final, sizeof (cmd_final), cmd, "\r\n"); /*adding 0d 0a to the cmd*/
//send cmd
if ( (sendto(socket_fd_rx , cmd_final, BUFFLEN , 0 , (struct sockaddr *)&addr_rx, serv_len_rx) ) < 0 )
{
perror("ERROR > send cmd failed to wass : ");
return 0;
}
else
{
printf( "cmd send to %s:%d\n" ,inet_ntoa(addr_rx.sin_addr), ntohs(addr_rx.sin_port) );
}
//printf("\n... waiting answer from %s:%d ... \n" ,inet_ntoa(addr_rx.sin_addr), ntohs(addr_rx.sin_port) );
//strcpy(recepbuff, "whileloop");
//try to receive some data, this is a blocking call
while(loop)
{
memset(recepbuff, '\0' ,sizeof(recepbuff)); //empty buffer
FD_ZERO(&readfds);
FD_SET(socket_fd_rx, &readfds); //set testing for rx
select(socket_fd_rx+1, &readfds, NULL, NULL, &tv); //block until cmd becomes available
if(FD_ISSET(socket_fd_rx, &readfds)) //input rx available
{
//printf("Data to be read \n");
recvfrom( socket_fd_rx, recepbuff , BUFFLEN, 0, (struct sockaddr *)&addr_rx, &serv_len_rx); //recep
printf("[=> RĂ©ponse : %s\n", recepbuff);
}
else
{
loop=0;
}
}
printf(".... RĂ©ponse done from %s:%d .... \n",inet_ntoa(addr_rx.sin_addr),ntohs(addr_rx.sin_port) );
i++;
}
close(socket_fd_rx);
return 0;
}
//FONCTIONS
//OPENING 1 SETTING A SOCKET
/** libf_build_udp_socket
*
* This function creates an UDP socket.
*
* \param udp_socket socket identifier
* \param server_address IP destination address
* \param udp_port Destination UDP port
* \param server_flag TRUE to bind socket on UDP port
*
* \return 0 if successful; error code otherwise
*/
unsigned short int libf_build_udp_socket(int * udp_socket, char * server_address, unsigned short int udp_port)
{
/*
** Defining of the local variables.
*/
struct sockaddr_in serv_addr; /* Server Socket address structure*/
short int status = 0; /* internal status return*/
unsigned short int return_status = 0; /* the returnes status value */
/*
** creating the socket ;
** call socket (it creates an endpoint for communication and
** returns the socket
** descriptor. To create an UDP socket
** the parameter family is set
** to AF_INET, the type to SOCK_DGRAM, and
** the protocol to
** DEF_PROTOCOL. The socket is a global variable.);
*/
*udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (*udp_socket < 0)
{
return_status = 1;
}
else
{
status = 1; //for future check
if (status >= 0)
{
/*
** reset the serv_addr variable
*/
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
/*
** set the sockname.sin_addr.s_addr to server address;
** sockname.sin_addr.s_addr = htonl(server address);
** set the sockname field sockname.sin_port to the used port number;
** sockname.sin_port = htons (udp port);
*/
serv_addr.sin_addr.s_addr = inet_addr(server_address);
serv_addr.sin_port = htons(udp_port);
/*
** Bind this socket to a name;
** call bind (it assigns a name or address to an unnamed socket.
** When a socket is created with socket it exists in
** a name space (address family) but has no name assigned.
** The bind requests the name, be assigned to the socket);
** If (return status signal an error)
** {
** set to return variable to error
** }
*/
status = bind(*udp_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (status < 0)
{
printf("bind failed with %s", strerror(errno));
return_status = 2;
}
}
else
{
return_status = 3;
}
}
/*
** return status;
*/
return return_status;
}
Maybe i'm missing something essential in socket programming, i made a lot of research and try different things but it still doesn't want to work ! I would appreciate some help ! Thank you !
How would I go about making this udpclient asynchronous using pthreads? I want to make sure UDP datagram won't be lost and also don't want the client program to wait forever and not be able to send any more messages
/*udpclient.c program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
/* Here are some details of the sockaddr_in structure and the sockaddr structure
These declarations are copied from winsock.h
struct in_addr { this struct holds a 32 bit IP address
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr
struct sockaddr_in { notice this structure is 16 bytes long
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr { this generic address structure is 16 bytes long, too!
u_short sa_family;
char sa_data[14];
};
*/
/* we have to send on the same port the server is listening on */
#define PORT 20009
/* simple upd client */
int main()
{
#ifdef WIN
SOCKET sock;
#else
int sock;
#endif
int size;
int nbytes, flags;
int i;
char * cp;
#ifdef WIN
WSADATA wsaData;
int nCode;
#endif
char buffer[100];
char str_addr[20]; /* holds the chars of an IP address */
struct sockaddr_in target_pc, me;
/* magic call to initialize the network I/O code - only Microsoft requires this */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
return -1;
}
#endif
/* create a socket to send on */
sock = socket(PF_INET,SOCK_DGRAM,0);
if(sock < 0) {
printf("socket error = %d\n", sock);
return -1;
}
/* we fill in the address family and port, but we do not know the destination IP address yet */
target_pc.sin_family = PF_INET;
target_pc.sin_port = htons(PORT);
/* fill in my address and port */
me.sin_family = PF_INET;
me.sin_port = htons(0);
me.sin_addr.s_addr = htonl(INADDR_ANY);
i = bind(sock, (struct sockaddr *) &me, sizeof(me));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
}
nbytes = 99;
while(1){
printf("Enter the target IP address: ");
cp = fgets(str_addr,19,stdin);
/* remove the \n */
str_addr[strlen(str_addr)-1] = '\0';
/* the inet_addr function converts a string form of IP address to a 32 binary integer */
target_pc.sin_addr.s_addr = inet_addr(&str_addr[0]);
printf("Enter your message: ");
cp = fgets(buffer,99,stdin);
/* get the string length so we send exactly this many characters */
nbytes = strlen(buffer);
flags = 0;
size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,sizeof(target_pc));
printf("msg size = %d size = %d\n", nbytes, size);
//added
int addrlen = sizeof(target_pc);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,&addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; //add the null byte so buffer now holds a string
i = puts((char *) buffer); // write this string to the display
}
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
/udpserver.c program/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#define PORT 20009
/* simple upd server
this program receives short messages (<99 characters) from any IP address
and writes them to the display
be sure to use the linker line option "-l wsock32"
*/
int main()
{
/* first define a socket
a socket is an I/O port like a file descriptor
*/
#ifdef WIN
SOCKET sock; /* SOCKET is a typedef for a structure */
#else
int sock;
#endif
int size;
int nbytes, flags;
#ifdef WIN
int addrlen;
#else
socklen_t addrlen;
#endif
int i;
/* char loopback[20]="127.0.0.1"; */
#ifdef WIN
WSADATA wsaData; /* This is struct holds Windows required data */
int nCode;
#endif
char buffer[100];
struct sockaddr_in server; /* this holds my IP address and port info */
struct sockaddr_in from; /* this holds the same info for the sender of the packet
I received */
/* the call to WSAStartup is Windows magic */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
exit;
}
#endif
/* create a socket called sock. It is a datagram socket */
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0){
printf("socket error = %d\n", sock);
return -1;
}
server.sin_family = AF_INET; /* initialize the server address family */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* notice this struct within a struct */
/* printf("%x\n",server.sin_addr.s_addr); */
server.sin_port = htons(PORT);
/* associate the socket with the address structure - this is called binding */
i = bind(sock, (struct sockaddr *) &server, sizeof(server));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
} else
printf("Simple UDP server is ready!\n\n");
nbytes = 99; /* receive packets up to 99 bytes long */
flags = 0; /* must be zero or this will not work! */
while(1){
/* the recvfrom function is a read and the arguments are:
sock - the socket we are reading
buffer - array into which to read the data
nbytes - read up to this many bytes
flags - used for special purposes - not needed here
from - sockaddr struct to hold the IP address and port of the sender of the packet
addrlen - the size of the sockaddr struct written by this function
*/
addrlen = sizeof(from);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&from, &addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; /* add the null byte so buffer now holds a string */
i = puts((char *) buffer); /* write this string to the display */
}
//echo message back to client
if(sock < 0) {//
printf("socket error = %d\n", sock);//
return -1;//
}//
sendto(sock, buffer, nbytes, flags, (struct sockaddr *)&from,addrlen); //
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
We could create two threads: one for the sendto (that waits for the user input) and the other for recvfrom(). Next, we can have the recvrom() use Pthread condvar (by calling pthread_cond_wait() on a condvar and a Pthread mutex) and wait. When the user provides an input, we can sendto (which is not really blocking) and then call pthread_cond_signal() to wake up the other thread.
You could certainly simply this, if you wanted. If your application permits, you could completely skip the pthread_cond_wait() since recvfrom() is anyways a blocking call. So, this way, recvfrom() would block but then it would go out of sync with the send calls. The other option is to use the main() thread for the sendto() thread -- in that case, you would just need one additional thread for the recv calls.