// 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(integer(val(4),0,65535,s)); room(); auto address=socketNumeric(host,port); auto p=std::make_shared(); 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(&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(&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(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(&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(&address.address),address.length); if(n<0 && !socketWouldBlock()) osError("UDP sendto"); if(n>=0 && static_cast(n)!=data.size()) fail(s,"udp non-atomic send failure"); result({{"status",n<0 ? "wouldblock" : "progress"},{"count",std::max(0,n)}}); return true; } auto max=static_cast(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(&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(n); data.resize(std::min(max,static_cast(n))); auto peer=socketPeer(address,s); put(3,data); result({{"status",static_cast(n)>max ? "truncated" : "progress"},{"count",data.size()},{"size",n},{"address",peer.first},{"port",peer.second}}); return true;