Newer
Older
/*
* Copyright 2013 Google Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/*
* Author: ncardwell@google.com (Neal Cardwell)
*
* A module to execute a system call from a test script.
*/
#include "run_system_call.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netinet/in.h>
#include <poll.h>
#include <pthread.h>
#if defined(__FreeBSD__)
#include <pthread_np.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <stddef.h>
#endif
#if defined(__FreeBSD__)
#include <kvm.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <libprocstat.h>
#endif
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/uio.h>
#if defined(linux)
#include <sys/sendfile.h>
#endif
#if defined(__APPLE__)
#include <pthread.h>
#include <mach/mach.h>
#endif
#include "logging.h"
#include "run.h"
#include "script.h"
static int to_live_fd(struct state *state, int script_fd, int *live_fd,
char **error);
#if defined(linux)
struct sctp_tlv {
u16 sn_type;
u16 sn_flags;
u32 sn_length;
};
#endif
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
#if defined(MSG_NOTIFICATION)
static int check_sctp_notification(struct socket *socket, struct iovec *iov, struct expression *iovec_expr,
static int parse_expression_to_sctp_initmsg(struct expression *expr, struct sctp_initmsg *init,
char **error);
static int parse_expression_to_sctp_sndrcvinfo(struct expression *expr, struct sctp_sndrcvinfo *info,
bool send, char **error);
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11) || (defined(linux) && defined(HAVE_SCTP_SENDV))
static int parse_expression_to_sctp_sndinfo(struct expression *expr, struct sctp_sndinfo *info,
char **error);
static int parse_expression_to_sctp_prinfo(struct expression *expr, struct sctp_prinfo *info,
char **error);
static int parse_expression_to_sctp_authinfo(struct expression *expr, struct sctp_authinfo *info,
char **error);
#endif
#if defined(SCTP_DEFAULT_SNDINFO) || defined(SCTP_SNDINFO)
static int check_sctp_sndinfo(struct sctp_sndinfo_expr *expr, struct sctp_sndinfo *sctp_sndinfo,
char **error);
#endif
#if defined(SCTP_INITMSG) || defined(SCTP_INIT)
static int check_sctp_initmsg(struct sctp_initmsg_expr *expr, struct sctp_initmsg *sctp_initmsg,
char **error);
#endif
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP))
static int check_sctp_extrcvinfo(struct sctp_extrcvinfo_expr *expr, struct sctp_extrcvinfo *sctp_info,
char **error);
#endif
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11) || (defined(linux) && defined(HAVE_SCTP_SENDV))
static int check_sctp_rcvinfo(struct sctp_rcvinfo_expr *expr, struct sctp_rcvinfo *sctp_rcvinfo,
char** error);
#endif
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11) || (defined(linux) && defined(HAVE_SCTP_SENDV))
static int check_sctp_nxtinfo(struct sctp_nxtinfo_expr *expr, struct sctp_nxtinfo *sctp_nxtinfo,
#if defined(linux) || defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
static int check_sctp_sndrcvinfo(struct sctp_sndrcvinfo_expr *expr,
struct sctp_sndrcvinfo *sctp_sndrcvinfo,
char** error);
#endif
/* Provide a wrapper for the Linux gettid() system call
* (glibc only provides it in version 2.30 or higher).
*/
#if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 30))
static pid_t gettid(void)
{
return syscall(__NR_gettid);
}
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* Read a whole file into the given buffer of the given length. */
static void read_whole_file(const char *path, char *buffer, int max_bytes)
{
int fd = open(path, O_RDONLY);
if (fd < 0)
die_perror("open");
int bytes = read(fd, buffer, max_bytes);
if (bytes < 0)
die_perror("read");
else if (bytes == max_bytes)
die("%s file too large to read\n", path);
if (close(fd) < 0)
die_perror("close");
}
/* Return true iff the given thread is sleeping. */
static bool is_thread_sleeping(pid_t process_id, pid_t thread_id)
{
/* Read the entire thread state file, using the buffer size ps uses. */
char *proc_path = NULL;
asprintf(&proc_path, "/proc/%d/task/%d/stat", process_id, thread_id);
const int STATE_BUFFER_BYTES = 1023;
char *state = calloc(STATE_BUFFER_BYTES, 1);
read_whole_file(proc_path, state, STATE_BUFFER_BYTES - 1);
state[STATE_BUFFER_BYTES - 1] = '\0';
/* Parse the thread state from the third space-delimited field. */
const int THREAD_STATE_INDEX = 3;
const char *field = state;
int i = 0;
for (i = 0; i < THREAD_STATE_INDEX - 1; i++) {
field = strchr(field, ' ');
if (field == NULL)
die("unable to parse %s\n", proc_path);
++field;
}
bool is_sleeping = (field[0] == 'S');
free(proc_path);
free(state);
return is_sleeping;
}
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#elif defined(__FreeBSD__)
static bool is_thread_sleeping(pid_t process_id, int thread_id)
{
struct procstat *procstat;
struct kinfo_proc *kinfo_proc;
unsigned int i, count;
bool is_sleeping;
procstat = procstat_open_sysctl();
if (procstat == NULL) {
die("procstat_open_sysctl() failed\n");
}
/* Get the information for all threads belonging to the given process.
* The number of entries (one for each thread) is returned in count.
*/
kinfo_proc = procstat_getprocs(procstat,
KERN_PROC_PID | KERN_PROC_INC_THREAD,
process_id, &count);
if (kinfo_proc == NULL) {
die("procstat_getprocs() failed\n");
}
/* Do a linear search to the entry for the requested thread.
* Since we have only two threads, that's OK performance-wise.
*/
for (i = 0; i < count; i++) {
if (kinfo_proc[i].ki_tid == thread_id)
break;
}
/* Die, if we can't find the entry for the requested thread. */
if (i == count)
die("unable to get state of thread %d\n", thread_id);
is_sleeping = (kinfo_proc[i].ki_stat == SSLEEP);
/* Cleanup the allocated data structures. */
procstat_freeprocs(procstat, kinfo_proc);
procstat_close(procstat);
return is_sleeping;
}
static bool is_thread_sleeping(pid_t process_id, mach_port_t port)
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
thread_info_data_t thinfo;
thread_basic_info_t basic_info_th;
mach_msg_type_number_t thread_info_count;
kern_return_t kr;
bool is_sleeping;
thread_info_count = THREAD_INFO_MAX;
kr = thread_info(port, THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count);
if (kr != KERN_SUCCESS) {
die("task_threads(): %s\n", mach_error_string(kr));
}
basic_info_th = (thread_basic_info_t)thinfo;
switch (basic_info_th->run_state) {
case TH_STATE_RUNNING:
DEBUGP("run_state = TH_STATE_RUNNING\n");
is_sleeping = false;
break;
case TH_STATE_STOPPED:
DEBUGP("run_state = TH_STATE_STOPPED\n");
is_sleeping = false;
break;
case TH_STATE_WAITING:
DEBUGP("run_state = TH_STATE_WAITING\n");
is_sleeping = true;
break;
case TH_STATE_UNINTERRUPTIBLE:
DEBUGP("run_state = TH_STATE_UNINTERRUPTIBLE\n");
is_sleeping = true;
break;
case TH_STATE_HALTED:
DEBUGP("run_state = TH_STATE_HALTED\n");
is_sleeping = false;
break;
default:
die("Unknown thread state: %d\n", basic_info_th->run_state);
is_sleeping = false;
break;
}
return is_sleeping;
#else
static bool is_thread_sleeping(pid_t process_id, int thread_id)
{
die("is_thread_sleeping not implemented on this platform\n");
return true;
}
#endif
/* Returns number of expressions in the list. */
static int expression_list_length(struct expression_list *list)
{
int count = 0;
while (list != NULL) {
list = list->next;
++count;
}
return count;
}
static int get_arg_count(struct expression_list *args)
{
return expression_list_length(args);
}
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/* Verify that the expression list has the expected number of
* expressions. Returns STATUS_OK on success; on failure returns
* STATUS_ERR and sets error message.
*/
static int check_arg_count(struct expression_list *args, int expected,
char **error)
{
assert(expected >= 0);
int actual = get_arg_count(args);
if (actual != expected) {
asprintf(error, "Expected %d args but got %d", expected,
actual);
return STATUS_ERR;
}
return STATUS_OK;
}
/* Returns the argument with the given index. Returns the argument on
* success; on failure returns NULL and sets error message.
*/
static struct expression *get_arg(struct expression_list *args,
int index, char **error)
{
assert(index >= 0);
int current = 0;
while ((args != NULL) && (current < index)) {
args = args->next;
++current;
}
if ((args != NULL) && (current == index)) {
if (!args->expression)
asprintf(error, "Unknown expression at index %d",
index);
return args->expression;
} else {
asprintf(error, "Argument list too short");
return NULL;
}
}
/* Return STATUS_OK if the expression is of the expected
* type. Otherwise fill in the error with a human-readable error
* message about the mismatch and return STATUS_ERR.
*/
static int check_type(struct expression *expression,
enum expression_t expected_type,
char **error)
{
if (expression->type == expected_type) {
return STATUS_OK;
} else {
asprintf(error, "Bad type; actual: %s expected: %s",
expression_type_to_string(expression->type),
expression_type_to_string(expected_type));
return STATUS_ERR;
}
}
/* Sets the value from the expression argument, checking that it is a
* valid socklen_t, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_socklen_t(struct expression *expression,
socklen_t *value, char **error)
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if (expression->value.num < 0) {
asprintf(error,
"Value out of range for socklen_t: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
#if defined(linux) || defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
/* Sets the value from the expression argument, checking that it is a
* valid size_t, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_size_t(struct expression *expression,
size_t *value, char **error)
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if (expression->value.num < 0) {
asprintf(error,
"Value out of range for size_t: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
#if defined(__FreeBSD__)
/* Sets the value from the expression argument, checking that it is a
* valid off_t, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_off_t(struct expression *expression,
off_t *value, char **error)
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if (expression->value.num < 0) {
asprintf(error,
"Value out of range for off_t: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
#endif
#if defined(linux) || defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
/* Sets the value from the expression argument, checking that it is a
* valid sctp_assoc_t, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_sctp_assoc_t(struct expression *expression,
sctp_assoc_t *value, char **error)
{
if (expression->type == EXPR_ELLIPSIS) {
} else {
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if (expression->value.num < 0) {
asprintf(error,
"Value out of range for sctp_assoc_t: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
}
return STATUS_OK;
}
#endif
/* Sets the value from the expression argument, checking that it is a
* valid u32, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_u32(struct expression *expression,
u32 *value, char **error)
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if ((expression->value.num > UINT32_MAX) ||
(expression->value.num < 0)) {
asprintf(error,
"Value out of range for 32-bit unsigned integer: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
/* Sets the value from the expression argument, checking that it is a
* valid s32 or u32, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_s32(struct expression *expression,
s32 *value, char **error)
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if ((expression->value.num > UINT_MAX) ||
(expression->value.num < INT_MIN)) {
"Value out of range for 32-bit integer: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
#if defined(SCTP_STATUS) || defined(SCTP_PEER_ADDR_PARAMS) || defined(SCTP_SS_VALUE)
/* Sets the value from the expression argument, checking that it is a
* valid u16, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_u16(struct expression *expression,
u16 *value, char **error)
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if ((expression->value.num > UINT16_MAX) ||
(expression->value.num < 0)) {
"Value out of range for 16-bit unsigned integer: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
/* Sets the value from the expression argument, checking that it is a
* valid s16, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_s16(struct expression *expression,
{
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if ((expression->value.num > INT16_MAX) ||
(expression->value.num < INT16_MIN)) {
asprintf(error,
"Value out of range for 16-bit integer: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
}
/* Sets the value from the expression argument, checking that it is a
* valid u8, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_u8(struct expression *expression,
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if ((expression->value.num > UINT8_MAX) ||
(expression->value.num < 0)) {
asprintf(error,
"Value out of range for 8-bit unsigned integer: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
/* Sets the value from the expression argument, checking that it is a
* valid s8, and matches the expected type. Returns STATUS_OK on
* success; on failure returns STATUS_ERR and sets error message.
*/
static int get_s8(struct expression *expression,
if (check_type(expression, EXPR_INTEGER, error))
return STATUS_ERR;
if ((expression->value.num > INT8_MAX) ||
(expression->value.num < INT8_MIN)) {
asprintf(error,
"Value out of range for 8-bit integer: %lld",
expression->value.num);
return STATUS_ERR;
}
*value = expression->value.num;
return STATUS_OK;
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
/* Return the value of the argument with the given index, and verify
* that it has the expected type.
*/
static int s32_arg(struct expression_list *args,
int index, s32 *value, char **error)
{
struct expression *expression = get_arg(args, index, error);
if (expression == NULL)
return STATUS_ERR;
return get_s32(expression, value, error);
}
/* Return the value of the argument with the given index, and verify
* that it has the expected type: a list with a single integer.
*/
static int s32_bracketed_arg(struct expression_list *args,
int index, s32 *value, char **error)
{
struct expression_list *list;
struct expression *expression;
expression = get_arg(args, index, error);
if (expression == NULL)
return STATUS_ERR;
if (check_type(expression, EXPR_LIST, error))
return STATUS_ERR;
list = expression->value.list;
if (expression_list_length(list) != 1) {
asprintf(error,
"Expected [<integer>] but got multiple elements");
return STATUS_ERR;
}
return get_s32(list->expression, value, error);
}
hoelscher
committed
/* Return the value of the argument with the given index, and verify
* that it has the expected type: a list with a single integer.
*/
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11) || (defined(linux) && defined(HAVE_SCTP_SENDV))
hoelscher
committed
static int u32_bracketed_arg(struct expression_list *args,
int index, u32 *value, char **error)
{
struct expression_list *list;
struct expression *expression;
expression = get_arg(args, index, error);
if (expression == NULL)
return STATUS_ERR;
if (check_type(expression, EXPR_LIST, error))
return STATUS_ERR;
list = expression->value.list;
if (expression_list_length(list) != 1) {
asprintf(error,
"Expected [<integer>] but got multiple elements");
return STATUS_ERR;
}
return get_u32(list->expression, value, error);
}
#if defined(__FreeBSD__)
static int off_t_bracketed_arg(struct expression_list *args,
int index, off_t *value, char **error)
{
struct expression_list *list;
struct expression *expression;
expression = get_arg(args, index, error);
if (expression == NULL)
return STATUS_ERR;
if (check_type(expression, EXPR_LIST, error))
return STATUS_ERR;
list = expression->value.list;
if (expression_list_length(list) != 1) {
asprintf(error,
"Expected [<integer>] but got multiple elements");
return STATUS_ERR;
}
return get_off_t(list->expression, value, error);
}
hoelscher
committed
#endif
static int socklen_t_bracketed_arg(struct expression_list *args,
int index, socklen_t *value, char **error)
{
struct expression_list *list;
struct expression *expression;
expression = get_arg(args, index, error);
if (expression == NULL)
return STATUS_ERR;
if (check_type(expression, EXPR_LIST, error))
return STATUS_ERR;
list = expression->value.list;
if (expression_list_length(list) != 1) {
asprintf(error,
"Expected [<integer>] but got multiple elements");
return STATUS_ERR;
}
return get_socklen_t(list->expression, value, error);
}
/* Return STATUS_OK iff the argument with the given index is an
* ellipsis (...).
*/
static int ellipsis_arg(struct expression_list *args, int index, char **error)
{
struct expression *expression = get_arg(args, index, error);
if (expression == NULL)
return STATUS_ERR;
if (check_type(expression, EXPR_ELLIPSIS, error))
return STATUS_ERR;
return STATUS_OK;
}
#if defined(SCTP_GET_PEER_ADDR_INFO) || defined(SCTP_PEER_ADDR_PARAMS) || defined(SCTP_SET_PEER_PRIMARY_ADDR)
/* Return STATUS_OK if the argument in from type sockaddr_in or
static int get_sockstorage_arg(struct expression *arg, struct sockaddr_storage *addr, int live_fd)
len = (socklen_t)sizeof(struct sockaddr_storage);
if (getpeername(live_fd, (struct sockaddr *)addr, &len)) {
return STATUS_ERR;
}
} else if (arg->type == EXPR_SOCKET_ADDRESS_IPV4) {
memcpy(addr, arg->value.socket_address_ipv4, sizeof(struct sockaddr_in));
} else if (arg->type == EXPR_SOCKET_ADDRESS_IPV6) {
memcpy(addr, arg->value.socket_address_ipv6, sizeof(struct sockaddr_in6));
} else {
return STATUS_ERR;
}
return STATUS_OK;
}
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
static int check_sockaddr(struct expression *sockaddr_expr, struct sockaddr *live_addr, char **error) {
if (sockaddr_expr->type != EXPR_ELLIPSIS) {
struct sockaddr *script_addr;
if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV4) {
script_addr = (struct sockaddr*)sockaddr_expr->value.socket_address_ipv4;
} else if (sockaddr_expr->type == EXPR_SOCKET_ADDRESS_IPV6) {
script_addr = (struct sockaddr*)sockaddr_expr->value.socket_address_ipv6;
} else {
asprintf(error, "Bad type for sockaddr");
return STATUS_ERR;
}
if (script_addr->sa_family != live_addr->sa_family) {
asprintf(error, "sockaddr sa_family expected: %d actual: %d",
script_addr->sa_family, live_addr->sa_family);
return STATUS_ERR;
}
switch(script_addr->sa_family) {
case AF_INET:
{
struct sockaddr_in *script_sockaddr = (struct sockaddr_in*)script_addr;
struct sockaddr_in *live_sockaddr = (struct sockaddr_in*)live_addr;
if (live_sockaddr->sin_port != script_sockaddr->sin_port) {
asprintf(error, "sockaddr_in from.sinport. expected: %d actual %d",
ntohs(script_sockaddr->sin_port), ntohs(live_sockaddr->sin_port));
return STATUS_ERR;
}
if (live_sockaddr->sin_addr.s_addr != script_sockaddr->sin_addr.s_addr) {
int len = strnlen(inet_ntoa(script_sockaddr->sin_addr), 16);
char *expected_addr = malloc(sizeof(char) * len);
memcpy(expected_addr, inet_ntoa(script_sockaddr->sin_addr), len);
asprintf(error, "sockaddr_in from.sin_addr. expected: %s actual %s",
expected_addr, inet_ntoa(live_sockaddr->sin_addr));
free(expected_addr);
return STATUS_ERR;
}
}
break;
case AF_INET6:
{
struct sockaddr_in6 *script_sockaddr = (struct sockaddr_in6*)script_addr;
struct sockaddr_in6 *live_sockaddr = (struct sockaddr_in6*)live_addr;
if (live_sockaddr->sin6_port != script_sockaddr->sin6_port) {
asprintf(error, "sockaddr_in6 from.sinport. expected: %d actual %d",
ntohs(script_sockaddr->sin6_port), ntohs(live_sockaddr->sin6_port));
return STATUS_ERR;
}
if (live_sockaddr->sin6_addr.s6_addr != script_sockaddr->sin6_addr.s6_addr) {
char expected_addr[INET6_ADDRSTRLEN];
char live_addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &script_sockaddr->sin6_addr, expected_addr, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &live_sockaddr->sin6_addr, live_addr, INET6_ADDRSTRLEN);
asprintf(error, "sockaddr_in6 from.sin6_addr. expected: %s actual %s",
expected_addr, live_addr);
return STATUS_ERR;
}
}
break;
}
}
return STATUS_OK;
}
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
int check_u8_expr(struct expression *expr, u8 value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
u8 script_val;
if (get_u8(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %hhu actual: %hhu", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
#endif
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
#ifdef SCTP_REMOTE_UDP_ENCAPS_PORT
int check_u16_htons_expr(struct expression *expr, u16 value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
u16 script_val;
if (get_u16(expr, &script_val, error)) {
return STATUS_ERR;
}
if (ntohs(script_val) != ntohs(value)) {
asprintf(error, "%s: expected: %hu actual: %hu",
val_name, ntohs(script_val), ntohs(value));
return STATUS_ERR;
}
}
return STATUS_OK;
}
#endif
int check_u16_expr(struct expression *expr, u16 value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
u16 script_val;
if (get_u16(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %hu actual: %hu", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
int check_s32_expr(struct expression *expr, s16 value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
s32 script_val;
if (get_s32(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %d actual: %d", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
int check_u32_hton_expr(struct expression *expr, u32 value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
u32 script_val;
if (get_u32(expr, &script_val, error)) {
return STATUS_ERR;
}
if (htonl(value) != htonl(script_val)) {
asprintf(error, "%s: expected: %u actual: %u", val_name,
ntohl(script_val), ntohl(value));
return STATUS_ERR;
}
}
return STATUS_OK;
}
int check_u32_expr(struct expression *expr, u32 value, char *val_name, char **error) {
if (get_u32(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %u actual: %u", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
int check_sctp_assoc_t_expr(struct expression *expr, sctp_assoc_t value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
sctp_assoc_t script_val;
if (get_sctp_assoc_t(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %u actual: %u", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
#endif
int check_socklen_t_expr(struct expression *expr, socklen_t value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
socklen_t script_val;
if (get_socklen_t(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %u actual: %u", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
#ifdef linux
int check_size_t_expr(struct expression *expr, size_t value, char *val_name, char **error) {
if (expr->type != EXPR_ELLIPSIS) {
size_t script_val;
if (get_size_t(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != value) {
asprintf(error, "%s: expected: %zu actual: %zu", val_name, script_val, value);
return STATUS_ERR;
}
}
return STATUS_OK;
}
#endif
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
static int check_u8array_expr(struct expression *expr_list, u8 *data, size_t data_len, char *val_name, char **error) {
if ( expr_list->type != EXPR_ELLIPSIS) {
struct expression *expr = NULL;
unsigned int i;
switch(expr_list->type) {
case EXPR_LIST:
if (data_len != expression_list_length(expr_list->value.list)) {
asprintf(error, "%s length: expected: %u actual %zu",
val_name, expression_list_length(expr_list->value.list), data_len);
return STATUS_ERR;
}
for (i = 0; i < data_len; i++) {
expr = get_arg(expr_list->value.list, i, error);
if (expr->type != EXPR_ELLIPSIS) {
u8 script_val;
if (get_u8(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != data[i]) {
asprintf(error, "%s[%d]: expected: %hhu actual: %hhu",
val_name, i, script_val, data[i]);
return STATUS_ERR;
}
}
}
break;
case EXPR_NULL:
if (data != NULL)
return STATUS_ERR;
break;
default: asprintf(error, "Bad expressiontype for %s", val_name);
return STATUS_ERR;
break;
}
}
return STATUS_OK;
}
#endif
#if defined(__FreeBSD__) || defined(linux) || (defined(__APPLE__) && defined(HAVE_SCTP)) || defined(__SunOS_5_11)
static int check_u16array_expr(struct expression *expr_list, u16 *data, int data_len, char *val_name, char **error) {
if ( expr_list->type != EXPR_ELLIPSIS) {
struct expression *expr = NULL;
unsigned int i;
switch(expr_list->type) {
case EXPR_LIST:
if (data_len != expression_list_length(expr_list->value.list)) {
asprintf(error, "%s length: expected: %u actual %d",
val_name, expression_list_length(expr_list->value.list), data_len);
return STATUS_ERR;
}
for (i = 0; i < data_len; i++) {
expr = get_arg(expr_list->value.list, i, error);
if (expr->type != EXPR_ELLIPSIS) {
u16 script_val;
if (get_u16(expr, &script_val, error)) {
return STATUS_ERR;
}
if (script_val != data[i]) {
asprintf(error, "%s[%d]: expected: %hu actual: %hu",
val_name, i, script_val, data[i]);
return STATUS_ERR;
}
}
break;
case EXPR_NULL:
if (data != NULL)
return STATUS_ERR;
break;
default: asprintf(error, "Bad expressiontype for %s", val_name);
return STATUS_ERR;
break;
}
}
return STATUS_OK;
}
#endif
/* Free all the space used by the given iovec. */
static void iovec_free(struct iovec *iov, size_t iov_len)
{
int i;
if (iov == NULL)
return;
for (i = 0; i < iov_len; ++i)
free(iov[i].iov_base);
free(iov);