Archived

This topic is now archived and is closed to further replies.

Melekor

UDP Sockets program only working on windows

Recommended Posts

Melekor    379
I just created a UDP sockets program with a sender and reciever, and it works great on my own computer. Then I asked my friend who uses OSX to compile it and see if we could send/recieve with eachother. It compiled, but it doesn''t send or recieve. My friend is really busy, and I''m finding it really hard to debug it cause.. well, it works on my windows machine and I only have one machine, heh. So, I have no idea what''s causing the problem. My guess is that somehow the way i''m using the sockets is not compatible with unix sockets, and I''ve been reading the man pages but can''t find any discrepencies. Maybe someone here can look over the code and find the problem? I have my code split into 4 files. udp.h:
#ifndef __UDP_H__
#define __UDP_H__

#ifdef WIN32
#pragma comment(lib, "wsock32.lib")
#include <winsock.h>
#include <windows.h>
#define sleep Sleep
#endif

#ifdef MAC // or something

#define SOCKET_ERROR (-1)
#define closesocket close
typedef unsigned int SOCKET
// insert mac includes here				<------------------------

#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;

#define PORT_NUMBER 6559

#define MAX_PACKET_SIZE (1024+12)
#define MAX_DATA_SIZE (MAX_PACKET_SIZE - sizeof(Packet))
#define MAX_CONNECTIONS 16

struct Packet
{
	u32 length, checksum, packet_id;
	u16 type;
	u8 flags, user_id;

	u32 size() const
	{
		return length + sizeof(Packet);
	}

	inline void gen_checksum()
	{
		// TODO:crc32 please

	}

	inline bool chk_checksum()
	{
		// TODO:crc32 please

		return true;
	}

	void swap_base()
	{
		//checksum = swap32(checksum);

		//packet_id = swap32(packet_id);

		//type = swap16(type);

	}
};

struct Endpoint
{
	int in_use;
	sockaddr_in addr;

	void init(char* adress = 0)
	{
		if(adress)
		{
			addr.sin_family = AF_INET;
			addr.sin_port = PORT_NUMBER;
			addr.sin_addr.s_addr = inet_addr(adress);
			if(addr.sin_addr.s_addr == INADDR_NONE)
			{
				if(hostent* host = gethostbyname(adress))
				{
					memcpy(&addr.sin_addr, host->h_addr_list[0], host->h_length);
					in_use = true;
				}
			}
			else
			{
				in_use = true;
			}
		}
		else
		{
			in_use = false;
		}
	}

	bool send_packet(SOCKET s, Packet* p)
	{
		return sendto(s, ((char*)p)+4, p->size(), 0, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR;
	}
};

struct PacketHandler
{
	virtual void handle_packet(Packet* p){}
};

class ConnectionManager
{

private:

	SOCKET s;
	fd_set read;
	Packet* packet_buffer;
	Endpoint endpoints[MAX_CONNECTIONS];

public:

	inline ConnectionManager()
	{
		s = 0;

#ifdef WIN32
		WSADATA wsda; 
		WSAStartup(MAKEWORD(1,1), &wsda);
#endif
		packet_buffer = (Packet*) new char[MAX_PACKET_SIZE];

		for(int i = 0; i < MAX_CONNECTIONS; ++i)
		{
			endpoints[i].init();
		}
	}

	bool open(int port, bool bind_local = true)
	{
		close();

		sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = port;
		addr.sin_addr.s_addr = INADDR_ANY;

		s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

		if(s)
		{
			if(bind_local && (bind(s, (sockaddr*)&addr, sizeof(addr)) != 0))
			{
				close();
				return false;
			}

			return true;
		}

		return false;
	}

	inline void close()
	{
		if(s)
		{
			closesocket(s);
		}
	}

	inline ~ConnectionManager()
	{
		delete [] ((char*)packet_buffer);

#ifdef WIN32
		WSACleanup();
#endif
		
		close();
	}

	inline void new_connection(char* adress, int client_number)
	{
		endpoints[client_number].init(adress);
	}

	inline void delete_connection(int client)
	{
		endpoints[client].init();
	}

	inline void send(Packet* p, int client)
	{
		endpoints[client].send_packet(s, p);
	}

