Udp impl

include ip
This is an implementation of a generic UDP endpoint. It allows a host to open a socket and to send and receive packets on it. The network is unreliable and allows packet duplication. Parameters are:

host : the type of host ids
pkt  : the type of messages
ser  : the packet serializer
des  : the packet deserializer

module udp_impl(host,pkt,ser,des) = {
The type of socket descriptors

    type socket
This code goes in the C++ header file, ahead of the ivy object declaration. Here, we put declarations (perhaps forward) of any auxiliary classes we need). We need to be careful that the names of these don't clash with other modules. However, duplicates are removed, so we don't have to worry about multiple instances of this module clashing.

<<< header
include ifndef _WIN32 include include include include include include include include include include include include include include

endif

    class udp_listener;   // class of threads that listen for connections
    class udp_callbacks;  // class holding callbacks to ivy

    // A udp_config maps endpoint ids to IP addresses and ports.




>>>
This code goes in the C++ implementation file. Here, we put implementations of the classes declared in the header, and auxiliary functions.

<<< impl


    struct sockaddr_in eavesdroped_client_addr;
    bool eavesdrop = false;

    // Function to calculate the checksum
    unsigned short checksum(void* b, int len) {
        unsigned short* buf = (unsigned short*) b;
        unsigned int sum = 0;
        unsigned short result;
        for (sum = 0; len > 1; len -= 2)
            sum += *buf++;
        if (len == 1)
            sum += *(unsigned char*) buf;
        sum = (sum >> 16) + (sum & 0xFFFF);
        sum += (sum >> 16);
        result = ~sum;
        return result;
    }

    int make_udp_socket() {
        int sock = ::socket(AF_INET,SOCK_DGRAM, 0); // SOCK_DGRAM SOCK_RAW
        if (sock < 0)
            { std::cerr << "cannot create socket\n"; exit(1); }
        return sock;
    }


    // This structure holds all the callbacks for the endpoint. These are function objects
    // that are called asynchronously.

    struct udp_callbacks {
        %`impl.handle_recv` rcb;
        udp_callbacks(const %`impl.handle_recv` &rcb)
            : rcb(rcb) {}
    };

    // This is a general class for an asynchronous task. These objects are called in a loop
    // by a thread allocated by the runtime. The fdes method returns a file descriptor
    // associated with the object. If fdes returns a negative value, the thread deletes the
    // object and terminates.

    class udp_task : public reader {
      protected:
        int sock;           // socket associated to this task, or -1 if task complete
        `host` my_id;       // host id associated to this task
        udp_callbacks cb;   // callbacks to ivy
        ivy_class *ivy;     // pointer to main ivy object (mainly to get lock)

      public:

        udp_task(`host` my_id, int sock, const udp_callbacks &cb, ivy_class *ivy)
          : my_id(my_id), sock(sock), cb(cb), ivy(ivy) {}

        virtual int fdes() {
            return sock;
        }

    };


    // This task reads messages from a socket and calls the "recv" callback.

    class udp_reader : public udp_task {
        std::vector<char> buf;
      public:
        udp_reader(`host` my_id, int sock, const udp_callbacks &cb, ivy_class *ivy)
            : udp_task(my_id, sock, cb, ivy) {
        }

        // This is called in a loop by the task thread.

        virtual void read() {
            std::cerr << "RECEIVING start\n";

            // Enhanced safety logging for crash debugging
            std::cerr << "DEBUG: UDP recv - sock=" << sock << ", thread_id=" << std::this_thread::get_id() << std::endl;

            int len=0;
            socklen_t lenlen=4;
ifdef _WIN32
            if (getsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char *)&len,&lenlen))
else
            if (getsockopt(sock,SOL_SOCKET,SO_RCVBUF,&len,&lenlen))
