/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvxs is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #include #include #include #include #include #include #include #include #include #include #include namespace { using namespace pvxs; void test_bind46(const char* saddr1, const char* saddr2, int type, int expect) { const std::string label = SB()<<__func__<<"("< G(ifs.lock); // since we are playing around with the internals... ifs.refresh(true); testFalse(ifs.byIndex.empty())<<" found "<sa, bind_addr.size()); testOk(ret==(int)sizeof(msg), "Send test ret==%d(%d)", ret, EVUTIL_SOCKET_ERROR()); uint8_t rxbuf[8] = {}; SockAddr src; SockAddr dest; testDiag("Call recvfrom()"); ret = recvfromx{A.sock, (char*)rxbuf, sizeof(rxbuf), &src, &dest}.call(); // only the destination address is captured, not the port if(dest.family()!=AF_UNSPEC) dest.setPort(bind_addr.port()); testOk(ret==4 && rxbuf[0]==0x12 && rxbuf[1]==0x34 && rxbuf[2]==0x56 && rxbuf[3]==0x78, "Recv'd %d(%d) [%u, %u, %u, %u]", ret, EVUTIL_SOCKET_ERROR(), rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3]); testEq(src, send_addr); testEq(dest, bind_addr); } void test_local_mcast() { testDiag("Enter %s", __func__); IfaceMap ifinfo; evsocket A(AF_INET, SOCK_DGRAM, 0), B(AF_INET, SOCK_DGRAM, 0); SockEndpoint mcast_addr("224.0.0.128,1@127.0.0.1"); // We could bind to mcast_addr on all targets except WIN32 SockAddr bind_addr(SockAddr::any(AF_INET)); A.enable_IP_PKTINFO(); A.bind(bind_addr); mcast_addr.addr.setPort(bind_addr.port()); SockAddr sender_addr(SockAddr::loopback(AF_INET)); B.bind(sender_addr); // receiving socket joins on the loopback interface A.mcast_join(mcast_addr.resolve()); // ignores port(s) // sending socket targets the loopback interface B.mcast_prep_sendto(mcast_addr); // ignores port(s) B.mcast_loop(true); uint8_t msg[] = {0x12, 0x34, 0x56, 0x78}; int ret = sendto(B.sock, (char*)msg, sizeof(msg), 0, &mcast_addr.addr->sa, mcast_addr.addr.size()); testEq(ret, (int)sizeof(msg))<<"Send test"; uint8_t rxbuf[8] = {}; SockAddr src; SockAddr dest; testDiag("Call recvfrom()"); recvfromx rx{A.sock, (char*)rxbuf, sizeof(rxbuf), &src, &dest}; ret = rx.call(); if(dest.family()==AF_INET) dest.setPort(mcast_addr.addr.port()); testTrue(ret>=0 && rx.dstif>0 && ifinfo.has_address(rx.dstif, sender_addr)) <<" received on index "<sa, mcast_addr.addr.size()); testEq(ret, int(msglen))<<" sendto("< "<in.sin_addr.s_addr==htonl(INADDR_LOOPBACK), "%08x == 0x7f000001", (unsigned)ntohl(val->in.sin_addr.s_addr)); } } void test_to_wire() { testDiag("Enter %s", __func__); { const uint32_t val = 0xdeadbeef; uint8_t buf[8+1]; FixedBuf pkt(true, buf); to_wire(pkt, val); testEq(pkt.size(), 4u); testOk1(pkt.good()); testOk(buf[0]==0xde && buf[1]==0xad && buf[2]==0xbe && buf[3]==0xef, "0x%02x%02x%02x%02x == 0xdeadbeef", buf[0], buf[1], buf[2], buf[3]); } { const uint32_t val = 0xdeadbeef; uint8_t buf[8+1]; FixedBuf pkt(false, buf); to_wire(pkt, val); testEq(pkt.size(), 4u); testOk1(pkt.good()); testOk(buf[0]==0xef && buf[1]==0xbe && buf[2]==0xad && buf[3]==0xde, "0x%02x%02x%02x%02x == 0xefbeadde", buf[0], buf[1], buf[2], buf[3]); } { const SockAddr val(SockAddr::loopback(AF_INET)); uint8_t buf[16+4+1]; FixedBuf pkt(true, buf); to_wire(pkt, val); testEq(pkt.size(), 4u); testOk1(pkt.good()); const uint8_t expect[16] = {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0x7f,0,0,1}; testOk1(std::memcmp(buf, expect, 16)==0); } { const uint32_t val = 0xdeadbeef; uint8_t buf[] = "\0\0\0\0\0\0\0\0"; FixedBuf pkt(true, buf, 2); to_wire(pkt, val); testEq(pkt.size(), 2u); testOk1(!pkt.good()); testOk(buf[0]==0 && buf[1]==0 && buf[2]==0 && buf[3]==0, "0x%02x%02x%02x%02x == 0", buf[0], buf[1], buf[2], buf[3]); } } } // namespace MAIN(testsock) { SockAttach attach; logger_config_env(); testPlan(66); testSetup(); // check for behavior when binding ipv4 and ipv6 to the same socket // as a function of socket type and order. if(evsocket::canIPv6) { // IPv4 and v6 loopback addresses are entirely distinct, // so no problem binding to both w/ or w/o IPV6_V6ONLY test_bind46("127.0.0.1" , "::1" , SOCK_DGRAM , 0); test_bind46("::1" , "127.0.0.1" , SOCK_DGRAM , 0); test_bind46("127.0.0.1" , "::1" , SOCK_STREAM , 0); test_bind46("::1" , "127.0.0.1" , SOCK_STREAM , 0); #if defined(_WIN32) || defined(__rtems__) test_bind46("0.0.0.0" , "::" , SOCK_DGRAM , 0); test_bind46("::" , "0.0.0.0" , SOCK_DGRAM , 0); test_bind46("0.0.0.0" , "::" , SOCK_STREAM , 0); test_bind46("::" , "0.0.0.0" , SOCK_STREAM , 0); #elif defined(__linux__) test_bind46("0.0.0.0" , "::" , SOCK_DGRAM , EADDRINUSE); test_bind46("::" , "0.0.0.0" , SOCK_DGRAM , EADDRINUSE); test_bind46("0.0.0.0" , "::" , SOCK_STREAM , EADDRINUSE); test_bind46("::" , "0.0.0.0" , SOCK_STREAM , EADDRINUSE); #else test_bind46("0.0.0.0" , "::" , SOCK_DGRAM , 0); test_bind46("::" , "0.0.0.0" , SOCK_DGRAM , EADDRINUSE); test_bind46("0.0.0.0" , "::" , SOCK_STREAM , 0); test_bind46("::" , "0.0.0.0" , SOCK_STREAM , EADDRINUSE); #endif } else { testSkip(8, "No IPv6 runtime support"); } test_ifacemap(); test_udp(AF_INET); try{ test_udp(AF_INET6); }catch(std::exception&e){ testAbort("test_udp6: %s", e.what()); } test_local_mcast(); test_mcast_scope(); test_from_wire(); test_to_wire(); testDiag("Done"); cleanup_for_valgrind(); return testDone(); }