How to send NACK message from receiver to sender

Viewed 110

I am trying to make application in C, in Visual Studio, where one 'Sender' will send multiple messages to more 'Receivers', on some random ID 'Receiver' gets NACK message and send NACK to 'Sender' to inform him to send the message again (just via string ), 'Sender' sends that message again and if he doesn't receive NACK message in the next 3 sec the message will be considered as successfully sent to 'Receiver'.

My problem is: 'Recevier' gets NACK message successfully, but when I try to tell to 'Sender' that I've received NACK message the string displays something which is not a string I am sending to him. Can you tell me what am I doing wrong?

Sender:

#include <Winsock2.h>
#define _WINSOCK_DEPCRECATED_NO_WARNINGS
#include <sys/types.h> /* for type definitions */
#include <winsock.h> 
#include <stdio.h>  /* for printf() */
#include <stdlib.h>  /* for atoi() */
#include <string.h>  /* for strlen() */
#include <time.h>

#define MAX_LEN 1000 /* maximum string size to send */
#define MIN_PORT 1024  /* minimum port allowed */
#define MAX_PORT 65535 /* maximum port allowed */
#define IP_MULTICAST_TTL          10

int main(int argc, char *argv[]) {

int sock; /* socket descriptor */
char send_str[MAX_LEN]; /* string to send */
struct sockaddr_in mc_addr; /* socket address structure */
int send_len; /* length of string to send */
char* mc_addr_str; /* multicast IP address */
int mc_port; /* multicast port */
char mc_ttl = 1; /* time to live (hop count) */
WSADATA wsaData;
int counter = 0;
struct sockaddr_in from_addr;
int recv_len;
char recv_str[MAX_LEN + 1];
int from_len;

/* Load Winsock 2.0 DLL */
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
    fprintf(stderr, "WSAStartup() failed");
    exit(1);
}

/* validate number of arguments */
if (argc != 3) {

    fprintf(stderr, "Usage: %s <Multicast IP> <Multicast Port>\n",
        argv[0]);
//  exit(1);

}

mc_addr_str = argv[1]; /* arg 1: multicast IP address */
mc_port = atoi(argv[2]); /* arg 2: multicast port number */

                         /* validate the port range */
if ((mc_port < MIN_PORT) || (mc_port > MAX_PORT)) {
    fprintf(stderr, "Invalid port number argument %d.\n", mc_port);
    fprintf(stderr, "Valid range is between %d and %d.\n",
        MIN_PORT, MAX_PORT);
    exit(1);

}

/* create a socket for sending to the multicast address */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    perror("socket() failed");
    exit(1);

}

/* set the TTL (time to live/hop count) for the send */
if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
    (void*)&mc_ttl, sizeof(mc_ttl))) < 0) {
    perror("setsockopt() failed");
    exit(1);

}

/* construct a multicast address structure */
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(mc_addr_str);
mc_addr.sin_port = htons(mc_port);

printf("Write a message to send:\n");
for(counter; counter < 70; counter++){

/* clear send buffer */
memset(send_str, 0, sizeof(send_str));

/*  while (*/fgets(send_str, MAX_LEN, stdin);/*) {*/

    printf("Write a message to send:\n");
    counter++;
    send_len = strlen(send_str);

    if ((sendto(sock, send_str, send_len, 0,
        (struct sockaddr *) &mc_addr,
        sizeof(mc_addr))) != send_len) {

        perror("sendto() sent incorrect number of bytes");
        /*exit(1);*/
    }
    else
    {
        if (rand() % 5 == 0) {
                recv_len = recvfrom(sock, (char *)recv_str, 1024, 0,
                  (struct sockaddr*)&mc_addr, sizeof(&mc_addr));

                    printf("\nMessage ID %d\n and message: %s\n",recv_str);
        }
    }
}
    /* clear send buffer */
    memset(send_str, 0, sizeof(send_str));

/*closesocket(sock);*/
close(sock);
exit(0);

}

Receiver:

#include <WinSock2.h> 
#define _WINSOCK_DEPCRECATED_NO_WARNINGS
#include <sys/types.h> /* for type definitions */
#include <winsock.h> 
#include <time.h>
#include <stdio.h>/* for printf() and fprintf() */
#include <stdlib.h>/* for atoi() */
#include <string.h>/* for strlen() */

#define MAX_LEN 1024 /* maximum receive string size */
#define MIN_PORT 1024 /* minimum port allowed */
#define  MAX_PORT 65535 /* maximum port allowed */
#define IP_ADD_MEMBERSHIP         12 
#define IP_DROP_MEMBERSHIP        13
#define TIME 3000

