static void handle_dns_result (DskDnsLookupResult *result, void *callback_data) { const char *name = callback_data; char *str; switch (result->type) { case DSK_DNS_LOOKUP_RESULT_FOUND: str = dsk_ip_address_to_string (result->addr); printf ("%s: %s\n", name, str); dsk_free (str); break; case DSK_DNS_LOOKUP_RESULT_NOT_FOUND: printf ("%s: not found\n", name); break; case DSK_DNS_LOOKUP_RESULT_TIMEOUT: printf ("%s: timeout\n", name); break; case DSK_DNS_LOOKUP_RESULT_BAD_RESPONSE: printf ("%s: bad response: %s\n", name, result->message); break; default: dsk_assert_not_reached (); } if (result->type != DSK_DNS_LOOKUP_RESULT_FOUND) { exit_status = 1; if (fatal_errors) exit (1); } --n_running; }
static dsk_boolean handle_incoming_connection (DskOctetListener *listener) { DskHttpServerStream *stream; /* accept connection */ switch (dsk_octet_listener_accept (listener, NULL, &source, &sink, &error)) { case DSK_IO_RESULT_SUCCESS: /* create http-server stream */ stream = dsk_http_server_stream_new (sink, source, &server_stream_options); dsk_assert (stream != NULL); dsk_hook_trap (&stream->request_available, (DskHookFunc) handle_http_stream_request_available, stream, dsk_object_unref); break; case DSK_IO_RESULT_AGAIN: break; case DSK_IO_RESULT_ERROR: dsk_main_exit (1); dsk_warning ("cannot accept a new socket: %s", error->message); dsk_error_unref (error); error = NULL; return DSK_FALSE; case DSK_IO_RESULT_EOF: dsk_assert_not_reached (); } /* invoke this handler when the next incoming connection is available. */ return DSK_TRUE; }
static void handle_expected_subvalue (DskJsonParser *parser, JsonTokenType token) { switch (token) { case JSON_TOKEN_LBRACE: push_stack (parser, STACK_NODE_OBJECT); parser->parse_state = PARSE_EXPECTING_MEMBER; break; case JSON_TOKEN_STRING: handle_subvalue (parser, dsk_json_value_new_string (parser->str_len, parser->str)); break; case JSON_TOKEN_LBRACKET: push_stack (parser, STACK_NODE_ARRAY); parser->parse_state = PARSE_EXPECTING_ELEMENT; break; case JSON_TOKEN_NUMBER: { /* parse number */ double value; append_char_to_string_buffer (parser, 0); value = strtod (parser->str, NULL); handle_subvalue (parser, dsk_json_value_new_number (value)); break; } case JSON_TOKEN_TRUE: handle_subvalue (parser, dsk_json_value_new_boolean (DSK_TRUE)); break; case JSON_TOKEN_FALSE: handle_subvalue (parser, dsk_json_value_new_boolean (DSK_FALSE)); break; case JSON_TOKEN_NULL: handle_subvalue (parser, dsk_json_value_new_null ()); break; default: dsk_assert_not_reached (); } }
static void handle_dns_done (DskDnsLookupResult *result, void *callback_data) { DskClientStream *stream = callback_data; stream->is_resolving_name = 0; switch (result->type) { case DSK_DNS_LOOKUP_RESULT_FOUND: { struct sockaddr_storage addr; unsigned addr_len; dsk_ip_address_to_sockaddr (result->addr, stream->port, &addr, &addr_len); begin_connecting_sockaddr (stream, addr_len, (struct sockaddr *) &addr); } break; case DSK_DNS_LOOKUP_RESULT_NOT_FOUND: dsk_octet_stream_set_last_error (&stream->base_instance, "dns entry for %s not found", stream->name); maybe_set_autoreconnect_timer (stream); break; case DSK_DNS_LOOKUP_RESULT_TIMEOUT: dsk_octet_stream_set_last_error (&stream->base_instance, "dns lookup for %s timed out", stream->name); maybe_set_autoreconnect_timer (stream); break; case DSK_DNS_LOOKUP_RESULT_BAD_RESPONSE: dsk_octet_stream_set_last_error (&stream->base_instance, "dns lookup for %s failed: %s", stream->name, result->message); maybe_set_autoreconnect_timer (stream); break; default: dsk_assert_not_reached (); } dsk_object_unref (stream); }
DskIOResult dsk_websocket_receive (DskWebsocket *websocket, unsigned *length_out, uint8_t **data_out, DskError **error) { uint8_t header[9]; uint64_t length; restart: maybe_discard_data (websocket); if (websocket->incoming.size < 9) return DSK_IO_RESULT_AGAIN; dsk_buffer_peek (&websocket->incoming, 9, header); length = dsk_uint64be_parse (header + 1); if (length > websocket->max_length) { switch (websocket->too_long_mode) { case DSK_WEBSOCKET_MODE_DROP: websocket->to_discard = length + 9; goto restart; case DSK_WEBSOCKET_MODE_SHUTDOWN: do_deferred_shutdown (websocket); return DSK_IO_RESULT_ERROR; case DSK_WEBSOCKET_MODE_RETURN_ERROR: websocket->to_discard = length + 9; maybe_discard_data (websocket); dsk_set_error (error, "packet too long (%"PRIu64" bytes)", length); return DSK_IO_RESULT_ERROR; } } switch (header[0]) { case 0x00: /* uh oh - shutdown packet */ dsk_buffer_discard (&websocket->incoming, 9 + length); do_deferred_shutdown (websocket); return DSK_IO_RESULT_EOF; case 0xff: if (websocket->incoming.size - 9 < length) return DSK_IO_RESULT_AGAIN; *length_out = length; *data_out = dsk_malloc (length); dsk_buffer_discard (&websocket->incoming, 9); *data_out = dsk_malloc (length); dsk_buffer_read (&websocket->incoming, length, *data_out); update_hooks_with_buffer (websocket); return DSK_IO_RESULT_SUCCESS; default: /* error */ switch (websocket->bad_packet_type_mode) { case DSK_WEBSOCKET_MODE_SHUTDOWN: do_deferred_shutdown (websocket); break; case DSK_WEBSOCKET_MODE_RETURN_ERROR: dsk_set_error (error, "packet had bad type: 0x%02x", header[0]); websocket->to_discard = length + 9; maybe_discard_data (websocket); return DSK_IO_RESULT_ERROR; case DSK_WEBSOCKET_MODE_DROP: websocket->to_discard = length + 9; goto restart; } } dsk_assert_not_reached (); return DSK_IO_RESULT_ERROR; }
/* Converting pattern to NFS_State, allowing transitions that don't consume characters */ static struct NFA_State * pattern_to_nfa_state (struct Pattern *pattern, unsigned pattern_index, struct NFA_State *result, DskMemPool *pool) { struct NFA_State *b, *rv; struct NFA_Transition *trans; tail_recurse: switch (pattern->type) { case PATTERN_LITERAL: /* Allocate state with one transition */ rv = dsk_mem_pool_alloc (pool, sizeof (struct NFA_State)); rv->pattern_index = pattern_index; rv->pattern = pattern; rv->transitions = NULL; rv->flag = 0; rv->is_match = DSK_FALSE; prepend_transition (&rv->transitions, pattern->info.literal, result, pool); break; case PATTERN_ALT: rv = pattern_to_nfa_state (pattern->info.alternation.a, pattern_index, result, pool); b = pattern_to_nfa_state (pattern->info.alternation.b, pattern_index, result, pool); for (trans = b->transitions; trans; trans = trans->next_in_state) prepend_transition (&rv->transitions, trans->char_class, trans->next_state, pool); break; case PATTERN_CONCAT: /* NOTE: we handle tail_recursion to benefit long strings of concatenation (((('a' . 'b') . 'c') . 'd') . 'e') thus, the parser should be careful to arrange the concat patterns thusly */ b = pattern_to_nfa_state (pattern->info.concat.b, pattern_index, result, pool); pattern = pattern->info.concat.a; result = b; goto tail_recurse; case PATTERN_OPTIONAL: rv = pattern_to_nfa_state (pattern->info.optional, pattern_index, result, pool); prepend_transition (&rv->transitions, NULL, result, pool); break; case PATTERN_PLUS: rv = pattern_to_nfa_state (pattern->info.plus, pattern_index, result, pool); prepend_transition (&result->transitions, NULL, rv, pool); break; case PATTERN_STAR: { struct NFA_State *new_result; new_result = dsk_mem_pool_alloc0 (pool, sizeof (struct NFA_State)); new_result->pattern = pattern; new_result->pattern_index = pattern_index; prepend_transition (&new_result->transitions, NULL, result, pool); rv = pattern_to_nfa_state (pattern->info.star, pattern_index, new_result, pool); prepend_transition (&rv->transitions, NULL, new_result, pool); prepend_transition (&new_result->transitions, NULL, rv, pool); break; } default: dsk_assert_not_reached (); } return rv; }
static struct Pattern * parse_pattern (unsigned pattern_index, struct Token *token_list, DskMemPool *pool, DskError **error) { dsk_boolean last_was_alter; dsk_boolean accept_empty; /* Handle parens */ struct Token *token; for (token = token_list; token; token = token->next) if (token->type == TOKEN_LPAREN) { /* find matching rparen (or error) */ struct Token *rparen = token->next; int balance = 1; struct Pattern *subpattern; while (rparen) { if (rparen->type == TOKEN_LPAREN) balance++; else if (rparen->type == TOKEN_RPAREN) { balance--; if (balance == 0) break; } rparen = rparen->next; } if (balance) { /* missing right-paren */ dsk_set_error (error, "missing right-paren in regex"); return NULL; } /* recurse */ rparen->prev->next = NULL; subpattern = parse_pattern (pattern_index, token->next, pool, error); if (subpattern == NULL) return NULL; /* replace parenthesized expr with subpattern; slice out remainder of list */ token->type = TOKEN_PATTERN; token->pattern = subpattern; token->next = rparen->next; if (rparen->next) token->next->prev = token; } else if (token->type == TOKEN_RPAREN) { dsk_set_error (error, "unexpected right-paren in regex"); return NULL; } /* Handle star/plus/qm */ for (token = token_list; token; token = token->next) if (token->type == TOKEN_QUESTION_MARK || token->type == TOKEN_STAR || token->type == TOKEN_PLUS) { struct Pattern *new_pattern; if (token->prev == NULL || token->prev->type != TOKEN_PATTERN) { dsk_set_error (error, "'%c' must be precede by pattern", token->type == TOKEN_QUESTION_MARK ? '?' : token->type == TOKEN_STAR ? '*' : '+'); return NULL; } new_pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern)); switch (token->type) { case TOKEN_QUESTION_MARK: new_pattern->type = PATTERN_OPTIONAL; new_pattern->info.optional = token->prev->pattern; break; case TOKEN_STAR: new_pattern->type = PATTERN_STAR; new_pattern->info.star = token->prev->pattern; break; case TOKEN_PLUS: new_pattern->type = PATTERN_PLUS; new_pattern->info.plus = token->prev->pattern; break; default: dsk_assert_not_reached (); } token->prev->pattern = new_pattern; /* remove token */ if (token->prev) token->prev->next = token->next; else token_list = token->next; if (token->next) token->next->prev = token->prev; /* token isn't in the list now! but it doesn't matter b/c token->next is still correct */ } /* Handle concatenation */ for (token = token_list; token && token->next; ) { if (token->type == TOKEN_PATTERN && token->next->type == TOKEN_PATTERN) { /* concat */ struct Pattern *new_pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern)); struct Token *kill; new_pattern->type = PATTERN_CONCAT; new_pattern->info.concat.a = token->pattern; new_pattern->info.concat.b = token->next->pattern; token->pattern = new_pattern; /* remove token->next */ kill = token->next; token->next = kill->next; if (kill->next) kill->next->prev = token; } else token = token->next; } /* At this point we consist of nothing but alternations and patterns. Scan through, discarding TOKEN_ALTER, and keeping track of whether the empty pattern matches */ last_was_alter = DSK_TRUE; /* trick the empty pattern detector into triggering on initial '|' */ accept_empty = DSK_FALSE; for (token = token_list; token; token = token->next) if (token->type == TOKEN_ALTER) { if (last_was_alter) accept_empty = DSK_TRUE; last_was_alter = DSK_TRUE; /* remove token from list */ if (token->prev) token->prev->next = token->next; else token_list = token->next; if (token->next) token->next->prev = token->prev; } else { last_was_alter = DSK_FALSE; } if (last_was_alter) accept_empty = DSK_TRUE; /* if we accept an empty token, toss a PATTERN_EMPTY onto the list of patterns in the alternation. */ if (accept_empty || token_list == NULL) { struct Token *t = dsk_mem_pool_alloc (pool, sizeof (struct Token)); t->next = token_list; t->prev = NULL; if (t->next) t->next->prev = t; token_list = t; t->type = TOKEN_PATTERN; t->pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern)); } /* At this point, token_list!=NULL, and it consists entirely of patterns. Reduce it to a singleton with the alternation pattern. */ while (token_list->next != NULL) { /* create alternation pattern */ struct Pattern *new_pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern)); new_pattern->type = PATTERN_ALT; new_pattern->info.alternation.a = token_list->pattern; new_pattern->info.alternation.b = token_list->next->pattern; token_list->pattern = new_pattern; /* remove token->next */ { struct Token *kill = token_list->next; token_list->next = kill->next; if (kill->next) kill->next->prev = token_list; } } /* Return value consists of merely a single token-list. */ dsk_assert (token_list != NULL && token_list->next == NULL); return token_list->pattern; }