0001:
0002:
0003:
0004:
0005:
0006:
0007:
0008:
0009:
0010:
0011:
0012:
0013:
0014:
0015:
0016:
0017:
0018:
0019:
0020:
0021:
0022:
0023:
0024:
0025:
0026:
0027:
0028:
0029:
0030:
0031:
0032:
0033:
0034:
0035:
0036:
0037:
0038:
0039:
0040:
0041:
0042:
0043:
0044:
0045:
0046:
0047:
0048:
0049:
0050:
0051:
0052:
0053:
0054:
0055:
0056:
0057:
0058:
0059:
0060:
0061:
0062:
0063:
0064:
0065:
0066:
0067:
0068:
0069:
0070:
0071:
0072:
0073:
0074:
0075:
0076:
0077:
0078:
0079:
0080:
0081:
0082:
0083:
0084:
0085:
0086:
0087:
0088:
0089:
0090:
0091:
0092:
0093:
0094:
0095:
0096:
0097:
0098:
0099:
0100:
0101:
0102:
0103:
0104:
0105:
0106:
0107:
0108:
0109:
0110:
0111:
0112:
0113:
0114:
0115:
0116:
0117:
0118:
0119:
0120:
0121:
0122:
0123:
0124:
0125:
0126:
0127:
0128:
0129:
0130:
0131:
0132:
0133:
0134:
0135:
0136:
0137:
0138:
0139:
0140:
0141:
0142:
0143:
0144:
0145:
0146:
0147:
0148:
0149:
0150:
0151:
0152:
0153:
0154:
0155:
0156:
0157:
0158:
0159:
0160:
0161:
0162:
0163:
0164:
0165:
0166:
0167:
0168:
0169:
0170:
0171:
0172:
0173:
0174:
0175:
0176:
0177:
0178:
0179:
0180:
0181:
0182:
0183:
0184:
0185:
0186:
0187:
0188:
0189:
0190:
0191:
0192:
0193:
0194:
0195:
0196:
0197:
0198:
0199:
0200:
0201:
0202:
0203:
0204:
0205:
0206:
0207:
0208:
0209:
0210:
0211:
0212:
0213:
0214:
0215:
0216:
0217:
0218:
0219:
0220:
0221:
0222:
0223:
0224:
0225:
0226:
0227:
0228:
0229:
0230:
0231:
0232:
0233:
0234:
0235:
0236:
0237:
0238:
0239:
0240:
0241:
0242:
0243:
0244:
0245:
0246:
0247:
0248:
0249:
0250:
0251:
0252:
0253:
0254:
0255:
0256:
0257:
0258:
0259:
0260:
0261:
0262:
0263:
0264:
0265:
0266:
0267:
0268:
0269:
0270:
0271:
0272:
0273:
0274:
0275:
0276:
0277:
0278:
0279:
0280:
0281:
0282:
0283:
0284:
0285:
0286:
0287:
0288:
0289:
0290:
0291:
0292:
0293:
0294:
0295:
0296:
0297:
0298:
0299:
0300:
0301:
0302:
0303:
0304:
0305:
0306:
0307:
0308:
0309:
0310:
0311:
0312:
0313:
0314:
0315:
0316:
0317:
0318:
0319:
0320:
0321:
0322:
0323:
0324:
0325:
0326:
0327:
0328:
0329:
0330:
0331:
0332:
0333:
0334:
0335:
0336:
0337:
0338:
0339:
0340:
0341:
0342:
0343:
0344:
0345:
0346:
0347:
0348:
0349:
0350:
0351:
0352:
0353:
0354:
0355:
0356:
0357:
0358:
0359:
0360:
0361:
0362:
0363:
0364:
0365:
0366:
0367:
0368:
0369:
0370:
0371:
0372:
0373:
0374:
0375:
0376:
0377:
0378:
0379:
0380:
0381:
0382:
0383:
0384:
0385:
0386:
0387:
0388:
0389:
0390:
0391:
0392:
0393:
0394:
0395:
0396:
0397:
0398:
0399:
0400:
0401:
0402:
0403:
0404:
0405:
0406:
0407:
0408:
0409:
0410:
0411:
0412:
0413:
0414:
0415:
0416:
0417:
0418:
0419:
0420:
0421:
0422:
0423:
0424:
0425:
0426:
0427:
0428:
0429:
0430:
0431:
0432:
0433:
0434:
0435:
0436:
0437:
0438:
0439:
0440:
0441:
0442:
0443:
0444:
0445:
0446:
0447:
0448:
0449:
0450:
0451:
0452:
0453:
0454:
0455:
0456:
0457:
0458:
0459:
0460:
0461:
0462:
0463:
0464:
0465:
0466:
0467:
0468:
0469:
0470:
0471:
0472:
0473:
0474:
0475:
0476:
0477:
0478:
0479:
0480:
0481:
0482:
0483:
0484:
0485:
0486:
0487:
0488:
0489:
0490:
0491:
0492:
0493:
0494:
0495:
0496:
0497:
0498:
0499:
0500:
0501:
0502:
0503:
0504:
0505:
0506:
0507:
0508:
0509:
0510:
0511:
0512:
0513:
0514:
0515:
0516:
0517:
0518:
0519:
0520:
0521:
0522:
0523:
0524:
0525:
0526:
0527:
0528:
0529:
0530:
0531:
0532:
0533:
0534:
0535:
0536:
0537:
0538:
0539:
0540:
0541:
0542:
0543:
0544:
0545:
0546:
0547:
0548:
0549:
0550:
0551:
0552:
0553:
0554:
0555:
0556:
0557:
0558:
0559:
0560:
0561:
0562:
0563:
0564:
0565:
0566:
0567:
0568:
0569:
0570:
0571:
0572:
0573:
0574:
0575:
0576:
0577:
0578:
0579:
0580:
0581:
0582:
0583:
0584:
0585:
0586:
0587:
0588:
0589:
0590:
0591:
0592:
0593:
0594:
0595:
0596:
0597:
0598:
0599:
0600:
0601:
0602:
0603:
0604:
0605:
0606:
0607:
0608:
0609:
0610:
0611:
0612:
0613:
0614:
0615:
0616:
0617:
0618:
0619:
0620:
0621:
0622:
0623:
0624:
0625:
0626:
0627:
0628:
0629:
0630:
0631:
0632:
0633:
0634:
0635:
0636:
0637:
0638:
0639:
0640:
0641:
0642:
0643:
0644:
0645:
0646:
0647:
0648:
0649:
0650:
0651:
0652:
0653:
0654:
0655:
0656:
0657:
0658:
0659:
0660:
0661:
0662:
0663:
0664:
0665:
0666:
0667:
0668:
0669:
0670:
0671:
0672:
0673:
0674:
0675:
0676:
0677:
0678:
0679:
0680:
0681:
0682:
0683:
0684:
0685:
0686:
0687:
0688:
0689:
0690:
0691:
0692:
0693:
0694:
0695:
0696:
0697:
0698:
0699:
0700:
0701:
0702:
0703:
0704:
0705:
0706:
0707:
0708:
0709:
0710:
0711:
0712:
0713:
0714:
0715:
0716:
0717:
0718:
0719:
0720:
0721:
0722:
0723:
0724:
0725:
0726:
0727:
0728:
0729:
0730:
0731:
0732:
0733:
0734:
0735:
0736:
0737:
0738:
0739:
0740:
0741:
0742:
0743:
0744:
0745:
0746:
0747:
0748:
0749:
0750:
0751:
0752:
0753:
0754:
0755:
0756:
0757:
0758:
0759:
0760:
0761:
0762:
0763:
0764:
0765:
0766:
0767:
0768:
0769:
0770:
0771:
0772:
0773:
0774:
0775:
0776:
0777:
0778:
0779:
0780:
0781:
0782:
0783:
0784:
0785:
0786:
0787:
0788:
0789:
0790:
0791:
0792:
0793:
0794:
0795:
0796:
0797:
0798:
0799:
0800:
0801:
0802:
0803:
0804:
0805:
0806:
0807:
0808:
0809:
0810:
0811:
0812:
0813:
0814:
0815:
0816:
0817:
0818:
0819:
0820:
0821:
0822:
0823:
0824:
0825:
0826:
0827:
0828:
0829:
0830:
0831:
0832:
0833:
0834:
0835:
0836:
0837:
0838:
0839:
0840:
0841:
0842:
0843:
0844:
0845:
0846:
0847:
0848:
0849:
0850:
0851:
0852:
0853:
0854:
0855:
0856:
0857:
0858:
0859:
0860:
0861:
0862:
0863:
0864:
0865:
0866:
0867:
0868:
0869:
0870:
0871:
0872:
0873:
0874:
0875:
0876:
0877:
0878:
0879:
0880:
0881:
0882:
0883:
0884:
0885:
0886:
0887:
0888:
0889:
0890:
0891:
0892:
0893:
0894:
0895:
0896:
0897:
0898:
0899:
0900:
0901:
0902:
0903:
0904:
0905:
0906:
0907:
0908:
0909:
0910:
0911:
0912:
0913:
0914:
0915:
0916:
0917:
0918:
0919:
0920:
0921:
0922:
0923:
0924:
0925:
0926:
0927:
0928:
0929:
0930:
0931:
0932:
0933:
0934:
0935:
0936:
0937:
0938:
0939:
0940:
0941:
0942:
0943:
0944:
0945:
0946:
0947:
0948:
0949:
0950:
0951:
0952:
0953:
0954:
0955:
0956:
0957:
0958:
0959:
0960:
0961:
0962:
0963:
0964:
0965:
0966:
0967:
0968:
0969:
0970:
0971:
0972:
0973:
0974:
0975:
0976:
0977:
0978:
0979:
0980:
0981:
0982:
0983:
0984:
0985:
0986:
0987:
0988:
0989:
0990:
0991:
0992:
0993:
0994:
0995:
0996:
0997:
0998:
0999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
Min/Max


















Min/Max
























































































Min/Max






















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* DEV_NOTE: this file is not intended to be used directly by any user code!

i.e. do not #include <omni/xxx_impl.hxx> and do not compile this source directly.
this file is included directly in other source.
*/

// so as not to accidentally build this file with the source
// these macros are defined in chrono
#if !defined(OMNI_NET_SOCKET6_HXX_FW)
    #error "invalid preprocessor directive detected"
#endif

#if defined(OMNI_SAFE_SOCKET6)
    #define OMNI_SAFE_SOCK6MTX_FW ,m_mtx()
    #define OMNI_SAFE_SOCK6LOCK_FW this->m_mtx.lock();
    #define OMNI_SAFE_SOCK6UNLOCK_FW this->m_mtx.unlock();
    #define OMNI_SAFE_SOCK6ALOCK_FW omni::sync::scoped_basic_lock uuid12345(&this->m_mtx);
    #define OMNI_SAFE_SOCK6OALOCK_FW(o) omni::sync::scoped_basic_lock uuid54321(&o.m_mtx);
#else
    #define OMNI_SAFE_SOCK6MTX_FW
    #define OMNI_SAFE_SOCK6LOCK_FW
    #define OMNI_SAFE_SOCK6UNLOCK_FW
    #define OMNI_SAFE_SOCK6ALOCK_FW
    #define OMNI_SAFE_SOCK6OALOCK_FW(o)
#endif

