{"action":"created","issue":{"url":"https://api.github.com/repos/Lichtso/netLink/issues/17","repository_url":"https://api.github.com/repos/Lichtso/netLink","labels_url":"https://api.github.com/repos/Lichtso/netLink/issues/17/labels{/name}","comments_url":"https://api.github.com/repos/Lichtso/netLink/issues/17/comments","events_url":"https://api.github.com/repos/Lichtso/netLink/issues/17/events","html_url":"https://github.com/Lichtso/netLink/issues/17","id":170234398,"number":17,"title":"Server sockets default to IPv6 only on windows","user":{"login":"powertomato","id":1530983,"avatar_url":"https://avatars.githubusercontent.com/u/1530983?v=3","gravatar_id":"","url":"https://api.github.com/users/powertomato","html_url":"https://github.com/powertomato","followers_url":"https://api.github.com/users/powertomato/followers","following_url":"https://api.github.com/users/powertomato/following{/other_user}","gists_url":"https://api.github.com/users/powertomato/gists{/gist_id}","starred_url":"https://api.github.com/users/powertomato/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/powertomato/subscriptions","organizations_url":"https://api.github.com/users/powertomato/orgs","repos_url":"https://api.github.com/users/powertomato/repos","events_url":"https://api.github.com/users/powertomato/events{/privacy}","received_events_url":"https://api.github.com/users/powertomato/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Lichtso/netLink/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2016-08-09T18:15:33Z","updated_at":"2016-08-11T19:59:27Z","closed_at":"2016-08-10T09:54:12Z","body":"Hi,\r\n\r\nI compiled the tcp example, and played around with it. I noticed that I could not connect using IPv4 addresses (it would connect to \"localhost\", \"::1\" but not \"127.0.0.1\") . I did a bit of research and the problem seems to be that on windows, the \"IPV6_V6ONLY\" socket option defaults to 1 according to http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections.\r\n\r\nI confirmed that by executing the following snippet within \"initSocket\" in Socket.cpp:\r\n```c++\r\nDWORD ipv6only = 0;\r\nif(setsockopt(handle, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only)) == -1) {\r\n\tdisconnect();\r\n\tthrow Exception(Exception::ERROR_SET_SOCK_OPT);\r\n}\r\n```\r\n\r\nUsing that fixed the issue and I could connect using both \"::1\" and \"127.0.0.1\". However I'm not really sure where the snippet belongs. I put it right after the other \"setsockopt\"-calls, but that seems wrong, as it would also be set for UDP or IPv4 clients.\r\n\r\nBest regards\r\n"},"comment":{"url":"https://api.github.com/repos/Lichtso/netLink/issues/comments/239273843","html_url":"https://github.com/Lichtso/netLink/issues/17#issuecomment-239273843","issue_url":"https://api.github.com/repos/Lichtso/netLink/issues/17","id":239273843,"user":{"login":"powertomato","id":1530983,"avatar_url":"https://avatars.githubusercontent.com/u/1530983?v=3","gravatar_id":"","url":"https://api.github.com/users/powertomato","html_url":"https://github.com/powertomato","followers_url":"https://api.github.com/users/powertomato/followers","following_url":"https://api.github.com/users/powertomato/following{/other_user}","gists_url":"https://api.github.com/users/powertomato/gists{/gist_id}","starred_url":"https://api.github.com/users/powertomato/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/powertomato/subscriptions","organizations_url":"https://api.github.com/users/powertomato/orgs","repos_url":"https://api.github.com/users/powertomato/repos","events_url":"https://api.github.com/users/powertomato/events{/privacy}","received_events_url":"https://api.github.com/users/powertomato/received_events","type":"User","site_admin":false},"created_at":"2016-08-11T19:59:27Z","updated_at":"2016-08-11T19:59:27Z","body":"Cool, thanks!\r\nAs for the UDP part: I found the error. It's \"getaddrinfo\"\r\nFigure 12.3 on http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch12lev1sec2.html helped a lot understanding the issue. \r\n\r\nIf we resolve a hostname with AF_UNSPEC set, we get a linked list of addres descriptors. The first one has the family that the OS prefers. If a numeric address is given ( e.g. \"127.0.0.1\", \"::1\" ) it will end up with the family according to it's format (IPv4 for \"127.0.0.1\", IPv6 for \"::1\"). If a hostname is given, then multiple descriptors are returned.\r\n\r\nSo if we bind/listen to an IPv4 address but the system prefers IPv6, then \"localhost\" will result in the first descriptor with the type \"sockaddr_in6\" and \"sendto\" will fail, with 10049 i.e. \"WSAEADDR NOTAVAIL\", as \"sendto\" expects a \"sockaddr_in\" in our context.\r\n\r\nSimilary if we bind to\"*\" and end up with a IPv6 socket, but provide a numeric IPv4 address we get a \"sockaddr_in\" but expect \"\"sockaddr_in6\".\r\nThe here is to simply use IPv6 syntax for IPv6 sockets, even with IPv4 hosts. I tested sending to \"::FFFF:127.0.0.1\" and that worked. Also using a socket initialized in IPv4 mode, sending to \"127.0.0.1\" also gets transfered to that same server. So a \"*\"-bound socket truly is dual stack, as expected after IPV6_V6ONLY is set to 0. It's just even IPv6 dualstack sockets don't like IPv4 syntax.\r\n\r\nFor the first problem we need to iterate trough the address descriptor list and use the one with a matching family.\r\n\r\nThe changed case for UDP_PEER in the Socket::send(...) method would be:\r\n```c++\r\ncase UDP_PEER: {\r\n\tAddrinfoContainer _info = getSocketInfoFor(hostRemote.c_str(), portRemote, false);\r\n\tstruct addrinfo *info = _info.get();\r\n\twhile( info->ai_next != NULL){\r\n\t\tif(ipVersion == ANY){\r\n\t\t\tthrow Exception(Exception::ERROR_SEND);\r\n\t\t}\r\n\t\tif(ipVersion == IPv6 && info->ai_family == AF_INET6)\r\n\t\t\tbreak;\r\n\t\tif(ipVersion == IPv4 && info->ai_family == AF_INET)\r\n\t\t\tbreak;\r\n\t\tinfo = info->ai_next;\r\n\t}\r\n\tif( (ipVersion == IPv6 && info->ai_family != AF_INET6) || (ipVersion == IPv4 && info->ai_family != AF_INET) ){\r\n\t\tthrow Exception(Exception::ERROR_SEND);\r\n\t}\r\n\tsize_t sentBytes = 0;\r\n\twhile(sentBytes < (size_t)size) {\r\n\t\tint result = ::sendto(handle, (const char*)buffer + sentBytes, size - sentBytes, 0, info->ai_addr, info->ai_addrlen);\r\n\t\tif(result <= 0) {\r\n\t\t\tstatus = BUSY;\r\n\t\t\tthrow Exception(Exception::ERROR_SEND);\r\n\t\t}\r\n\t\tsentBytes += result;\r\n\t}\r\n\r\n\treturn sentBytes;\r\n}\r\n```"}}
{"actor":{"display_login":"powertomato"}}