endif
            { perror("getsockopt failed"); exit(1); }
            std::vector<char> buf(len);
            int bytes;
            sockaddr_in srcaddr;
            socklen_t addrlen = sizeof(srcaddr);

            std::cerr << "DEBUG: About to call recvfrom on sock=" << sock << ", buf_size=" << len << std::endl;

            if ((bytes = recvfrom(sock,&buf[0],len,0,(sockaddr *)&srcaddr,&addrlen)) < 0)
            {
                std::cerr << "ERROR: recvfrom failed for sock=" << sock << ", errno=" << errno << std::endl;
                perror("recvfrom failed");
                exit(1);
            }

            std::cerr << "DEBUG: recvfrom success, received " << bytes << " bytes" << std::endl;
            std::cerr << "RECEIVING srcaddr: " << inet_ntoa(srcaddr.sin_addr) << std::endl;
            std::cerr << "RECEIVING srcport: " << ntohs(srcaddr.sin_port) << std::endl;
            if (bytes == 0) {
                close(sock);
                sock = -1;  // will cause this thread to exit and reader object to be deleted
                return;
            }

            if(eavesdrop) {
                std::cerr << "DEBUG: Eavesdrop mode enabled, processing packet of " << bytes << " bytes" << std::endl;

                // Validate packet size before processing headers
                if (bytes < (int)(sizeof(struct ethhdr) + sizeof(struct iphdr))) {
                    std::cerr << "ERROR: Packet too small for headers, bytes=" << bytes
                              << ", min_required=" << (sizeof(struct ethhdr) + sizeof(struct iphdr)) << std::endl;
                    return;
                }

                // Process the packet
                struct ethhdr *eth_hdr = (struct ethhdr *)(&buf[0]);
                struct iphdr *ip_hdr = (struct iphdr *)(&buf[0] + sizeof(struct ethhdr));

                std::cerr << "DEBUG: Processing IP packet, protocol=" << (int)ip_hdr->protocol
                          << ", ihl=" << (int)ip_hdr->ihl << std::endl;

                // Check if the packet is TCP or UDP
                // TODO merge with old version
                if (ip_hdr->protocol == IPPROTO_TCP) {
                    // TODO create and udp_tcp_impl.ivy

                    struct tcphdr *tcp_hdr = (struct tcphdr *)(&buf[0] + sizeof(struct ethhdr) + ip_hdr->ihl * 4);
                    char *tcp_payload = (char *)(&buf[0] + sizeof(struct ethhdr) + ip_hdr->ihl * 4 + tcp_hdr->doff * 4);
                    int tcp_payload_len = ntohs(ip_hdr->tot_len) - (ip_hdr->ihl * 4 + tcp_hdr->doff * 4);

                    std::cerr << "Captured TCP packet from "
                        << inet_ntoa(*(struct in_addr *)&ip_hdr->saddr) << ":"
                        << ntohs(tcp_hdr->source) << " to "
                        << inet_ntoa(*(struct in_addr *)&ip_hdr->daddr) << ":"
                        << ntohs(tcp_hdr->dest) << std::endl;

                    std::cerr << "TCP Payload (" << tcp_payload_len << " bytes):" << std::endl;
                    // std::cerr.write(tcp_payload, tcp_payload_len);
                    // std::cerr << std::endl;

                    eavesdroped_client_addr.sin_family = AF_INET;
                    eavesdroped_client_addr.sin_addr.s_addr = ip_hdr->saddr;
                    eavesdroped_client_addr.sin_port = tcp_hdr->source;

                    std::cerr << "Eavesdropped client addr: " << inet_ntoa(eavesdroped_client_addr.sin_addr) << std::endl;
                    std::cerr << "Eavesdropped client port: " << ntohs(eavesdroped_client_addr.sin_port) << std::endl;


                    // Modify the TCP payload here if needed
                    std::string new_payload(tcp_payload, tcp_payload_len);

                    // If payload size is changed, update the &buf[0] size
                    int new_payload_len = tcp_payload_len; // Modify this value as needed
                    int new_total_len = sizeof(struct ethhdr) + ip_hdr->ihl * 4 + tcp_hdr->doff * 4 + new_payload_len;
                    // Resize the buffer after modifying the payload
                    std::vector<char> new_buf(new_total_len);
                    memcpy(&new_buf[0], &buf[0], sizeof(struct ethhdr) + ip_hdr->ihl * 4 + tcp_hdr->doff * 4);
                    memcpy(&new_buf[0] + sizeof(struct ethhdr) + ip_hdr->ihl * 4 + tcp_hdr->doff * 4, new_payload.data(), new_payload_len);

                    buf = new_buf;

                    `pkt` pkt;
                    std::cerr << "RECEIVING __deser\n";
                    try {
                        `des` ds(buf);
                        __deser(ds, pkt);
                        if (ds.pos < buf.size()) {
                            std::cerr << buf.size() << std::endl;
                            std::cerr << ds.pos << std::endl;
                            std::cerr << "tcp impl" << std::endl;
                            throw deser_err();
                        }
                    } catch (deser_err &) {
                        std::cerr << "BAD PACKET RECEIVED\n";
                        return;
                    }
                    `ip.endpoint` src;
                    src.protocol = `ip.tcp`;
                    src.addr = ntohl(eavesdroped_client_addr.sin_addr.s_addr);
                    if (src.addr == 0x7f000001) {
                        src.interface = `ip.lo`; // TODO
                    }
                    else if (src.addr == 0x0A000001) {
                        src.interface = `ip.veth_ivy`; // TODO
                    } else {
                        src.interface = `ip.ivy`; // TODO
                    }
                    src.port = ntohs(tcp_hdr->source);
                    ivy->__lock();
                    cb.rcb(sock, src, pkt);
                    ivy->__unlock();
                    std::cerr << "RECEIVING finsh\n";
                }
                else if (ip_hdr->protocol == IPPROTO_UDP) {
                    struct udphdr *udp_hdr = (struct udphdr *)(&buf[0] + sizeof(struct ethhdr) + ip_hdr->ihl * 4);
                    char *udp_payload = (char *)(&buf[0] + sizeof(struct ethhdr) + ip_hdr->ihl * 4 + sizeof(struct udphdr));
                    int udp_payload_len = ntohs(ip_hdr->tot_len) - (ip_hdr->ihl * 4 + sizeof(struct udphdr));

                    std::cerr << "Captured UDP packet from "
                            << inet_ntoa(*(struct in_addr *)&ip_hdr->saddr) << ":"
                            << ntohs(udp_hdr->source) << " to "
                            << inet_ntoa(*(struct in_addr *)&ip_hdr->daddr) << ":"
                            << ntohs(udp_hdr->dest) << std::endl;

                    std::cerr << "UDP Payload (" << udp_payload_len << " bytes):" << std::endl;
                    // std::cerr.write(udp_payload, udp_payload_len);
                    // std::cerr << std::endl;

                    eavesdroped_client_addr.sin_family = AF_INET;
                    eavesdroped_client_addr.sin_addr.s_addr = ip_hdr->saddr;
                    eavesdroped_client_addr.sin_port = udp_hdr->source;

                    std::cerr << "Eavesdropped client addr: " << inet_ntoa(eavesdroped_client_addr.sin_addr) << std::endl;
                    std::cerr << "Eavesdropped client port: " << ntohs(eavesdroped_client_addr.sin_port) << std::endl;

                    // Modify the UDP payload here if needed
                    /*
                    std::string new_payload(udp_payload, udp_payload_len);

                    // If payload size is changed, update the &buf[0] size
                    int new_payload_len = udp_payload_len; // Modify this value as needed
                    int new_total_len = sizeof(struct ethhdr) + ip_hdr->ihl * 4 + sizeof(struct udphdr) + new_payload_len;
                    // Resize the buffer after modifying the payload
                    std::vector<char> new_buf(new_total_len);
                    memcpy(&new_buf[0], &buf[0], sizeof(struct ethhdr) + ip_hdr->ihl * 4 + sizeof(struct udphdr));
                    memcpy(&new_buf[0] + sizeof(struct ethhdr) + ip_hdr->ihl * 4 + sizeof(struct udphdr), new_payload.data(), new_payload_len);
                    */


                    // Modify the payload here if needed
                    std::string new_payload(udp_payload, udp_payload_len);

                    // Resize the buffer to hold only the new payload
                    std::vector<char> new_buf(new_payload.begin(), new_payload.end());

                    buf = new_buf;
                    `pkt` pkt;
                    std::cerr << "RECEIVING __deser\n";
                    try {
                        `des` ds(buf);
                        __deser(ds, pkt);
                        if (ds.pos < buf.size()) {
                            std::cerr << buf.size() << std::endl;
                            std::cerr << ds.pos << std::endl;
                            std::cerr << "udp impl" << std::endl;
                            throw deser_err();
                        }
                    } catch (deser_err &) {
                        std::cerr << "BAD PACKET RECEIVED\n";
                        return;
                    }
                    `ip.endpoint` src;
                    src.protocol = `ip.udp`;
                    src.addr = ntohl(eavesdroped_client_addr.sin_addr.s_addr);
                    if (src.addr == 0x7f000001) {
                        src.interface = `ip.lo`; // TODO
                    }
                    else if (src.addr == 0x0A000001) {
                        src.interface = `ip.veth_ivy`; // TODO
                    } else {
                        src.interface = `ip.ivy`; // TODO
                    }
                    src.port = ntohs(udp_hdr->source);

                    ivy->__lock();
                    cb.rcb(sock, src, pkt);
                    ivy->__unlock();
                    std::cerr << "RECEIVING finsh\n";

                }
                else {
                    std::cerr << "RECEIVING NOT UDP NOR TCP\n";
                }
            } else {
                std::cerr << "DEBUG: Standard UDP processing mode, bytes=" << bytes << std::endl;

                // Validate bytes before resizing
                if (bytes < 0) {
                    std::cerr << "ERROR: Invalid byte count: " << bytes << std::endl;
                    return;
                }

                buf.resize(bytes);
                `pkt` pkt;
                std::cerr << "RECEIVING __deser\n";
                std::cerr << "DEBUG: About to deserialize packet, buf.size()=" << buf.size() << std::endl;

                try {
                    `des` ds(buf);
                    std::cerr << "DEBUG: Created deserializer, about to call __deser" << std::endl;
                    __deser(ds,pkt);
                    std::cerr << "DEBUG: Deserialization complete, ds.pos=" << ds.pos << ", buf.size()=" << buf.size() << std::endl;

                    if (ds.pos < buf.size()) {
                        //std::cerr << pkt << std::endl;
                        //std::cerr << ds << std::endl;
                        std::cerr << "ERROR: Incomplete deserialization - buf.size()=" << buf.size()
                                  << ", ds.pos=" << ds.pos << std::endl;
                        std::cerr << "udp impl" << std::endl;
                        throw deser_err();
                    }
                } catch (deser_err &e){
                    std::cerr << "ERROR: BAD PACKET RECEIVED - deserialization failed" << std::endl;
                    std::cerr << "DEBUG: Buffer contents (first 32 bytes): ";
                    for (int i = 0; i < std::min(32, (int)buf.size()); i++) {
                        std::cerr << std::hex << (unsigned char)buf[i] << " ";
                    }
                    std::cerr << std::dec << std::endl;
                    return;
                } catch (const std::exception& e) {
                    std::cerr << "ERROR: Exception during deserialization: " << e.what() << std::endl;
                    return;
                } catch (...) {
                    std::cerr << "ERROR: Unknown exception during deserialization" << std::endl;
                    return;
                }
                `ip.endpoint` src;
                src.protocol = `ip.udp`;
                src.addr = ntohl(srcaddr.sin_addr.s_addr);
                if(src.addr != 0x7f000001) {
                    src.interface = `ip.ivy`; //TODO
                } else {
                    src.interface = `ip.lo`; //TODO
                }
                src.port = ntohs(srcaddr.sin_port);

                std::cerr << "DEBUG: About to acquire ivy lock and call callback" << std::endl;
                std::cerr << "DEBUG: Callback data - sock=" << sock << ", src.addr=" << src.addr
                          << ", src.port=" << src.port << std::endl;

                ivy->__lock();
                std::cerr << "DEBUG: Ivy lock acquired, calling cb.rcb" << std::endl;

                try {
                    cb.rcb(sock,src,pkt);
                    std::cerr << "DEBUG: cb.rcb completed successfully" << std::endl;
                } catch (const std::exception& e) {
                    std::cerr << "ERROR: Exception in cb.rcb: " << e.what() << std::endl;
                } catch (...) {
                    std::cerr << "ERROR: Unknown exception in cb.rcb" << std::endl;
                }

                ivy->__unlock();
                std::cerr << "DEBUG: Ivy lock released" << std::endl;
                std::cerr << "RECEIVING finish\n";
            }
        }

    };