omni::net::socket_error omni::net::socket6::_bind()
{
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    switch (this->m_family) {
        case omni::net::address_family::INET: {
            this->m_addr.addr4.sin_family = static_cast<OMNI_SIN_FAMILY_FW>(this->m_family);
            this->m_addr.addr4.sin_port = htons(this->m_port);
            this->m_addr.addr4.sin_addr.s_addr = htonl(this->m_ep.ep4);
            if (::bind(this->m_socket, omni::net::to_sockaddr(this->m_addr.addr4), sizeof(this->m_addr.addr4)) != 0) {
                omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::BOUND);
                return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            }
        } break;
        case omni::net::address_family::INET6: {
            this->m_addr.addr6.sin6_family = static_cast<OMNI_SIN_FAMILY_FW>(this->m_family);
            this->m_addr.addr6.sin6_port = htons(this->m_port);
            std::memcpy(&this->m_addr.addr6.sin6_addr.s6_addr, &this->m_ep.ep6, sizeof(this->m_addr.addr6.sin6_addr.s6_addr));
            if (::bind(this->m_socket, omni::net::to_sockaddr(this->m_addr.addr6), sizeof(this->m_addr.addr6)) != 0) {
                omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::BOUND);
                return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            }
        } break;
        // omni::net::address_family::UNIX is not suppored in this socket since that is an IPC protocol
        case omni::net::address_family::UNIX:
        case omni::net::address_family::UNSPECIFIED:
        default:
            return (this->m_last_err = omni::net::socket_error::PROTOCOL_FAMILY_NOT_SUPPORTED);
    }
    omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::BOUND);
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::_close(uint16_t timeout, bool shutdown)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    // regardless if it's connected/bound, if we request a close and it's open, actually close
    omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::OPEN);
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::CONNECTED) ||
        omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND))
    {
        if (timeout > 0) {
            struct linger lop;
            lop.l_onoff = 1;
            lop.l_linger = timeout;
            if (::setsockopt(this->m_socket, SOL_SOCKET, SO_LINGER, reinterpret_cast<char*>(&lop), sizeof(struct linger)) != 0) {
                return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            }
        }
        if (shutdown && (this->shutdown(omni::net::socket_shutdown::BOTH) != omni::net::socket_error::SUCCESS)) {
            OMNI_DBGE("could not shutdown the socket")
            return this->m_last_err;
        }
        if (OMNI_SOCKET_CLOSE_FW(this->m_socket) != 0) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        OMNI_SOCK_CLOSE_FW
        if (shutdown) {
            this->m_socket = OMNI_INVALID_SOCKET;
            std::memset(&this->m_addr, 0, sizeof(this->m_addr));
        }
        /* DEV_NOTE: if the socket was not elected to be shutdown, then we could just set
        conops to 0, but since a shutdown could have happened, we can just logically AND
        (1 << omni::net::connection_option::SHUT) and if `shut` is set, it will stay set,
        if it is not, then it 0s out the rest. */
        this->m_conops &= (1 << omni::net::connection_option::SHUT);
        this->m_last_err = omni::net::socket_error::SUCCESS;
    } else {
        this->m_last_err = omni::net::socket_error::NOT_CONNECTED;
    }
    return this->m_last_err;
}

omni::net::socket_error omni::net::socket6::_receive(void* buffer, std::size_t buffer_size, omni::net::socket_flags flags, uint32_t& received)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    #if defined(OMNI_WIN_API)
        DWORD flag = static_cast<int>(flags);
        DWORD recd = static_cast<DWORD>(received);
        WSABUF buf;
        buf.len = buffer_size;
        buf.buf = reinterpret_cast<omni::net::xfr_t*>(buffer);
        if (::WSARecv(this->m_socket, &buf, 1, &recd, &flag, NULL, NULL) == SOCKET_ERROR) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        received = static_cast<uint32_t>(recd);
    #else
        long r = ::recv(this->m_socket, (reinterpret_cast<omni::net::xfr_t*>(buffer)), buffer_size, ((flags == omni::net::socket_flags::NONE) ? 0 : static_cast<int>(flags)));
        switch (r) {
            // connection closed
            case 0: return (this->m_last_err = omni::net::socket_error::CONNECTION_RESET);
            // error
            case OMNI_SOCK_SYSERR_FW: return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            // success
            default: received = static_cast<uint32_t>(r); break;
        }
    #endif
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::_receive_from(void* buffer, std::size_t buffer_size, omni::net::socket_flags flags, std::string& from_ip, uint16_t& from_port, uint32_t& received)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    omni::net::sockaddr_in6_t src_addr;
    OMNI_SOCKLEN_FW addrlen = sizeof(omni::net::sockaddr_in6_t);
    std::memset(&src_addr, 0, addrlen);
    #if defined(OMNI_WIN_API)
        DWORD flag = static_cast<int>(flags);
        DWORD recd = static_cast<DWORD>(received);
        WSABUF buf;
        buf.len = buffer_size;
        buf.buf = reinterpret_cast<omni::net::xfr_t*>(buffer);
        if (::WSARecvFrom(this->m_socket, &buf, 1, &recd, &flag, omni::net::to_sockaddr(src_addr), &addrlen, NULL, NULL) == SOCKET_ERROR) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        received = static_cast<uint32_t>(recd);
    #else
        long r = ::recvfrom(this->m_socket, (reinterpret_cast<omni::net::xfr_t*>(buffer)), buffer_size, ((flags == omni::net::socket_flags::NONE) ? 0 : static_cast<int>(flags)), omni::net::to_sockaddr(src_addr), &addrlen);
        switch (r) {
            // connection closed
            case 0: return (this->m_last_err = omni::net::socket_error::CONNECTION_RESET);
            // error
            case OMNI_SOCK_SYSERR_FW: return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            // success
            default: received = static_cast<uint32_t>(r); break;
        }
    #endif
    from_ip = omni::net::util::ip6_binary_to_string(src_addr.sin6_addr.s6_addr);
    //from_ip.assign(inet_ntoa(src_addr.sin6_addr));
    from_port = ntohs(src_addr.sin6_port);
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::_send(const void* buffer, std::size_t buffer_size, omni::net::socket_flags flags, uint32_t& sent)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    #if defined(OMNI_WIN_API)
        DWORD flag = static_cast<int>(flags);
        DWORD recd = static_cast<DWORD>(sent);
        WSABUF buf;
        buf.len = buffer_size;
        buf.buf = const_cast<omni::net::xfr_t*>(reinterpret_cast<const omni::net::xfr_t*>(buffer));
        if (::WSASend(this->m_socket, &buf, 1, &recd, flag, NULL, NULL) == SOCKET_ERROR) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        sent = static_cast<uint32_t>(recd);
    #else
        long r = ::send(this->m_socket, (reinterpret_cast<const omni::net::xfr_t*>(buffer)), buffer_size, ((flags == omni::net::socket_flags::NONE) ? 0 : static_cast<int>(flags)));
        if (r == OMNI_SOCK_SYSERR_FW) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        // success
        sent = static_cast<uint32_t>(r);
    #endif
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::_send_to(const void* buffer, std::size_t buffer_size, omni::net::socket_flags flags, const std::string& ip, uint16_t port, uint32_t& sent)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    uint8_t ep[16] = {0};
    if (omni::net::util::try_parse_ip6(ip, ep)) {
        return (this->m_last_err = omni::net::socket_error::DESTINATION_ADDRESS_REQUIRED);
    }
    omni::net::sockaddr_in6_t to_addr;
    OMNI_SOCKLEN_FW addrlen = sizeof(omni::net::sockaddr_in6_t);
    std::memset(&to_addr, 0, addrlen);
    to_addr.sin6_family = static_cast<OMNI_SIN_FAMILY_FW>(this->m_family);
    to_addr.sin6_port = htons(port);
    // to_addr.sin6_addr.s6_addr = htonl(ep);
    std::memcpy(&to_addr.sin6_addr.s6_addr, &ep, sizeof(to_addr.sin6_addr.s6_addr));
    #if defined(OMNI_WIN_API)
        DWORD flag = static_cast<int>(flags);
        DWORD recd = static_cast<DWORD>(sent);
        WSABUF buf;
        buf.len = buffer_size;
        buf.buf = const_cast<omni::net::xfr_t*>(reinterpret_cast<const omni::net::xfr_t*>(buffer));
        if (::WSASendTo(this->m_socket, &buf, 1, &recd, flag, omni::net::to_sockaddr(to_addr), addrlen, NULL, NULL) == SOCKET_ERROR) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        sent = static_cast<uint32_t>(recd);
    #else
        long r = ::sendto(this->m_socket, (reinterpret_cast<const omni::net::xfr_t*>(buffer)), buffer_size, ((flags == omni::net::socket_flags::NONE) ? 0 : static_cast<int>(flags)), omni::net::to_sockaddr(to_addr), addrlen);
        if (r == OMNI_SOCK_SYSERR_FW) {
            return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
        }
        // success
        sent = static_cast<uint32_t>(r);
    #endif
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket6::socket6(omni::net::address_family family,
                            omni::net::socket_type type,
                            omni::net::protocol_type protocol) :
    OMNI_CTOR_FW(omni::net::socket6)
    m_socket(OMNI_INVALID_SOCKET),
    m_addr(),
    m_family(family),
    m_proto(protocol),
    m_type(type),
    m_ep(),
    m_last_err(omni::net::socket_error::UNSPECIFIED),
    m_port(0),
    m_conops(0)
    OMNI_SOCK_WSA_FW
    OMNI_SAFE_SOCK6MTX_FW
{
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    std::memset(&this->m_ep, 0, sizeof(this->m_ep));
    if (this->open() != omni::net::socket_error::SUCCESS) {
        OMNI_D1_FW("error opening the socket");
    }
}

