[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(usagi-users 03469) Re: IPv6 Multicast question - connect fails



On Tue, 2005-08-09 at 17:01 +0200, Bas Vermeulen wrote:
> On Tue, 2005-08-09 at 13:54 +0200, Jeroen Massar wrote:
> > On Mon, 2005-08-08 at 15:58 +0200, Bas Vermeulen wrote:
<SNIP>
> > You definitely should be using getaddrinfo() See google(eva ipv6) =
> > gsyc.escet.urjc.es/~eva/IPv6-web/ipv6.html for the details.
> 
> Right. I've changed the code slightly to use getaddrinfo(). I still get
> the same result. What I do now:

Making a getaddr() function, copying that the structure you get from it
and reusing it with the wrong lenghts is a bad idea, treat it as a big
black box and don't touch/care about the contents.

This line:
> if (bind(s, &addr6, sizeof(addr6)
fails simply because sizeof(addr6) != res->ai_addrlen...
adding a variable to store the length of res->ai_addrlen in and then
passing this to bind might work though.

Another reason why the bind() might fail is because you bind to it,
close it, and then rebind it, the OS might not have cleansed the bind,
using additionally REUSEPORT helps a bit here, then again, the OS
probably nicely closes it and you didn't specify a local port in the
first place... hmm...

Also, when doing this, check that res->ai_addrlen < sizeof(struct
sockaddr_storage) just in case it ever becomes to big, which it should
not do, but still.

The other thing is that you are bind()'ing and connect()'ing to the same
address, the OS will refuse to do that I hope.

That all said, find attached a 'working' version:

jeroen@firenze:~$ ./mcast ff80::1 5060 fe80::202:55ff:fee6:21e8%eth0
1234
Trying to connect to [ff80::1]:5060
Binding local socket to [fe80::202:55ff:fee6:21e8%eth0]:1234
Trying [fe80::202:55ff:fee6:21e8%eth0]:1234 OK
Connecting to [ff80::1]:5060... OK
All went fine
Shutting down

jeroen@firenze:~$ ./mcast ff80::1
5060                                   
Trying to connect to [ff80::1]:5060
Connecting to [ff80::1]:5060... OK
All went fine
Shutting down

(Tested on a debianized Linux 2.6.10-1-686, thus basically stock kernel)

See, one can even fill in eth0 because of getaddrinfo() and I really
don't have any clue what it does with it (well I do, but I don't need to
have any ;)

Greets & Enjoy,
 Jeroen

(btw using goto's ????)

/* mcast.c - Example multicast thingy with getaddrinfo() etc
 * by Jeroen Massar <jeroen@xxxxxxxxx>
 *
 * Notez bien:
 *  this is connect() stuff, thus one only uses the first combo that works
 *  when making a listen server, one should make a pool of sockets and then
 *  either use a thread/fork to handle each or use select() to, for tcp, accept
 *  clients on them or recv() for udp to handle them...
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#ifndef SO_REUSEPORT
#define SO_REUSEPORT 15
#endif

#ifndef _WIN32
#define SOCKET int
#define closesocket(x) close(x)
#endif

void bindsocket(SOCKET sock, const char *host, const char *service);
void bindsocket(SOCKET sock, const char *host, const char *service)
{
	int		error = 0;
	struct addrinfo	hints, *res, *ressave;

	printf("Binding local socket to [%s]%s%s\n", host, service ? ":" : "", service ? service : "");

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_INET6;
	hints.ai_socktype = SOCK_DGRAM;

	error = getaddrinfo(host, service, &hints, &res);

        if (error != 0)
	{
                fprintf(stderr, "getaddrinfo(%s,%s) error: %d: %s\n", host, service, error, gai_strerror(error));
		return;
	}

	ressave = res;

	while (res)
	{
		char buf[NI_MAXHOST], buf2[NI_MAXSERV];
		getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf), buf2, sizeof(buf2), NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM);
		printf("Trying [%s]:%s ", buf, buf2);
		if (bind(sock, res->ai_addr, res->ai_addrlen) == 0)
		{
			printf("OK\n");
			break;
		}
		printf("FAIL\n");
		res = res->ai_next;
	}
        freeaddrinfo(ressave);
}

int main(int argc, char **argv);
int main(int argc, char **argv)
{
	int		error = 0;
	struct addrinfo	hints, *res, *ressave;
	SOCKET		sock = -1;
	socklen_t	on;
	char		*service = "5060";
	unsigned int	ttl = 16;

	if (argc == 1)
	{
		fprintf(stderr, "Usage: %s <remotehost> [<remoteport> [<localhost> [<localport>]]]\n", argv[0]);
		return -1;
	}

	if (argc >= 3) service = argv[2];

	printf("Trying to connect to [%s]:%s\n", argv[1], service);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_INET6;
	hints.ai_socktype = SOCK_DGRAM;

	error = getaddrinfo(argv[1], service, &hints, &res);

	if (error != 0)
	{
		fprintf(stderr, "getaddrinfo(%s,%s) error: %d: %s\n", argv[1], service, error, gai_strerror(error));
		return -1;
	}

	ressave = res;

	while (res)
	{
		sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

		if (sock >= 0)
		{
			char buf[NI_MAXHOST], buf2[NI_MAXSERV];

			on = 1;
			setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
			on = 1;
			setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));

			/* Make a local bind to host [port] ? */
			if (argc >= 4) bindsocket(sock, argv[3], argc >= 5 ? argv[4] : NULL);

			getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf), buf2, sizeof(buf2), NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM);
			printf("Connecting to [%s]:%s... ", buf, buf2);

			if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
			{
				printf("OK\n");
                		setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
				break;
			}

			printf("FAIL!\n");

			closesocket(sock);
			sock = -1;
		}
		res = res->ai_next;
	}

        freeaddrinfo(ressave);

	if (sock != -1)
	{
		printf("All went fine\n");

		/* Do stuff, note this is a connected UDP socket thus one can use normal read/write() */

		printf("Shutting down\n");
		closesocket(sock);
	}

        return 0;
}

Attachment: signature.asc
Description: This is a digitally signed message part