establishing UDP/IP communication

Started by
19 comments, last by karx11erx 19 years, 1 month ago
Quote:Original post by karx11erx
WI have been looking on the ethereal web site for a packet sniffer. All I could find was a program named winpcap. It seems to be a command shell (DOS box) application, no documentation, no GUI, you aren't even asked by the installer which folder you'd like to install this too.


Ethereal is a GUI program with a comprehensive and helpful GUI. That's why we use it.

WinPCap is just a component required before its (Ethereal's) installation.

Quote:
Honestly, this typical for the stuff Linux ppl do. It's complicated, it's cryptic, it's hard to use....


You just haven't read the Ethereal info.

Installation instructions

and to quote them,

" Both steps are extremely simply, as you only have to download and install the two exe files."

I'll ignore the rest of your rant about Linux users :)

In reply to your second bit about "netstat"...

Use "netstat -a" to display non-connected sockets too. "netstat" only displays connected ones, and seeing as UDP sockets are never connected, they generally aren't displayed.

Mark
Advertisement
Oh yes one thing:

On win32, Ethereal seems unable to sniff traffic on the loopback interface (127.0.0.1).

So if you've been using that for testing, change it to the real IP address of your machine on the LAN.

It's also possible that there are some other interface types that Ethereal doesn't work with on win32 - but it works fine on Ethernet (as its name implies) and that's what nearly everyone uses.

If you're having trouble finding the Ethereal win32 installer, it's in a subdirectory called "all-versions", check the timestamps, as they are not listed in chronological order (look for 0.10 versions).

Although Ethereal has an apparently low version number (< 1.0), it's actually been around for a long time and is extremely comprehensive with a lot of features.

I use it on Win32 and Linux for debugging all sorts of network problems - especially network / web applications.

Mark
Thanks. In the meantime I have been able to get and run Ethereal with some help from another forum.

There doesn't seem to be any UDP traffic generated by my program.

Currently it works like this:

(a) Server

The server gets a UDP socket, binds it to INADDR_ANY:<server port>, sets it to non blocking, listens with recvfrom().

(b) Client

The client gets a UDP socket, binds it to INADDR_ANY:<client port>, sets it to non blocking, sends data with sendto(). sendto() returns a function result indicating successful operation (i.e. the amount [bytes] of data sent). The data is sent to <server IP>:<server port>. As the server IP I have taken the IP returned by gethostbyaddr() and queryhost() (which is 192.168.0.1).

Well, Ethereal doesn't show any UDP traffic to <server IP>:<server port>, and I don't know enough about UDP to understand what's going wrong.

As a reminder: Both server and client run on the same machine.
_________karx11erxVisit my Descent site or see my case mod.
I didn't make it clear enough when to use ioctlsocket. Look for it twice in this version:


#include <winsock2.h>#include <iostream>using std::cout;using std::endl;#include <string>using std::string;#pragma comment(lib, "ws2_32.lib")bool Init(void){	WSADATA wsaData;	WORD wVersionRequested = MAKEWORD(2,2);	if(WSAStartup(wVersionRequested, &wsaData))		return false;	if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)		return false;	return true;}void Cleanup(SOCKET &Socket){	if(INVALID_SOCKET != Socket)		closesocket(Socket);	WSACleanup();}int main(void){	// init winsock	if(!Init())		return 1;	// create socket	SOCKET UDPSocket = INVALID_SOCKET;	if(INVALID_SOCKET == (UDPSocket = socket(AF_INET, SOCK_DGRAM, 0)))	{		cout << "  Could not allocate a new socket." << endl;		Cleanup(UDPSocket);		return 1;	}	// set non-blocking mode	unsigned long int non_blocking = 1;	if(0 != ioctlsocket(UDPSocket, FIONBIO, &non_blocking))	{		cout << "Could not set non-blocking mode.";		Cleanup(UDPSocket);		return 1;	}	// toggle this for client/server	bool send_mode = true;	if(send_mode)	{		struct sockaddr_in dest_addr;		struct hostent *he = gethostbyname("127.0.0.1");		if(0 == he)		{			cout << "Could not resolve target host.";			Cleanup(UDPSocket);			return 1;		}		dest_addr.sin_family = AF_INET;		dest_addr.sin_port = htons(55555);		dest_addr.sin_addr = *((struct in_addr *)he->h_addr);		memset(&(dest_addr.sin_zero), '\0', 8);		char *TXBuffer = "Hello World";		while(1)		{			cout << "Sending data..." << endl;			if(SOCKET_ERROR == (sendto(UDPSocket, TXBuffer, (int)strlen(TXBuffer) + 1, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))))			{				cout << "sendto error";				break;			}			Sleep(1000);		}	}	else	{		struct sockaddr_in my_addr;		struct sockaddr_in their_addr;		int addr_len = sizeof(struct sockaddr);		my_addr.sin_family = AF_INET;		my_addr.sin_port = htons(55555);		my_addr.sin_addr.s_addr = INADDR_ANY;		memset(&(my_addr.sin_zero), '\0', 8);		if(SOCKET_ERROR == bind(UDPSocket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)))		{			cout << "  Could not bind socket to port 55555";			Cleanup(UDPSocket);			return 1;		}		char RXBuffer[4096];		while(1)		{			long unsigned int NumBytesToBeRead = 0;			int bytes_received = 0;			if(0 != ioctlsocket(UDPSocket, FIONREAD, &NumBytesToBeRead))			{				cout << "ioctlsocket error";				break;			}			else if(0 != NumBytesToBeRead) // ioctl socket worked, and didn't report 0 bytes in the buffer			{				bytes_received = recvfrom(UDPSocket, RXBuffer, sizeof(RXBuffer), 0, (struct sockaddr *)&their_addr, &addr_len);				if(SOCKET_ERROR == bytes_received)				{					cout << "recvfrom error";					break;				}				cout << "Received: " << RXBuffer << endl;			}		}	}	Cleanup(UDPSocket);	return 0;}
Ok, you are checking for available data with ioctlsocket(), too.

What I don't understand is that you don't bind an address to the socket when sending data.

What do I have to use instead of 127.0.0.1 if I want to send data to some other computer? That computer's IP address?

Do I have to use 127.0.0.1 when sending to the same computer the sender is running on? Can't I use that computer's IP address as returned by gethostname() and gethostbyname() with the result of gethostname()?

Edit:

Well, whatever I try, Ethereal doesn't show me any UDP packets from my program. The last thing I have tried was to specify my network adapter's IP address as destination address. Didn't work.

[Edited by - karx11erx on March 10, 2005 3:29:08 PM]
_________karx11erxVisit my Descent site or see my case mod.
Rather than busy-waiting, try just setting the sockets into blocking mode. That way you can keep your receiver (server) running as you want.

Confirm with netstat (with -a option or whatever required to show open sockets) that the socket is really there.

If at all possible, obtain a packet-generation program to send some messages to it and confirm with Ethereal that they're really there.

Obviously test Ethereal with something which generates local UDP traffic first to ensure that it really works (hint: using nslookup to the local host as a nameserver (even if a DNS is not running locally) will generate UDP traffic).

There really is no point in checking the number of bytes to be read - you may as well go ahead and try to read them - if the socket is nonblocking, it will fail with EWOULDBLOCK.

If any socket errors occur be sure to print out and look up the error code you get (not sure how to do that on win32, it's not too tricky though).

Mark
I've gotten further.

First of all, both server and client need to bind INADDR_ANY to their sockets.

As both are on the same machine, they must not both use the same port, so I chose <client port> = <server port> + 1.

Now the server is receiving something, and it has the right "fingerprint", but the rest of the data doesn't seem to fit.

At least I have the communication going, so I can get into that.

Edit: I am having first positive results now. Things had gotten complicated because server and client were running on the same machine, so I had to use different ports and take that into regard at various spots in the code.

Thanks for all the help. :)

[Edited by - karx11erx on March 10, 2005 7:06:34 PM]
_________karx11erxVisit my Descent site or see my case mod.
Look at what I said before - the client SHOULD NOT bind to a specific port - rather it should bind to port "0" and let the OS choose an unused one.

Failure to observe this rule will cause your game to fail on multiuser machines, over NAT etc.

The server should store the port number of the client too in its user list and always send back to the same port the requests came from - regardless of the port that the client *thinks* it's using.

Mark
The client has to call bind() (with whatever port). That's my point, and that's what is *not* happening in the above code examples.

I will deal with client port handling when I have the communication completely working with a fixed port number.
_________karx11erxVisit my Descent site or see my case mod.
The client doesn't have to call bind(). If a UDP socket is not bound, it will be auto-bound to whatever port at the point of the first send().

Anyway, if you're binding to a specific port, I'd suggest checking for error, and re-trying with port+1 (and repeating up to about port+10 or so) before giving up and telling the user about the problem. That way, a collision with some other program, or a collision with another instance of the same program, won't shut you out. Also, a command-line option or configuration that lets the user choose the port is also useful to work around certain corporate firewall policies (where admins will only open ports where they know the port numbers on both sides).
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement