| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /**
- * @file NCDUdevMonitorParser.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- *
- * @section LICENSE
- *
- * This file is part of BadVPN.
- *
- * BadVPN is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * BadVPN 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.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <misc/string_begins_with.h>
- #include <misc/balloc.h>
- #include <base/BLog.h>
- #include <udevmonitor/NCDUdevMonitorParser.h>
- #include <generated/blog_channel_NCDUdevMonitorParser.h>
- #define PROPERTY_REGEX "^([^=]+)=(.*)$"
- static uint8_t * find_end (uint8_t *buf, size_t len)
- {
- while (len >= 2) {
- if (buf[0] == '\n' && buf[1] == '\n') {
- return (buf + 2);
- }
- buf++;
- len--;
- }
-
- return NULL;
- }
- static int parse_property (NCDUdevMonitorParser *o, char *data)
- {
- ASSERT(o->ready_num_properties >= 0)
- ASSERT(o->ready_num_properties <= o->max_properties)
-
- if (o->ready_num_properties == o->max_properties) {
- BLog(BLOG_ERROR, "too many properties");
- return 0;
- }
- struct NCDUdevMonitorParser_property *prop = &o->ready_properties[o->ready_num_properties];
-
- // execute property regex
- regmatch_t matches[3];
- if (regexec(&o->property_regex, data, 3, matches, 0) != 0) {
- BLog(BLOG_ERROR, "failed to parse property");
- return 0;
- }
-
- // extract components
- prop->name = data + matches[1].rm_so;
- *(data + matches[1].rm_eo) = '\0';
- prop->value = data + matches[2].rm_so;
- *(data + matches[2].rm_eo) = '\0';
-
- // register property
- o->ready_num_properties++;
-
- return 1;
- }
- static int parse_message (NCDUdevMonitorParser *o)
- {
- ASSERT(!o->is_ready)
- ASSERT(o->ready_len >= 2)
- ASSERT(o->buf[o->ready_len - 2] == '\n')
- ASSERT(o->buf[o->ready_len - 1] == '\n')
-
- // zero terminate message (replacing the second newline)
- o->buf[o->ready_len - 1] = '\0';
-
- // start parsing
- char *line = (char *)o->buf;
- int first_line = 1;
-
- // set is not ready event
- o->ready_is_ready_event = 0;
-
- // init properties
- o->ready_num_properties = 0;
-
- do {
- // find end of line
- char *line_end = strchr(line, '\n');
- ASSERT(line_end)
-
- // zero terminate line
- *line_end = '\0';
-
- if (o->is_info_mode) {
- // parse prefix
- if (strlen(line) < 3 || line[1] != ':' || line[2] != ' ') {
- BLog(BLOG_ERROR, "failed to parse head");
- return 0;
- }
- char line_type = line[0];
- char *line_value = line + 3;
-
- if (first_line) {
- if (line_type != 'P') {
- BLog(BLOG_ERROR, "wrong first line type");
- return 0;
- }
- } else {
- if (line_type == 'E') {
- if (!parse_property(o, line_value)) {
- return 0;
- }
- }
- }
- } else {
- if (first_line) {
- // is this the initial informational message?
- if (string_begins_with(line, "monitor")) {
- o->ready_is_ready_event = 1;
- break;
- }
-
- // check first line
- if (!string_begins_with(line, "UDEV ")) {
- BLog(BLOG_ERROR, "failed to parse head");
- return 0;
- }
- } else {
- if (!parse_property(o, line)) {
- return 0;
- }
- }
- }
-
- first_line = 0;
- line = line_end + 1;
- } while (*line);
-
- // set ready
- o->is_ready = 1;
-
- return 1;
- }
- static void process_data (NCDUdevMonitorParser *o)
- {
- ASSERT(!o->is_ready)
-
- while (1) {
- // look for end of event
- uint8_t *c = find_end(o->buf, o->buf_used);
- if (!c) {
- // check for out of buffer condition
- if (o->buf_used == o->buf_size) {
- BLog(BLOG_ERROR, "out of buffer");
- o->buf_used = 0;
- }
-
- // receive more data
- StreamRecvInterface_Receiver_Recv(o->input, o->buf + o->buf_used, o->buf_size - o->buf_used);
- return;
- }
-
- // remember message length
- o->ready_len = c - o->buf;
-
- // parse message
- if (parse_message(o)) {
- break;
- }
-
- // shift buffer
- memmove(o->buf, o->buf + o->ready_len, o->buf_used - o->ready_len);
- o->buf_used -= o->ready_len;
- }
-
- // call handler
- o->handler(o->user);
- return;
- }
- static void input_handler_done (NCDUdevMonitorParser *o, int data_len)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(!o->is_ready)
- ASSERT(data_len > 0)
- ASSERT(data_len <= o->buf_size - o->buf_used)
-
- // increment buffer position
- o->buf_used += data_len;
-
- // process data
- process_data(o);
- return;
- }
- static void done_job_handler (NCDUdevMonitorParser *o)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(o->is_ready)
-
- // shift buffer
- memmove(o->buf, o->buf + o->ready_len, o->buf_used - o->ready_len);
- o->buf_used -= o->ready_len;
-
- // set not ready
- o->is_ready = 0;
-
- // process data
- process_data(o);
- return;
- }
- int NCDUdevMonitorParser_Init (NCDUdevMonitorParser *o, StreamRecvInterface *input, int buf_size, int max_properties,
- int is_info_mode, BPendingGroup *pg, void *user,
- NCDUdevMonitorParser_handler handler)
- {
- ASSERT(buf_size > 0)
- ASSERT(max_properties >= 0)
- ASSERT(is_info_mode == 0 || is_info_mode == 1)
-
- // init arguments
- o->input = input;
- o->buf_size = buf_size;
- o->max_properties = max_properties;
- o->is_info_mode = is_info_mode;
- o->user = user;
- o->handler = handler;
-
- // init input
- StreamRecvInterface_Receiver_Init(o->input, (StreamRecvInterface_handler_done)input_handler_done, o);
-
- // init property regex
- if (regcomp(&o->property_regex, PROPERTY_REGEX, REG_EXTENDED) != 0) {
- BLog(BLOG_ERROR, "regcomp failed");
- goto fail1;
- }
-
- // init done job
- BPending_Init(&o->done_job, pg, (BPending_handler)done_job_handler, o);
-
- // allocate buffer
- if (!(o->buf = malloc(o->buf_size))) {
- BLog(BLOG_ERROR, "malloc failed");
- goto fail2;
- }
-
- // set buffer position
- o->buf_used = 0;
-
- // set not ready
- o->is_ready = 0;
-
- // allocate properties
- if (!(o->ready_properties = BAllocArray(o->max_properties, sizeof(o->ready_properties[0])))) {
- BLog(BLOG_ERROR, "BAllocArray failed");
- goto fail3;
- }
-
- // start receiving
- StreamRecvInterface_Receiver_Recv(o->input, o->buf, o->buf_size);
-
- DebugObject_Init(&o->d_obj);
- return 1;
-
- fail3:
- free(o->buf);
- fail2:
- BPending_Free(&o->done_job);
- regfree(&o->property_regex);
- fail1:
- return 0;
- }
- void NCDUdevMonitorParser_Free (NCDUdevMonitorParser *o)
- {
- DebugObject_Free(&o->d_obj);
-
- // free properties
- BFree(o->ready_properties);
-
- // free buffer
- free(o->buf);
-
- // free done job
- BPending_Free(&o->done_job);
-
- // free property regex
- regfree(&o->property_regex);
- }
- void NCDUdevMonitorParser_AssertReady (NCDUdevMonitorParser *o)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(o->is_ready)
- }
- void NCDUdevMonitorParser_Done (NCDUdevMonitorParser *o)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(o->is_ready)
-
- // schedule done job
- BPending_Set(&o->done_job);
- }
- int NCDUdevMonitorParser_IsReadyEvent (NCDUdevMonitorParser *o)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(o->is_ready)
-
- return o->ready_is_ready_event;
- }
- int NCDUdevMonitorParser_GetNumProperties (NCDUdevMonitorParser *o)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(o->is_ready)
-
- return o->ready_num_properties;
- }
- void NCDUdevMonitorParser_GetProperty (NCDUdevMonitorParser *o, int index, const char **name, const char **value)
- {
- DebugObject_Access(&o->d_obj);
- ASSERT(o->is_ready)
- ASSERT(index >= 0)
- ASSERT(index < o->ready_num_properties)
-
- *name = o->ready_properties[index].name;
- *value = o->ready_properties[index].value;
- }
|