omni::net::socket6::socket6(omni::net::address_family family,
                            omni::net::socket_type type,
                            omni::net::protocol_type protocol,
                            omni::net::socket_create_options create_ops) :
    OMNI_CTOR_FW(omni::net::socket6)
    m_socket(OMNI_INVALID_SOCKET),
    m_addr(),
    m_family(family),
    m_proto(protocol),
    m_type(type),
    m_ep(),
    m_last_err(omni::net::socket_error::UNSPECIFIED),
    m_port(0),
    m_conops(0)
    OMNI_SOCK_WSA_FW
    OMNI_SAFE_SOCK6MTX_FW
{
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    std::memset(&this->m_ep, 0, sizeof(this->m_ep));
    if (create_ops == omni::net::socket_create_options::OPEN_ON_CREATE) {
        if (this->open() != omni::net::socket_error::SUCCESS) {
            OMNI_D1_FW("error opening the socket");
        }
    }
}

omni::net::socket6::socket6(omni::net::socket_type type,
                            omni::net::protocol_type protocol) :
    OMNI_CTOR_FW(omni::net::socket6)
    m_socket(OMNI_INVALID_SOCKET),
    m_addr(),
    m_family(omni::net::address_family::UNSPECIFIED),
    m_proto(protocol),
    m_type(type),
    m_ep(),
    m_last_err(omni::net::socket_error::UNSPECIFIED),
    m_port(0),
    m_conops(0)
    OMNI_SOCK_WSA_FW
    OMNI_SAFE_SOCK6MTX_FW
{
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    std::memset(&this->m_ep, 0, sizeof(this->m_ep));
    if (this->open() != omni::net::socket_error::SUCCESS) {
        OMNI_D1_FW("error opening the socket");
    }
}

omni::net::socket6::socket6(omni::net::address_family family,
                            omni::net::socket_type type,
                            omni::net::protocol_type protocol,
                            bool allow_ip4_fallback) :
    OMNI_CTOR_FW(omni::net::socket6)
    m_socket(OMNI_INVALID_SOCKET),
    m_addr(),
    m_family(family),
    m_proto(protocol),
    m_type(type),
    m_ep(),
    m_last_err(omni::net::socket_error::UNSPECIFIED),
    m_port(0),
    m_conops(0)
    OMNI_SOCK_WSA_FW
    OMNI_SAFE_SOCK6MTX_FW
{
    if (allow_ip4_fallback) {
        omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::ALLOW_IP4_FALLBACK);
    }
    if (this->open() != omni::net::socket_error::SUCCESS) {
        OMNI_D1_FW("error opening the socket");
    }
}

omni::net::socket6::socket6(omni::net::address_family family,
                            omni::net::socket_type type,
                            omni::net::protocol_type protocol,
                            omni::net::socket_create_options create_ops,
                            bool allow_ip4_fallback) :
    OMNI_CTOR_FW(omni::net::socket6)
    m_socket(OMNI_INVALID_SOCKET),
    m_addr(),
    m_family(family),
    m_proto(protocol),
    m_type(type),
    m_ep(),
    m_last_err(omni::net::socket_error::UNSPECIFIED),
    m_port(0),
    m_conops(0)
    OMNI_SOCK_WSA_FW
    OMNI_SAFE_SOCK6MTX_FW
{
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    std::memset(&this->m_ep, 0, sizeof(this->m_ep));
    if (allow_ip4_fallback) {
        omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::ALLOW_IP4_FALLBACK);
    }
    if (create_ops == omni::net::socket_create_options::OPEN_ON_CREATE) {
        if (this->open() != omni::net::socket_error::SUCCESS) {
            OMNI_D1_FW("error opening the socket");
        }
    }
}

