0

I'm trying to communicate through a connected-udp-socket between two peer's. The address information between the peers is transmitted via a server using tcp.

First each peer set's up an udp-socket, binds an address and then transmit the address information via tcp to a server. The server sends the connection information to the other peer.

When the peer receives the information it tries to 'connect' the udp-socket to the other peer. The connect call succeed, but send gives me the following error: 'errno: 89, Destination address required'.

peer.c:

#include "Socket.h"
#include "function.h"

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

if(argc != 4) {
    printf("3 Parameter must be given.\nclient-ip server-ip server-port\n");
    exit(-1);
}

struct sockaddr_in my_addr, server_addr, other_peer_addr;

address_info* msg_address_info;
header *msg;

int recv_done = 0;
int optval = 1;
int fd_udp, fd_server;
ssize_t len;
socklen_t my_addr_len;
fd_set rfds;

FD_ZERO(&rfds);

fd_udp = Socket(AF_INET, SOCK_DGRAM, 0);

memset((void *) &my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
    my_addr.sin_len = sizeof(struct sockaddr_in);
#endif
my_addr.sin_port = 0; // any port
if ((my_addr.sin_addr.s_addr = (in_addr_t)inet_addr(argv[1])) == INADDR_NONE) {
    fprintf(stderr, "Invalid address\n");
}

Bind(fd_udp, (const struct sockaddr *) &my_addr, sizeof(my_addr));

Setsockopt(fd_udp, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
Setsockopt(fd_udp, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(int));

memset((void *) &my_addr, 0, sizeof(my_addr));
my_addr_len = sizeof(my_addr);
//get the current address for server registration
Getsockname(fd_udp, (struct sockaddr *) &my_addr, &my_addr_len);


/* TCP Communication */
/* i use 127.0.0.1:55555 for the server */
fd_server = Socket(AF_INET, SOCK_STREAM, 0);

memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
     server_addr.sin_len = sizeof(struct sockaddr_in);
#endif
server_addr.sin_port = htons(atoi(argv[3]));
if ((server_addr.sin_addr.s_addr = (in_addr_t) inet_addr(argv[2]))
        == INADDR_NONE) {
    fprintf(stderr, "Invalid address\n");
}

Connect(fd_server, (const struct sockaddr *) &server_addr, sizeof(server_addr));

len = sizeof(address_info);

msg_address_info = malloc(len + get_padding(len));

memset((void*)msg_address_info, 0, len + get_padding(len));

msg_address_info->head.type = htons(30);
msg_address_info->head.length = htons(sizeof(address_info));
msg_address_info->ip = my_addr.sin_addr.s_addr;
msg_address_info->port = my_addr.sin_port;

Send(fd_server, msg_address_info, len + get_padding(len), 0);

free(msg_address_info);

while(!recv_done) {

    FD_ZERO(&rfds);
    FD_SET(fd_server, &rfds);

    //data is ready for recv
    if(FD_ISSET(fd_server, &rfds)) {

        msg = recv_stream(fd_server);
        if(msg != NULL) {
            if(ntohs(msg->type) == 3) {
                Close(fd_server);
                recv_done = 1;

                msg_address_info = (address_info *) msg;

                other_peer_addr.sin_addr.s_addr = msg_address_info->ip;
                other_peer_addr.sin_port = msg_address_info->port;
            }
        }
    }
}

char buf[512];
memset((void*)&buf, 0, 512);

char* other_peer_ip;
int other_peer_port;

other_peer_ip = inet_ntoa(other_peer_addr.sin_addr);
other_peer_port = ntohs(other_peer_addr.sin_port);

printf("other_peer ip: %s\nother_peer port: %i\n", other_peer_ip, other_peer_port); //matches on bothe peer's

int ret_con = connect(fd_udp, (const struct sockaddr *) &other_peer_addr, sizeof(other_peer_addr));
fprintf(stderr, "ret_con: %i, errno: %i, %s\n", ret_con, errno, strerror(errno));

int ret_send = send(fd_udp, buf, 512, 0);
if(ret_send < 0) {
    fprintf(stderr, "ret_send: %i, errno: %i, %s\n", ret_send, errno, strerror(errno));
}

}

function.h:

#define BUFFER_SIZE  (1<<16)

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

#include <errno.h>

#include "Socket.h"

typedef struct {
    uint16_t type;
    uint16_t length;
} header;

typedef struct {
    header head;
    uint32_t ip;
    uint16_t port;
} address_info;

int get_padding(int length);
void* recv_stream(int fd);

functions.c:

#include "functions.h"

void* recv_stream(int fd) {
    if(fd < 0) {
        fprintf(stderr, "recv_stream: Invaild fd\n");
        return NULL;
    }
    ssize_t len;
    int msg_length;
    char buf[BUFFER_SIZE];
    char* msg;

    len = recv(fd, &buf, BUFFER_SIZE, MSG_PEEK);

    //Client has closed the connection
    if(len <= 0) {
        fprintf(stderr, "recv_stream: Client closed the connection.\n");
        exit(-1);
    }

#ifdef DEBUG
    printf("PEEKED %zd bytes.\n", len);
#endif

    if(len < sizeof(header)) {
        fprintf(stderr, "recv_stream: Message to small no header\n");
        return NULL;
    }

    header *head = (header *) buf;

    msg_length = ntohs(head->length);

    if(len < msg_length) {
        fprintf(stderr, "recv_stream: Message to small\n");
        return NULL;
    }
    else if(len >= msg_length + get_padding(msg_length)) {
        msg = malloc(msg_length + get_padding(msg_length));

        len = Recv(fd, msg, msg_length + get_padding(msg_length), 0);

        head = (header *) msg;
    }

    return head;
}


int get_padding(int length) {
    if(length <= 0) {
        fprintf(stderr, "get_padding: wrong length");
    }

    int pad = length % 4;
    if(pad == 3)
        pad = 1;
    else if(pad == 1)
        pad = 3;

    return pad;
}

Socket.c with Wrapper functions

int Socket(int fd, int type, int protocol) {

    int n;
    if((n=socket(fd,type,protocol)) < 0) {
        perror("socket");
        exit(-1);
    }
    return n;
}

/* many more */

I read already following question Can you bind() and connect() both ends of a UDP connection but it did not solve my problem.

The transfer of the address information seems to be correct. I printed the send and received addresses on both peers and they match.

I'm stucked on this problem and can't figure out my mistake. Can you help me?

Edit: provided new example

Now i get the following error:

ret_con: -1, errno: 97, Address family not supported by protocol
ret_send: -1, errno: 89, Destination address required
Community
  • 1
  • 1
P S
  • 38
  • 2
  • 8
  • With that code it is impossible for you to know that either `bind()` or `connect()` succeeded, or `socket()` or `send()` for that matter, or `getsockname()`. – user207421 Dec 31 '15 at 10:57
  • I know i have stripped it out. I have written wrappers for all of them. They look like: if((n=connect(s,name,namelen)) < 0) { perror("connect"); exit(-1); } – P S Dec 31 '15 at 10:58
  • 3
    You need to post the real code. – user207421 Dec 31 '15 at 10:59
  • has to be fd_udp sry. – P S Dec 31 '15 at 11:04
  • Please show us the logic for `other_peer_addr`... In fact, [write up an MCVE](http://stackoverflow.com/help/mcve)... I have a theory, but I won't share it until you learn how to provide examples to us that we can compile and run to reproduce the problems. Ping me once you've done that. – autistic Dec 31 '15 at 11:14
  • Error 89 means that the `connect()` *didn't* succeed. Impossible to tell what's really going on until you post the real code. – user207421 Dec 31 '15 at 11:23
  • 89 is the errno of send. I'm working on MCVE but it is hard. I have about 1500 lines of code. across multiple files. – P S Dec 31 '15 at 11:30
  • Just so. If `send()` returns -1 with `errno == 89` it means that the prior `connect()` didn't work. Period. – user207421 Dec 31 '15 at 11:32
  • Thanks. connect returns 0 with `errno == 0` – P S Dec 31 '15 at 11:33
  • Unfortunately `send()` doesn't agree with you. *Ergo* your observations are mistaken, or you're using a different socket. – user207421 Dec 31 '15 at 11:36
  • i have improved my example. @Seb – P S Dec 31 '15 at 13:42
  • Exactly as I stated hours ago. `connect()` is failing. – user207421 Dec 31 '15 at 23:49

1 Answers1

2

You are not populating the sin_family field of other_peer_addr before calling connect() on the UDP socket. You are only populating the sin_addr and sin_port fields, which is not enough. connect() needs to be told the type of address being passed to it and that must use the same family as the socket (just like with bind()). Since you are not populating the sin_family field, it contains a random value from the stack, and that is causing connect() to fail with the "Address family not supported" error, and send() cannot be called on an unconnected socket, thus causing the "Destination address required" error.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks. That was my mistake. `other_peer_addr.sin_family = AF_INET;` solved the problem. – P S Jan 01 '16 at 13:09