int nb_io_expect(struct tnt_stream *t, char *sz) { struct tnt_stream_net *sn = TNT_SNET_CAST(t); char buf[256]; size_t len = strlen(sz); if (len > sizeof(buf)) { sn->error = TNT_EBIG; return -1; } if (tnt_io_recv(TNT_SNET_CAST(t), buf, len) == -1) return -1; if (!memcmp(buf, sz, len)) return 0; sn->error = TNT_EFAIL; return -1; }
/* * tnt_net() * * create and initialize network stream; * * s - stream pointer, maybe NULL * * if stream pointer is NULL, then new stream will be created. * * returns stream pointer, or NULL on error. */ struct tnt_stream *tnt_net(struct tnt_stream *s) { int allocated = s == NULL; s = tnt_net_tryalloc(s); if (s == NULL) return NULL; /* allocating stream data */ s->data = tnt_mem_alloc(sizeof(struct tnt_stream_net)); if (s->data == NULL) { if (allocated) tnt_stream_free(s); return NULL; } memset(s->data, 0, sizeof(struct tnt_stream_net)); /* initializing interfaces */ s->read = tnt_net_read; s->reply = tnt_net_reply; s->write = tnt_net_write; s->writev = tnt_net_writev; s->free = tnt_net_free; /* initializing internal data */ struct tnt_stream_net *sn = TNT_SNET_CAST(s); sn->fd = -1; tnt_opt_init(&sn->opt); return s; }
static void tnt_net_free(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); tnt_io_close(sn); tnt_iob_free(&sn->sbuf); tnt_iob_free(&sn->rbuf); tnt_opt_free(&sn->opt); tnt_mem_free(s->data); }
/* * tnt_set() * * set options to network stream; * * s - network stream pointer * opt - option id * ... - option value * * returns 0 on success, or -1 on error. */ int tnt_set(struct tnt_stream *s, int opt, ...) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); va_list args; va_start(args, opt); sn->error = tnt_opt_set(&sn->opt, opt, args); va_end(args); return (sn->error == TNT_EOK) ? 0 : -1; }
static ssize_t tnt_net_write(struct tnt_stream *s, char *buf, size_t size) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); ssize_t rc = tnt_io_send(sn, buf, size); if (rc != -1) s->wrcnt++; return rc; }
static ssize_t tnt_net_writev(struct tnt_stream *s, struct iovec *iov, int count) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); ssize_t rc = tnt_io_sendv(sn, iov, count); if (rc != -1) s->wrcnt++; return rc; }
/* * tnt_connect() * * connect to server; * reconnect to server; * * s - network stream pointer * * returns 0 on success, or -1 on error. */ int tnt_connect(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); if (sn->connected) tnt_close(s); sn->error = tnt_io_connect(sn, sn->opt.hostname, sn->opt.port); if (sn->error != TNT_EOK) return -1; return 0; }
/* * tnt_strerror() * * get library error status description string; * * s - network stream pointer */ char *tnt_strerror(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); if (sn->error == TNT_ESYSTEM) { static char msg[256]; snprintf(msg, sizeof(msg), "%s (errno: %d)", strerror(sn->errno_), sn->errno_); return msg; } return tnt_error_list[(int)sn->error].desc; }
int nb_mc_get(struct tnt_stream *t, char *key) { char buf[64]; int len = snprintf(buf, sizeof(buf), "get %s\r\n", key); struct iovec v[1]; v[0].iov_base = buf; v[0].iov_len = len; int r = tnt_io_sendv(TNT_SNET_CAST(t), v, 1); return (r < 0) ? -1 : 0; }
ssize_t tnt_auth(struct tnt_stream *s, const char *user, int ulen, const char *pass, int plen) { struct tnt_iheader hdr; struct iovec v[6]; int v_sz = 5; char *data = NULL, *body_start = NULL; int guest = !user || (ulen == 5 && !strncmp(user, "guest", 5)); if (guest) { user = "******"; ulen = 5; } encode_header(&hdr, TNT_OP_AUTH, s->reqid++); v[1].iov_base = (void *)hdr.header; v[1].iov_len = hdr.end - hdr.header; char body[64]; data = body; body_start = data; data = mp_encode_map(data, 2); data = mp_encode_uint(data, TNT_USERNAME); data = mp_encode_strl(data, ulen); v[2].iov_base = body_start; v[2].iov_len = data - body_start; v[3].iov_base = (void *)user; v[3].iov_len = ulen; body_start = data; data = mp_encode_uint(data, TNT_TUPLE); if (!guest) { data = mp_encode_array(data, 2); data = mp_encode_str(data, "chap-sha1", strlen("chap-sha1")); data = mp_encode_strl(data, TNT_SCRAMBLE_SIZE); char salt[64], scramble[TNT_SCRAMBLE_SIZE]; base64_decode(TNT_SNET_CAST(s)->greeting + TNT_VERSION_SIZE, TNT_SALT_SIZE, salt, 64); tnt_scramble_prepare(scramble, salt, pass, plen); v[5].iov_base = scramble; v[5].iov_len = TNT_SCRAMBLE_SIZE; v_sz++; } else { data = mp_encode_array(data, 0); } v[4].iov_base = body_start; v[4].iov_len = data - body_start; size_t package_len = 0; for (int i = 1; i < v_sz; ++i) { package_len += v[i].iov_len; } char len_prefix[9]; char *len_end = mp_encode_luint32(len_prefix, package_len); v[0].iov_base = len_prefix; v[0].iov_len = len_end - len_prefix; return s->writev(s, v, v_sz); }
int nb_mc_set(struct tnt_stream *t, char *key, char *data, int data_size) { char buf[64]; int len = snprintf(buf, sizeof(buf), "set %s 0 0 %d\r\n", key, data_size); struct iovec v[3]; v[0].iov_base = buf; v[0].iov_len = len; v[1].iov_base = data; v[1].iov_len = data_size; v[2].iov_base = "\r\n"; v[2].iov_len = 2; int r = tnt_io_sendv(TNT_SNET_CAST(t), v, 3); tnt_flush(t); return (r < 0) ? -1 : 0; }
/* * tnt_rpl_open() * * connect to a server and initialize handshake; * * s - replication stream pointer * lsn - start lsn * * network stream must be properly initialized before * this function called (see ttnt_rpl_net, tnt_set). * * returns 0 on success, or -1 on error. */ int tnt_rpl_open(struct tnt_stream *s, uint64_t lsn) { struct tnt_stream_rpl *sr = TNT_RPL_CAST(s); /* intializing connection */ if (tnt_init(sr->net) == -1) return -1; if (tnt_connect(sr->net) == -1) return -1; /* sending initial lsn */ struct tnt_stream_net *sn = TNT_SNET_CAST(sr->net); if (tnt_io_send_raw(sn, (char*)&lsn, sizeof(lsn), 1) == -1) return -1; /* reading and checking version */ uint32_t version = 0; if (tnt_io_recv_raw(sn, (char*)&version, sizeof(version), 1) == -1) return -1; if (version != tnt_rpl_version) return -1; return 0; }
/* * tnt_init() * * initialize prepared network stream; * * s - network stream pointer * * returns 0 on success, or -1 on error. */ int tnt_init(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); if (tnt_iob_init(&sn->sbuf, sn->opt.send_buf, sn->opt.send_cb, sn->opt.send_cbv, sn->opt.send_cb_arg) == -1) { sn->error = TNT_EMEMORY; return -1; } if (tnt_iob_init(&sn->rbuf, sn->opt.recv_buf, sn->opt.recv_cb, NULL, sn->opt.recv_cb_arg) == -1) { sn->error = TNT_EMEMORY; return -1; } if (sn->opt.hostname == NULL) { sn->error = TNT_EBADVAL; return -1; } if (sn->opt.port == 0) { sn->error = TNT_EBADVAL; return -1; } return 0; }
static int tnt_rpl_request(struct tnt_stream *s, struct tnt_request *r) { struct tnt_stream_rpl *sr = TNT_RPL_CAST(s); struct tnt_stream_net *sn = TNT_SNET_CAST(sr->net); /* fetching header */ if (tnt_io_recv(sn, (char*)&sr->hdr, sizeof(sr->hdr)) == -1) return -1; /* fetching row header */ if (tnt_io_recv(sn, (char*)&sr->row, sizeof(sr->row)) == -1) return -1; /* preparing pseudo iproto header */ struct tnt_header hdr_iproto; hdr_iproto.type = sr->row.op; hdr_iproto.len = sr->hdr.len - sizeof(struct tnt_log_row_v11); hdr_iproto.reqid = 0; /* deserializing operation */ if (tnt_request_from(r, (tnt_request_t)tnt_rpl_recv_cb, sr->net, &hdr_iproto) == -1) return -1; return 0; }
/* * tnt_flush() * * send bufferized data to server; * * s - network stream pointer * * returns size of data been sended on success, or -1 on error. */ ssize_t tnt_flush(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); return tnt_io_flush(sn); }
static ssize_t tnt_net_reply_cb(struct tnt_stream *s, char *buf, ssize_t size) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); return tnt_io_recv(sn, buf, size); }
int nb_io_getc(struct tnt_stream *t, char buf[1]) { return tnt_io_recv(TNT_SNET_CAST(t), buf, 1); }
static ssize_t tnt_net_read(struct tnt_stream *s, char *buf, size_t size) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); /* read doesn't touches wrcnt */ return tnt_io_recv(sn, buf, size); }
/* * tnt_errno() * * get saved errno; * * s - network stream pointer */ int tnt_errno(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); return sn->errno_; }
/* * tnt_close() * * close connection to server; * * s - network stream pointer * * returns 0 on success, or -1 on error. */ void tnt_close(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); tnt_io_close(sn); }
/* * tnt_error() * * get library error status; * * s - network stream pointer */ enum tnt_error tnt_error(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); return sn->error; }
int nb_mc_get_recv(struct tnt_stream *t, char **data, int *data_size) { struct tnt_stream_net *sn = TNT_SNET_CAST(t); /* VALUE <key> <flags> <bytes> [<cas unique>]\r\n * <data block>\r\n * ... * END\r\n */ *data = NULL; if (nb_io_expect(t, "VALUE ") == -1) return -1; /* key */ int key_len = 0; char key[128], ch[1]; for (;; key_len++) { if (key_len > (int)sizeof(key)) { sn->error = TNT_EBIG; goto error; } if (nb_io_getc(t, ch) == -1) goto error; if (ch[0] == ' ') { key[key_len] = 0; break; } key[key_len] = ch[0]; } /* flags */ int flags = 0; while (1) { if (nb_io_getc(t, ch) == -1) goto error; if (!isdigit(ch[0])) { if (ch[0] == ' ') break; sn->error = TNT_EFAIL; goto error; } flags *= 10; flags += ch[0] - 48; } /* bytes */ int value_size = 0; while (1) { if (nb_io_getc(t, ch) == -1) goto error; if (!isdigit(ch[0])) { if (ch[0] == '\r') break; sn->error = TNT_EFAIL; goto error; } value_size *= 10; value_size += ch[0] - 48; } /* \n */ if (nb_io_getc(t, ch) == -1) goto error; /* data */ *data_size = value_size; *data = tnt_mem_alloc(*data_size); if (*data == NULL) { sn->error = TNT_EMEMORY; goto error; } if (tnt_io_recv(sn, *data, *data_size) == -1) goto error; if (nb_io_expect(t, "\r\n") == -1) goto error; if (nb_io_expect(t, "END\r\n") == -1) goto error; return 0; error: if (*data) tnt_mem_free(*data); return -1; }
/* * tnt_fd() * * get connection socket description; * * s - network stream pointer */ int tnt_fd(struct tnt_stream *s) { struct tnt_stream_net *sn = TNT_SNET_CAST(s); return sn->fd; }