omni::net::socket6::socket6(omni::net::socket_type type,
                            omni::net::protocol_type protocol,
                            bool allow_ip4_fallback) :
    OMNI_CTOR_FW(omni::net::socket6)
    m_socket(OMNI_INVALID_SOCKET),
    m_addr(),
    m_family(omni::net::address_family::UNSPECIFIED),
    m_proto(protocol),
    m_type(type),
    m_ep(),
    m_last_err(omni::net::socket_error::UNSPECIFIED),
    m_port(0),
    m_conops(0)
    OMNI_SOCK_WSA_FW
    OMNI_SAFE_SOCK6MTX_FW
{
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    std::memset(&this->m_ep, 0, sizeof(this->m_ep));
    if (allow_ip4_fallback) {
        omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::ALLOW_IP4_FALLBACK);
    }
    if (this->open() != omni::net::socket_error::SUCCESS) {
        OMNI_D1_FW("error opening the socket");
    }
}

omni::net::socket6::~socket6()
{
    OMNI_TRY_FW
    if (this->close() != omni::net::socket_error::SUCCESS) {
        OMNI_D1_FW("error closing socket");
    }
    OMNI_DTOR_FW
    OMNI_CATCH_FW
    OMNI_D5_FW("destroyed");
}

omni::net::socket_error omni::net::socket6::accept(omni::net::endpoint_descriptor6& remote_ep)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    } else if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::LISTEN)) { // includes bound (cannot listen if not bound)
        return (this->m_last_err = omni::net::socket_error::DESTINATION_ADDRESS_REQUIRED);
    } else if (remote_ep.is_connected()) {
        return (this->m_last_err = omni::net::socket_error::IS_CONNECTED);
    }
    return (this->m_last_err = remote_ep.connect(this->m_socket));
}

omni::net::socket_error omni::net::socket6::bind()
{
    OMNI_SAFE_SOCK6LOCK_FW
    uint16_t port = this->m_port;
    if (this->m_family == omni::net::address_family::INET) {
        uint32_t ip = this->m_ep.ep4;
        OMNI_SAFE_SOCK6UNLOCK_FW
        return this->bind(ip, port);
    }
    uint8_t ip[16] = {0};
    std::memcpy(&(this->m_ep.ep6), &ip, sizeof(ip));
    OMNI_SAFE_SOCK6UNLOCK_FW
    return this->bind(ip, port);
}

omni::net::socket_error omni::net::socket6::bind(uint16_t port)
{
    OMNI_SAFE_SOCK6LOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        uint32_t ip = this->m_ep.ep4;
        OMNI_SAFE_SOCK6UNLOCK_FW
        return this->bind(ip, port);
    }
    uint8_t ip[16] = {0};
    std::memcpy(&(this->m_ep.ep6), &ip, sizeof(ip));
    OMNI_SAFE_SOCK6UNLOCK_FW
    return this->bind(ip, port);
}

omni::net::socket_error omni::net::socket6::bind(uint32_t ip, uint16_t port)
{
    OMNI_SAFE_SOCKALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::CONNECTED)) { // cannot bind to a connect()-ed socket
        return (this->m_last_err = omni::net::socket_error::IS_CONNECTED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        return (this->m_last_err = omni::net::socket_error::ADDRESS_ALREADY_IN_USE);
    }
    if (this->m_family == omni::net::address_family::INET6) {
        return omni::net::socket_error::INVALID_ARGUMENT;
    }
    this->m_ep.ep4 = ip;
    this->m_port = port;
    return this->_bind();
}

omni::net::socket_error omni::net::socket6::bind(const omni::net::ip6_binary_address& ip, uint16_t port)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::CONNECTED)) { // cannot bind to a connect()-ed socket
        return (this->m_last_err = omni::net::socket_error::IS_CONNECTED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        return (this->m_last_err = omni::net::socket_error::ADDRESS_ALREADY_IN_USE);
    }
    if (this->m_family == omni::net::address_family::INET) {
        return omni::net::socket_error::INVALID_ARGUMENT;
    }
    ip.copy_to(this->m_ep.ep6);
    this->m_port = port;
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    return this->_bind();
}

omni::net::socket_error omni::net::socket6::bind4(const std::string& ip, uint16_t port)
{
    uint32_t ep = 0;
    if (omni::net::util::try_parse_ip4(ip, ep)) {
        return this->bind(ep, port);
    }
    return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
}

omni::net::socket_error omni::net::socket6::bind6(const std::string& ip, uint16_t port)
{
    uint8_t ep[16] = {0};
    if (omni::net::util::try_parse_ip6(ip, ep)) {
        return this->bind(ep, port);
    }
    return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
}

omni::net::socket_error omni::net::socket6::bind4(const std::wstring& ip, uint16_t port)
{
    uint32_t ep = 0;
    if (omni::net::util::try_parse_ip4(omni::string::util::to_string(ip), ep)) {
        return this->bind(ep, port);
    }
    return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
}

omni::net::socket_error omni::net::socket6::bind6(const std::wstring& ip, uint16_t port)
{
    uint8_t ep[16] = {0};
    if (omni::net::util::try_parse_ip6(omni::string::util::to_string(ip), ep)) {
        return this->bind(ep, port);
    }
    return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
}

omni::net::socket_error omni::net::socket6::bind4(const std::string& ip)
{
    return this->bind4(ip, 0);
}

omni::net::socket_error omni::net::socket6::bind6(const std::string& ip)
{
    return this->bind6(ip, 0);
}

omni::net::socket_error omni::net::socket6::bind4(const std::wstring& ip)
{
    return this->bind4(ip, 0);
}

omni::net::socket_error omni::net::socket6::bind6(const std::wstring& ip)
{
    return this->bind6(ip, 0);
}

omni::net::socket_error omni::net::socket6::close()
{
    return this->close(0);
}

omni::net::socket_error omni::net::socket6::close(uint16_t timeout)
{
    return this->_close(timeout, false);
}