int main(int argc, char *argv[]) {
int sock;  /* socket descriptor */
int flag_on = 1;  /* socket option flag */
struct sockaddr_in mc_addr;  /* socket address structure */
char recv_str[MAX_LEN + 1]; /* buffer to receive string */
int recv_len; /* length of string received */
              // struct ip_mreq mc_req; /* multicast request structure */
struct ip_mreq {
    struct in_addr imr_multiaddr; /* Group multicast address */
    struct in_addr imr_interface; /* Local interface address */
}mc_req;
char* mc_addr_str; /* multicast IP address */
/*unsigned*/ short mc_port; /* multicast port */
struct sockaddr_in from_addr;  /* packet source */
/*unsigned*/ int from_len;  /* source addr length */
int counter = 0;
char bufferData;
WSADATA wsaData;
char send_str[MAX_LEN];
int send_len;

/* Load Winsock 2.0 DLL */
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
    fprintf(stderr, "WSAStartup() failed");
    exit(1);
}
/* validate number of arguments */
if (argc != 3) {
    fprintf(stderr,
        "Usage: %s <Multicast IP> <Multicast Port>\n",
        argv[0]);
    exit(1);

}

mc_addr_str = argv[1]; /* arg 1' multicast ip address */
mc_port = atoi(argv[2]); /* arg 2' multicast port number */

                         /* validate the port range */
if ((mc_port < MIN_PORT) || (mc_port > MAX_PORT)) {
    fprintf(stderr, "Invalid port number argument %d.\n",
        mc_port);
    fprintf(stderr, "Valid range is between %d and %d.\n",
        MIN_PORT, MAX_PORT);
    exit(1);

}

/* create socket to join multicast group on */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    perror("socket() failed");
    exit(1);

}

/* set reuse port to on to allow multiple binds per host */
if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag_on,
    sizeof(flag_on))) < 0) {
    perror("setsockopt() failed");
    exit(1);

}

/* construct a multicast address structure */
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
mc_addr.sin_port = htons(mc_port);

/* bind multicast address to socket */
if ((bind(sock, (struct sockaddr *) &mc_addr,
    sizeof(mc_addr))) < 0) {
    perror("bind() failed");
    exit(1);

}

/* construct an IGMP join request structure */
mc_req.imr_multiaddr.s_addr = inet_addr(mc_addr_str);
mc_req.imr_interface.s_addr = htonl(INADDR_ANY);

/* send an ADD MEMBERSHIP message via setsockopt */
if ((setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
    (void*)&mc_req, sizeof(mc_req)))  <  0) {
    perror("setsockopt() failed");
    exit(1);

}

for (; ;) { /* loop forever */

            /* clear the receive buffers & structs */
    memset(recv_str, 0, sizeof(recv_str));
    from_len = sizeof(from_addr);
    memset(&from_addr, 0, from_len);

    /* block waiting to receive a packet */
    if ((recv_len = recvfrom(sock, recv_str, MAX_LEN, 0,
        (struct sockaddr*)&from_addr, &from_len)) < 0) {
        perror("recvfrom() failed");
        exit(1);

    }
    counter++;

    if (rand() % 5 == 0) {
        printf("\nNACK received for message with ID: %d\n", counter);

        sendto(sock, "NACK", strlen("NACK"),
            0, (struct sockaddr *) &from_addr,
            sizeof(&from_addr));

        printf("NACK message sent.\n");
        Sleep(TIME);
        if (TIME < 3000) {
            printf("\nError while receiving message.NACK received for message with ID: %d\n", counter);
        }
        else {

            printf("\nReceived %d bytes from %s ", recv_len,
                inet_ntoa(from_addr.sin_addr));
            printf("\nMessage ID: %d\nMessage: %s", counter, recv_str);
            //memset(recv_str, 0, sizeof(recv_str));
        }
    }
    else {
        /* output received string */
        printf("\nReceived %d bytes from %s ", recv_len,
            inet_ntoa(from_addr.sin_addr));
        printf("\nMessage ID: %d\nMessage: %s", counter, recv_str);
    }

}

/* send a DROP MEMBERSHIP message via setsockopt */
if ((setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
    (void*)&mc_req, sizeof(mc_req))) < 0) {
    perror("setsockopt() failed");
    exit(1);

}

close(sock);

}
1 Answers

The problem is in how you're printing the message the sender gets back from the receiver:

printf("\nMessage ID %d\n and message: %s\n",recv_str);

Your format string expects an int and a char * as arguments but you're only passing a char *. This means that you have a format specifier mismatch and not enough arguments for the format specifiers. The result is undefined behavior, which manifests as displaying the wrong message.

Visual Studio should warn you of this. When I compiled the sender code I got the following output:

sender.c(102): warning C4047: 'function': 'int *' differs in levels of indirection from 'unsigned int'
sender.c(102): warning C4024: 'recvfrom': different types for formal and actual parameter 6
sender.c(104): warning C4477: 'printf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'char *'
sender.c(104): warning C4473: 'printf' : not enough arguments passed for format string
sender.c(104): note: placeholders and their parameters expect 2 variadic arguments, but 1 were provided
sender.c(104): note: the missing variadic argument 2 is required by format string '%s'

Warnings from the compiler should not be ignored. Note that you have other issues besides the one you asked about.

Since you don't yet have a message ID, remove that from the format string.

printf("Message: %s\n",recv_str);
Related