Tyler
Tyler

Reputation: 955

Receiving UDP message but recv returns 0

Problem: I have two c programs, one sends a UDP message, then gets a response and prints it. The other receives a UDP message, modifies it, and sends it back. I receive the message correctly, modify correctly (prints ok) and send it. I am receiving the message on the other end but with a recv return value of 0.

Question: Why do I get the proper message, but don't have the length of the message returned? This is hard to check that I received the proper length message as my goal is to access the 320th byte of a status message

I found this but I am not using strlen(), plus the buffer actually contains the proper message. Also i am not disconnecting the socket, as I am using UDP.

Here is the code for the client:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#define SERVICE_PORT    9090

#define BUFLEN 2048
#define MSGS 5

int main(void)
{
    struct sockaddr_in myaddr, remaddr;
    int fd, i, slen=sizeof(remaddr);
    char *server = "127.0.0.1"; 
    char buf[BUFLEN];
    ssize_t msglen;


    if ((fd=socket(AF_INET, SOCK_DGRAM, 0))==-1)
        printf("socket not created\n");


    memset((char *)&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myaddr.sin_port = htons(7096);

    if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
        perror("bind failed");
        return 0;
    }

    memset((char *) &remaddr, 0, sizeof(remaddr));
    remaddr.sin_family = AF_INET;
    remaddr.sin_port = htons(SERVICE_PORT);
    if (inet_aton(server, &remaddr.sin_addr)==0) {
        fprintf(stderr, "inet_aton() failed\n");
        exit(1);
    }

    char msg[4096];
    memset(msg, 0, 4096);
    for (i=0; i < MSGS; i++) {
        printf("Sending packet %d to %s port %d\n", i, server, SERVICE_PORT);
        sprintf(buf, "This is packet %d", i);
        if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, slen)==-1)
            perror("sendto");
        memset(msg, 0, 4096);
        if(msglen = recv(fd, msg, sizeof(msg), MSG_WAITALL) == -1){
            printf("Bad recv\n");
        }
        printf("recieved %d bytes: %s\n", msglen, msg);
    }
    close(fd);
    return 0;
}

here is the code for the server:

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

#include <linux/ip.h> /* for ipv4 header */
#include <linux/udp.h> /* for upd header */

#define ADDR_TO_BIND "127.0.0.1"
#define PORT_TO_BIND 9090
#define SERVICE_PORT 7096
#define MSG_SIZE 256
#define HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr))

int main(void) {
    int raw_socket, fd;
    struct sockaddr_in sockstr, remaddr;
    socklen_t socklen;

    int retval = 0; 

    char msg[MSG_SIZE];
    ssize_t msglen; 


    if ((raw_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        return 1; 
    }
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        return 1;
    }
    sockstr.sin_family = AF_INET;
    sockstr.sin_port = htons(PORT_TO_BIND);
    sockstr.sin_addr.s_addr = inet_addr(ADDR_TO_BIND);
    socklen = (socklen_t) sizeof(sockstr);
    if (bind(raw_socket, (struct sockaddr*) &sockstr, socklen) == -1) {
        perror("bind");
        retval = 1; 
        goto _go_close_socket;
    }
    if(bind(fd, (struct sockaddr*) &remaddr, socklen) == -1){
        perror("bind");
    }
    memset(msg, 0, MSG_SIZE);
while(1){
    if ((msglen = recv(raw_socket, msg, MSG_SIZE, 0)) == -1) {
        perror("recv");
        retval = 1;
        goto _go_close_socket;
    }
    memset((char *) &remaddr, 0, sizeof(remaddr));
    remaddr.sin_family = AF_INET;
    remaddr.sin_port = htons(SERVICE_PORT);
    if (inet_aton(ADDR_TO_BIND, &remaddr.sin_addr)==0) {
        fprintf(stderr, "inet_aton() failed\n");
        exit(1);
    }
    unsigned char buf[4096];
    msg[msglen] = '\0';
    printf("recieve %d bytes: %s\n", msglen, msg);
    sprintf(buf, "Your msg is: %s\n",msg );
    int slen=sizeof(remaddr);
    if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, slen)==-1){
        printf("send failed");    
    }
    printf("sent: %s\n", buf);
}
_go_close_socket:
    close(raw_socket);

    return retval;
}

The output of running the client is:

Sending packet 0 to 127.0.0.1 port 9090
recieved 0 bytes: Your msg is: This is packet 0

Sending packet 1 to 127.0.0.1 port 9090
recieved 0 bytes: Your msg is: This is packet 1

Sending packet 2 to 127.0.0.1 port 9090
recieved 0 bytes: Your msg is: This is packet 2

Sending packet 3 to 127.0.0.1 port 9090
recieved 0 bytes: Your msg is: This is packet 3

Sending packet 4 to 127.0.0.1 port 9090
recieved 0 bytes: Your msg is: This is packet 4

The output of running the server is:

recieve 256 bytes: This is packet 0
sent: Your msg is: This is packet 0

recieve 256 bytes: This is packet 1
sent: Your msg is: This is packet 1

recieve 256 bytes: This is packet 2
sent: Your msg is: This is packet 2

recieve 256 bytes: This is packet 3
sent: Your msg is: This is packet 3

recieve 256 bytes: This is packet 4
sent: Your msg is: This is packet 4

As you see, the message I get on the server is changed to have "your msg is: " at the beginning, and I am seeing that on the client side, but the return value is 0 for the length. Why is this?

This code are just slightly modified code samples of example UDP server client, so I won't be offended if the code quality is pointed out to be bad!

EDIT This was resolved, it was an issue with wrapping the recv() call in parentheses so the conditional was stored in msglen rather than the actual return value. See my answer below

Upvotes: 2

Views: 1717

Answers (2)

Tyler
Tyler

Reputation: 955

I was able to fix the issue, it seems I forgot to wrap my if statement for recv in parentheses, so I was assigning msglen the bool value of the conditional

recv(fd, msg, sizeof(msg), 0) == -1

Which of course was 0 as the return value was not equal to -1.

The fix was

if((msglen = recv(fd, msg, sizeof(msg), 0)) = -1)

Thanks to those who tried for their help

Upvotes: 2

Ahmed Masud
Ahmed Masud

Reputation: 22372

Normally you should be using recvfrom:

From the recv(2) man-page:

The recv() call is normally used only on a connected socket (see connect(2)) and is identical to recvfrom() with a NULL src_addr argument.

and from socket(2) man-page:

SOCK_DGRAM and SOCK_RAW sockets allow sending of datagrams to correspondents named in sendto(2) calls. Datagrams are generally received with recvfrom(2), which returns the next datagram along with the address of its sender.

Using recv(2) or read(2)

In order to use recv(2) or read(2), because you're exchaning a lot of datagrams, you have to call connect(2) first:

if (connect(fd,remote_addr,sizeof(remote_addr))==-1) {
    die("%s",strerror(errno));
}

Now you're good to go with recv or write.

Upvotes: 1

Related Questions