omni::net::socket_error omni::net::socket6::connect()
{
    OMNI_SAFE_SOCK6ALOCK_FW
    // DEV_NOTE: htons/etc. could be macros so we do not use global namespace (i.e. ::htons)
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::CONNECTED)) {
        return (this->m_last_err = omni::net::socket_error::IS_CONNECTED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        return (this->m_last_err = omni::net::socket_error::ADDRESS_ALREADY_IN_USE);
    }
    std::memset(&this->m_addr, 0, sizeof(this->m_addr));
    switch (this->m_family) {
        case omni::net::address_family::INET: {
            this->m_addr.addr4.sin_family = static_cast<OMNI_SIN_FAMILY_FW>(this->m_family);
            this->m_addr.addr4.sin_port = htons(this->m_port);
            this->m_addr.addr4.sin_addr.s_addr = htonl(this->m_ep.ep4);
            if (OMNI_SOCKET_CONNECT_FW(this->m_socket, omni::net::to_sockaddr(this->m_addr.addr4), sizeof(this->m_addr.addr4)) != 0) {
                omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::CONNECTED);
                return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            }
        } break;
        case omni::net::address_family::INET6: {
            this->m_addr.addr6.sin6_family = static_cast<OMNI_SIN_FAMILY_FW>(this->m_family);
            this->m_addr.addr6.sin6_port = htons(this->m_port);
            std::memcpy(&this->m_addr.addr6.sin6_addr.s6_addr, &this->m_ep.ep6, sizeof(this->m_addr.addr6.sin6_addr.s6_addr));
            if (OMNI_SOCKET_CONNECT_FW(this->m_socket, omni::net::to_sockaddr(this->m_addr.addr6), sizeof(this->m_addr.addr6)) != 0) {
                omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::CONNECTED);
                return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
            }
        } break;
        
        // omni::net::address_family::UNIX is not support in this socket since that is an IPC protocol
        case omni::net::address_family::UNIX:
        case omni::net::address_family::UNSPECIFIED:
        default:
            return (this->m_last_err = omni::net::socket_error::PROTOCOL_FAMILY_NOT_SUPPORTED);
    }
    omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::CONNECTED);
    omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::SHUT);
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
    
}

omni::net::socket_error omni::net::socket6::connect(uint32_t ip, uint16_t port)
{
    OMNI_SAFE_SOCKLOCK_FW
    if (this->m_family == omni::net::address_family::INET6) {
        OMNI_SAFE_SOCKUNLOCK_FW
        return omni::net::socket_error::INVALID_ARGUMENT;
    }
    this->m_ep.ep4 = ip;
    this->m_port = port;
    OMNI_SAFE_SOCKUNLOCK_FW
    return this->connect();
}

omni::net::socket_error omni::net::socket6::connect(const omni::net::ip6_binary_address& ip, uint16_t port)
{
    OMNI_SAFE_SOCK6LOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        OMNI_SAFE_SOCKUNLOCK_FW
        return omni::net::socket_error::INVALID_ARGUMENT;
    }
    ip.copy_to(this->m_ep.ep6);
    this->m_port = port;
    OMNI_SAFE_SOCK6UNLOCK_FW
    return this->connect();
}

omni::net::socket_error omni::net::socket6::connect4(const std::string& ip, uint16_t port)
{
    uint32_t ep = 0;
    if (!omni::net::util::try_parse_ip4(ip, ep)) {
        return (this->m_last_err = omni::net::socket_error::ADDRESS_NOT_AVAILABLE);
    }
    return this->connect(ep, port);
}

omni::net::socket_error omni::net::socket6::connect6(const std::string& ip, uint16_t port)
{
    uint8_t ep[16] = {0};
    if (!omni::net::util::try_parse_ip6(ip, ep)) {
        return (this->m_last_err = omni::net::socket_error::ADDRESS_NOT_AVAILABLE);
    }
    return this->connect(ep, port);
}

omni::net::socket_error omni::net::socket6::connect4(const std::wstring& ip, uint16_t port)
{
    return this->connect4(omni::string::util::to_string(ip), port);
}

omni::net::socket_error omni::net::socket6::connect6(const std::wstring& ip, uint16_t port)
{
    return this->connect6(omni::string::util::to_string(ip), port);
}

omni::net::socket_error omni::net::socket6::connect_host(const std::string& host, uint16_t port)
{
    omni::seq::std_string_t ip;
    omni::net::server_error serr = omni::net::util::get_ip(host, port, ip);
    if (serr == omni::net::server_error::SUCCESS) {
        if (ip.size() > 0) {
            return this->connect4(ip[0], port);
        } else {
            return (this->m_last_err = omni::net::socket_error::ADDRESS_NOT_AVAILABLE);
        }
    }
    return (this->m_last_err = omni::net::server_error_to_socket_error(serr));
}

omni::net::socket_error omni::net::socket6::connect_host(const std::wstring& host, uint16_t port)
{
    return this->connect_host(omni::string::to_string(host), port);
}

omni::net::socket_error omni::net::socket6::disconnect(bool reuse)
{
    return this->_close(0, reuse);
}

omni::net::socket_error omni::net::socket6::ioc(uint32_t op_code, omni::net::xfr_t* val)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    int32_t
    #if defined(OMNI_OS_WIN)
        result = ::ioctlsocket(this->m_socket, static_cast<long>(op_code), reinterpret_cast<u_long*>(val));
    #else
        result = ::ioctl(this->m_socket, static_cast<unsigned long>(op_code), val);
    #endif
    if (result == OMNI_SOCK_SYSERR_FW) {
        return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
    }
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::get_socket_option(omni::net::socket_option_level op_level, int32_t op_name, int32_t& op_val)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    int serr = 0;
    OMNI_SOCKLEN_FW sz;
    if ((op_level == omni::net::socket_option_level::SOCKET) &&
        ((op_name == omni::net::socket_option::LINGER) || (op_name == omni::net::socket_option::DONT_LINGER)))
    {
        struct linger lop;
        std::memset(&lop, 0, sizeof(struct linger));
        sz = static_cast<OMNI_SOCKLEN_FW>(sizeof(struct linger));
        serr = ::getsockopt(this->m_socket,
                         static_cast<int>(op_level),
                         static_cast<int>(omni::net::socket_option::LINGER),
                         reinterpret_cast<OMNI_SOCKET_XFR_T_FW*>(&lop),
                         &sz);
        if (serr == 0) { op_val = static_cast<int32_t>(lop.l_linger); }
    } else {
        OMNI_SOCKET_XFR_T_FW* val = reinterpret_cast<OMNI_SOCKET_XFR_T_FW*>(&op_val);
        sz = static_cast<OMNI_SOCKLEN_FW>(sizeof(val));
        serr = ::getsockopt(this->m_socket, static_cast<int>(op_level), static_cast<int>(op_name), val, &sz);
        if (serr == 0) { op_val = *(reinterpret_cast<int32_t*>(val)); }
    }
    if (serr != 0) { return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW)); }
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::get_socket_option(omni::net::socket_option_level op_level, omni::net::socket_option op_name, int32_t& op_val)
{
    return this->get_socket_option(op_level, static_cast<int32_t>(op_name), op_val);
}

