static ssize_t __guac_wol_send_packet()

in src/libguac/wol.c [83:171]


static ssize_t __guac_wol_send_packet(const char* broadcast_addr,
        const unsigned short udp_port, unsigned char packet[]) {
    
    struct sockaddr_in wol_dest;
    int wol_socket;
    
    /* Determine the IP version, starting with IPv4. */
    wol_dest.sin_port = htons(udp_port);
    wol_dest.sin_family = AF_INET;
    int retval = inet_pton(wol_dest.sin_family, broadcast_addr, &(wol_dest.sin_addr));
    
    /* If return value is less than zero, this system doesn't know about IPv4. */
    if (retval < 0) {
        guac_error = GUAC_STATUS_SEE_ERRNO;
        guac_error_message = "IPv4 address family is not supported";
        return 0;
    }
    
    /* If return value is zero, address doesn't match the IPv4, so try IPv6. */
    else if (retval == 0) {
        wol_dest.sin_family = AF_INET6;
        retval = inet_pton(wol_dest.sin_family, broadcast_addr, &(wol_dest.sin_addr));
        
        /* System does not support IPv6. */
        if (retval < 0) {
            guac_error = GUAC_STATUS_SEE_ERRNO;
            guac_error_message = "IPv6 address family is not supported";
            return 0;
        }
        
        /* Address didn't match IPv6. */
        else if (retval == 0) {
            guac_error = GUAC_STATUS_INVALID_ARGUMENT;
            guac_error_message = "Invalid broadcast or multicast address specified for Wake-on-LAN";
            return 0;
        }
    }
    
    
    
    /* Set up the socket */
    wol_socket = socket(wol_dest.sin_family, SOCK_DGRAM, 0);
    
    /* If socket open fails, bail out. */
    if (wol_socket < 0) {
        guac_error = GUAC_STATUS_SEE_ERRNO;
        guac_error_message = "Failed to open socket to send Wake-on-LAN packet";
        return 0;
    }
    
    /* Set up socket for IPv4 broadcast. */
    if (wol_dest.sin_family == AF_INET) {
        
        /* For configuring socket broadcast */
        int wol_bcast = 1;

        /* Attempt to set IPv4 broadcast; exit with error if this fails. */
        if (setsockopt(wol_socket, SOL_SOCKET, SO_BROADCAST, &wol_bcast,
                sizeof(wol_bcast)) < 0) {
            close(wol_socket);
            guac_error = GUAC_STATUS_SEE_ERRNO;
            guac_error_message = "Failed to set IPv4 broadcast for Wake-on-LAN socket";
            return 0;
        }
    }
    
    /* Set up socket for IPv6 multicast. */
    else {
        
        /* Stick to a single hop for now. */
        int hops = 1;
        
        /* Attempt to set IPv6 multicast; exit with error if this fails. */
        if (setsockopt(wol_socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
                sizeof(hops)) < 0) {
            close(wol_socket);
            guac_error = GUAC_STATUS_SEE_ERRNO;
            guac_error_message = "Failed to set IPv6 multicast for Wake-on-LAN socket";
            return 0;
        }
    }
    
    /* Send the packet and return number of bytes sent. */
    int bytes = sendto(wol_socket, packet, GUAC_WOL_PACKET_SIZE, 0,
            (struct sockaddr*) &wol_dest, sizeof(wol_dest));
    close(wol_socket);
    return bytes;
 
}