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