nested_send_instruction.c (4467B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include <CUnit/CUnit.h> 21#include <guacamole/protocol.h> 22#include <guacamole/socket.h> 23 24#include <stdlib.h> 25#include <unistd.h> 26 27/** 28 * Test string which contains exactly four Unicode characters encoded in UTF-8. 29 * This particular test string uses several characters which encode to multiple 30 * bytes in UTF-8. 31 */ 32#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1" 33 34/** 35 * Writes a series of Guacamole instructions using a nested guac_socket 36 * wrapping another guac_socket which writes to the given file descriptor. The 37 * instructions written correspond to the instructions verified by 38 * read_expected_instructions(). The given file descriptor is automatically 39 * closed as a result of calling this function. 40 * 41 * @param fd 42 * The file descriptor to write instructions to. 43 */ 44static void write_instructions(int fd) { 45 46 /* Open guac socket */ 47 guac_socket* socket = guac_socket_open(fd); 48 49 /* Write nothing if socket cannot be allocated (test will fail in parent 50 * process due to failure to read) */ 51 if (socket == NULL) { 52 close(fd); 53 return; 54 } 55 56 /* Nest socket */ 57 guac_socket* nested_socket = guac_socket_nest(socket, 123); 58 59 /* Write nothing if nested socket cannot be allocated (test will fail in 60 * parent process due to failure to read) */ 61 if (socket == NULL) { 62 guac_socket_free(socket); 63 return; 64 } 65 66 /* Write instructions */ 67 guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c"); 68 guac_protocol_send_sync(nested_socket, 12345); 69 70 /* Close and free sockets */ 71 guac_socket_free(nested_socket); 72 guac_socket_free(socket); 73 74} 75 76/** 77 * Reads raw bytes from the given file descriptor until no further bytes 78 * remain, verifying that those bytes represent the series of Guacamole 79 * instructions expected to be written by write_instructions(). The given 80 * file descriptor is automatically closed as a result of calling this 81 * function. 82 * 83 * @param fd 84 * The file descriptor to read data from. 85 */ 86static void read_expected_instructions(int fd) { 87 88 char expected[] = 89 "4.nest,3.123,37." 90 "4.name,11.a" UTF8_4 "b" UTF8_4 "c;" 91 "4.sync,5.12345;" 92 ";"; 93 94 int numread; 95 char buffer[1024]; 96 int offset = 0; 97 98 /* Read everything available into buffer */ 99 while ((numread = read(fd, &(buffer[offset]), 100 sizeof(buffer) - offset)) > 0) { 101 offset += numread; 102 } 103 104 /* Verify length of read data */ 105 CU_ASSERT_EQUAL(offset, strlen(expected)); 106 107 /* Add NULL terminator */ 108 buffer[offset] = '\0'; 109 110 /* Read value should be equal to expected value */ 111 CU_ASSERT_STRING_EQUAL(buffer, expected); 112 113 /* File descriptor is no longer needed */ 114 close(fd); 115 116} 117 118/** 119 * Tests that the nested socket implementation of guac_socket properly 120 * implements writing of instructions. A child process is forked to write a 121 * series of instructions which are read and verified by the parent process. 122 */ 123void test_socket__nested_send_instruction() { 124 125 int fd[2]; 126 127 /* Create pipe */ 128 CU_ASSERT_EQUAL_FATAL(pipe(fd), 0); 129 130 int read_fd = fd[0]; 131 int write_fd = fd[1]; 132 133 /* Fork into writer process (child) and reader process (parent) */ 134 int childpid; 135 CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1); 136 137 /* Attempt to write a series of instructions within the child process */ 138 if (childpid == 0) { 139 close(read_fd); 140 write_instructions(write_fd); 141 exit(0); 142 } 143 144 /* Read and verify the expected instructions within the parent process */ 145 close(write_fd); 146 read_expected_instructions(read_fd); 147 148} 149