void PortLineSplitter::DataReceived(const void *_data, size_t length) { assert(_data != NULL); assert(length > 0); const char *data = (const char *)_data, *end = data + length; do { /* append new data to buffer, as much as fits there */ auto range = buffer.Write(); if (range.IsEmpty()) { /* overflow: reset buffer to recover quickly */ buffer.Clear(); continue; } size_t nbytes = std::min(size_t(range.size), size_t(end - data)); memcpy(range.data, data, nbytes); data += nbytes; buffer.Append(nbytes); while (true) { /* read data from the buffer, to see if there's a newline character */ range = buffer.Read(); if (range.IsEmpty()) break; char *newline = (char *)memchr(range.data, '\n', range.size); if (newline == NULL) /* no newline here: wait for more data */ break; /* remove trailing whitespace, such as '\r' */ char *end = newline; while (end > range.data && IsWhitespaceOrNull(end[-1])) --end; *end = '\0'; SanitiseLine(range.data, end); const char *line = range.data; /* if there are NUL bytes in the line, skip to after the last one, to avoid conflicts with NUL terminated C strings due to binary garbage */ const void *nul; while ((nul = memchr(line, 0, end - line)) != NULL) line = (const char *)nul + 1; LineReceived(line); buffer.Consume(newline - range.data + 1); } } while (data < end); }
void EventLoop(int fd, void *handle) { intf_thread_t *intf = (intf_thread_t*)handle; intf_sys_t *sys = intf->p_sys; sys->line = (char *)malloc(MAX_LINE * sizeof(char)); while(1) { struct pollfd ufd = { .fd = fd, .events = POLLIN | POLLOUT, }; if(poll(&ufd, 1, 1000) <= 0) /* block for 1s so we don't spin */ continue; if(ufd.revents & POLLIN) { int rv = HandleRead(handle); if(rv != 0) { msg_Err(intf, "Read error: %s", strerror(rv)); break; } } else if(ufd.revents & POLLOUT) { int rv = HandleWrite(handle); if(rv != 0) { msg_Err(intf, "Write error: %s", strerror(rv)); break; } } } free(sys->line); } int HandleRead(void *handle) { intf_thread_t *intf = (intf_thread_t*)handle; intf_sys_t *sys = intf->p_sys; static char ch, pch; int rv = recv(sys->fd, &ch, 1, 0); if(rv == -1) return errno; else if(rv == 0) return -2; if(pch == '\r' && ch == '\n') { /* were the last two characters \r\n? */ sys->line[sys->line_loc-1] = '\0'; /* overwrite CR with a nullbyte */ LineReceived(handle, sys->line); sys->line_loc = 0; sys->line = (char *)malloc(MAX_LINE * sizeof(char)); /* allocate a new line, lineReceived will free the old one */ } else { sys->line[sys->line_loc] = ch; pch = ch; sys->line_loc++; } return 0; }