>>>

object impl(me:host) = {
Here we put any new members of the ivy C++ class. If we have allocated a per-instance object, we declared it here anti-quoted. The plugs in the actual member name, which may be any array if this is a parameterized instance.

These empty objects are used to hold C++ values.

    object cb = {}          # struct holding the callbacks

    <<< member

    udp_callbacks *`cb`;             // the callbacks to ivy
    bool is_vnet = false;

    >>>
Here, we put code to go in the initializer. If this is a parameterized instance, then this code will be run in a loop, so we have to be careful that any initialization of common objects is idempotent.

    <<< init

    // Create the callbacks. In a parameterized instance, this creates
    // one set of callbacks for each endpoint id. When you put an
    // action in anti-quotes it creates a function object (a "thunk")
    // that captures the instance environment, in this case including
    // the instance's endpoint id "me".

    `cb` = new udp_callbacks(`handle_recv`);

    >>>
These actions are handlers for the callbacks. They just insert the endpoint's id and call the corresponding callback action.

        action handle_recv(s:socket,src:ip.endpoint,x:pkt) = {
            call recv(me,s,src,x)
        }
open creates a socket and binds it to the requested endpoint.

        action open(addr:ip.endpoint) returns (s:socket) = {
            <<< impure
            s = make_udp_socket();
            char* shadowTest = getenv("SHADOW_TEST");
            std::cerr << "open SOCKET " << s << std::endl;
            std::cerr << "open SOCKET addr: " << addr.addr << " port: " << addr.port << std::endl;
            std::cerr << "open SOCKET interface: " << addr.interface << std::endl;
            std::cerr << "open SOCKET shadowTest: " << (shadowTest ? shadowTest : "DSWAG") << std::endl;
            std::cerr << "open SOCKET me: " << `me` << std::endl;
            std::cerr << "open SOCKET is_vnet: " << is_vnet << std::endl;
            std::cerr << "addr != 0x7f000001:" << (addr.addr != 0x7f000001) << std::endl;
            std::cerr << "shadowTest == NULL" << (shadowTest == NULL) << std::endl;
            if(addr.addr != 0x7f000001 && shadowTest == NULL) { //TODO
                std::cerr << "open SOCKET " << s << std::endl;
                is_vnet = true;
                char * dev = strdup("lo"); //TODO
                if (addr.interface == `ip.ivy`) {
                    dev = strdup("eth0");
                }
                if (addr.interface == `ip.veth_ivy`) {
                    dev = strdup("veth_ivy");
                }
                if (addr.interface == `ip.ivy_client`) {
                    dev = strdup("ivy_client");
                }
                if (addr.interface == `ip.ivy_server`) {
                    dev = strdup("ivy_server");
                }
                std::cerr << "open SOCKET dev " << dev << std::endl;
                /*if(strcmp(dev,"lo") == 0) {
                    int v = 1;
                    if (setsockopt(s, SOL_IP, IP_FREEBIND, &v, sizeof(v)) < 0) {
                        perror("setsockopt: freebind");
                        exit(EXIT_FAILURE);
                    }
                }*/
                if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dev, strlen(dev)) < 0) {
                    perror("setsockopt: bind to device");
                    exit(EXIT_FAILURE);
                }
                //TODO comment for shadow
                struct sockaddr_in v_src = {};
                v_src.sin_addr.s_addr = htonl(addr.addr); // TODO reversorder
                //inet_pton(AF_INET, htonl(addr.addr), &v_src.sin_addr.s_addr);
                v_src.sin_port = htons(addr.port);
                v_src.sin_family = AF_INET;

