terom@40: #include "sock_test.h" terom@40: terom@40: #include terom@40: #include terom@40: #include terom@40: terom@41: /** terom@41: * Grow buf->vecs as needed, to ensure that buf->write_vec is valid terom@41: */ terom@41: static err_t sock_test_grow_buf (struct io_buf *buf) terom@41: { terom@41: size_t read_vec_offset = buf->read_vec ? (buf->read_vec - buf->vecs) : 0; terom@41: size_t write_vec_offset = buf->write_vec ? (buf->write_vec - buf->vecs) : 0; terom@41: struct io_vec *v; terom@41: struct io_vec *vecs_tmp = buf->vecs; terom@41: terom@41: // don't grow if not full terom@41: if (buf->vecs && buf->write_vec < buf->vecs + buf->count) terom@41: return SUCCESS; terom@41: terom@41: // new size terom@41: buf->count = buf->count * 2 + 1; terom@41: terom@41: // grow terom@41: if ((buf->vecs = realloc(buf->vecs, buf->count * sizeof(struct io_vec))) == NULL) { terom@41: // restore old value terom@41: buf->vecs = vecs_tmp; terom@41: terom@41: return ERR_CALLOC; terom@41: } terom@41: terom@41: // set vec terom@41: buf->write_vec = buf->vecs + write_vec_offset; terom@41: buf->read_vec = buf->vecs + read_vec_offset; terom@41: terom@41: // zero new vecs terom@41: for (v = buf->write_vec; v < buf->vecs + buf->count; v++) { terom@41: v->buf = NULL; terom@41: v->len = 0; terom@41: } terom@41: terom@41: // ok terom@41: return SUCCESS; terom@41: } terom@41: terom@40: static err_t sock_test_read (struct sock_stream *base_sock, void *buf_ptr, size_t *len) terom@40: { terom@40: struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); terom@40: struct io_buf *buf = &sock->recv_buf; terom@41: struct io_vec *vec = buf->read_vec; terom@41: terom@41: // EOF/nonblock if we're past the end of the last vector terom@41: if (!vec || vec == buf->vecs + buf->count || buf->off >= vec->len) { terom@41: if (sock->nonblocking && !sock->eof) { terom@41: // wait for more to be fed in terom@41: *len = 0; terom@41: return SUCCESS; terom@40: terom@41: } else { terom@41: // EOF! terom@41: return SET_ERROR(SOCK_TEST_ERR(sock), ERR_READ_EOF); terom@41: } terom@41: } terom@40: terom@40: // amount of data available in this iovec terom@40: size_t available = vec->len - buf->off; terom@40: terom@40: // amount to read terom@40: size_t to_read = *len; terom@40: terom@40: // trim down? terom@40: if (to_read > available) terom@40: to_read = available; terom@40: terom@40: // copy terom@40: memcpy(buf_ptr, vec->buf + buf->off, to_read); terom@40: terom@40: // consumed the whole vec? terom@40: if (to_read < available) { terom@40: // move offset terom@40: buf->off += to_read; terom@40: terom@40: } else { terom@40: // next vector terom@41: buf->read_vec++; terom@40: } terom@40: terom@40: // update len terom@40: *len = to_read; terom@40: terom@40: // ok terom@40: return SUCCESS; terom@40: } terom@40: terom@40: static err_t sock_test_write (struct sock_stream *base_sock, const void *buf_ptr, size_t *len) terom@40: { terom@40: struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); terom@40: struct io_buf *buf = &sock->send_buf; terom@40: terom@41: // ensure there's room terom@41: assert(sock_test_grow_buf(buf) == SUCCESS); terom@41: terom@41: // the next buffer terom@41: struct io_vec *vec = buf->write_vec; terom@40: terom@40: // store terom@40: vec->len = *len; terom@40: assert((vec->buf = malloc(vec->len))); terom@40: memcpy(vec->buf, buf_ptr, vec->len); terom@40: terom@40: // move vec onwards terom@41: buf->write_vec++; terom@40: terom@40: // ok terom@40: return SUCCESS; terom@40: } terom@40: terom@40: static err_t sock_test_event_init (struct sock_stream *base_sock) terom@40: { terom@41: struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); terom@41: terom@41: // set the nonblocking flag terom@41: sock->nonblocking = true; terom@41: terom@40: return SUCCESS; terom@40: } terom@40: terom@40: static err_t sock_test_event_enable (struct sock_stream *base_sock, short mask) terom@40: { terom@41: struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); terom@41: terom@40: return SUCCESS; terom@40: } terom@40: terom@40: static void sock_test_release (struct sock_stream *base_sock) terom@40: { terom@41: struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test); terom@40: terom@41: sock_test_destroy(sock); terom@40: } terom@40: terom@40: /* terom@40: * Our sock_stream_type terom@40: */ terom@40: static struct sock_stream_type sock_test_type = { terom@40: .methods = { terom@40: .read = &sock_test_read, terom@40: .write = &sock_test_write, terom@40: .event_init = &sock_test_event_init, terom@40: .event_enable = &sock_test_event_enable, terom@40: .release = &sock_test_release, terom@40: }, terom@40: }; terom@40: terom@40: struct sock_test* sock_test_create (void) terom@40: { terom@40: struct sock_test *sock; terom@40: terom@40: // allocate terom@40: assert((sock = calloc(1, sizeof(*sock)))); terom@40: terom@40: // initialize base with our sock_stream_type terom@40: sock_stream_init(SOCK_TEST_BASE(sock), &sock_test_type); terom@40: terom@40: // ok terom@40: return sock; terom@40: } terom@40: terom@41: void sock_test_destroy (struct sock_test *sock) terom@40: { terom@41: size_t i; terom@41: struct io_buf *sbuf = &sock->send_buf, *rbuf = &sock->recv_buf; terom@41: terom@41: // free the send buffer terom@41: for (i = 0; i < sbuf->count; i++) { terom@41: free(sbuf->vecs[i].buf); terom@41: } terom@41: terom@41: // free the buffer vector lists terom@41: free(sbuf->vecs); terom@41: free(rbuf->vecs); terom@41: terom@41: // free the sock itself terom@41: free(sock); terom@41: } terom@41: terom@41: void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count, bool eof) terom@41: { terom@41: struct io_buf *buf = &sock->recv_buf; terom@41: terom@41: // allocate + copy terom@41: assert((buf->vecs = calloc(count, sizeof(struct io_vec)))); terom@41: memcpy(buf->vecs, vecs, count * sizeof(struct io_vec)); terom@41: terom@41: // set terom@41: buf->count = count; terom@41: buf->read_vec = buf->vecs; terom@41: buf->write_vec = buf->vecs + count; terom@41: buf->off = 0; terom@41: terom@41: // set EOF flag? terom@41: if (eof) terom@41: sock->eof = true; terom@41: } terom@41: terom@41: void sock_test_add_recv_vec (struct sock_test *sock, struct io_vec new_vec) terom@41: { terom@41: struct io_buf *buf = &sock->recv_buf; terom@41: terom@41: // ensure there's room terom@41: assert(sock_test_grow_buf(buf) == SUCCESS); terom@41: terom@41: // copy terom@41: *(buf->write_vec++) = new_vec; terom@40: } terom@40: terom@40: void sock_test_get_send_data (struct sock_test *sock, char **buf_ptr, size_t *len_ptr) terom@40: { terom@40: struct io_buf *buf = &sock->send_buf; terom@40: size_t len = 0, i, off = 0; terom@40: char *out; terom@40: terom@40: // calculate total size terom@40: for (i = 0; i < buf->count; i++) { terom@40: len += buf->vecs[i].len; terom@40: } terom@40: terom@40: // alloc terom@40: assert((out = malloc(len))); terom@40: terom@40: // copy terom@40: for (i = 0; i < buf->count; i++) { terom@40: memcpy(out + off, buf->vecs[i].buf, buf->vecs[i].len); terom@40: off += buf->vecs[i].len; terom@40: } terom@40: terom@40: // update return terom@40: *buf_ptr = out; terom@40: *len_ptr = len; terom@40: } terom@40: