3

I am trying to implement basic UDP multicast client and server on Linux. The server, based on a message sent by the client, is supposed to reply with system parameters (kinda like SNMP). Right now, I am testing with a single server. After running client and server on different terminals, I send a 3 character request to the server, but it appears that server is not able to proceed, and just stays suspended there, waiting for client. The codes are given here:

Client:

#include <stdio.h>
#include <stdlib.h>  
#include <string.h> 
#include <sys/types.h> 
#include <arpa/inet.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <unistd.h> 
#include <sys/time.h>
#include <time.h>

char* createheader(int , int , int , char , int );

#define PORT 15002 
#define MAXLINE 10000 
char* MULTICAST = "224.0.0.3";
char* myIP = "127.0.0.1";

// Driver code 
int main(int argc, char *argv[]) 
{    
    char buffer[10000];
    char message[10000]; 
    char *msg;
    int sockfd, n;
    char c = '0';
    int req1, req2, req3;

    int ctr = 0;
    int prev = 0, curr = 0;

    char tp = 'Q';
    int seq = 0, len;
    int yes = 1;
    short int resendflag = 0;
    struct timeval time1, time2, tv={2,0}; // structures that can take time in seconds and micro seconds.

    struct sockaddr_in servaddr;   
    bzero(&servaddr, sizeof(servaddr)); 

    servaddr.sin_addr.s_addr = inet_addr(MULTICAST); 
    servaddr.sin_port = htons(PORT); 
    servaddr.sin_family = AF_INET;

    struct in_addr interface_addr;
    interface_addr.s_addr = inet_addr(myIP);


    // create datagram socket  
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (int*) &yes, sizeof(yes));

       if (sockfd < 0) {
     perror("Error: socket");
     exit(1);
   }

    /*if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) 
        { 
            printf("\n Error : Connect Failed \n"); 
            exit(0); 
        }*/

    setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&tv,sizeof(struct timeval));

    //u_char loop;
    //setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));

    //Create Tx Header

    while(1)
    {
        prev = seq; 
        seq++;

        printf("\nEnter the 3 request characters, each followed by newline\n");
        scanf("%d%d%d", &req1, &req2, &req3);    
        msg = createheader(req1, req2, req3, tp, seq);


        while(c!='\0')
        {
            c = *(msg+ctr);
            //puts(&c);
            message[ctr] = c;
            ctr++;
        }   
        //printf("\nsize of %d",sizeof(c));
        c = '0';
        ctr = 0;

        //msg = NULL; 

        // connect to server 


        // request to send datagram 
        // connect stores the peers IP and port

        sendto(sockfd, message, sizeof(message), 0, (struct sockaddr*)&servaddr, sizeof(servaddr)); 
        puts(message);
        // waiting for response
        n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&servaddr, &len);

Portion after this is specific to my application: may be ignored unless you want to test it out.

        curr = buffer[4]-'0' + (buffer[5]-'0')*256 + (buffer[6]-'0')*65536 + (buffer[7]-'0')*65536*256;

        if (prev == curr || n == -1)
            {   
                resendflag = 1;     
                while(resendflag)
                    {
                        printf("No Response Recieved. Resending...\n");                       
                        sendto(sockfd, message, strlen(message), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
                        n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)NULL, NULL); 
                        curr = buffer[4]-'0' + (buffer[5]-'0')*256 + (buffer[6]-'0')*65536 + (buffer[7]-'0')*65536*256;

                        if (prev == curr || n == -1)
                            {
                                resendflag = 1;
                            }
                        else
                            {
                                resendflag = 0;
                                puts(buffer+12);
                            }

                        sleep(1);
                     }
            }
        else
            puts(buffer+12);

        //tp = 'A';        
        //msg = createheader(req1, req2, req3, tp, seq);
        // close the descriptor

    } 
    close(sockfd);
} 

char* createheader(int req1, int req2, int req3, char tp, int seq)
{
    static char msg1[1000];
    int len;
    //char req;
    msg1[0] = 'A';
    msg1[1] = tp;
    msg1[3] = '0';
    msg1[4] = seq%256+'0';
    msg1[5] = (seq/256)%256+'0';
    msg1[6] = (seq/65536)%256+'0';
    msg1[7] = (seq/(65536*256))%256+'0';
    msg1[8] = req1+'0';
    msg1[9] = req2+'0';
    msg1[10] = req3+'0';   
    msg1[12] = '\0';
    len = strlen(msg1);

    msg1[2] = len +'0';


    return msg1;   

}

And this is the server:

    #include <stdio.h>
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <arpa/inet.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <sys/time.h>
#include <time.h>

#define PORT 15002 
#define MAXLINE 10000
char* MULTICAST = "224.0.0.3";
char* myIP = "127.0.0.2";

char* createheader(int , int , int , char , int , int);
char* sysfunc(int , int , int); 

// Driver code 
int main(int argc, char *argv[]) 
{    
    setbuf(stdout, NULL);
    printf("lololol5"); //Just some indicators to see the progress
    char buffer[10000]; 
    char *message = "Hello Client";
    char msg[10000];
    char *msg1;
    char tp = 'R';
    int yes = 1; 
    int listenfd, len, l=0, seq = 0, req1, req2, req3, i, curr = 0, exc = 0;
    const char* syscl= NULL;

    int drop;
    srand(time(NULL));

    FILE* fp;

    struct sockaddr_in servaddr, cliaddr; 
    bzero(&servaddr, sizeof(servaddr)); 
    printf("lololol4");  
    // Create a UDP Socket 
    listenfd = socket(AF_INET, SOCK_DGRAM, 0);
       if (listenfd < 0) {
     perror("socket");
     exit(1);
   }

    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (int*)&yes, sizeof(yes))<0)
        {
            perror("socket");
            exit(1);
        }

    printf("lololol3");

    servaddr.sin_addr.s_addr = INADDR_ANY; 
    servaddr.sin_port = htons(PORT); 
    servaddr.sin_family = AF_INET;

    char *ip = inet_ntoa(servaddr.sin_addr);
    printf("\nip is %s\n", ip); 

    // bind server address to socket descriptor 
    if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {        
         perror("bind");
     exit(1);
      }

     printf("lololol2");   

    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST);
    mreq.imr_interface.s_addr = inet_addr(myIP);

    char *ip1 = inet_ntoa(mreq.imr_multiaddr);
    printf("\nmulip is %s\n", ip1); 

    if (setsockopt(listenfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq, sizeof(mreq)) < 0)
    {
        perror("setsockopt");
        return 1;
    } 
    while(1)
    {   
        //receive the datagram 
        len = sizeof(cliaddr);
        int n = recvfrom(listenfd, (char*) buffer, sizeof(buffer), 0, (struct sockaddr*)&cliaddr, &len); //receive message from client 

As before, application specific portion.

printf("\nHi\n"); 
        puts(buffer); //display message
        printf("\n");
        curr = buffer[4]-'0' + (buffer[5]-'0')*256 + (buffer[6]-'0')*65536 + (buffer[7]-'0')*65536*256;//acquire client seq. no

        req1 = buffer[8]; req2 = buffer[9]; req3 = buffer[10];//extract request bytes      
        syscl = sysfunc(req1-48, req2-48, req3-48); //Function call to get system corresponding system command string

        l = 12; //After 12 bytes of header
        puts(syscl);

        if (strcmp(syscl, "\nInvalid Command...\n\0"))
            {
                system(syscl); //The system call with the string gotten
                fp = fopen("sysstat.txt","r"); //Open the file where system output is written    
                while(!feof(fp))
                    {
                        msg[l] = fgetc(fp); //write file into an array
                        l++;
                    }
                fclose(fp);
                msg[l] = '\0'; //Append string with end of text char

            }
        else
            {
                char c1 = '0';
                while(c1 != '\0')
                    {
                        c1 = *(syscl+l-12); //write file into an array
                        //printf("\n %c", msg[l]);
                        msg[l] = c1; 
                        l++;
                    }
            }



        msg1 = createheader(req1, req2, req3, tp, curr, l); //Create Header  

        for (i=0; i<12; i++)
           {
                msg[i] = *(msg1+i);

            }

        drop = rand()%10+1; //to simulate dropped packets

        if (drop > 2) //Drop with a given prob (i.e (x-1)/10)
        {
            sendto(listenfd, &msg, MAXLINE, 0,(struct sockaddr*)&cliaddr, sizeof(cliaddr));
            puts(msg);
        }

        l = 0; 
    }
}

char* createheader(int req1, int req2, int req3, char tp, int seq, int len) //header
{
    static char msg1[10000];
    //int len;
    //char req;
    msg1[0] = '$'; //Start Char
    msg1[1] = tp; //Type of req.
    //msg1[3] = '0';
    msg1[4] = seq%256+'0'; //4-7: seq no in little endian
    msg1[5] = (seq/256)%256+'0';
    msg1[6] = (seq/65536)%256+'0';
    msg1[7] = (seq/(65536*256))%256+'0';
    msg1[8] = req1;
    msg1[9] = req2;
    msg1[10] = req3;   
    msg1[11] = '0';//Reserved Byte, Also for alignment
    //len = strlen(msg1);

    msg1[2] = (len +'0')%256+'0'; //2-3:Length in lil' endian
    msg1[3] = ((len+'0')/256)%256+'0';

    return msg1;   

}