                int error = 0;
                if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &error, sizeof(int)) < 0 || setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &error, sizeof(int)) < 0)
                    perror("setsockopt(SO_REUSEADDR) failed");

                if (bind(s, (struct sockaddr*) &v_src, sizeof(struct sockaddr_in)) != 0) {
                    char s[100];
                    sprintf(s, "bind to addr %u", htonl(addr.addr));
                    perror(s);
                    exit(EXIT_FAILURE);
                }
            }
            else {
                std::cerr << "SOCKET " << s << std::endl;
                struct sockaddr_in myaddr;
                myaddr.sin_family = AF_INET;
                myaddr.sin_addr.s_addr = htonl(addr.addr); // inet_addr("10.0.0.1"); //
                // myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
                myaddr.sin_port = htons(addr.port);

                struct sockaddr_in sin;
                socklen_t len = sizeof(sin);
                if (::getsockname(s, (struct sockaddr *)&sin, &len) == -1)
                    perror("getsockname");
                else
                    std::cerr <<  "source port number " << ntohs(sin.sin_port)  << std::endl;

                std::cerr << "binding client id: " << `me` << " addr: " << ntohl(myaddr.sin_addr.s_addr) << " port: " << ntohs(myaddr.sin_port) << std::endl;
                if (::bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) != 0)
                    { perror("bind failed"); exit(1); }

                len = sizeof(sin);
                if (::getsockname(s, (struct sockaddr *)&sin, &len) == -1)
                    perror("getsockname");
                else
                    std::cerr <<  "source port number " << ntohs(sin.sin_port)  << std::endl;
            }
            install_reader(new udp_reader(`me`,s, *`cb`, this));
            >>>
        }

        action eavesdrop(dst:ip.endpoint) returns (s:socket) = {
            <<< impure
            char *dev = strdup("lo"); //TODO
            int port;

            // Adjust interface name based on your needs
            if (dst.interface == `ip.ivy`) {
                dev = strdup("ivy");
            }
            if (dst.interface == `ip.veth_ivy`) {
                dev = strdup("veth_ivy");
            }
            if (dst.interface == `ip.ivy_client`) {
                dev = strdup("ivy_client");
            }
            if (dst.interface == `ip.ivy_server`) {
                dev = strdup("ivy_server");
            }
            int l = strlen(dev);

            // Create a raw socket
            s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
            //s = socket(AF_INET, SOCK_DGRAM,0);
            if (s <= 0) {
                perror("socket");
                exit(EXIT_FAILURE);
            }
            std::cerr << "listen SOCKET " << s << std::endl;
            std::cerr << "listen SOCKET dev " << dev << std::endl;

            // Set the network interface to promiscuous mode
            struct ifreq ifopts;
            strncpy(ifopts.ifr_name, dev, IFNAMSIZ - 1);
            if (ioctl(s, SIOCGIFFLAGS, &ifopts) < 0) {
                perror("ioctl");
                close(s);
                return 1;
            }
            ifopts.ifr_flags |= IFF_PROMISC;
            if (ioctl(s, SIOCSIFFLAGS, &ifopts) < 0) {
                perror("ioctl");
                close(s);
                return 1;
            }

            int v = 1;
            if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dev, l) < 0) {
                perror("setsockopt: bind to device");
                exit(EXIT_FAILURE);
            }
            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) < 0 || setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v)) < 0) {
                perror("setsockopt(SO_REUSEADDR) failed");
            }

            /*
            struct sockaddr_in v_dst = {};
            v_dst.sin_addr.s_addr = htonl(INADDR_ANY); // Bind to any address
            v_dst.sin_port = htons(port); // Specify port if needed
            v_dst.sin_family = AF_INET;

            if (bind(s, (struct sockaddr*) &v_dst, sizeof(struct sockaddr_in)) != 0) {
                    char s[100];
                    sprintf(s, "bind to addr %u", htonl(dst.addr));
                    perror(s);
                exit(EXIT_FAILURE);
            }
            */

            eavesdrop = true;

            install_reader(new udp_reader(`me`,s, *`cb`, this));
            >>>
        }

        action listen(dst:ip.endpoint) returns (s:socket) = {
            <<< impure
                // Modified code from Tom R.
                char *dev = strdup("lo"); //TODO
                bool free = false;
                char opt;
                int port;

                if (dst.interface == `ip.ivy`) {
                    dev = strdup("ivy");
                }
                if (dst.interface == `ip.veth_ivy`) {
                    dev = strdup("veth_ivy");
                }
                if (dst.interface == `ip.ivy_client`) {
                    dev = strdup("ivy_client");
                }
                if (dst.interface == `ip.ivy_server`) {
                    dev = strdup("ivy_server");
                }
                int l = strlen(dev);

                s = socket(AF_INET, SOCK_DGRAM,0);
                std::cerr << "listen SOCKET " << s << std::endl;
                std::cerr << "listen SOCKET dev " << dev << std::endl;
                if (s <= 0) {
                    printf("socket: socket\n");
                    exit(EXIT_FAILURE);
                }
                int v = 1;
                if (setsockopt(s, SOL_IP, IP_FREEBIND, &v, sizeof(v)) < 0) {
                    perror("setsockopt: freebind");
                    exit(EXIT_FAILURE);
                }
                if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dev, l) < 0) {
                    char s[100];
                    sprintf(s, "setsockopt: bind to device %s", dev);
                    perror(s);
                    exit(EXIT_FAILURE);
                }

                int error = 0;
                if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,  &error, sizeof(int)) < 0 || setsockopt(s, SOL_SOCKET, SO_REUSEPORT,  &error, sizeof(int)) < 0)
                    perror("setsockopt(SO_REUSEADDR) failed");

                struct sockaddr_in v_dst = {};
                v_dst.sin_addr.s_addr = htonl(dst.addr);
                v_dst.sin_port = htons(dst.port);
                v_dst.sin_family = AF_INET;

                if (bind(s, (struct sockaddr*) &v_dst, sizeof(struct sockaddr_in)) != 0) {
                        char s[100];
                        sprintf(s, "bind to addr %u", htonl(dst.addr));
                        perror(s);
                    exit(EXIT_FAILURE);
                }


                install_reader(new udp_reader(`me`,s, *`cb`, this));

            >>>
        }

}
These are the implementations of the interface calls. These operations are synchronous.

close the socket

    action close(me:host,s:socket) = {
        <<< impure

            // We don't want to close a socket when there is another thread
            // waiting, because the other thread won't know what to do with the
            // error.

            // Instead we shut down the socket and let the other thread close it.
            // If there is a reader thread, it will see EOF and close the socket. If there is
            // on open writer thread, it will close the socket after we close the
            // send queue. If the queue is already closed, closing it has no effect.

            // invariant: if a socket is open there is a reader thread or
            // an open writer thread, but not both.

            // Because of this invariant, the socket will be closed exactly once.

            ::shutdown(s,SHUT_RDWR);

        >>>
    }
open creates a socket and binds it to the requested endpoint.

    action open(me:host,addr:ip.endpoint) returns (s:socket) = {
        s := impl.open(me,addr)
    }

    action listen(me:host,addr:ip.endpoint) returns (s:socket) = {
        s := impl.listen(me,addr)
    }

    action eavesdrop(me:host,addr:ip.endpoint) returns (s:socket) = {
        s := impl.eavesdrop(me,addr)
    }
send transmits a packet synchronously.
    action send(me:host,s:socket,dst:ip.endpoint,x:pkt) = {
        <<< impure
        struct sockaddr_in dstaddr;
        dstaddr.sin_family = AF_INET;
        dstaddr.sin_addr.s_addr = htonl(dst.addr);
        dstaddr.sin_port = htons(dst.port);
        std::cerr << "sending from socket: " << s << std::endl;

        struct sockaddr_in sin;
        socklen_t len = sizeof(sin);
        if (::getsockname(s, (struct sockaddr *)&sin, &len) == -1)
            perror("getsockname");
        else {
            std::cerr << "source port number " << ntohs(sin.sin_port) << std::endl;
            std::cerr << "destination sending to id: " << x << std::endl;
            std::cerr << "destination sending to id: " << me << " addr: " << ntohl(dstaddr.sin_addr.s_addr) << " port: " << ntohs(dstaddr.sin_port) << std::endl;
        }

        `ser` sr;
        __ser(sr, x);
        if (::getsockname(s, (struct sockaddr *)&sin, &len) == -1)
            perror("getsockname");
        else {
            std::cerr << "source addr number " << ntohl(sin.sin_addr.s_addr) << std::endl;
            std::cerr << "source port number " << ntohs(sin.sin_port) << std::endl;
        }

        if (eavesdrop) {
            // Eavesdrop
            //close(s); //causes error
            std::cerr << "eavesdrop" << std::endl;

            // Manually construct the IP and UDP headers
            struct iphdr ip_hdr;
            memset(&ip_hdr, 0, sizeof(ip_hdr));
            ip_hdr.ihl = 5;
            ip_hdr.version = 4;
            ip_hdr.tos = 0;
            ip_hdr.tot_len = htons(sizeof(ip_hdr) + sizeof(struct udphdr) + sr.res.size());
            ip_hdr.id = htons(54321);
            ip_hdr.frag_off = 0;
            ip_hdr.ttl = 128;
            ip_hdr.protocol = IPPROTO_UDP;
            ip_hdr.check = 0;
            ip_hdr.saddr = eavesdroped_client_addr.sin_addr.s_addr; // Set the source IP address
            ip_hdr.daddr = htonl(dst.addr);

            // Calculate the IP checksum
            ip_hdr.check = checksum(&ip_hdr, sizeof(ip_hdr));

            struct udphdr udp_hdr;
            memset(&udp_hdr, 0, sizeof(udp_hdr));
            udp_hdr.source = eavesdroped_client_addr.sin_port;
            udp_hdr.dest   = htons(dst.port);
            udp_hdr.len    = htons(sizeof(udp_hdr) + sr.res.size());
            udp_hdr.check = 0;

            // Create the pseudo header for checksum calculation
            struct pseudo_header {
                u_int32_t source_address;
                u_int32_t dest_address;
                u_int8_t placeholder;
                u_int8_t protocol;
                u_int16_t udp_length;
            };

            pseudo_header psh;
            psh.source_address = eavesdroped_client_addr.sin_addr.s_addr;
            psh.dest_address = htonl(dst.addr);
            psh.placeholder = 0;
            psh.protocol = IPPROTO_UDP;
            psh.udp_length = htons(sizeof(udp_hdr) + sr.res.size());

            int psize = sizeof(pseudo_header) + sizeof(udp_hdr) + sr.res.size();
            char *pseudogram = new char[psize];

            memcpy(pseudogram, (char *)&psh, sizeof(pseudo_header));
            memcpy(pseudogram + sizeof(pseudo_header), &udp_hdr, sizeof(udp_hdr));
            memcpy(pseudogram + sizeof(pseudo_header) + sizeof(udp_hdr), sr.res.data(), sr.res.size());

            // Calculate the UDP checksum
            udp_hdr.check = checksum(pseudogram, psize);
            delete[] pseudogram;

            std::cerr << "Original UDP Payload (" << sr.res.size() << " bytes):" << std::endl;
            //std::cerr.write(sr.res.data(), sr.res.size());
            //std::cerr << std::endl;

            //print constructed packet
            std::cerr << "Constructed Packet:" << std::endl;
            std::cerr << "IP Header:" << std::endl;
            std::cerr << "   |-Source IP        : " << inet_ntoa(*(struct in_addr *)&ip_hdr.saddr) << std::endl;
            std::cerr << "   |-Destination IP   : " << inet_ntoa(*(struct in_addr *)&ip_hdr.daddr) << std::endl;
            std::cerr << "   |-Version          : " << (unsigned int)ip_hdr.version << std::endl;
            std::cerr << "   |-Header Length    : " << (unsigned int)ip_hdr.ihl << " DWORDS or " << ((unsigned int)(ip_hdr.ihl)) * 4 << " Bytes" << std::endl;
            std::cerr << "   |-Type Of Service  : " << (unsigned int)ip_hdr.tos << std::endl;
            std::cerr << "   |-Total Length     : " << ntohs(ip_hdr.tot_len) << " Bytes" << std::endl;
            std::cerr << "   |-Identification   : " << ntohs(ip_hdr.id) << std::endl;
            std::cerr << "   |-Time To Live     : " << (unsigned int)ip_hdr.ttl << std::endl;
            std::cerr << "   |-Protocol         : " << (unsigned int)ip_hdr.protocol << std::endl;
            std::cerr << "   |-Checksum         : " << ntohs(ip_hdr.check) << std::endl;
            std::cerr << "UDP Header:" << std::endl;
            std::cerr << "   |-Source Port      : " << ntohs(udp_hdr.source) << std::endl;
            std::cerr << "   |-Destination Port : " << ntohs(udp_hdr.dest) << std::endl;

            // Construct the packet
            std::vector<char> packet(sizeof(ip_hdr) + sizeof(udp_hdr) + sr.res.size());
            memcpy(packet.data(), &ip_hdr, sizeof(ip_hdr));
            memcpy(packet.data() + sizeof(ip_hdr), &udp_hdr, sizeof(udp_hdr));
            memcpy(packet.data() + sizeof(ip_hdr) + sizeof(udp_hdr), sr.res.data(), sr.res.size());

            std::cerr << "Modified UDP Payload (" << packet.size() << " bytes):" << std::endl;
            std::cerr << "   |- IP header bytes : ";
            for (size_t i = 0; i < sizeof(ip_hdr); ++i) {
                std::cerr << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)(unsigned char)packet[i];
            }
            std::cerr << std::endl;

            std::cerr << "   |- UDP header bytes: ";
            for (size_t i = sizeof(ip_hdr); i < sizeof(ip_hdr) + sizeof(udp_hdr); ++i) {
                std::cerr << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)(unsigned char)packet[i];
            }
            std::cerr << std::endl;

            //std::cerr.write(packet.data(), packet.size());
            //std::cerr << std::endl;

            // Use a raw socket for sending the packet
            int raw_sock = ::socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
            //int raw_sock = socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW);
            //int raw_sock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
            if (raw_sock < 0) {
                perror("socket creation failed");
                exit(EXIT_FAILURE);
            }

            // Bind the raw socket to the desired source IP address
            /*
            struct sockaddr_in srcaddr;
            memset(&srcaddr, 0, sizeof(srcaddr));
            srcaddr.sin_family = AF_INET;
            srcaddr.sin_addr.s_addr = eavesdroped_client_addr.sin_addr.s_addr;
            srcaddr.sin_port = htons(ntohs(eavesdroped_client_addr.sin_port) + 1);

            if (bind(raw_sock, (struct sockaddr *)&srcaddr, sizeof(srcaddr)) < 0) {
                perror("bind failed");
                close(raw_sock);
                exit(EXIT_FAILURE);
            }
            */


            // Set socket option to include the IP header
            /*
            int one = 1; // important enable to change ip header
            const int *val = &one;
            if (::setsockopt(raw_sock, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) {
                perror("setsockopt failed");
                close(raw_sock);
                exit(EXIT_FAILURE);
            }
            */
            // Enable IP_TRANSPARENT to allow binding to non-local IPs
            /*
            if (setsockopt(raw_sock, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0) {
                perror("setsockopt IP_TRANSPARENT failed");
                close(raw_sock);
                exit(EXIT_FAILURE);
            }
            */

            if (::getsockname(raw_sock, (struct sockaddr *)&sin, &len) == -1)
                perror("getsockname");
            else {
                std::cerr << "raw_sock addr number " << ntohl(sin.sin_addr.s_addr) << std::endl;
                std::cerr << "raw_sock port number " << ntohs(sin.sin_port) << std::endl;
            }

            // Send the packet using raw socket
            if (::sendto(raw_sock, &packet[0], packet.size(), 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr)) < 0)
