diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 097cdc9e1fad2ecca067097b58813f9cf022af6b..1244636e640f55631833deeaf5e96884b3785888 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -103,6 +103,95 @@ static s64 hextol(const char *s) return strtol(yytext + 2, NULL, 16); } +enum ifdef_os { + Linux_IFDEF = 1, FreeBSD_IFDEF, NetBSD_IFDEF, OpenBSD_IFDEF +}; + +#define MAX_IFDEF_DEPTH 1 +YY_BUFFER_STATE ifdef_stack[MAX_IFDEF_DEPTH]; +int ifdef_stack_ptr = 0; + +static inline int get_os_name_length(enum ifdef_os os) { + switch (os) { + case Linux_IFDEF: + return strlen("Linux"); + case FreeBSD_IFDEF: + return strlen("FreeBSD"); + case NetBSD_IFDEF: + return strlen("NetBSD"); + case OpenBSD_IFDEF: + return strlen("OpenBSD"); + default: + return -1; + } +} + +static inline bool ignore_ifdef(enum ifdef_os os) { +#ifdef linux + if (os == Linux_IFDEF) { + return false; + } +#endif +#ifdef __FreeBSD__ + if (os == FreeBSD_IFDEF) { + return false; + } +#endif +#ifdef __OpenBSD__ + if (os == OpenBSD_IFDEF) { + return false; + } +#endif +#ifdef __NetBSD__ + if (os == NetBSD_IFDEF) { + return false; + } +#endif + + return true; +} + +static inline char* remove_ifdef_start_and_endtag(char *code, int os_name_length) { + unsigned int ifdef_length = strlen("#ifdef "); + unsigned int endif_length = strlen("#endif"); + unsigned int newline_before_endif = 0; + char *code_without_ifdef = NULL; + + code_without_ifdef = code + ifdef_length + os_name_length; + newline_before_endif = strlen(code_without_ifdef) - endif_length; + code_without_ifdef[newline_before_endif] = (char) 0; + return code_without_ifdef; +} + + +static void handle_ifdef(enum ifdef_os os, const char *s) { + char *code = NULL; + char *code_without_ifdef = NULL; + int os_name_length = get_os_name_length(os); + + if (os_name_length == -1) { + fprintf(stderr, "handle_ifdef with unknown os called.\n"); + exit(1); + } + + if (ignore_ifdef(os)) { + return; + } + + if (ifdef_stack_ptr >= MAX_IFDEF_DEPTH) { + fprintf(stderr, "Ifdefs nested too deeply"); + exit(1); + } + + code = strdup(s); + + code_without_ifdef = remove_ifdef_start_and_endtag(code, os_name_length); + ifdef_stack[ifdef_stack_ptr++] = YY_CURRENT_BUFFER; + yy_switch_to_buffer(yy_scan_string(code_without_ifdef)); + + free(code); +} + %} %{ @@ -122,6 +211,29 @@ cpp_comment \/\/[^\n]*\n */ c_comment \/\*(([^*])|(\*[^\/]))*\*\/ +/* This matches the following platform specific #ifdef-forms: + * #ifdef Linux => Code that only Linux hosts should execute + * #ifdef FreeBSD => Code that only FreeBSD hosts should execute + * #ifdef OpenBSD => Code that only OpenBSD hosts should execute + * #ifdef NetBSD => Code that only NetBSD hosts should execute + * + * the pattern for using #ifdef is like this: + * #ifdef Linux + * (specific code only for linux) + * #endif + */ + +/* these are the tags that identify the start and ending of an ifdef block */ +ifdef_begin #ifdef[ ] +ifdef_end #endif +/* end_matcher actually matches everything except the "#endif" tag. */ +end_matcher (([^#])|(#[^e])|(#e[^n])|(#en[^d])|(#end[^i])|(#endi[^f]))* + +ifdef_freebsd {ifdef_begin}(?i:FreeBSD){end_matcher}{ifdef_end} +ifdef_linux {ifdef_begin}(?i:Linux){end_matcher}{ifdef_end} +ifdef_openbsd {ifdef_begin}(?i:OpenBSD){end_matcher}{ifdef_end} +ifdef_netbsd {ifdef_begin}(?i:NetBSD){end_matcher}{ifdef_end} + /* The regexp for code snippets is analogous to that for C comments. * Here is a summary of the regexp for code snippets: * %{ @@ -480,7 +592,19 @@ NULL return NULL_; [ \t\n]+ /* ignore whitespace */; {cpp_comment} /* ignore C++-style comment */; {c_comment} /* ignore C-style comment */; +{ifdef_freebsd} handle_ifdef(FreeBSD_IFDEF, yytext); +{ifdef_linux} handle_ifdef(Linux_IFDEF, yytext); +{ifdef_openbsd} handle_ifdef(OpenBSD_IFDEF, yytext); +{ifdef_netbsd} handle_ifdef(NetBSD_IFDEF, yytext); {code} yylval.string = code(yytext); return CODE; {ipv4_addr} yylval.string = strdup(yytext); return IPV4_ADDR; {ipv6_addr} yylval.string = strdup(yytext); return IPV6_ADDR; +<<EOF>> { + if ( --ifdef_stack_ptr < 0 ) { + yyterminate(); + } else { + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(ifdef_stack[ifdef_stack_ptr]); + } + } %% diff --git a/gtests/net/packetdrill/tests/bsd/sctp/ifdef_testcase.pkt b/gtests/net/packetdrill/tests/bsd/sctp/ifdef_testcase.pkt new file mode 100644 index 0000000000000000000000000000000000000000..996106632f3f299ddc206100e0873181ac76cbb9 --- /dev/null +++ b/gtests/net/packetdrill/tests/bsd/sctp/ifdef_testcase.pkt @@ -0,0 +1,26 @@ +// Create a non-blocking 1-to-1 style socket + 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3 ++0.0 bind(3, ..., ...) = 0 ++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR) ++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0 +// Trigger the active associtation setup ++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) ++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...] ++0.0 < 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.0 < sctp: COOKIE_ACK[flgs=0] +// Check if the setup was sucessful ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +// inject sack-chunk(type=3) with invalid len=8| cumulative tsn ack | ++0.0 < sctp: CHUNK[type=3, flgs=0, len=8, val=[0x00, 0x00, 0x00, 0x01]] +#ifdef Linux +// expect protocol violation ++0.0 > sctp: ABORT[flgs=..., PROTOCOL_VIOLATION[info=...]] +#endif +#ifdef FreeBSD ++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 ++0.0 close(3) = 0 ++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0] ++0.1 < sctp: SHUTDOWN_ACK[flgs=0] ++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0] +#endif