omni::net::socket_error omni::net::socket6::get_socket_option(omni::net::socket_option_level op_level, omni::net::tcp_option op_name, int32_t& op_val)
{
    return this->get_socket_option(op_level, static_cast<int32_t>(op_name), op_val);
}

omni::net::socket_error omni::net::socket6::open()
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::ADDRESS_ALREADY_IN_USE);
    }
    OMNI_SOCK_OPEN_FW
    this->m_socket = OMNI_SOCKET_OPEN_FW(this->m_family, this->m_type, this->m_proto);
    if (this->m_socket == OMNI_INVALID_SOCKET) {
        if ((this->m_family == omni::net::address_family::INET6) && omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::ALLOW_IP4_FALLBACK)) {
            this->m_family = omni::net::address_family::INET;
            this->m_socket = OMNI_SOCKET_OPEN_FW(this->m_family, this->m_type, this->m_proto);
            this->m_ep.ep4 = 0;
            if (this->m_socket == OMNI_INVALID_SOCKET) {
                int serr = OMNI_SOCKET_ERR_FW;
                OMNI_DBGEV("a system error occurred creating the socket: ", serr)
                return (this->m_last_err = omni::net::parse_error(serr));
            }
        } else {
            int serr = OMNI_SOCKET_ERR_FW;
            OMNI_DBGEV("a system error occurred creating the socket: ", serr)
            return (this->m_last_err = omni::net::parse_error(serr));
        }
    }
    omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::OPEN);
    omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::SHUT);
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::open(omni::net::socket_type type, omni::net::protocol_type protocol)
{
    OMNI_SAFE_SOCK6LOCK_FW
    this->m_type = type;
    this->m_proto = protocol;
    OMNI_SAFE_SOCK6UNLOCK_FW
    return this->open();
}

omni::net::socket_error omni::net::socket6::open(omni::net::address_family family, omni::net::socket_type type, omni::net::protocol_type protocol)
{
    OMNI_SAFE_SOCK6LOCK_FW
    this->m_family = family;
    this->m_type = type;
    this->m_proto = protocol;
    OMNI_SAFE_SOCK6UNLOCK_FW
    return this->open();
}

omni::net::socket_error omni::net::socket6::listen()
{
    return this->listen(OMNI_SOCKET_DEFAULT_BACKLOG);
}

omni::net::socket_error omni::net::socket6::listen(int32_t backlog)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    } else if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        return (this->m_last_err = omni::net::socket_error::DESTINATION_ADDRESS_REQUIRED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::CONNECTED)) {
        return (this->m_last_err = omni::net::socket_error::IS_CONNECTED);
    }
    if (backlog > OMNI_SOMAXCONN) {
        return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
    }
    if (::listen(this->m_socket, static_cast<int>(backlog)) != 0) {
        return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
    }
    omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::LISTEN);
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::shutdown(omni::net::socket_shutdown how)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    } else if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::SHUT)) {
        return (this->m_last_err = omni::net::socket_error::SUCCESS);
    }
    int serr = ::shutdown(this->m_socket, static_cast<int>(how));
    if (serr == OMNI_SOCK_SYSERR_FW) {
        return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
    }
    omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::SHUT);
    omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::LISTEN);
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::set_socket_option(omni::net::socket_option_level op_level, int32_t op_name, int32_t op_val)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (!omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
    }
    int serr = 0;
    if ((op_level == omni::net::socket_option_level::SOCKET) &&
        ((op_name == omni::net::socket_option::LINGER) || (op_name == omni::net::socket_option::DONT_LINGER)))
    {
        struct linger lop;
        std::memset(&lop, 0, sizeof(struct linger));
        if (op_name == omni::net::socket_option::LINGER) {
            lop.l_onoff = 1;
            lop.l_linger = op_val;
        }
        serr = ::setsockopt(this->m_socket,
                         static_cast<int>(op_level),
                         static_cast<int>(omni::net::socket_option::LINGER),
                         reinterpret_cast<OMNI_SOCKET_XFR_T_FW*>(&lop),
                         sizeof(struct linger));
    } else {
        serr = ::setsockopt(this->m_socket,
                         static_cast<int>(op_level),
                         static_cast<int>(op_name),
                         reinterpret_cast<OMNI_SOCKET_XFR_T_FW*>(&op_val),
                         sizeof(int32_t));
    }
    if (serr != 0) {
        return (this->m_last_err = omni::net::parse_error(OMNI_SOCKET_ERR_FW));
    }
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::set_socket_option(omni::net::socket_option_level op_level, omni::net::socket_option op_name, int32_t op_val)
{
    return this->set_socket_option(op_level, static_cast<int32_t>(op_name), op_val);
}

omni::net::socket_error omni::net::socket6::set_socket_option(omni::net::socket_option_level op_level, omni::net::tcp_option op_name, int32_t op_val)
{
    return this->set_socket_option(op_level, static_cast<int32_t>(op_name), op_val);
}

omni::net::socket_error omni::net::socket6::set_blocking_mode(omni::net::blocking_mode mode)
{
    uint32_t val = mode;
    return this->ioc(FIONBIO, reinterpret_cast<omni::net::xfr_t*>(&val));
}

omni::net::address_family omni::net::socket6::address_family() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return this->m_family;
}

std::string omni::net::socket6::endpoint() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (this->m_family == omni::net::address_family::INET6) {
        return omni::net::util::ip6_binary_to_string(this->m_ep.ep6);
    }
    return omni::net::util::to_dotted_ip4_string(this->m_ep.ep4);
}