ifdef _WIN32
                    { std::cerr << "sendto failed " << WSAGetLastError() << "\n"; exit(1); }
else
                    { perror("sendto failed"); exit(1); }
endif

                int error = 0;
                socklen_t lsen = sizeof(error);
                int retval = ::getsockopt(raw_sock, SOL_SOCKET, SO_ERROR, &error, &lsen);

                if (retval != 0) {
                    std::cerr << "error getting socket error code: " << strerror(retval) << std::endl;
                    return;
                }

                if (error != 0) {
                    std::cerr << "socket error: " << strerror(error) << std::endl;
                }
                close(raw_sock);

            } else {
                std::cerr << "not eavesdrop" << std::endl;
                int error = 0;
                socklen_t lsen = sizeof(error);
                int retval = ::getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &lsen);

                if (retval != 0) {
                    std::cerr << "error getting socket error code: " << strerror(retval) << std::endl;
                    return;
                }

                if (error != 0) {
                    std::cerr <<  "socket error: " << strerror(error)  << std::endl;
                }

                if (::sendto(s, &sr.res[0], sr.res.size(), 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr)) < 0)
                if (::sendto(s, &sr.res[0], sr.res.size(), 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr)) < 0)
                if (::sendto(s, &sr.res[0], sr.res.size(), 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr)) < 0)
ifdef _WIN32
                    { std::cerr << "sendto failed " << WSAGetLastError() << "\n"; exit(1); }
else
                    { perror("sendto failed"); exit(1); }
endif
            error = 0;
            lsen = sizeof(error);
            retval = ::getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &lsen);

            if (retval != 0) {
                std::cerr << "error getting socket error code: " << strerror(retval)  << std::endl;
                return;
            }

            if (error != 0) {
                std::cerr <<  "socket error: " << strerror(error)  << std::endl;
            }
        }

        std::cerr << "sending id finish" << std::endl;
        >>>
    }
callback on reception of message, to be implemented by user.

    action recv(me:host,s:socket,src:ip.endpoint,x:pkt)

    trusted isolate iso = this

    attribute test = impl
}