v. vanilla 2.0

restored/socket_udp.inc

← All source files · Download this file

3,853 bytes · SHA256 df2affe5c0ad0136a9cfb41c315b57a6faa56efb1864b8103f1577d2563cfbb3

// Included inside foundationCommand: shared validation, ownership and budgets.
        if(sub=="bind") {
            reserve(128,false,true);
            if(!options.allowListen) fail(s,"udp bind requires --allow-listen and --allow-network");
            auto host=val(3); if(host.empty() || host=="localhost") host="127.0.0.1";
            socketHost(host,true,s); int port=static_cast<int>(integer(val(4),0,65535,s)); room();
            auto address=socketNumeric(host,port); auto p=std::make_shared<Socket>(); creating=p; p->datagram=true;
            p->fd=::socket(address.address.ss_family,SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC,0);
            if(p->fd<0) osError("UDP create");
            if(address.address.ss_family==AF_INET6) { int yes=1; if(setsockopt(p->fd,IPPROTO_IPV6,IPV6_V6ONLY,&yes,sizeof(yes))<0) osError("IPv6-only"); }
            if(::bind(p->fd,reinterpret_cast<const sockaddr*>(&address.address),address.length)<0) osError("UDP bind");
            store(p,2); return true;
        }
        if(sub=="close") {
            auto key=val(2); if(!get(key)->datagram) fail(s,"udp operation requires UDP handle");
            sockets.erase(key); return true;
        }
        if(sub=="endpoint") {
            reserve(128,true,true); auto p=get(val(4)); if(!p->datagram) fail(s,"udp operation requires UDP handle");
            sockaddr_storage address{}; socklen_t size=sizeof(address);
            if(getsockname(p->fd,reinterpret_cast<sockaddr*>(&address),&size)<0) osError("UDP endpoint");
            auto peer=socketPeer(address,s); put(2,peer.first); put(3,std::to_string(peer.second)); return true;
        }
        if(sub=="sendto") {
            reserve(256); auto p=get(val(3)); if(!p->datagram) fail(s,"udp operation requires UDP handle");
            auto host=val(4); if(host=="localhost") host="127.0.0.1";
            socketHost(host,true,s); int port=static_cast<int>(integer(val(5),1,65535,s));
            auto data=val(6); if(data.size()>65507) fail(s,"udp datagram size limit (65507)");
            auto address=socketNumeric(host,port);
            sockaddr_storage local{}; socklen_t size=sizeof(local);
            if(getsockname(p->fd,reinterpret_cast<sockaddr*>(&local),&size)<0) osError("UDP endpoint");
            if(local.ss_family!=address.address.ss_family) fail(s,"udp address family mismatch");
            bytesRoom(data.size()); socketBytes+=data.size(); // Attempts count, including wouldblock.
            auto n=::sendto(p->fd,data.data(),data.size(),MSG_NOSIGNAL,reinterpret_cast<const sockaddr*>(&address.address),address.length);
            if(n<0 && !socketWouldBlock()) osError("UDP sendto");
            if(n>=0 && static_cast<std::size_t>(n)!=data.size()) fail(s,"udp non-atomic send failure");
            result({{"status",n<0 ? "wouldblock" : "progress"},{"count",std::max<ssize_t>(0,n)}}); return true;
        }
        auto max=static_cast<std::size_t>(integer(val(5),1,65507,s)); reserve(max,true);
        auto p=get(val(4)); if(!p->datagram) fail(s,"udp operation requires UDP handle");
        bytesRoom(65535); storage(max);
        std::string data(max,'\0'); sockaddr_storage address{}; socklen_t size=sizeof(address);
        auto n=::recvfrom(p->fd,data.data(),max,MSG_TRUNC,reinterpret_cast<sockaddr*>(&address),&size);
        if(n<0) {
            if(!socketWouldBlock()) osError("UDP recvfrom");
            put(3,""); result({{"status","wouldblock"},{"count",0},{"size",0},{"address",""},{"port",0}}); return true;
        }
        socketBytes+=static_cast<std::size_t>(n); data.resize(std::min(max,static_cast<std::size_t>(n)));
        auto peer=socketPeer(address,s); put(3,data);
        result({{"status",static_cast<std::size_t>(n)>max ? "truncated" : "progress"},{"count",data.size()},{"size",n},{"address",peer.first},{"port",peer.second}}); return true;