| /* 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 "apr_fnmatch.h" |
| #include "apr_lib.h" |
| #include "apr_strings.h" |
| |
| #include "httpd.h" |
| #include "http_log.h" |
| |
| #include "ssl_ct_util.h" |
| |
| APLOG_USE_MODULE(ssl_ct); |
| |
| apr_status_t ctutil_path_join(char **out, const char *dirname, const char *basename, |
| apr_pool_t *p, server_rec *s) |
| { |
| apr_status_t rv; |
| |
| rv = apr_filepath_merge(out, dirname, basename, 0, p); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02776) "can't build filename from %s and %s", |
| dirname, basename); |
| } |
| |
| return rv; |
| } |
| |
| int ctutil_dir_exists(apr_pool_t *p, const char *dirname) |
| { |
| apr_finfo_t finfo; |
| apr_status_t rv = apr_stat(&finfo, dirname, APR_FINFO_TYPE, p); |
| |
| return rv == APR_SUCCESS && finfo.filetype == APR_DIR; |
| } |
| |
| int ctutil_file_exists(apr_pool_t *p, const char *filename) |
| { |
| apr_finfo_t finfo; |
| apr_status_t rv = apr_stat(&finfo, filename, APR_FINFO_TYPE, p); |
| |
| return rv == APR_SUCCESS && finfo.filetype == APR_REG; |
| } |
| |
| void ctutil_buffer_to_array(apr_pool_t *p, const char *b, |
| apr_size_t b_size, apr_array_header_t **out) |
| { |
| apr_array_header_t *arr = apr_array_make(p, 10, sizeof(char *)); |
| const char *ch, *last; |
| |
| ch = b; |
| last = b + b_size - 1; |
| while (ch < last) { |
| const char *end = memchr(ch, '\n', last - ch); |
| const char *line; |
| |
| if (!end) { |
| end = last + 1; |
| } |
| while (apr_isspace(*ch) && ch < end) { |
| ch++; |
| } |
| if (ch < end) { |
| const char *tmpend = end - 1; |
| |
| while (tmpend > ch |
| && isspace(*tmpend)) { |
| --tmpend; |
| } |
| |
| line = apr_pstrndup(p, ch, 1 + tmpend - ch); |
| *(const char **)apr_array_push(arr) = line; |
| } |
| ch = end + 1; |
| } |
| |
| *out = arr; |
| } |
| |
| int ctutil_in_array(const char *needle, const apr_array_header_t *haystack) |
| { |
| const char * const *elts; |
| int i; |
| |
| elts = (const char * const *)haystack->elts; |
| for (i = 0; i < haystack->nelts; i++) { |
| if (!strcmp(needle, elts[i])) { |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| apr_status_t ctutil_fopen(const char *fn, const char *mode, FILE **f) |
| { |
| apr_status_t rv; |
| |
| *f = fopen(fn, mode); |
| if (*f == NULL) { |
| rv = errno; /* XXX Windows equivalent -- CreateFile + fdopen? */ |
| } |
| else { |
| rv = APR_SUCCESS; |
| } |
| |
| return rv; |
| } |
| |
| /* read_dir() is remarkably like apr_match_glob(), which could |
| * probably use some processing flags to indicate variations on |
| * the basic behavior (and implement better error checking). |
| */ |
| apr_status_t ctutil_read_dir(apr_pool_t *p, |
| server_rec *s, |
| const char *dirname, |
| const char *pattern, |
| apr_array_header_t **outarr) |
| { |
| apr_array_header_t *arr; |
| apr_dir_t *d; |
| apr_finfo_t finfo; |
| apr_status_t rv; |
| int reported = 0; |
| |
| /* add to existing array if it already exists */ |
| arr = *outarr; |
| if (arr == NULL) { |
| arr = apr_array_make(p, 4, sizeof(char *)); |
| } |
| |
| rv = apr_dir_open(&d, dirname, p); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02777) "couldn't read dir %s", |
| dirname); |
| return rv; |
| } |
| |
| while ((rv = apr_dir_read(&finfo, APR_FINFO_NAME, d)) == APR_SUCCESS) { |
| const char *fn; |
| |
| if (APR_SUCCESS == apr_fnmatch(pattern, finfo.name, APR_FNM_CASE_BLIND)) { |
| rv = ctutil_path_join((char **)&fn, dirname, finfo.name, p, s); |
| if (rv != APR_SUCCESS) { |
| reported = 1; |
| break; |
| } |
| |
| *(char **)apr_array_push(arr) = apr_pstrdup(p, fn); |
| } |
| } |
| |
| if (APR_STATUS_IS_ENOENT(rv)) { |
| rv = APR_SUCCESS; |
| } |
| else if (rv != APR_SUCCESS && !reported) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02778) "couldn't read entry from dir %s", dirname); |
| } |
| |
| apr_dir_close(d); |
| |
| if (rv == APR_SUCCESS) { |
| *outarr = arr; |
| } |
| |
| return rv; |
| } |
| |
| apr_status_t ctutil_read_file(apr_pool_t *p, |
| server_rec *s, |
| const char *fn, |
| apr_off_t limit, |
| char **contents, |
| apr_size_t *contents_size) |
| { |
| apr_file_t *f; |
| apr_finfo_t finfo; |
| apr_status_t rv; |
| apr_size_t nbytes; |
| |
| *contents = NULL; |
| *contents_size = 0; |
| |
| rv = apr_file_open(&f, fn, APR_READ | APR_BINARY, APR_FPROT_OS_DEFAULT, p); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02779) "couldn't read %s", fn); |
| return rv; |
| } |
| |
| rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, f); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02780) "couldn't retrieve size of %s", fn); |
| apr_file_close(f); |
| return rv; |
| } |
| |
| if (finfo.size > limit) { |
| rv = APR_ENOSPC; |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02781) "size %" APR_OFF_T_FMT " of %s exceeds " |
| "limit (%" APR_OFF_T_FMT ")", finfo.size, fn, limit); |
| apr_file_close(f); |
| return rv; |
| } |
| |
| nbytes = (apr_size_t)finfo.size; |
| *contents = apr_palloc(p, nbytes); |
| rv = apr_file_read_full(f, *contents, nbytes, contents_size); |
| if (rv != APR_SUCCESS) { /* shouldn't get APR_EOF since we know |
| * how big the file is |
| */ |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02782) "apr_file_read_full"); |
| } |
| apr_file_close(f); |
| |
| return rv; |
| } |
| |
| #if APR_FILES_AS_SOCKETS |
| static void io_loop(apr_pool_t *p, server_rec *s, apr_proc_t *proc, |
| const char *desc_for_log) |
| { |
| apr_status_t rv; |
| apr_pollfd_t pfd = {0}; |
| apr_pollset_t *pollset; |
| int fds_waiting; |
| |
| rv = apr_pollset_create(&pollset, 2, p, 0); |
| ap_assert(rv == APR_SUCCESS); |
| |
| fds_waiting = 0; |
| |
| pfd.p = p; |
| pfd.desc_type = APR_POLL_FILE; |
| pfd.reqevents = APR_POLLIN; |
| pfd.desc.f = proc->err; |
| rv = apr_pollset_add(pollset, &pfd); |
| ap_assert(rv == APR_SUCCESS); |
| ++fds_waiting; |
| |
| pfd.desc.f = proc->out; |
| rv = apr_pollset_add(pollset, &pfd); |
| ap_assert(rv == APR_SUCCESS); |
| ++fds_waiting; |
| |
| while (fds_waiting) { |
| int i, num_events; |
| const apr_pollfd_t *pdesc; |
| char buf[4096]; |
| apr_size_t len; |
| |
| rv = apr_pollset_poll(pollset, apr_time_from_sec(10), |
| &num_events, &pdesc); |
| if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02783) "apr_pollset_poll"); |
| break; |
| } |
| |
| for (i = 0; i < num_events; i++) { |
| len = sizeof buf; |
| rv = apr_file_read(pdesc[i].desc.f, buf, &len); |
| if (APR_STATUS_IS_EOF(rv)) { |
| apr_file_close(pdesc[i].desc.f); |
| apr_pollset_remove(pollset, &pdesc[i]); |
| --fds_waiting; |
| } |
| else if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02784) "apr_file_read"); |
| } |
| else { |
| ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, |
| "%s: %.*s", desc_for_log, (int)len, buf); |
| } |
| } |
| } |
| } |
| #else /* APR_FILES_AS_SOCKETS */ |
| static void io_loop(apr_pool_t *p, server_rec *s, apr_proc_t *proc, |
| const char *desc_for_log) |
| { |
| apr_status_t rv; |
| apr_file_t *fds[2] = {proc->out, proc->err}; |
| apr_size_t len; |
| char buf[4096]; |
| int fds_waiting = 2; |
| |
| while (fds_waiting) { |
| int i; |
| int read = 0; |
| |
| for (i = 0; i < sizeof fds / sizeof fds[0]; i++) { |
| if (!fds[i]) { |
| continue; |
| } |
| len = sizeof buf; |
| rv = apr_file_read(fds[i], buf, &len); |
| if (APR_STATUS_IS_EOF(rv)) { |
| apr_file_close(fds[i]); |
| fds[i] = NULL; |
| --fds_waiting; |
| } |
| else if (APR_STATUS_IS_EAGAIN(rv)) { |
| /* we don't actually know if data is ready before reading, so |
| * this isn't an error |
| */ |
| } |
| else if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02785) "apr_file_read"); |
| } |
| else { |
| ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, |
| "%s: %.*s", desc_for_log, (int)len, buf); |
| ++read; |
| } |
| } |
| if (fds_waiting && !read) { |
| /* no tight loop */ |
| apr_sleep(apr_time_from_msec(100)); |
| } |
| } |
| } |
| #endif /* APR_FILES_AS_SOCKETS */ |
| |
| apr_status_t ctutil_run_to_log(apr_pool_t *p, |
| server_rec *s, |
| const char *args[8], |
| const char *desc_for_log) |
| { |
| apr_exit_why_e exitwhy; |
| apr_proc_t proc = {0}; |
| apr_procattr_t *attr; |
| apr_status_t rv; |
| int exitcode; |
| |
| rv = apr_procattr_create(&attr, p); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02786) "apr_procattr_create failed"); |
| return rv; |
| } |
| |
| rv = apr_procattr_io_set(attr, |
| APR_NO_PIPE, |
| APR_CHILD_BLOCK, |
| APR_CHILD_BLOCK); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02787) "apr_procattr_io_set failed"); |
| return rv; |
| } |
| |
| if (APLOGtrace1(s)) { |
| const char *cmdline = ""; |
| const char **curarg = args; |
| |
| while (*curarg) { |
| cmdline = apr_pstrcat(p, cmdline, *curarg, " ", NULL); |
| curarg++; |
| } |
| ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, |
| "Running \"%s\"", cmdline); |
| } |
| |
| rv = apr_proc_create(&proc, args[0], args, NULL, attr, p); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02788) "apr_proc_create failed"); |
| return rv; |
| } |
| |
| io_loop(p, s, &proc, desc_for_log); |
| |
| rv = apr_proc_wait(&proc, &exitcode, &exitwhy, APR_WAIT); |
| rv = rv == APR_CHILD_DONE ? APR_SUCCESS : rv; |
| |
| ap_log_error(APLOG_MARK, |
| rv != APR_SUCCESS || exitcode ? APLOG_ERR : APLOG_DEBUG, |
| rv, s, |
| APLOGNO(02789) "exit code from %s: %d (%s)", |
| desc_for_log, exitcode, |
| exitwhy == APR_PROC_EXIT ? "exited normally" : "exited due to a signal"); |
| |
| if (rv == APR_SUCCESS && exitcode) { |
| rv = APR_EGENERAL; |
| } |
| |
| return rv; |
| } |
| |
| void ctutil_thread_mutex_lock(apr_thread_mutex_t *m) |
| { |
| apr_status_t rv = apr_thread_mutex_lock(m); |
| ap_assert(rv == APR_SUCCESS); |
| } |
| |
| void ctutil_thread_mutex_unlock(apr_thread_mutex_t *m) |
| { |
| apr_status_t rv = apr_thread_mutex_unlock(m); |
| ap_assert(rv == APR_SUCCESS); |
| } |
| |
| apr_status_t ctutil_file_write_uint16(server_rec *s, |
| apr_file_t *f, |
| apr_uint16_t in_val) |
| { |
| apr_size_t nbytes; |
| apr_status_t rv; |
| char vals[2]; |
| |
| vals[0] = (in_val & 0xFF00) >> 8; |
| vals[1] = (in_val & 0x00FF); |
| nbytes = sizeof(vals); |
| rv = apr_file_write(f, vals, &nbytes); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02790) "can't write 2-byte length to file"); |
| } |
| return rv; |
| } |
| |
| apr_status_t ctutil_file_write_uint24(server_rec *s, |
| apr_file_t *f, |
| apr_uint32_t in_val) |
| { |
| apr_size_t nbytes; |
| apr_status_t rv; |
| char vals[3]; |
| |
| vals[0] = (in_val & 0xFF0000) >> 16; |
| vals[1] = (in_val & 0x00FF00) >> 8; |
| vals[2] = (in_val & 0x0000FF) >> 0; |
| nbytes = sizeof(vals); |
| rv = apr_file_write(f, vals, &nbytes); |
| if (rv != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, |
| APLOGNO(02791) "can't write 3-byte length to file"); |
| } |
| return rv; |
| } |
| |
| void ctutil_log_array(const char *file, int line, int module_index, |
| int level, server_rec *s, const char *desc, |
| apr_array_header_t *arr) |
| { |
| const char **elts = (const char **)arr->elts; |
| int i; |
| |
| /* Intentional no APLOGNO */ |
| ap_log_error(file, line, module_index, level, |
| 0, s, "%s", desc); |
| for (i = 0; i < arr->nelts; i++) { |
| /* Intentional no APLOGNO */ |
| ap_log_error(file, line, module_index, level, |
| 0, s, ">>%s", elts[i]); |
| } |
| } |
| |
| static apr_status_t deserialize_uint(const unsigned char **mem, |
| apr_size_t *avail, |
| apr_byte_t num_bits, apr_uint64_t *pval) |
| { |
| apr_byte_t num_bytes = num_bits / 8; |
| apr_uint64_t val = 0; |
| int i; |
| |
| if (*avail < num_bytes || num_bits > 64) { |
| return APR_EINVAL; |
| } |
| |
| for (i = 0; i < num_bytes; i++) { |
| val = (val << 8) | **mem; |
| *mem += 1; |
| *avail -= 1; |
| } |
| |
| *pval = val; |
| return APR_SUCCESS; |
| } |
| |
| apr_status_t ctutil_deserialize_uint64(const unsigned char **mem, |
| apr_size_t *avail, |
| apr_uint64_t *pval) |
| { |
| return deserialize_uint(mem, avail, 64, pval); |
| } |
| |
| apr_status_t ctutil_deserialize_uint16(const unsigned char **mem, |
| apr_size_t *avail, |
| apr_uint16_t *pval) |
| { |
| apr_status_t rv; |
| apr_uint64_t val64 = 0; |
| |
| rv = deserialize_uint(mem, avail, 16, &val64); |
| *pval = (apr_uint16_t)val64; |
| return rv; |
| } |
| |
| static apr_status_t serialize_uint(unsigned char **mem, apr_size_t *avail, |
| apr_byte_t num_bits, apr_uint64_t val) |
| { |
| apr_byte_t num_bytes = num_bits / 8; |
| int i; |
| apr_uint64_t mask; |
| apr_byte_t shift; |
| |
| if (*avail < num_bytes || num_bits > 64) { |
| return APR_EINVAL; |
| } |
| |
| mask = (apr_uint64_t)0xFF << (num_bits - 8); |
| shift = num_bits - 8; |
| for (i = 0; i < num_bytes; i++) { |
| **mem = (unsigned char)((val & mask) >> shift); |
| *mem += 1; |
| *avail -= 1; |
| mask = mask >> 8; |
| shift -= 8; |
| } |
| |
| return APR_SUCCESS; |
| } |
| |
| apr_status_t ctutil_serialize_uint64(unsigned char **mem, apr_size_t *avail, |
| apr_uint64_t val) |
| { |
| return serialize_uint(mem, avail, 64, val); |
| } |
| |
| apr_status_t ctutil_serialize_uint24(unsigned char **mem, apr_size_t *avail, |
| apr_uint32_t val) |
| { |
| return serialize_uint(mem, avail, 24, val); |
| } |
| |
| apr_status_t ctutil_serialize_uint16(unsigned char **mem, apr_size_t *avail, |
| apr_uint16_t val) |
| { |
| return serialize_uint(mem, avail, 16, val); |
| } |
| |
| apr_status_t ctutil_serialize_uint8(unsigned char **mem, apr_size_t *avail, |
| unsigned char val) |
| { |
| return serialize_uint(mem, avail, 8, val); |
| } |
| |
| apr_status_t ctutil_write_var16_bytes(unsigned char **mem, apr_size_t *avail, |
| const unsigned char *val, |
| apr_uint16_t len) |
| { |
| apr_status_t rv; |
| |
| if (*avail < (sizeof(apr_uint16_t) + len)) { |
| return APR_EINVAL; |
| } |
| |
| rv = ctutil_serialize_uint16(mem, avail, len); |
| if (rv != APR_SUCCESS) { /* should not occur */ |
| return rv; |
| } |
| |
| memcpy(*mem, val, len); |
| *mem += len; |
| *avail -= len; |
| return APR_SUCCESS; |
| } |
| |
| apr_status_t ctutil_write_var24_bytes(unsigned char **mem, apr_size_t *avail, |
| const unsigned char *val, |
| apr_uint32_t len) |
| { |
| apr_status_t rv; |
| |
| if (*avail < (3 + len)) { |
| return APR_EINVAL; |
| } |
| |
| rv = ctutil_serialize_uint24(mem, avail, len); |
| if (rv != APR_SUCCESS) { /* should not occur */ |
| return rv; |
| } |
| |
| memcpy(*mem, val, len); |
| *mem += len; |
| *avail -= len; |
| return APR_SUCCESS; |
| } |
| |
| /* all this deserialization crap is of course from |
| * c-t/src/proto/serializer.cc |
| */ |
| static apr_status_t read_length_prefix(const unsigned char **mem, apr_size_t *avail, |
| apr_size_t *result) |
| { |
| apr_status_t rv; |
| apr_uint16_t val; |
| |
| rv = ctutil_deserialize_uint16(mem, avail, &val); |
| if (rv == APR_SUCCESS) { |
| *result = val; |
| } |
| |
| return rv; |
| } |
| |
| static apr_status_t read_fixed_bytes(const unsigned char **mem, apr_size_t *avail, |
| apr_size_t len, |
| const unsigned char **start) |
| { |
| if (*avail < len) { |
| return APR_EINVAL; |
| } |
| |
| *start = *mem; |
| *avail -= len; |
| *mem += len; |
| |
| return APR_SUCCESS; |
| } |
| |
| apr_status_t ctutil_read_var_bytes(const unsigned char **mem, apr_size_t *avail, |
| const unsigned char **start, apr_size_t *len) |
| { |
| apr_status_t rv; |
| |
| rv = read_length_prefix(mem, avail, len); |
| if (rv != APR_SUCCESS) { |
| return rv; |
| } |
| |
| rv = read_fixed_bytes(mem, avail, *len, start); |
| return rv; |
| } |
| |
| #define TESTURL1 "http://127.0.0.1:8888" |
| #define TESTURL2 "http://127.0.0.1:9999" |
| #define TESTURL3 "http://127.0.0.1:10000" |
| |
| void ctutil_run_internal_tests(apr_pool_t *p) |
| { |
| apr_array_header_t *arr; |
| const char *filecontents = |
| " " TESTURL1 " \r\n" TESTURL2 "\n" |
| TESTURL3 /* no "\n" */ ; |
| unsigned char buf[8], *ch; |
| const unsigned char *const_ch; |
| apr_size_t avail; |
| apr_status_t rv; |
| apr_uint16_t val16; |
| apr_uint64_t val64; |
| |
| ctutil_buffer_to_array(p, filecontents, strlen(filecontents), &arr); |
| |
| ap_assert(ctutil_in_array(TESTURL1, arr)); |
| ap_assert(ctutil_in_array(TESTURL2, arr)); |
| ap_assert(ctutil_in_array(TESTURL3, arr)); |
| ap_assert(!ctutil_in_array(TESTURL1 "x", arr)); |
| |
| ch = buf; |
| avail = 8; |
| rv = ctutil_serialize_uint64(&ch, &avail, 0xDEADBEEFCAFEBABE); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 0); |
| ap_assert(ch == buf + 8); |
| ap_assert(buf[0] == 0xDE); |
| ap_assert(buf[1] == 0xAD); |
| ap_assert(buf[2] == 0xBE); |
| ap_assert(buf[3] == 0xEF); |
| ap_assert(buf[4] == 0xCA); |
| ap_assert(buf[5] == 0xFE); |
| ap_assert(buf[6] == 0xBA); |
| ap_assert(buf[7] == 0xBE); |
| |
| const_ch = buf; |
| avail = 8; |
| rv = ctutil_deserialize_uint64(&const_ch, &avail, &val64); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 0); |
| ap_assert(const_ch == buf + 8); |
| ap_assert(val64 == 0xDEADBEEFCAFEBABE); |
| |
| ch = buf; |
| avail = 7; |
| ap_assert(ctutil_serialize_uint64(&ch, &avail, 0xDEADBEEFCAFEBABE) |
| == APR_EINVAL); |
| |
| ch = buf; |
| avail = 3; |
| rv = ctutil_serialize_uint24(&ch, &avail, 0xDEADBE); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 0); |
| ap_assert(ch == buf + 3); |
| ap_assert(buf[0] == 0xDE); |
| ap_assert(buf[1] == 0xAD); |
| ap_assert(buf[2] == 0xBE); |
| |
| ch = buf; |
| avail = 1; |
| ap_assert(ctutil_serialize_uint16(&ch, &avail, 0xDEAD) |
| == APR_EINVAL); |
| |
| ch = buf; |
| avail = 2; |
| rv = ctutil_serialize_uint16(&ch, &avail, 0xDEAD); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 0); |
| ap_assert(ch == buf + 2); |
| ap_assert(buf[0] == 0xDE); |
| ap_assert(buf[1] == 0xAD); |
| |
| const_ch = buf; |
| avail = 2; |
| rv = ctutil_deserialize_uint16(&const_ch, &avail, &val16); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 0); |
| ap_assert(val16 == 0xDEAD); |
| |
| ch = buf; |
| avail = 1; |
| ap_assert(ctutil_serialize_uint16(&ch, &avail, 0xDEAD) |
| == APR_EINVAL); |
| |
| ch = buf; |
| avail = 1; |
| rv = ctutil_serialize_uint8(&ch, &avail, 0xDE); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 0); |
| ap_assert(ch == buf + 1); |
| ap_assert(buf[0] == 0xDE); |
| |
| ch = buf; |
| avail = 0; |
| ap_assert(ctutil_serialize_uint8(&ch, &avail, 0xDE) |
| == APR_EINVAL); |
| |
| ch = buf; |
| avail = 8; |
| rv = ctutil_write_var16_bytes(&ch, &avail, |
| (unsigned char *)"\x01""\x02""\x03""\x04", 4); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 2); |
| ap_assert(ch == buf + 6); |
| ap_assert(buf[0] == 0); |
| ap_assert(buf[1] == 4); |
| ap_assert(buf[2] == 0x01); |
| ap_assert(buf[3] == 0x02); |
| ap_assert(buf[4] == 0x03); |
| ap_assert(buf[5] == 0x04); |
| |
| ch = buf; |
| avail = 3; |
| rv = ctutil_write_var16_bytes(&ch, &avail, |
| (unsigned char *)"\x01""\x02""\x03""\x04", 4); |
| ap_assert(rv == APR_EINVAL); |
| |
| ch = buf; |
| avail = 8; |
| rv = ctutil_write_var24_bytes(&ch, &avail, |
| (unsigned char *)"\x01""\x02""\x03""\x04", 4); |
| ap_assert(rv == APR_SUCCESS); |
| ap_assert(avail == 1); |
| ap_assert(ch == buf + 7); |
| ap_assert(buf[0] == 0); |
| ap_assert(buf[1] == 0); |
| ap_assert(buf[2] == 4); |
| ap_assert(buf[3] == 0x01); |
| ap_assert(buf[4] == 0x02); |
| ap_assert(buf[5] == 0x03); |
| ap_assert(buf[6] == 0x04); |
| |
| ch = buf; |
| avail = 4; |
| rv = ctutil_write_var24_bytes(&ch, &avail, |
| (unsigned char *)"\x01""\x02""\x03""\x04", 4); |
| ap_assert(rv == APR_EINVAL); |
| } |