I am programming a UDP server-client program with WinSock2.h
, where the needed arguments (SOCKET
, sockaddr_in
) to respective threads are passed to the thread through a struct.
My receive function keeps throwing an exception whenever it gets to the recvfrom()
part, but only when I'm debugging the program. If I start it without debugger, it doesn't show me any errors nor stops the program running. This exception only happens at the server's side. Also, the recvfrom()
error checking keeps throwing error 10022 on the client's side, but as far as I understand, this is caused by not having bind()
on the client side.
Does the server side have the problem with bind()
being in another function or are my pointers somewhere wrong? I don't have any other ideas why is it only throwing the exception on the server side.
typedef struct thread_args {
struct sockaddr_in sockaddr;
SOCKET socket;
int keep_alive_count;
}THREAD_ARG;
void* receive_packets(void* arguments) {
THREAD_ARG* args = (THREAD_ARG*)arguments;
struct sockaddr_in* from;
char buffer[MAX_FRAGMENTATION + sizeof(HEADER)];
HEADER* message;
while (1) {
memset(buffer, "\0", MAX_FRAGMENTATION + sizeof(HEADER));
//this is where I get the exception thrown
if (recvfrom(args->socket, buffer, sizeof(buffer), 0, (struct sockaddr*) & from, sizeof(from)) == SOCKET_ERROR) {
printf("recvfrom() failed, error code: %d\n", WSAGetLastError());
exit(RECVFAIL);
}
message = (HEADER*)buffer;
char flag = message->flags;
}
}
return 0;
}
int client(THREAD_ARG* args) {
u_short port;
char ip[50];
struct sockaddr_in client_sock;
void* return_value1, *return_value2;
getchar();
printf("Please enter the IP address you would like to communicate with:\n");
gets(IP);
printf("Please enter the port number you would like to communicate with:\n");
scanf("%hu", &port);
client_sock.sin_family = AF_INET;
client_sock.sin_addr.s_addr = inet_addr(IP);
client_sock.sin_port = htons(port);
args->sockaddr = client_sock;
pthread_t send_thread, receive_thread, keep_alive_thread;
pthread_create(&send_thread, NULL, send_packets, args);
pthread_create(&receive_thread, NULL, receive_packets, args);
pthread_create(&keep_alive_thread, NULL, keep_alive, args);
pthread_join(send_thread, &return_value1);
pthread_join(receive_thread, &return_value2);
pthread_join(keep_alive_thread, NULL);
return 0;
}
int server(THREAD_ARG* args) {
u_short port;
int valid;
struct sockaddr_in server_sock;
void* return_value1, * return_value2;
printf("Please enter the port number you would like to listen on:\n");
scanf("%hu", &port);
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = INADDR_ANY;
server_sock.sin_port = htons(port);
if(bind(args->socket, (struct sockaddr_in*) & server_sock, sizeof(server_sock)) == SOCKET_ERROR) {
printf("Bind failed, error code: %d\n", WSAGetLastError());
return 1;
}
printf("Bind done\n");
args->sockaddr = server_sock;
pthread_t receive_thread;
pthread_create(&receive_thread, NULL, receive_packets, args);
pthread_join(receive_thread, &return_value2);
}
int main() {
WSADATA was;
SOCKET sock;
char choice;
THREAD_ARG* args;
printf("WinSock initialisation.\n");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("WinSock initialisation failed. Error code: %d\n", WSAGetLastError());
return 1;
}
printf("WinSock initialised.");
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
printf("Couldn't create socket: %d\n", WSAGetLastError());
}
printf("Socket created.\n");
printf("Would you like to be a server or a client?\n");
printf("1 - Server\n");
printf("2 - Client\n");
printf("0 - Exit\n");
args = (THREAD_ARG*)malloc(sizeof(THREAD_ARG));
args->socket = sock;
switch (choice = getchar())
{
case '0':
return 0;
case '1':
server(args);
break;
case '2':
client(args);
break;
default:
printf("Please choose from above\n");
}
return 0;
}
struct sockaddr_in* from;
char buffer[MAX_FRAGMENTATION + sizeof(HEADER)];
HEADER* message;
You have a problem here. You allocate only a sockaddr_in*
. But you need an actual sockaddr_in
to hold the address.
while (1) {
memset(buffer, "\0", MAX_FRAGMENTATION + sizeof(HEADER));
Here, the second parameter to memset
is wrong. It's supposed to be the value to set to, not a pointer to a value.
if (recvfrom(args->socket, buffer, sizeof(buffer), 0, (struct sockaddr*) & from, sizeof(from)) == SOCKET_ERROR) {
Here, you cast a struct sockaddr_in **
to a struct sockaddr *
, throwing away a level of indirection. That doesn't make any sense. And the last parameter, sizeof(from)
is the size of a pointer. That's not right.
THREAD_ARG* args;
...
args = (THREAD_ARG*)malloc(sizeof(THREAD_ARG));
args->socket = sock;
Why this weird indirection? Why not just THREAD_ARD args;
and get rid of the malloc
and ->
stuff?