std::string omni::net::socket6::bound_endpoint() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        if (this->m_family == omni::net::address_family::INET6) {
            return omni::net::util::ip6_binary_to_string(this->m_ep.ep6);
        }
        return omni::net::util::to_dotted_ip4_string(this->m_ep.ep4);
    }
    return 0;
}

omni::net::socket_error omni::net::socket6::get_bound_endpoint4_binary(uint32_t& ep) const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (this->m_family == omni::net::address_family::INET6) {
        return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
    }
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        ep = this->m_ep.ep4;
        return (this->m_last_err = omni::net::socket_error::SUCCESS);
    }
    return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
}

omni::net::socket_error omni::net::socket6::get_bound_endpoint6_binary(omni::net::ip6_binary_address& ep) const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
    }
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        ep = this->m_ep.ep6;
        return (this->m_last_err = omni::net::socket_error::SUCCESS);
    }
    return (this->m_last_err = omni::net::socket_error::NOT_INITIALIZED);
}

omni::net::socket_error omni::net::socket6::get_endpoint4_binary(uint32_t& ep) const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (this->m_family == omni::net::address_family::INET6) {
        return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
    }
    ep = this->m_ep.ep4;
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

omni::net::socket_error omni::net::socket6::get_endpoint6_binary(omni::net::ip6_binary_address& ep) const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        return (this->m_last_err = omni::net::socket_error::INVALID_ARGUMENT);
    }
    ep = this->m_ep.ep6;
    return (this->m_last_err = omni::net::socket_error::SUCCESS);
}

uint16_t omni::net::socket6::port() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return this->m_port;
}

uint16_t omni::net::socket6::bound_port() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND)) {
        return this->m_port;
    }
    return 0;
}

omni::net::socket_t omni::net::socket6::native_handle() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return this->m_socket;
}

bool omni::net::socket6::is_bound() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::BOUND);
}

bool omni::net::socket6::is_connected() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::CONNECTED);
}

bool omni::net::socket6::is_open() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN);
}

bool omni::net::socket6::is_shutdown() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::SHUT);
}

bool omni::net::socket6::is_listening() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::LISTEN);
}

omni::net::socket_error omni::net::socket6::last_error() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return this->m_last_err;
}

omni::net::protocol_type omni::net::socket6::protocol() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return this->m_proto;
}

void omni::net::socket6::set_allow_ip4_fallback(bool set)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (set) {
        omni::bits::unsafe_set(this->m_conops, omni::net::connection_option::ALLOW_IP4_FALLBACK);
    } else {
        omni::bits::unsafe_unset(this->m_conops, omni::net::connection_option::ALLOW_IP4_FALLBACK);
    }
}

omni::net::socket6& omni::net::socket6::set_address_family(omni::net::address_family family)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        OMNI_ERR_FW("The socket is open", omni::exceptions::socket_exception(static_cast<int>(omni::net::socket_error::IS_CONNECTED)));
    }
    this->m_family = family;
    return *this;
}

omni::net::socket6& omni::net::socket6::set_protocol_type(omni::net::protocol_type protocol)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        OMNI_ERR_FW("The socket is open", omni::exceptions::socket_exception(static_cast<int>(omni::net::socket_error::IS_CONNECTED)));
    }
    this->m_proto = protocol;
    return *this;
}

omni::net::socket6& omni::net::socket6::set_socket_type(omni::net::socket_type type)
{
    OMNI_SAFE_SOCK6ALOCK_FW
    if (omni::bits::unsafe_is_set(this->m_conops, omni::net::connection_option::OPEN)) {
        OMNI_ERR_FW("The socket is open", omni::exceptions::socket_exception(static_cast<int>(omni::net::socket_error::IS_CONNECTED)));
    }
    this->m_type = type;
    return *this;
}

omni::net::socket_type omni::net::socket6::socket_type() const
{
    OMNI_SAFE_SOCK6ALOCK_FW
    return this->m_type;
}

void omni::net::socket6::swap(omni::net::socket6& other)
{
    if (this != &other) {
        OMNI_SAFE_SOCK6ALOCK_FW
        OMNI_SAFE_SOCK6OALOCK_FW(other)
        std::swap(this->m_socket, other.m_socket);
        std::swap(this->m_addr, other.m_addr);
        std::swap(this->m_family, other.m_family);
        std::swap(this->m_proto, other.m_proto);
        std::swap(this->m_type, other.m_type);
        std::swap(this->m_last_err, other.m_last_err);
        std::swap(this->m_ep, other.m_ep);
        std::swap(this->m_port, other.m_port);
        std::swap(this->m_conops, other.m_conops);
        #if defined(OMNI_OS_WIN)
            this->m_wsa.swap(other.m_wsa);
        #endif
    }
}

omni::string_t omni::net::socket6::to_string_t() const
{
    omni::sstream_t s;
    OMNI_SAFE_SOCK6LOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        s << omni::net::util::to_dotted_ip4_string_t(this->m_ep.ep4);
    } else {
        s << omni::net::util::ip6_binary_to_string(this->m_ep.ep6).c_str();
    }
    s << ":" << this->m_port;
    OMNI_SAFE_SOCK6UNLOCK_FW
    return s.str();
}

std::string omni::net::socket6::to_string() const
{
    std::stringstream s;
    OMNI_SAFE_SOCK6LOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        s << omni::net::util::to_dotted_ip4_string(this->m_ep.ep4);
    } else {
        s << omni::net::util::ip6_binary_to_string(this->m_ep.ep6).c_str();
    }
    s << ":" << this->m_port;
    OMNI_SAFE_SOCK6UNLOCK_FW
    return s.str();
}

std::wstring omni::net::socket6::to_wstring() const
{
    std::wstringstream s;
    OMNI_SAFE_SOCK6LOCK_FW
    if (this->m_family == omni::net::address_family::INET) {
        s << omni::net::util::to_dotted_ip4_wstring(this->m_ep.ep4);
    } else {
        s << omni::net::util::ip6_binary_to_string(this->m_ep.ep6).c_str();
    }
    s << ":" << this->m_port;
    OMNI_SAFE_SOCK6UNLOCK_FW
    return s.str();
}