Hi Oliver, Oliver Tappe <zooey@xxxxxxxxxxxxxxx> wrote: > On 2010-01-09 at 18:36:12 [+0100], Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> > > wrote: > > when I connect() a UDP socket to a peer in Haiku, no matter if I > > bound > > it implicitly or explicitly to INADDR_ANY, it's local address stays > > bound to INADDR_ANY, whereas it is resolved to a local address in > > Linux. > > I would tend to think that our behaviour is indeed wrong, but the > > documentation I read isn't as explicit about this as I would want > > it to > > be. > Well, I think Stevens' Unix Network Programming Vol I, Chapter 9.11 > is pretty > explicit when it states that a connected UDP socket receives only > datagrams > "destined to the connected socket's local address (IP and port)". I > think > this supports your interpretation that we are doing it incorrectly. Interestingly, we obviously correctly restrict the sender to the connected address. > Shall I have a look at it tomorrow, or would you prefer doing that > yourself? I already looked into it a bit, but I'm afraid one needs a stack function for this to work (or otherwise use SIOCGETRT). Feel free to look into it, if you want to -- if not I could do it, too. > Anything specific that triggered your question (a testcase)? I ran into the problem of not knowing the outgoing interface in UDP -- I created a work-around for Haiku via SIOCGETRT, only to later found out that at least Linux does not support this. I then read the connect() description again, and it looked like it would do what I needed, but it didn't work under Haiku. I've attached a small test application that you can use to reproduce the problem; we should probably put it into our repository. Bye, Axel.
/* * Copyright 2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main(int argc, char** argv) { const char* peerAddress = "192.168.0.1"; if (argc > 1) peerAddress = argv[1]; int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return 1; #if 1 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(8888); if (bind(fd, (sockaddr*)&addr, sizeof(addr)) != 0) perror("bind"); sockaddr ours; socklen_t ourLength = sizeof(sockaddr); if (getsockname(fd, &ours, &ourLength) != 0) perror("getsockname"); else { printf("After bind: local address %s (%u)\n", inet_ntoa(((sockaddr_in&)ours).sin_addr), ntohs(((sockaddr_in&)ours).sin_port)); } #endif sockaddr_in peer; peer.sin_family = AF_INET; peer.sin_addr.s_addr = inet_addr(peerAddress); peer.sin_port = htons(8888); if (connect(fd, (sockaddr*)&peer, sizeof(peer)) != 0) perror("connect"); ourLength = sizeof(sockaddr); if (getsockname(fd, &ours, &ourLength) != 0) perror("getsockname"); else { printf("After connect: local address %s (%u)\n", inet_ntoa(((sockaddr_in&)ours).sin_addr), ntohs(((sockaddr_in&)ours).sin_port)); } char buffer[256]; if (argc > 2 && !strcmp(argv[2], "recv")) { ssize_t bytesReceived = recv(fd, buffer, sizeof(buffer), 0); if (bytesReceived > 0) { buffer[bytesReceived] = 0; printf("received: %s\n", buffer); } else perror("recv"); } else { if (argc > 2) send(fd, argv[2], strlen(argv[2]), 0); fgets(buffer, sizeof(buffer), stdin); } close(fd); return 0; }