char* sysfunc(int req1, int req2, int req3)
{
    static char syscl[100];
    //printf("\ncomm %d\n", req2);
    //printf("\ncomm %d\n", req3);

    switch (req2)
    {
        case 1: //Hardware
            {
                switch (req3)
                {
                    case 1: strcpy(syscl, "lscpu > sysstat.txt\0"); //CPU
                    break;

                    case 2: strcpy(syscl, "lsmem > sysstat.txt\0"); //Memoru=y
                    break;

                    case 3: strcpy(syscl, "lsblk > sysstat.txt\0"); //HDDs
                    break;

                    case 4: strcpy(syscl, "lspci > sysstat.txt\0"); //PCI Add-Ons
                    break;

                    default: strcpy(syscl, "\nInvalid Command...\n\0"); //Default
                    break;
                }

            }
        break;

        case 2: //OS
            {
                 switch (req3)
                {
                    case 1: strcpy(syscl, "hostname > sysstat.txt\0");//Hostname
                    break;

                    case 2: strcpy(syscl, "hostnamectl > sysstat.txt\0");//OS and Kernel
                    break;

                    case 3: strcpy(syscl, "uptime > sysstat.txt\0");//Uptime
                    break;

                    default: strcpy(syscl, "\nInvalid Command...\n\0");
                    break;
                }
            }
        break;

        case 3: //Network
            {
                 switch (req3)
                {
                    case 1: strcpy(syscl, "ip link show > sysstat.txt\0");//Ifs
                    break;

                    case 2: strcpy(syscl, "ifconfig | grep ether > sysstat.txt\0");//Ethernet
                    break;

                    case 3: strcpy(syscl, "ifconfig > sysstat.txt\0");//IP
                    break;

                    case 4: strcpy(syscl, "route -n > sysstat.txt\0");//Routing Table
                    break;

                    default: strcpy(syscl, "\nInvalid Command...\n\0");
                    break;
                }
            }
        break;

        default: strcpy(syscl, "\nInvalid Command...\n\0");
        break;
    }

    return syscl;            
}

Have been at it for 2 days. Unable to figure out where I went wrong. Since the server is showing no reaction, I am assuming there is something wrong in the initial portions (recvfrom on the server side) and therefore have split the code in such a way. Sorry if I have made some obvious noob mistakes.

dbush
  • 205,898
  • 23
  • 218
  • 273
psk1993
  • 33
  • 5
  • You are using a [reserved multicast address](https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml). – user207421 Sep 26 '19 at 06:56

1 Answers1

1

It seems you chose a wrong local IP address of interface in the server (where did you get the "127.0.0.2" from?) - if I change

    mreq.imr_interface.s_addr = inet_addr(myIP);

to

    mreq.imr_interface.s_addr = INADDR_ANY;

the server starts receiving.

Aren't 127.0.0.0/8 block of local addresses?

These are loopback addresses (see What is the rest of the 127.0.0.0/8 address space used for?). The comment local IP address of interface in the definition of struct ip_mreq may be a bit misleading, since it can remind one of localhost, but it actually means an IP address assigned to an interface of the local host seen from outside.

It is still not working with INADDR_ANY.

As so often, not working is an insufficient problem description. You could gather more information e. g. by running the server with strace -enetwork …. And I recommend to leave aside unnecessary complications like Mininet until the programs work on a pure network.

Armali
  • 18,255
  • 14
  • 57
  • 171
  • Aren't 127.0.0.0/8 block of local addresses? I just assigned one to client and another to server. It is still not working with INADDR_ANY. I also tried it on mininet with mreq.imr_interface.s_addr as the mininet host ID, but still blank. (with INADDR_ANY, setsockopt on mininet shows setsocopt error: No Such Device) – psk1993 Sep 25 '19 at 16:03
  • I expanded the answer. – Armali Sep 26 '19 at 06:16
  • 1
    Hi sorry. It did not initially, and I could not revisit this problem to do the strace to report the exact nature of the problem. I am sorry for leaving this hanging. If I get time, I will retry. I will however mark it as useful. Thanks. – psk1993 Dec 01 '19 at 13:00