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