diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index bf8fee59727ecc630199882b5a7b136862c15875..a443838695b6f5e0e772fb9c5a57bea52e1b0e12 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -565,9 +565,10 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression_list> expression_list function_arguments %type <expression> expression binary_expression array %type <expression> decimal_integer hex_integer -%type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents linger -%type <expression> sctp_rtoinfo sctp_initmsg sctp_assocval sctp_sackinfo -%type <expression> sctp_status +%type <expression> inaddr sockaddr msghdr iovec pollfd opt_revents +%type <expression> linger l_onoff l_linger +%type <expression> sctp_status sctp_initmsg sctp_assocval sctp_sackinfo +%type <expression> sctp_rtoinfo srto_initial srto_max srto_min %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec %type <chunk_list_item> sctp_chunk_spec @@ -2459,30 +2460,74 @@ opt_revents | ',' REVENTS '=' expression { $$ = $4; } ; +l_onoff +: ONOFF '=' INTEGER { + if (!is_valid_s32($3)) { + semantic_error("linger onoff out of range"); + } else { + $$ = new_integer_expression($3, "%ld"); + } +} +| ONOFF '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +l_linger +: LINGER '=' INTEGER { + if (!is_valid_s32($3)) { + semantic_error("linger out of range"); + } + $$ = new_integer_expression($3, "%ld"); +} +| LINGER '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + linger -: '{' ONOFF '=' INTEGER ',' LINGER '=' INTEGER '}' { +: '{' l_onoff ',' l_linger '}' { $$ = new_expression(EXPR_LINGER); - $$->value.linger.l_onoff = $4; - $$->value.linger.l_linger = $8; + $$->value.linger = (struct linger_expr*) calloc(1, sizeof(struct linger_expr)); + $$->value.linger->l_onoff = $2; + $$->value.linger->l_linger = $4; } ; -sctp_rtoinfo -: '{' SRTO_INITIAL '=' INTEGER ',' SRTO_MAX '=' INTEGER ',' SRTO_MIN '=' INTEGER '}' { -#ifdef SCTP_RTOINFO - $$ = new_expression(EXPR_SCTP_RTOINFO); - if (!is_valid_u32($4)) { +srto_initial +: SRTO_INITIAL '=' INTEGER { + if (!is_valid_u32($3)){ semantic_error("srto_initial out of range"); } - $$->value.sctp_rtoinfo.srto_initial = $4; - if (!is_valid_u32($8)) { + $$ = new_integer_expression($3, "%u"); +} +| SRTO_INITIAL '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +srto_max +: SRTO_MAX '=' INTEGER { + if (!is_valid_u32($3)) { semantic_error("srto_max out of range"); } - $$->value.sctp_rtoinfo.srto_max = $8; - if (!is_valid_u32($12)) { + $$ = new_integer_expression($3, "%u"); +} +| SRTO_MAX '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +srto_min +: SRTO_MIN '=' INTEGER { + if (!is_valid_u32($3)) { semantic_error("srto_min out of range"); } - $$->value.sctp_rtoinfo.srto_min = $12; + $$ = new_integer_expression($3, "%u"); +} +| SRTO_MIN '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } +; + +sctp_rtoinfo +: '{' srto_initial ',' srto_max ',' srto_min '}' { +#ifdef SCTP_RTOINFO + $$ = new_expression(EXPR_SCTP_RTOINFO); + $$->value.sctp_rtoinfo = (struct sctp_rtoinfo_expr*) calloc(1, sizeof(struct sctp_rtoinfo_expr)); + $$->value.sctp_rtoinfo->srto_initial = $2; + $$->value.sctp_rtoinfo->srto_max = $4; + $$->value.sctp_rtoinfo->srto_min = $6; #else $$ = NULL; #endif diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index 77d7aeb432215834049319ba7f5b26cc791ce6d2..9387b06f80ea0d5fd04e5f88ba5144a9539d8fd4 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -514,6 +514,7 @@ static void begin_syscall(struct state *state, struct syscall_spec *syscall) enum result_check_t { CHECK_EXACT, /* check that result matches exactly */ CHECK_NON_NEGATIVE, /* check that result is non-negative */ + CHECK_ALLOW_MAPPING, /* checks for results after accept-syscall */ }; static int end_syscall(struct state *state, struct syscall_spec *syscall, enum result_check_t mode, int actual, char **error) @@ -557,6 +558,19 @@ static int end_syscall(struct state *state, struct syscall_spec *syscall, expected, actual); return STATUS_ERR; } + } else if (mode == CHECK_ALLOW_MAPPING) { + if ((expected >= 0) && (actual < 0)) { + asprintf(error, + "Expected non-negative result but got %d " + "with errno %d (%s)", + actual, actual_errno, strerror(actual_errno)); + return STATUS_ERR; + } else if ((expected < 0) && (actual != expected)) { + asprintf(error, + "Expected result %d but got %d", + expected, actual); + return STATUS_ERR; + } } else { assert(!"bad mode"); } @@ -994,7 +1008,7 @@ static int syscall_accept(struct state *state, struct syscall_spec *syscall, result = accept(live_fd, (struct sockaddr *)&live_addr, &live_addrlen); - if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error)) + if (end_syscall(state, syscall, CHECK_ALLOW_MAPPING, result, error)) return STATUS_ERR; if (result >= 0) { @@ -1560,8 +1574,10 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, struct expression_list *args, char **error) { int script_fd, live_fd, level, optname, result; - s32 script_optval, live_optval, script_optlen; - socklen_t live_optlen = sizeof(live_optval); + s32 script_optval, script_optlen, expected; + void *live_optval; + socklen_t live_optlen; + struct expression *val_expression; if (check_arg_count(args, 5, error)) return STATUS_ERR; if (s32_arg(args, 0, &script_fd, error)) @@ -1572,37 +1588,170 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, return STATUS_ERR; if (s32_arg(args, 2, &optname, error)) return STATUS_ERR; - if (s32_bracketed_arg(args, 3, &script_optval, error)) - return STATUS_ERR; if (s32_bracketed_arg(args, 4, &script_optlen, error)) return STATUS_ERR; - if (script_optlen != 4) { - asprintf(error, "Unsupported getsockopt optlen: %d", - (int)script_optlen); + if (get_s32(syscall->result, &expected, error)) + return STATUS_ERR; + val_expression = get_arg(args, 3, error); + if (val_expression == NULL) { return STATUS_ERR; + } else if (val_expression->type == EXPR_LINGER) { + live_optval = malloc(sizeof(struct linger)); + live_optlen = (socklen_t)sizeof(struct linger); +#ifdef SCTP_RTOINFO + } else if (val_expression->type == EXPR_SCTP_RTOINFO) { + live_optval = malloc(sizeof(struct sctp_rtoinfo)); + live_optlen = (socklen_t)sizeof(struct sctp_rtoinfo); + ((struct sctp_rtoinfo*)live_optval)->srto_assoc_id = 0; +#endif +#ifdef SCTP_STATUS + } else if (val_expression->type == EXPR_SCTP_STATUS) { + live_optval = malloc(sizeof(val_expression->value.sctp_status)); + live_optlen = (socklen_t)sizeof(val_expression->value.sctp_status); + ((struct sctp_status*) live_optval)->sstat_assoc_id = val_expression->value.sctp_status.sstat_assoc_id; +#endif + } else { + s32_bracketed_arg(args, 3, &script_optval, error); + live_optval = malloc(sizeof(int)); + live_optlen = (socklen_t)sizeof(int); } begin_syscall(state, syscall); - result = getsockopt(live_fd, level, optname, - &live_optval, &live_optlen); - - if (end_syscall(state, syscall, CHECK_EXACT, result, error)) - return STATUS_ERR; - - if ((int)live_optlen != script_optlen) { - asprintf(error, - "Bad getsockopt optlen: expected: %d actual: %d", - (int)script_optlen, (int)live_optlen); + result = getsockopt(live_fd, level, optname, live_optval, &live_optlen); + if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error)) { return STATUS_ERR; } - if (live_optval != script_optval) { - asprintf(error, - "Bad getsockopt optval: expected: %d actual: %d", - (int)script_optval, (int)live_optval); + + if (live_optlen != script_optlen) { + asprintf(error, "Bad getsockopt optlen: expected: %d actual: %d", + (int)script_optlen, (int)live_optlen); + free(live_optval); return STATUS_ERR; } + if (val_expression->type == EXPR_LINGER) { + struct expression *l_onoff = val_expression->value.linger->l_onoff; + struct expression *l_linger = val_expression->value.linger->l_linger; + struct linger *ling = live_optval; + int val_onoff = 0; + if (l_onoff->type == EXPR_INTEGER) { + if (get_s32(l_onoff, &val_onoff, error)) { + free(live_optval); + return STATUS_ERR; + } + if (val_onoff != ling->l_onoff) { + asprintf(error, "Bad getsockopt Linger onoff: expected: %d actual: %d", + (int) val_onoff, ling->l_onoff); + free(live_optval); + return STATUS_ERR; + } + } + int val_linger = 0; + if (l_linger->type == EXPR_INTEGER) { + if (get_s32(l_linger, &val_linger, error)) { + free(live_optval); + return STATUS_ERR; + } + if (ling->l_linger != val_linger) { + asprintf(error, "Bad getsockopt Linger Value: expected: %d actual: %d", + val_linger, ling->l_linger); + free(live_optval); + return STATUS_ERR; + } + } +#ifdef SCTP_RTOINFO + } else if (val_expression->type == EXPR_SCTP_RTOINFO) { + struct expression *srto_initial = val_expression->value.sctp_rtoinfo->srto_initial; + struct expression *srto_max = val_expression->value.sctp_rtoinfo->srto_max; + struct expression *srto_min = val_expression->value.sctp_rtoinfo->srto_min; + struct sctp_rtoinfo *rtoinfo = live_optval; + int initial=0, max=0, min=0; + if (srto_initial->type == EXPR_INTEGER) { + if (get_s32(srto_initial, &initial, error)) { + free(live_optval); + return STATUS_ERR; + } + if (rtoinfo->srto_initial != initial) { + asprintf(error, "Bad getsockopt SCTP_RTOINFO initial: expected: %u actual: %u", + initial, rtoinfo->srto_initial); + free(live_optval); + return STATUS_ERR; + } + } else if (srto_max->type == EXPR_INTEGER) { + if (get_s32(srto_max, &max, error)) { + free(live_optval); + return STATUS_ERR; + } + if (rtoinfo->srto_max != max) { + asprintf(error, "Bad getsockopt SCTP_RTOINFO SRTO_MAX: expected: %u actual: %u", + max, rtoinfo->srto_max); + free(live_optval); + return STATUS_ERR; + } + } else if (srto_min->type == EXPR_INTEGER) { + if (get_s32(srto_min, &min, error)) { + free(live_optval); + return STATUS_ERR; + } + if (rtoinfo->srto_min != min) { + asprintf(error, "Bad getsockopt SCTP_RTOINFO SRTO_MIN: expected: %u actual: %u", + min, rtoinfo->srto_min); + free(live_optval); + return STATUS_ERR; + } + } +#endif +#ifdef SCTP_STATUS + } else if (val_expression->type == EXPR_SCTP_STATUS) { + struct sctp_status *live_val = live_optval; + struct sctp_status *expected_val = &(val_expression->value.sctp_status); + if (live_val->sstat_state != expected_val->sstat_state) { + asprintf(error, "Bad getsockopt SCTP_STATUS state: expected: %d actual: %d ", + expected_val->sstat_state, live_val->sstat_state); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_rwnd != expected_val->sstat_rwnd) { + asprintf(error, "Bad getsockopt SCTP_STATUS rwnd: expected: %u actual: %u ", + expected_val->sstat_rwnd, live_val->sstat_rwnd); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_unackdata != expected_val->sstat_unackdata) { + asprintf(error, "Bad getsockopt SCTP_STATUS unackdata: expected: %u actual: %u", + expected_val->sstat_unackdata, live_val->sstat_unackdata); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_penddata != expected_val->sstat_penddata) { + asprintf(error, "Bad getsockopt SCTP_STATUS penddata: expected: %u actual: %u", + expected_val->sstat_penddata, live_val->sstat_penddata); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_instrms != expected_val->sstat_instrms) { + asprintf(error, "Bad getsockopt SCTP_STATUS instreams: expected: %u actual: %u", + expected_val->sstat_instrms, live_val->sstat_instrms); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_outstrms != expected_val->sstat_outstrms) { + asprintf(error, "Bad getsockopt SCTP_STATUS outstreams: expected: %u actual: %u", + expected_val->sstat_outstrms, live_val->sstat_outstrms); + free(live_optval); + return STATUS_ERR; + } else if (live_val->sstat_fragmentation_point != expected_val->sstat_fragmentation_point){ + asprintf(error, "Bad getsockopt SCTP_STATUS fragmentation point: expected: %u actual: %u", + expected_val->sstat_fragmentation_point, live_val->sstat_fragmentation_point); + free(live_optval); + return STATUS_ERR; + } +#endif + } else { + if (*(int*)live_optval != script_optval) { + asprintf(error, "Bad getsockopt optval: expected: %d actual: %d", + (int)script_optval, *(int*)live_optval); + free(live_optval); + return STATUS_ERR; + } + } + free(live_optval); return STATUS_OK; } @@ -1630,7 +1779,11 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, if (val_expression == NULL) return STATUS_ERR; if (val_expression->type == EXPR_LINGER) { - optval = &val_expression->value.linger; + optval = malloc(sizeof(struct linger)); + get_s32(val_expression->value.linger->l_onoff, + &(((struct linger*) optval)->l_onoff), error); + get_s32(val_expression->value.linger->l_linger, + &(((struct linger*) optval)->l_linger), error); } else if (val_expression->type == EXPR_STRING) { optval = val_expression->value.string; } else if (val_expression->type == EXPR_LIST) { @@ -1639,7 +1792,20 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, optval = &optval_s32; #ifdef SCTP_RTOINFO } else if (val_expression->type == EXPR_SCTP_RTOINFO) { - optval = &val_expression->value.sctp_rtoinfo; + struct sctp_rtoinfo *rtoinfo; + struct sctp_rtoinfo_expr *expr_rtoinfo = val_expression->value.sctp_rtoinfo; + if (expr_rtoinfo->srto_initial->type != EXPR_INTEGER || + expr_rtoinfo->srto_max->type != EXPR_INTEGER || + expr_rtoinfo->srto_min->type != EXPR_INTEGER) { + asprintf(error, "Bad setsockopt, bad inputtype for rtoinfo"); + return STATUS_ERR; + } + rtoinfo = malloc(sizeof(struct sctp_rtoinfo)); + rtoinfo->srto_initial = expr_rtoinfo->srto_initial->value.num; + rtoinfo->srto_max = expr_rtoinfo->srto_max->value.num; + rtoinfo->srto_min = expr_rtoinfo->srto_min->value.num; + rtoinfo->srto_assoc_id = 0; + optval = rtoinfo; #endif #ifdef SCTP_INITMSG } else if (val_expression->type == EXPR_SCTP_INITMSG) { @@ -1669,6 +1835,7 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, result = setsockopt(live_fd, level, optname, optval, optlen); return end_syscall(state, syscall, CHECK_EXACT, result, error); + free(optval); } static int syscall_poll(struct state *state, struct syscall_spec *syscall, diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index 96e53b8062521b97c84a9c62cea36cb8b69d4511..d6d774ade62503dc457114f7262b15dd0fcb388c 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -285,9 +285,17 @@ void free_expression(struct expression *expression) switch (expression->type) { case EXPR_ELLIPSIS: case EXPR_INTEGER: + break; case EXPR_LINGER: + free(expression->value.linger->l_onoff); + free(expression->value.linger->l_linger); + break; #ifdef SCTP_RTOINFO case EXPR_SCTP_RTOINFO: + free(expression->value.sctp_rtoinfo->srto_initial); + free(expression->value.sctp_rtoinfo->srto_max); + free(expression->value.sctp_rtoinfo->srto_min); + break; #endif #ifdef SCTP_INITMSG case EXPR_SCTP_INITMSG: diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index 62fa122ad7eb75eb26ae738d1afd345a445d42b2..aff29336e071fa858a1d3db160a32acdf3abcc0f 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -72,7 +72,7 @@ struct expression { union { s64 num; char *string; - struct linger linger; + struct linger_expr *linger; struct sockaddr_in *socket_address_ipv4; struct sockaddr_in6 *socket_address_ipv6; struct binary_expression *binary; @@ -81,7 +81,7 @@ struct expression { struct msghdr_expr *msghdr; struct pollfd_expr *pollfd; #ifdef SCTP_RTOINFO - struct sctp_rtoinfo sctp_rtoinfo; + struct sctp_rtoinfo_expr *sctp_rtoinfo; #endif #ifdef SCTP_INITMSG struct sctp_initmsg sctp_initmsg; @@ -136,6 +136,20 @@ struct pollfd_expr { struct expression *revents; /* returned events */ }; +/* Handle values for socketoption SO_Linger with inputtypes and values*/ +struct linger_expr { + struct expression *l_onoff; + struct expression *l_linger; +}; +/* Parse tree for syscall get/setsockopt for sctp_rtoinfo*/ +#ifdef SCTP_RTOINFO +struct sctp_rtoinfo_expr { + struct expression *srto_initial; + struct expression *srto_max; + struct expression *srto_min; +}; +#endif + /* The errno-related info from strace to summarize a system call error */ struct errno_spec { const char *errno_macro; /* errno symbol (C macro name) */ diff --git a/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt new file mode 100644 index 0000000000000000000000000000000000000000..8374c2c9fb78140ccaaeeeefef61792e53cb6ef0 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/sctp_get_socket_options.pkt @@ -0,0 +1,29 @@ +0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +// Check the handshake with an empty(!) cookie ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=1, ...] ++0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...]] ++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...] ++0.1 < sctp: COOKIE_ACK[flgs=0] + ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 + ++0 getsockopt(3, IPPROTO_SCTP, SCTP_STATUS, {sstat_state=8, sstat_rwnd=1500, sstat_unackdata=0, sstat_penddata=0, sstat_instrms=1, sstat_outstrms=1, + sstat_fragmentation_point=1452, sstat_primary=...}, [176])= 0 + ++0 setsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=1, linger=30}, 8) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=128, linger=30}, [8]) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=128, linger=...}, [8]) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=..., linger=30}, [8]) = 0 ++0 getsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=..., linger=...}, [8]) = 0 + ++0 setsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=50}, 16) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=50}, [16]) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=..., srto_max=200, srto_min=50}, [16]) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=..., srto_min=50}, [16]) = 0 ++0 getsockopt(3, IPPROTO_SCTP, SCTP_RTOINFO, {srto_initial=100, srto_max=200, srto_min=...}, [16]) = 0 + ++0 close(3) = 0 +