	void process(PacketHandler* p)
	{
		FD_ZERO(&read);
		FD_SET(s, &read);

		const timeval nowait = {0, 0};

		while(select(1, &read, 0, 0, &nowait))
		{
			FD_ZERO(&read);
			FD_SET(s, &read);

			int length = recvfrom(s, ((char*)packet_buffer)+4, MAX_PACKET_SIZE, 0, 0, 0);
			packet_buffer->length = length - sizeof(Packet);

			if(length >= sizeof(Packet) && packet_buffer->chk_checksum())
				p->handle_packet(packet_buffer);
		}
	}
};

class Network : PacketHandler
{

public:

	ConnectionManager* net;

	inline Network()
	{
		net = new ConnectionManager;
	}

	inline ~Network()
	{
		delete net;
	}

	inline void process()
	{
		net->process(this);
	}

	inline bool open(int port, bool bind = true)
	{
		return net->open(port, bind);
	}
};

#endif
packets.h
#ifndef __PACKETS_H__
#define __PACKETS_H__

enum
{
	TEXT_PACKET,
};

struct TextPacket : Packet
{
	char message[MAX_DATA_SIZE];

	inline TextPacket() {}

	inline TextPacket(const char* fmt, ...)
	{
		va_list args;
		va_start(args, fmt);
		set(fmt, args);
	}

	void set(const char* fmt, va_list args)
	{
		type = TEXT_PACKET;
		length = _vsnprintf(message, sizeof(message), fmt, args);
	}
};

#endif
sender.cpp
#include "udp.h"
#include "packets.h"

class Sender : public Network
{

public:

	void open_connection(char* ip)
	{
		net->new_connection(ip, 0);
	}

	void send_message(char* fmt, ...)
	{
		va_list args;
		va_start(args, fmt);

		TextPacket the_text;
		the_text.set(fmt, args);

		net->send(&the_text, 0);
	}
};

int main(int argc, int** argv)
{
	Sender s;

	if(s.open(0, false))
	{
		// if this is a remote computer running osX, it doesn''t seem to work

		s.open_connection("localhost");

		int i = 0;

		for(;;)
		{
			s.send_message("Hello! + %d\n", i++);
			sleep(1000);
		}
	}
}
receiver.cpp
#include "udp.h"
#include "packets.h"

class Receiver : public Network
{
	void handle_packet(Packet* p)
	{
		switch(p->type)
		{
			case TEXT_PACKET:
				printf(((TextPacket*)p)->message);
				break;
		}
	}
};

int main(int argc, int** argv)
{
	Receiver r;

	if(r.open(PORT_NUMBER))
	{
		for(;;)
		{
			r.process();
			sleep(1);
		}
	}
}
I realize that''s a lot of source to look over(about 250 lines) I really do appreciate your time and I assure you I spent a lot of my own trying to find the problem myself. Thanks in advance for any help! -Melekor

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
just did a quick look so I there may be more but,
addr.sin_port = PORT_NUMBER;
needs to be in network byte order:
addr.sin_port = htons(PORT_NUMBER);

Has the mac tried to connect with itself?

Share this post


Link to post
Share on other sites
Melekor    379
Thank you very much AP! That could very well be the problem!(no, the mac hasn''t tried communicating with itself.)

I will try this fix as soon as my mac friend gets back from work

Share this post


Link to post
Share on other sites
Melekor    379
All right, my friend had some more time and we went over the programs quite a bit. I fixed that endian problem and we did some tests and now at least there we''ve figured out some things.

Here are the results of the tests:

pc->pc: works
mac->pc: works
pc->mac: doesn''t work
mac->mac: doesn''t work

So I think we can conclude that its''s the receiving code causing the problem on the mac. BTW, I know for sure it''s not a firewall problem.

Even after all this though, we don''t know what the problem is with the receiving code. So, does anyone have any more ideas as to what could be wrong?

Thanks!

Share this post


Link to post
Share on other sites
Melekor    379
Phew, finally figured it out.

The problem(besides the endian thing) was the first parameter of select(), nfds. I took this to mean the number of sockets in the set, whereas it really means the value of the highest file descriptor. The reason this bug didn''t show up on windows is because winsock ignores the nfds paramater.

I found the info here

Working on the problem was fun, because my friend let me use something called ssh to remotely compile and run stuff on his computer, so I got to use the unix command line. Pretty cool

So anyways, thanks again for your help AP, and maybe someone can find the info on select() useful, because the nfds parameter really isn''t very intuitive at all.

Share this post


Link to post
Share on other sites