void *buffer_append_space(Buffer *buffer, unsigned int len) { unsigned int newlen; void *p; if (len > BUFFER_MAX_CHUNK) return NULL; /* If the buffer is empty, start using it from the beginning. */ if (buffer->offset == buffer->end) { buffer->offset = 0; buffer->end = 0; } restart: /* If there is enough space to store all data, store it now. */ if (buffer->end + len < buffer->alloc) { p = buffer->buf + buffer->end; buffer->end += len; return p; } /* Compact data back to the start of the buffer if necessary */ if (buffer_compact(buffer)) goto restart; /* Increase the size of the buffer and retry. */ newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); if (newlen > BUFFER_MAX_LEN) return NULL; buffer->buf = (unsigned char *)realloc(buffer->buf, newlen); buffer->alloc = newlen; goto restart; /* NOTREACHED */ }
static void write_cb(int fd, int mask, void* user) { int fork_id = (int)user; fork_state* fs = get_fork(fork_id); fs->has_yielded_writer = 0; if (mask & STD2_CALLBACK_ABORT) { assert(!"abort not implemented"); abort(); return; } int r = write_buffer(fd, &fs->out_buffer); if (r < 0) { // TODO: abort requests and stuff fprintf(stderr, "std2: write error: %s\n", strerror(errno)); abort(); } buffer_compact(&fs->out_buffer); yield_callbacks(fork_id); }
struct fast_message *fast_session_recv(struct fast_session *self, int flags) { struct buffer *buffer = self->rx_buffer; struct fast_message *msg; size_t size; ssize_t nr; msg = fast_message_decode(self); if (msg) return msg; size = buffer_remaining(buffer); if (size <= FAST_MESSAGE_MAX_SIZE) buffer_compact(buffer); /* * If buffer's capacity is at least * 2 times FAST_MESSAGE_MAX_SIZE then, * remaining > FAST_MESSAGE_MAX_SIZE */ nr = self->recv(buffer, self->sockfd, FAST_MESSAGE_MAX_SIZE, flags); if (nr <= 0) return NULL; return fast_message_decode(self); }
static void return_func(int id, void* ret, void* arg0, void* arg1) { (void)arg0; request* req = arg1; fork_state* fs = get_fork(req->fork_id); int ret_id = buffer_read_32(&fs->in_buffer); int ret_size = buffer_read_32(&fs->in_buffer); buffer_compact(&fs->in_buffer); assert(req->id == ret_id); assert(req->return_id == id); char* p = buffer_cursor(&fs->in_buffer); char* start = p; switch (req->ret_type.type) { case STD2_VOID: break; case STD2_INT32: *(std2_int32*)ret = *(std2_int32*)p; p += 4; break; case STD2_C_STRING: { int size = *(int*)p; p += 4; *(const char**)ret = p; p += size; } break; case STD2_INSTANCE: *(void**)ret = *(void**)p; p += sizeof(void*); break; default: fprintf(stderr, "std2: todo return type %d\n", req->ret_type.type); abort(); } assert(p - start == ret_size); fs->in_buffer.pos += ret_size; fs->return_processed = 1; request** prev = &fs->first_request; while (*prev != req && *prev) prev = &(*prev)->next; assert(*prev); *prev = (*prev)->next; free(req); }
char *buffer_deconstruct(buffer *b) { char *data; (void) buffer_compact(b); data = buffer_data(b); free(b); return data; }
/* * Check whether an allocation of 'len' will fit in the buffer * This must follow the same math as buffer_append_space */ int buffer_check_alloc(Buffer *buffer, u_int len) { if (buffer->offset == buffer->end) { buffer->offset = 0; buffer->end = 0; } restart: if (buffer->end + len < buffer->alloc) return (1); if (buffer_compact(buffer)) goto restart; if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN) return (1); return (0); }
void * buffer_append_space(Buffer *buffer, uint32_t len) { uint32_t newlen; void *p; if (len > BUFFER_MAX_CHUNK) croak("buffer_append_space: len %u too large (max %u)", len, BUFFER_MAX_CHUNK); /* If the buffer is empty, start using it from the beginning. */ if (buffer->offset == buffer->end) { buffer->offset = 0; buffer->end = 0; } restart: /* If there is enough space to store all data, store it now. */ if (buffer->end + len <= buffer->alloc) { p = buffer->buf + buffer->end; buffer->end += len; return p; } /* Compact data back to the start of the buffer if necessary */ if (buffer_compact(buffer)) goto restart; /* Increase the size of the buffer and retry. */ if (buffer->alloc + len < 4096) newlen = (buffer->alloc + len) * 2; else newlen = buffer->alloc + len + 4096; if (newlen > BUFFER_MAX_LEN) croak("buffer_append_space: alloc %u too large (max %u)", newlen, BUFFER_MAX_LEN); #ifdef XS_DEBUG PerlIO_printf(PerlIO_stderr(), "Buffer extended to %d\n", newlen); #endif Renew(buffer->buf, (int)newlen, u_char); buffer->alloc = newlen; goto restart; /* NOTREACHED */ }
frameparser_outcome frameparser_parse(frameparser *fp, buffer *b) { // Parse as much as we can from the buffer bool done = false; while ((!done) && (buffer_get_length(b) > 0)) { if (!frameparser_parse_internal(fp, b)) done = true; } // Can't make any more parsing progress for now. Might as well compact the buffer. buffer_compact(b); if (fp->state == FP_STATE_ERROR) return FP_OUTCOME_ERROR; else if (fp->fin_frame) return FP_OUTCOME_FRAME; return FP_OUTCOME_WAITING; }
void * pamsshagentauth_buffer_append_space(Buffer *buffer, u_int len) { u_int newlen; void *p; if (len > BUFFER_MAX_CHUNK) pamsshagentauth_fatal("buffer_append_space: len %u not supported", len); /* If the buffer is empty, start using it from the beginning. */ if (buffer->offset == buffer->end) { buffer->offset = 0; buffer->end = 0; } restart: /* If there is enough space to store all data, store it now. */ if (buffer->end + len < buffer->alloc) { p = buffer->buf + buffer->end; buffer->end += len; return p; } /* Compact data back to the start of the buffer if necessary */ if (buffer_compact(buffer)) goto restart; /* Increase the size of the buffer and retry. */ newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); if (newlen > BUFFER_MAX_LEN) pamsshagentauth_fatal("buffer_append_space: alloc %u not supported", newlen); buffer->buf = pamsshagentauth_xrealloc(buffer->buf, 1, newlen); buffer->alloc = newlen; goto restart; /* NOTREACHED */ }
int string_shrink_to_fit(string *s) { return buffer_compact(&s->buffer); }
int cmd_check(int argc, char *argv[]) { struct buffer *comp_buf, *uncomp_buf; z_stream stream; struct stat st; int fd; setlocale(LC_ALL, ""); if (argc < 2) usage(); parse_args(argc, argv); init_stream(&stream); fd = open(filename, O_RDONLY); if (fd < 0) die("%s: %s: %s\n", program, filename, strerror(errno)); if (fstat(fd, &st) < 0) die("%s: %s: %s\n", program, filename, strerror(errno)); comp_buf = buffer_mmap(fd, st.st_size); if (!comp_buf) die("%s: %s\n", program, strerror(errno)); stream.next_in = (void *) buffer_start(comp_buf); uncomp_buf = buffer_new(BUFFER_SIZE); if (!uncomp_buf) die("%s: %s\n", program, strerror(errno)); for (;;) { struct itch41_message *msg; retry_size: if (buffer_size(uncomp_buf) < sizeof(u16)) { ssize_t nr; buffer_compact(uncomp_buf); nr = buffer_inflate(comp_buf, uncomp_buf, &stream); if (nr < 0) die("%s: zlib error\n", program); if (!nr) break; if (show_progress) print_progress(comp_buf, st.st_size); goto retry_size; } buffer_advance(uncomp_buf, sizeof(u16)); retry_message: msg = itch41_message_decode(uncomp_buf); if (!msg) { ssize_t nr; buffer_compact(uncomp_buf); nr = buffer_inflate(comp_buf, uncomp_buf, &stream); if (nr < 0) die("%s: zlib error\n", program); if (!nr) break; if (show_progress) print_progress(comp_buf, st.st_size); goto retry_message; } if (verbose) printf("%c", msg->MessageType); stats[msg->MessageType - 'A']++; } printf("\n"); buffer_munmap(comp_buf); buffer_delete(uncomp_buf); if (close(fd) < 0) die("%s: %s: %s\n", program, filename, strerror(errno)); release_stream(&stream); print_stats(); return 0; }
int main(void) { struct buffer one = { 0, 0, 0, NULL }; struct buffer two = { 0, 0, 0, NULL }; struct buffer *three; int fd; char *data; ssize_t count; size_t offset; plan(89); /* buffer_set, buffer_append, buffer_swap */ buffer_set(&one, test_string1, sizeof(test_string1)); is_int(1024, one.size, "minimum size is 1024"); is_int(0, one.used, "used starts at 0"); is_int(sizeof(test_string1), one.left, "left is correct"); is_string(test_string1, one.data, "data is corect"); buffer_append(&one, test_string2, sizeof(test_string2)); is_int(1024, one.size, "appended data doesn't change size"); is_int(0, one.used, "or used"); is_int(sizeof(test_string3), one.left, "but left is the right size"); ok(memcmp(one.data, test_string3, sizeof(test_string3)) == 0, "and the resulting data is correct"); one.left -= sizeof(test_string1); one.used += sizeof(test_string1); buffer_append(&one, test_string1, sizeof(test_string1)); is_int(1024, one.size, "size still isn't larger after adding data"); is_int(sizeof(test_string1), one.used, "and used is preserved on append"); is_int(sizeof(test_string3), one.left, "and left is updated properly"); ok(memcmp(one.data + one.used, test_string2, sizeof(test_string2)) == 0, "and the middle data is unchanged"); ok(memcmp(one.data + one.used + sizeof(test_string2), test_string1, sizeof(test_string1)) == 0, "and the final data is correct"); buffer_set(&one, test_string1, sizeof(test_string1)); buffer_set(&two, test_string2, sizeof(test_string2)); buffer_swap(&one, &two); is_int(1024, one.size, "swap #1 size is correct"); is_int(0, one.used, "swap #1 used is correct"); is_int(sizeof(test_string2), one.left, "swap #1 left is correct"); is_string(test_string2, one.data, "swap #1 data is correct"); is_int(1024, two.size, "swap #2 size is correct"); is_int(0, two.used, "swap #2 used is correct"); is_int(sizeof(test_string1), two.left, "swap #2 left is correct"); is_string(test_string1, two.data, "swap #2 data is correct"); free(one.data); free(two.data); one.data = NULL; two.data = NULL; one.size = 0; two.size = 0; /* buffer_resize */ three = buffer_new(); ok(three != NULL, "buffer_new works"); if (three == NULL) bail("buffer_new returned NULL"); is_int(0, three->size, "initial size is 0"); buffer_set(three, test_string1, sizeof(test_string1)); is_int(1024, three->size, "size becomes 1024 when adding data"); buffer_resize(three, 512); is_int(1024, three->size, "resizing to something smaller doesn't change"); buffer_resize(three, 1025); is_int(2048, three->size, "resizing to something larger goes to 2048"); buffer_free(three); /* buffer_read, buffer_find_string, buffer_compact */ fd = open("buffer-test", O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd < 0) sysbail("cannot create buffer-test"); data = bmalloc(2048); memset(data, 'a', 1023); data[1023] = '\r'; data[1024] = '\n'; memset(data + 1025, 'b', 1023); if (xwrite(fd, data, 2048) < 2048) sysbail("cannot write to buffer-test"); if (lseek(fd, 0, SEEK_SET) == (off_t) -1) sysbail("cannot rewind buffer-test"); three = buffer_new(); ok(three != NULL, "buffer_new works"); if (three == NULL) bail("buffer_new returned NULL"); is_int(0, three->size, "and initial size is 0"); buffer_resize(three, 1024); is_int(1024, three->size, "resize to 1024 works"); count = buffer_read(three, fd); is_int(1024, count, "reading into a buffer of size 1024 reads 1024"); offset = 0; ok(!buffer_find_string(three, "\r\n", 0, &offset), "buffer_find_string with truncated string fails"); is_int(0, offset, "and offset is unchanged"); ok(memcmp(three->data, data, three->size) == 0, "buffer data is correct"); buffer_resize(three, 2048); is_int(2048, three->size, "resizing the buffer to 2048 works"); count = buffer_read(three, fd); is_int(1024, count, "and now we can read the rest of the data"); ok(memcmp(three->data, data, 2048) == 0, "and it's all there"); ok(!buffer_find_string(three, "\r\n", 1024, &offset), "buffer_find_string with a string starting before offset fails"); is_int(0, offset, "and offset is unchanged"); ok(buffer_find_string(three, "\r\n", 0, &offset), "finding the string on the whole buffer works"); is_int(1023, offset, "and returns the correct location"); three->used += 400; three->left -= 400; buffer_compact(three); is_int(2048, three->size, "compacting buffer doesn't change the size"); is_int(0, three->used, "but used is now zero"); is_int(1648, three->left, "and left is decreased appropriately"); ok(memcmp(three->data, data + 400, 1648) == 0, "and the data is correct"); count = buffer_read(three, fd); is_int(0, count, "reading at EOF returns 0"); close(fd); unlink("buffer-test"); free(data); buffer_free(three); /* buffer_sprintf and buffer_append_sprintf */ three = buffer_new(); buffer_append_sprintf(three, "testing %d testing", 6); is_int(0, three->used, "buffer_append_sprintf doesn't change used"); is_int(17, three->left, "but sets left correctly"); buffer_append(three, "", 1); is_int(18, three->left, "appending a nul works"); is_string("testing 6 testing", three->data, "and the data is correct"); three->left--; three->used += 5; three->left -= 5; buffer_append_sprintf(three, " %d", 7); is_int(14, three->left, "appending a digit works"); buffer_append(three, "", 1); is_string("testing 6 testing 7", three->data, "and the data is correct"); buffer_sprintf(three, "%d testing", 8); is_int(9, three->left, "replacing the buffer works"); is_string("8 testing", three->data, "and the results are correct"); data = bmalloc(1050); memset(data, 'a', 1049); data[1049] = '\0'; is_int(1024, three->size, "size before large sprintf is 1024"); buffer_sprintf(three, "%s", data); is_int(2048, three->size, "size after large sprintf is 2048"); is_int(1049, three->left, "and left is correct"); buffer_append(three, "", 1); is_string(data, three->data, "and data is correct"); free(data); buffer_free(three); /* buffer_read_all */ fd = open("buffer-test", O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd < 0) sysbail("cannot create buffer-test"); data = bmalloc(2049); memset(data, 'a', 2049); if (xwrite(fd, data, 2049) < 2049) sysbail("cannot write to buffer-test"); if (lseek(fd, 0, SEEK_SET) == (off_t) -1) sysbail("cannot rewind buffer-test"); three = buffer_new(); ok(buffer_read_all(three, fd), "buffer_read_all succeeds"); is_int(0, three->used, "and unused is zero"); is_int(2049, three->left, "and left is correct"); is_int(4096, three->size, "and size is correct"); ok(memcmp(data, three->data, 2049) == 0, "and data is correct"); if (lseek(fd, 0, SEEK_SET) == (off_t) -1) sysbail("cannot rewind buffer-test"); ok(buffer_read_all(three, fd), "reading again succeeds"); is_int(0, three->used, "and used is correct"); is_int(4098, three->left, "and left is now larger"); is_int(8192, three->size, "and size doubled"); ok(memcmp(data, three->data + 2049, 2049) == 0, "and data is correct"); /* buffer_read_file */ if (lseek(fd, 0, SEEK_SET) == (off_t) -1) sysbail("cannot rewind buffer-test"); buffer_free(three); three = buffer_new(); ok(buffer_read_file(three, fd), "buffer_read_file succeeds"); is_int(0, three->used, "and leaves unused at 0"); is_int(2049, three->left, "and left is correct"); is_int(3072, three->size, "and size is a multiple of 1024"); ok(memcmp(data, three->data, 2049) == 0, "and the data is correct"); /* buffer_read_all and buffer_read_file errors */ close(fd); ok(!buffer_read_all(three, fd), "buffer_read_all on closed fd fails"); is_int(3072, three->size, "and size is unchanged"); ok(!buffer_read_file(three, fd), "buffer_read_file on closed fd fails"); is_int(3072, three->size, "and size is unchanged"); is_int(2049, three->left, "and left is unchanged"); unlink("buffer-test"); free(data); buffer_free(three); /* buffer_vsprintf and buffer_append_vsprintf */ three = buffer_new(); test_append_vsprintf(three, "testing %d testing", 6); is_int(0, three->used, "buffer_append_vsprintf leaves used as 0"); is_int(17, three->left, "and left is correct"); buffer_append(three, "", 1); is_int(18, three->left, "and left is correct after appending a nul"); is_string("testing 6 testing", three->data, "and data is correct"); three->left--; three->used += 5; three->left -= 5; test_append_vsprintf(three, " %d", 7); is_int(14, three->left, "and appending results in the correct left"); buffer_append(three, "", 1); is_string("testing 6 testing 7", three->data, "and the right data"); test_vsprintf(three, "%d testing", 8); is_int(9, three->left, "replacing the buffer results in the correct size"); is_string("8 testing", three->data, "and the correct data"); data = bmalloc(1050); memset(data, 'a', 1049); data[1049] = '\0'; is_int(1024, three->size, "size is 1024 before large vsprintf"); test_vsprintf(three, "%s", data); is_int(2048, three->size, "and 2048 afterwards"); is_int(1049, three->left, "and left is correct"); buffer_append(three, "", 1); is_string(data, three->data, "and data is correct"); free(data); buffer_free(three); /* Test buffer_free with NULL and ensure it doesn't explode. */ buffer_free(NULL); return 0; }
bool do_write(struct epoll_event *p_entry, some_fd epoll_fd) { g2_connection_t *w_entry = (g2_connection_t *)p_entry->data.ptr; bool ret_val = true, more_write; ssize_t result = 0; #ifdef DEBUG_DEVEL if(!w_entry->send) { logg_posd(LOGF_DEBUG, "%s Ip: %p#I\tFDNum: %i\n", "no send buffer!", &w_entry->remote_host, w_entry->com_socket); w_entry->flags.dismissed = true; ret_val = false; } #endif buffer_flip(*w_entry->send); do { set_s_errno(0); result = my_epoll_send(epoll_fd, w_entry->com_socket, w_entry->send->data, w_entry->send->limit, 0); } while(-1 == result && EINTR == s_errno); switch(result) { default: w_entry->send->pos += result; w_entry->flags.has_written = true; w_entry->last_send = local_time_now; if(buffer_remaining(*w_entry->send)) break; shortlock_lock(&w_entry->pts_lock); if(list_empty(&w_entry->packets_to_send)) { w_entry->poll_interrests &= ~((uint32_t)EPOLLOUT); more_write = true; } else more_write = false; if(more_write) { if(!(w_entry->poll_interrests & EPOLLONESHOT)) { struct epoll_event t_entry; t_entry.data.u64 = p_entry->data.u64; t_entry.events = w_entry->poll_interrests; shortlock_unlock(&w_entry->pts_lock); if(0 > my_epoll_ctl(epoll_fd, EPOLL_CTL_MOD, w_entry->com_socket, &t_entry)) { logg_serrno(LOGF_DEBUG, "changing sockets Epoll-interrests"); w_entry->flags.dismissed = true; ret_val = false; } } else { shortlock_unlock(&w_entry->pts_lock); if(w_entry->flags.dismissed) { logg_posd(LOGF_DEVEL_OLD, "%s\tIP: %p#I\tFDNum: %i\n", "Dismissed!", &w_entry->remote_host, w_entry->com_socket); ret_val = false; } } } else shortlock_unlock(&w_entry->pts_lock); break; case 0: if(buffer_remaining(*w_entry->send)) { if(EAGAIN != s_errno) { logg_posd(LOGF_DEVEL_OLD, "%s Ip: %p#I\tFDNum: %i\n", "Dismissed!", &w_entry->remote_host, w_entry->com_socket); w_entry->flags.dismissed = true; ret_val = false; } else logg_devel("not ready to write\n"); } else { shortlock_lock(&w_entry->pts_lock); w_entry->poll_interrests &= ~((uint32_t)EPOLLOUT); if(!(w_entry->poll_interrests & EPOLLONESHOT)) { struct epoll_event t_entry; t_entry.data.u64 = p_entry->data.u64; t_entry.events = w_entry->poll_interrests; shortlock_unlock(&w_entry->pts_lock); if(0 > my_epoll_ctl(epoll_fd, EPOLL_CTL_MOD, w_entry->com_socket, &t_entry)) { logg_serrno(LOGF_DEBUG, "changing sockets Epoll-interrests"); w_entry->flags.dismissed = true; ret_val = false; } } else { shortlock_unlock(&w_entry->pts_lock); if(w_entry->flags.dismissed) { logg_posd(LOGF_DEVEL_OLD, "%s ERRNO=%i Ip: %p#I\tFDNum: %i\n", "EOF reached!", s_errno, &w_entry->remote_host, w_entry->com_socket); ret_val = false; } } } break; case -1: if(!(EAGAIN == errno || EWOULDBLOCK == s_errno)) { logg_serrno(LOGF_DEBUG, "write"); ret_val = false; } break; } logg_develd_old("ret_val: %i\tpos: %u\tlim: %u\n", ret_val, w_entry->send->pos, w_entry->send->limit); buffer_compact(*w_entry->send); logg_develd_old("ret_val: %i\tpos: %u\tlim: %u\n", ret_val, w_entry->send->pos, w_entry->send->limit); return ret_val; }
int bats_pitch_read(struct stream *stream, struct pitch_message **msg_p) { struct pitch_message *msg; unsigned char ch; *msg_p = NULL; retry_size: if (buffer_size(stream->uncomp_buf) < sizeof(u8) + sizeof(struct pitch_message)) { ssize_t nr; buffer_compact(stream->uncomp_buf); nr = buffer_inflate(stream->comp_buf, stream->uncomp_buf, stream->zstream); if (nr < 0) return nr; if (!nr) return 0; if (stream->progress) stream->progress(stream->comp_buf); goto retry_size; } ch = buffer_peek_8(stream->uncomp_buf); if (ch != 0x53) return -EINVAL; buffer_advance(stream->uncomp_buf, sizeof(u8)); retry_message: msg = pitch_message_decode(stream->uncomp_buf, 1); if (!msg) { ssize_t nr; buffer_compact(stream->uncomp_buf); nr = buffer_inflate(stream->comp_buf, stream->uncomp_buf, stream->zstream); if (nr < 0) return nr; if (!nr) return 0; if (stream->progress) stream->progress(stream->comp_buf); goto retry_message; } ch = buffer_peek_8(stream->uncomp_buf); if (ch != 0x0A) return -EINVAL; buffer_advance(stream->uncomp_buf, sizeof(u8)); *msg_p = msg; return 0; }
void std2_process_request() { fork_state* fs = get_fork(current_fork_id); if (read_buffer_append(fs->to_client_fd[0], &fs->in_buffer, 20)) { fprintf(stderr, "std2: child got disconnection\n"); exit(1); } int marker = buffer_read_32(&fs->in_buffer); int req_id = buffer_read_32(&fs->in_buffer); if (marker == 'c') { int m = buffer_read_32(&fs->in_buffer); int f = buffer_read_32(&fs->in_buffer); int params_size = buffer_read_32(&fs->in_buffer); read_buffer_append(fs->to_client_fd[0], &fs->in_buffer, params_size); fprintf(stderr, "call id=%d, %d, %d, %d\n", req_id, m, f, params_size); // Construct parameters. void* start_ptr = buffer_cursor(&fs->in_buffer); void* end_ptr = (char*)buffer_cursor(&fs->in_buffer) + params_size; void* p = start_ptr; void* args[16]; int param_count = std2_get_param_count(m, f); int i; for (i = 0; i < param_count; i++) { struct std2_param t = std2_get_param_type(m, f, i); switch (t.type) { case STD2_INT32: args[i] = p; p = (char*)p + 4; break; case STD2_C_STRING: { int size = *(int*)p; p = (char*)p + 4; args[i] = p; p = (char*)p + size; } break; case STD2_INSTANCE: args[i] = *(void**)p; p = (char*)p + sizeof(void*); break; default: fprintf(stderr, "std2: (c) unknown type %d\n", t.type); abort(); } assert(p <= end_ptr); } fs->in_buffer.pos += (char*)p - (char*)start_ptr; // Do the call. struct std2_param ret_type = std2_get_return_type(m, f); buffer_append_32(&fs->out_buffer, req_id); // size will be filled afterwards int size_pos = fs->out_buffer.size; buffer_append_32(&fs->out_buffer, 0); // size will be filled afterwards int ret; switch (ret_type.type) { case STD2_VOID: ret = std2_call(0, m, f, 0, args); break; case STD2_INT32: { std2_int32 v; ret = std2_call(0, m, f, &v, args); if (!ret) buffer_append_32(&fs->out_buffer, v); } break; case STD2_C_STRING: { const char* v; ret = std2_call(0, m, f, &v, args); if (!ret) { int l = strlen(v) + 1; int n = (l + 3) & ~3; buffer_append_32(&fs->out_buffer, n); buffer_append_data(&fs->out_buffer, v, l); buffer_append_alignment(&fs->out_buffer, 4); } } break; case STD2_INSTANCE: { void* v; ret = std2_call(0, m, f, &v, args); if (!ret) buffer_append_data(&fs->out_buffer, &v, sizeof(void*)); } break; default: fprintf(stderr, "std2: (a) unknown type %d\n", ret_type.type); abort(); } if (ret) { fprintf(stderr, "delayed return\n"); fs->out_buffer.size -= 8; // req_id and size return; } *(int*)((char*)fs->out_buffer.data + size_pos) = fs->out_buffer.size - size_pos - 4; while (buffer_avail(&fs->out_buffer)) write_buffer(fs->to_host_fd[1], &fs->out_buffer); fprintf(stderr, "response written\n"); buffer_compact(&fs->in_buffer); buffer_compact(&fs->out_buffer); } else if (marker == 'u') { assert(!"todo unrefer"); } else { fprintf(stderr, "std2: protocol error, bad marker %d\n", marker); abort(); } }