diff --git a/src/common-ssh/ssh.c b/src/common-ssh/ssh.c index c4af066b8..ac7867006 100644 --- a/src/common-ssh/ssh.c +++ b/src/common-ssh/ssh.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -34,15 +35,11 @@ #include #include -#include -#include -#include #include #include #include #include #include -#include #include #ifdef LIBSSH2_USES_GCRYPT @@ -414,81 +411,10 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, int keepalive, const char* host_key, guac_ssh_credential_handler* credential_handler) { - int retval; - - int fd; - struct addrinfo* addresses; - struct addrinfo* current_address; - - char connected_address[1024]; - char connected_port[64]; - - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = IPPROTO_TCP - }; - - /* Get addresses connection */ - if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) { + int fd = guac_socket_tcp_connect(hostname, port); + if (fd < 0) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, - "Error parsing given address or port: %s", - gai_strerror(retval)); - return NULL; - } - - /* Attempt connection to each address until success */ - current_address = addresses; - while (current_address != NULL) { - - /* Resolve hostname */ - if ((retval = getnameinfo(current_address->ai_addr, - current_address->ai_addrlen, - connected_address, sizeof(connected_address), - connected_port, sizeof(connected_port), - NI_NUMERICHOST | NI_NUMERICSERV))) - guac_client_log(client, GUAC_LOG_DEBUG, - "Unable to resolve host: %s", gai_strerror(retval)); - - /* Get socket */ - fd = socket(current_address->ai_family, SOCK_STREAM, 0); - if (fd < 0) { - guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, - "Unable to create socket: %s", strerror(errno)); - freeaddrinfo(addresses); - return NULL; - } - - /* Connect */ - if (connect(fd, current_address->ai_addr, - current_address->ai_addrlen) == 0) { - - guac_client_log(client, GUAC_LOG_DEBUG, - "Successfully connected to host %s, port %s", - connected_address, connected_port); - - /* Done if successful connect */ - break; - - } - - /* Otherwise log information regarding bind failure */ - guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to " - "host %s, port %s: %s", - connected_address, connected_port, strerror(errno)); - - close(fd); - current_address = current_address->ai_next; - - } - - /* Free addrinfo */ - freeaddrinfo(addresses); - - /* If unable to connect to anything, fail */ - if (current_address == NULL) { - guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND, - "Unable to connect to any addresses."); + "Failed to open TCP connection to %s on %s.", hostname, port); return NULL; } diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am index b52f476e4..06ced8cc3 100644 --- a/src/libguac/Makefile.am +++ b/src/libguac/Makefile.am @@ -70,6 +70,7 @@ libguacinc_HEADERS = \ guacamole/socket-constants.h \ guacamole/socket.h \ guacamole/socket-fntypes.h \ + guacamole/socket-tcp.h \ guacamole/socket-types.h \ guacamole/stream.h \ guacamole/stream-types.h \ @@ -128,6 +129,7 @@ libguac_la_SOURCES = \ socket-broadcast.c \ socket-fd.c \ socket-nest.c \ + socket-tcp.c \ socket-tee.c \ string.c \ timestamp.c \ diff --git a/src/libguac/guacamole/socket-tcp.h b/src/libguac/guacamole/socket-tcp.h new file mode 100644 index 000000000..48c0743ab --- /dev/null +++ b/src/libguac/guacamole/socket-tcp.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __GUAC_SOCKET_TCP_H +#define __GUAC_SOCKET_TCP_H + +#include "config.h" + +#include + +/** + * Given a hostname or IP address and port, attempt to connect to that + * system, returning an open socket if the connection succeeds, or a negative + * value if it fails. If it fails the errno variable will be set. + * + * @param hostname + * The hostname or IP address to which to attempt connections. + * + * @param port + * The TCP port to which to attempt to connect. + * + * @return + * A valid socket if the connection succeeds, or a negative integer if it + * fails. + */ +int guac_socket_tcp_connect(const char* hostname, const char* port); + +#endif // __GUAC_SOCKET_TCP_H \ No newline at end of file diff --git a/src/libguac/guacamole/string.h b/src/libguac/guacamole/string.h index a94d53c29..6db3d7e12 100644 --- a/src/libguac/guacamole/string.h +++ b/src/libguac/guacamole/string.h @@ -29,6 +29,24 @@ #include #include +/** + * Convert the provided unsigned integer into a string, returning the number of + * characters written into the destination string, or a negative value if an + * error occurs. + * + * @param dest + * The destination string to copy the data into, which should already be + * allocated and at a size that can handle the string representation of the + * inteer. + * + * @param integer + * The unsigned integer to convert to a string. + * + * @return + * The number of characters written into the dest string. + */ +int guac_itoa(char* restrict dest, unsigned int integer); + /** * Copies a limited number of bytes from the given source string to the given * destination buffer. The resulting buffer will always be null-terminated, diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 215e6b881..8b43fd181 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -27,6 +27,12 @@ * @file wol-constants.h */ +/** + * The default number of times to retry a connection to a server after waking + * the server with a WOL packet before giving up. + */ +#define GUAC_WOL_DEFAULT_CONNECT_RETRIES 5 + /** * The value for the local IPv4 broadcast address. */ diff --git a/src/libguac/guacamole/wol.h b/src/libguac/guacamole/wol.h index 9af1a8d03..f4c7d66ea 100644 --- a/src/libguac/guacamole/wol.h +++ b/src/libguac/guacamole/wol.h @@ -52,5 +52,45 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, const unsigned short udp_port); +/** + * Send the wake-up packet to the specified destination, returning zero if the + * wake was sent successfully, or non-zero if an error occurs sending the + * wake packet. Note that the return value does not specify whether the + * system actually wakes up successfully, only whether or not the packet + * is transmitted. + * + * @param mac_addr + * The MAC address to place in the magic Wake-on-LAN packet. + * + * @param broadcast_addr + * The broadcast address to which to send the magic Wake-on-LAN packet. + * + * @param udp_port + * The UDP port to use when sending the WoL packet. + * + * @param wait_time + * The number of seconds to wait between connection attempts after the WOL + * packet has been sent. + * + * @param retries + * The number of attempts to make to connect to the system before giving up + * on the connection. + * + * @param hostname + * The hostname or IP address of the system that has been woken up and to + * to which the connection will be attempted. + * + * @param port + * The TCP port of the remote system on which the connection will be + * attempted after the system has been woken. + * + * @return + * Zero if the packet is successfully sent to the destination; non-zero + * if the packet cannot be sent. + */ +int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr, + const unsigned short udp_port, int wait_time, int retries, + const char* hostname, const char* port); + #endif /* GUAC_WOL_H */ diff --git a/src/libguac/socket-tcp.c b/src/libguac/socket-tcp.c new file mode 100644 index 000000000..7e41d0218 --- /dev/null +++ b/src/libguac/socket-tcp.c @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" +#include "guacamole/error.h" +#include "guacamole/socket.h" + +#include +#include +#include +#include + +int guac_socket_tcp_connect(const char* hostname, const char* port) { + + int retval; + + int fd = EBADFD; + struct addrinfo* addresses; + struct addrinfo* current_address; + + char connected_address[1024]; + char connected_port[64]; + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP + }; + + /* Get addresses for requested hostname and port. */ + if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) { + guac_error = GUAC_STATUS_INVALID_ARGUMENT; + guac_error_message = "Error parsing address or port."; + return retval; + } + + /* Attempt connection to each address until success */ + current_address = addresses; + while (current_address != NULL) { + + /* Resolve hostname */ + if ((retval = getnameinfo(current_address->ai_addr, + current_address->ai_addrlen, + connected_address, sizeof(connected_address), + connected_port, sizeof(connected_port), + NI_NUMERICHOST | NI_NUMERICSERV))) { + + guac_error = GUAC_STATUS_INVALID_ARGUMENT; + guac_error_message = "Error resolving host."; + continue; + } + + /* Get socket */ + fd = socket(current_address->ai_family, SOCK_STREAM, 0); + if (fd < 0) { + freeaddrinfo(addresses); + return fd; + } + + /* Connect */ + if (connect(fd, current_address->ai_addr, + current_address->ai_addrlen) == 0) { + + /* Done if successful connect */ + break; + + } + + close(fd); + current_address = current_address->ai_next; + + } + + /* Free addrinfo */ + freeaddrinfo(addresses); + + /* If unable to connect to anything, set error status. */ + if (current_address == NULL) { + guac_error = GUAC_STATUS_REFUSED; + guac_error_message = "Unable to connect to remote host."; + } + + /* Return the fd, or the error message if the socket connection failed. */ + return fd; + +} \ No newline at end of file diff --git a/src/libguac/string.c b/src/libguac/string.c index 2a7ec2cd4..528d83f61 100644 --- a/src/libguac/string.c +++ b/src/libguac/string.c @@ -22,6 +22,7 @@ #include "guacamole/mem.h" #include +#include #include /** @@ -44,6 +45,20 @@ */ #define REMAINING(n, length) (((n) < (length)) ? 0 : ((n) - (length))) +int guac_itoa(char* restrict dest, unsigned int integer) { + + /* Determine size of string. */ + int str_size = snprintf(dest, 0, "%i", integer); + + /* If an error occurs, just return that and skip the conversion. */ + if (str_size < 0) + return str_size; + + /* Do the conversion and return. */ + return snprintf(dest, (str_size + 1), "%i", integer); + +} + size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n) { #ifdef HAVE_STRLCPY diff --git a/src/libguac/wol.c b/src/libguac/wol.c index 9d69306c9..c669dc47a 100644 --- a/src/libguac/wol.c +++ b/src/libguac/wol.c @@ -20,6 +20,8 @@ #include "config.h" #include "guacamole/error.h" +#include "guacamole/socket-tcp.h" +#include "guacamole/timestamp.h" #include "guacamole/wol.h" #include @@ -195,4 +197,50 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, return 0; return -1; +} + +int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr, + const unsigned short udp_port, int wait_time, int retries, + const char* hostname, const char* port) { + + /* Attempt to connect, first. */ + int sockfd = guac_socket_tcp_connect(hostname, port); + + /* If connection succeeds, no need to wake the system. */ + if (sockfd > 0) { + close(sockfd); + return 0; + } + + /* Send the magic WOL packet and store return value. */ + int retval = guac_wol_wake(mac_addr, broadcast_addr, udp_port); + + /* If sending WOL packet fails, just return the received return value. */ + if (retval) + return retval; + + /* Try to connect on the specified TCP port and hostname or IP. */ + for (int i = 0; i < retries; i++) { + + sockfd = guac_socket_tcp_connect(hostname, port); + + /* Connection succeeded - close socket and exit. */ + if (sockfd > 0) { + close(sockfd); + return 0; + } + + /** + * Connection did not succed - close the socket and sleep for the + * specified amount of time before retrying. + */ + close(sockfd); + guac_timestamp_msleep(wait_time * 1000); + } + + /* Failed to connect, set error message and return an error. */ + guac_error = GUAC_STATUS_REFUSED; + guac_error_message = "Unable to connect to remote host."; + return -1; + } \ No newline at end of file diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index dff536eff..d2e5bf960 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -698,19 +699,49 @@ void* guac_rdp_client_thread(void* data) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; - /* If Wake-on-LAN is enabled, try to wake. */ + /* If Wake-on-LAN is enabled, attempt to wake. */ if (settings->wol_send_packet) { - guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " - "and pausing for %d seconds.", settings->wol_wait_time); - - /* Send the Wake-on-LAN request. */ - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - settings->wol_udp_port)) + + /** + * If wait time is set, send the wake packet and try to connect to the + * server, failing if the server does not respond. + */ + if (settings->wol_wait_time > 0) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* char representation of a port should be, at most, 5 digits plus terminator. */ + char* str_port = guac_mem_alloc(6); + if (guac_itoa(str_port, settings->port) < 1) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to convert port to integer for WOL function."); + guac_mem_free(str_port); + return NULL; + } + + /* Send the Wake-on-LAN request and wait until the server is responsive. */ + if (guac_wol_wake_and_wait(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port, + settings->wol_wait_time, + GUAC_WOL_DEFAULT_CONNECT_RETRIES, + settings->hostname, + (const char *) str_port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet, or server failed to wake up."); + guac_mem_free(str_port); + return NULL; + } + + guac_mem_free(str_port); + + } + + /* Just send the packet and continue the connection, or return if failed. */ + else if(guac_wol_wake(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet."); return NULL; - - /* If wait time is specified, sleep for that amount of time. */ - if (settings->wol_wait_time > 0) - guac_timestamp_msleep(settings->wol_wait_time * 1000); + } } /* If audio enabled, choose an encoder */ diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 96d9d15d3..8db094af6 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -233,17 +234,35 @@ void* ssh_client_thread(void* data) { /* If Wake-on-LAN is enabled, attempt to wake. */ if (settings->wol_send_packet) { - guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " - "and pausing for %d seconds.", settings->wol_wait_time); - /* Send the Wake-on-LAN request. */ - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - settings->wol_udp_port)) - return NULL; + /** + * If wait time is set, send the wake packet and try to connect to the + * server, failing if the server does not respond. + */ + if (settings->wol_wait_time > 0) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* Send the Wake-on-LAN request and wait until the server is responsive. */ + if (guac_wol_wake_and_wait(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port, + settings->wol_wait_time, + GUAC_WOL_DEFAULT_CONNECT_RETRIES, + settings->hostname, + settings->port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote server."); + return NULL; + } + } - /* If wait time is specified, sleep for that amount of time. */ - if (settings->wol_wait_time > 0) - guac_timestamp_msleep(settings->wol_wait_time * 1000); + /* Just send the packet and continue the connection, or return if failed. */ + else if(guac_wol_wake(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet."); + return NULL; + } } /* Init SSH base libraries */ diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 40874c7f8..80ce6c878 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include #include @@ -381,101 +383,10 @@ static void* __guac_telnet_input_thread(void* data) { */ static telnet_t* __guac_telnet_create_session(guac_client* client) { - int retval; - - int fd; - struct addrinfo* addresses; - struct addrinfo* current_address; - - char connected_address[1024]; - char connected_port[64]; - guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; guac_telnet_settings* settings = telnet_client->settings; - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = IPPROTO_TCP - }; - - /* Get socket */ - fd = socket(AF_INET, SOCK_STREAM, 0); - - /* Get addresses connection */ - if ((retval = getaddrinfo(settings->hostname, settings->port, - &hints, &addresses))) { - guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error parsing given address or port: %s", - gai_strerror(retval)); - return NULL; - - } - - /* Attempt connection to each address until success */ - current_address = addresses; - while (current_address != NULL) { - - int retval; - - /* Resolve hostname */ - if ((retval = getnameinfo(current_address->ai_addr, - current_address->ai_addrlen, - connected_address, sizeof(connected_address), - connected_port, sizeof(connected_port), - NI_NUMERICHOST | NI_NUMERICSERV))) - guac_client_log(client, GUAC_LOG_DEBUG, "Unable to resolve host: %s", gai_strerror(retval)); - - fd_set fdset; - FD_ZERO(&fdset); - FD_SET(fd, &fdset); - - struct timeval timeout_tv; - timeout_tv.tv_sec = settings->timeout; - timeout_tv.tv_usec = 0; - - if (connect(fd, current_address->ai_addr, current_address->ai_addrlen) < 0) { - guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, - "Failed to connect: %s", strerror(errno)); - return NULL; - } - - retval = select(fd + 1, NULL, &fdset, NULL, &timeout_tv); - - if (retval == 0) { - guac_client_log(client, GUAC_LOG_ERROR, "Timeout connecting to " - "host %s, port %s", connected_address, connected_port); - continue; - } - - else if (retval > 0) { - - guac_client_log(client, GUAC_LOG_DEBUG, "Successfully connected to " - "host %s, port %s", connected_address, connected_port); - - /* Done if successful connect */ - break; - - } - - /* Otherwise log information regarding bind failure */ - else - guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to " - "host %s, port %s: %s", - connected_address, connected_port, strerror(errno)); - - current_address = current_address->ai_next; - - } - - /* If unable to connect to anything, fail */ - if (current_address == NULL) { - guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND, - "Unable to connect to any addresses."); - return NULL; - } - - /* Free addrinfo */ - freeaddrinfo(addresses); + int fd = guac_socket_tcp_connect(settings->hostname, settings->port); /* Open telnet session */ telnet_t* telnet = telnet_init(__telnet_options, __guac_telnet_event_handler, 0, client); @@ -584,17 +495,35 @@ void* guac_telnet_client_thread(void* data) { /* If Wake-on-LAN is enabled, attempt to wake. */ if (settings->wol_send_packet) { - guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " - "and pausing for %d seconds.", settings->wol_wait_time); - /* Send the Wake-on-LAN request. */ - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - settings->wol_udp_port)) - return NULL; + /** + * If wait time is set, send the wake packet and try to connect to the + * server, failing if the server does not respond. + */ + if (settings->wol_wait_time > 0) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* Send the Wake-on-LAN request and wait until the server is responsive. */ + if (guac_wol_wake_and_wait(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port, + settings->wol_wait_time, + GUAC_WOL_DEFAULT_CONNECT_RETRIES, + settings->hostname, + settings->port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote server."); + return NULL; + } + } - /* If wait time is specified, sleep for that amount of time. */ - if (settings->wol_wait_time > 0) - guac_timestamp_msleep(settings->wol_wait_time * 1000); + /* Just send the packet and continue the connection, or return if failed. */ + else if(guac_wol_wake(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet."); + return NULL; + } } /* Set up screen recording, if requested */ diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index 9fd9156a8..e3c6602c7 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -42,10 +42,13 @@ #endif #include +#include #include #include #include +#include #include +#include #include #include #include @@ -274,17 +277,47 @@ void* guac_vnc_client_thread(void* data) { /* If Wake-on-LAN is enabled, attempt to wake. */ if (settings->wol_send_packet) { - guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " - "and pausing for %d seconds.", settings->wol_wait_time); - - /* Send the Wake-on-LAN request. */ - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - settings->wol_udp_port)) + + /** + * If wait time is set, send the wake packet and try to connect to the + * server, failing if the server does not respond. + */ + if (settings->wol_wait_time > 0) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* char representation of a port should be, at most, 5 characters plus terminator. */ + char* str_port = guac_mem_alloc(6); + if (guac_itoa(str_port, settings->port) < 1) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to convert port to integer for WOL function."); + guac_mem_free(str_port); + return NULL; + } + + /* Send the Wake-on-LAN request and wait until the server is responsive. */ + if (guac_wol_wake_and_wait(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port, + settings->wol_wait_time, + GUAC_WOL_DEFAULT_CONNECT_RETRIES, + settings->hostname, + (const char *) str_port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote system."); + guac_mem_free(str_port); + return NULL; + } + + guac_mem_free(str_port); + + } + + /* Just send the packet and continue the connection, or return if failed. */ + else if(guac_wol_wake(settings->wol_mac_addr, + settings->wol_broadcast_addr, + settings->wol_udp_port)) { + guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet."); return NULL; - - /* If wait time is specified, sleep for that amount of time. */ - if (settings->wol_wait_time > 0) - guac_timestamp_msleep(settings->wol_wait_time * 1000); + } } /* Configure clipboard encoding */