137 lines
4.0 KiB
C
137 lines
4.0 KiB
C
/*
|
|
* 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 <CUnit/CUnit.h>
|
|
#include <guacamole/protocol.h>
|
|
#include <guacamole/socket.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
/**
|
|
* Test string which contains exactly four Unicode characters encoded in UTF-8.
|
|
* This particular test string uses several characters which encode to multiple
|
|
* bytes in UTF-8.
|
|
*/
|
|
#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1"
|
|
|
|
/**
|
|
* Writes a series of Guacamole instructions using a normal guac_socket
|
|
* wrapping the given file descriptor. The instructions written correspond to
|
|
* the instructions verified by read_expected_instructions(). The given file
|
|
* descriptor is automatically closed as a result of calling this function.
|
|
*
|
|
* @param fd
|
|
* The file descriptor to write instructions to.
|
|
*/
|
|
static void write_instructions(int fd) {
|
|
|
|
/* Open guac socket */
|
|
guac_socket* socket = guac_socket_open(fd);
|
|
|
|
/* Write nothing if socket cannot be allocated (test will fail in parent
|
|
* process due to failure to read) */
|
|
if (socket == NULL) {
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
/* Write instructions */
|
|
guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c");
|
|
guac_protocol_send_sync(socket, 12345);
|
|
guac_socket_flush(socket);
|
|
|
|
/* Close and free socket */
|
|
guac_socket_free(socket);
|
|
|
|
}
|
|
|
|
/**
|
|
* Reads raw bytes from the given file descriptor until no further bytes
|
|
* remain, verfying that those bytes represent the series of Guacamole
|
|
* instructions expected to be written by write_instructions(). The given
|
|
* file descriptor is automatically closed as a result of calling this
|
|
* function.
|
|
*
|
|
* @param fd
|
|
* The file descriptor to read data from.
|
|
*/
|
|
static void read_expected_instructions(int fd) {
|
|
|
|
char expected[] =
|
|
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
|
|
"4.sync,5.12345;";
|
|
|
|
int numread;
|
|
char buffer[1024];
|
|
int offset = 0;
|
|
|
|
/* Read everything available into buffer */
|
|
while ((numread = read(fd, &(buffer[offset]),
|
|
sizeof(buffer) - offset)) > 0) {
|
|
offset += numread;
|
|
}
|
|
|
|
/* Verify length of read data */
|
|
CU_ASSERT_EQUAL(offset, strlen(expected));
|
|
|
|
/* Add NULL terminator */
|
|
buffer[offset] = '\0';
|
|
|
|
/* Read value should be equal to expected value */
|
|
CU_ASSERT_STRING_EQUAL(buffer, expected);
|
|
|
|
/* File descriptor is no longer needed */
|
|
close(fd);
|
|
|
|
}
|
|
|
|
/**
|
|
* Tests that the file descriptor implementation of guac_socket properly
|
|
* implements writing of instructions. A child process is forked to write a
|
|
* series of instructions which are read and verified by the parent process.
|
|
*/
|
|
void test_socket__fd_send_instruction() {
|
|
|
|
int fd[2];
|
|
|
|
/* Create pipe */
|
|
CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
|
|
|
|
int read_fd = fd[0];
|
|
int write_fd = fd[1];
|
|
|
|
/* Fork into writer process (child) and reader process (parent) */
|
|
int childpid;
|
|
CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1);
|
|
|
|
/* Attempt to write a series of instructions within the child process */
|
|
if (childpid == 0) {
|
|
close(read_fd);
|
|
write_instructions(write_fd);
|
|
exit(0);
|
|
}
|
|
|
|
/* Read and verify the expected instructions within the parent process */
|
|
close(write_fd);
|
|
read_expected_instructions(read_fd);
|
|
|
|
}
|
|
|