static void request_config(cccp_provider *cccp) { protocol_binary_request_set_cluster_config req; lcb_connection_t conn = &cccp->connection; ringbuffer_t *buf = conn->output; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.opcode = CMD_GET_CLUSTER_CONFIG; req.message.header.request.opaque = 0xF00D; if (!buf) { if ((buf = calloc(1, sizeof(*buf))) == NULL) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } conn->output = buf; } if (!ringbuffer_ensure_capacity(buf, sizeof(req.bytes))) { mcio_error(cccp, LCB_CLIENT_ENOMEM); } ringbuffer_write(buf, req.bytes, sizeof(req.bytes)); lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 1); lcb_sockrw_apply_want(conn); lcb_timer_rearm(cccp->timer, PROVIDER_SETTING(&cccp->base, config_node_timeout)); }
static void connect_done_handler(lcb_connection_t conn, lcb_error_t err) { http_provider *http = (http_provider *)conn->data; const lcb_host_t *host = lcb_connection_get_host(conn); if (err != LCB_SUCCESS) { lcb_log(LOGARGS(http, ERR), "Connection to REST API @%s:%s failed with code=0x%x", host->host, host->port, err); io_error(http, err); return; } lcb_log(LOGARGS(http, DEBUG), "Successfuly connected to REST API %s:%s", host->host, host->port); lcb_connection_reset_buffers(conn); ringbuffer_strcat(conn->output, http->request_buf); lcb_assert(conn->output->nbytes > 0); lcb_sockrw_set_want(conn, LCB_RW_EVENT, 0); lcb_sockrw_apply_want(conn); lcb_timer_rearm(http->io_timer, PROVIDER_SETTING(&http->base, config_node_timeout)); }
static void event_complete_common(lcb_server_t *c, lcb_error_t rc) { lcb_t instance = c->instance; if (rc != LCB_SUCCESS) { lcb_failout_server(c, rc); } else { if (instance->bootstrap.type == LCB_CONFIG_TRANSPORT_HTTP && c->is_config_node) { c->instance->bootstrap.via.http.weird_things = 0; } lcb_sockrw_apply_want(&c->connection); c->inside_handler = 0; } if (instance->compat.type == LCB_CACHED_CONFIG && instance->compat.value.cached.needs_update) { lcb_refresh_config_cache(instance); } else if (instance->bootstrap.type == LCB_CONFIG_TRANSPORT_CCCP && instance->bootstrap.via.cccp.next_config) { lcb_update_vbconfig(instance, instance->bootstrap.via.cccp.next_config); instance->bootstrap.via.cccp.next_config = NULL; } lcb_maybe_breakout(instance); lcb_error_handler(instance, rc, NULL); }
/** * Common function to handle parsing the HTTP stream for both v0 and v1 io * implementations. */ static void read_common(http_provider *http) { lcb_error_t err; lcb_connection_t conn = &http->connection; int old_generation = http->stream.generation; lcb_log(LOGARGS(http, TRACE), "Received %d bytes on HTTP stream", conn->input->nbytes); lcb_timer_rearm(http->io_timer, PROVIDER_SETTING(&http->base, config_node_timeout)); lcb_string_rbappend(&http->stream.chunk, conn->input, 1); err = htvb_parse(&http->stream, http->base.parent->settings->conntype); if (http->stream.generation != old_generation) { lcb_log(LOGARGS(http, DEBUG), "Generation %d -> %d", old_generation, http->stream.generation); set_new_config(http); } else { lcb_log(LOGARGS(http, TRACE), "HTTP not yet done. Err=0x%x", err); } if (err != LCB_BUSY && err != LCB_SUCCESS) { io_error(http, err); return; } lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); }
static void v0_generic_handler(lcb_socket_t sock, short which, void *arg) { lcb_connection_t conn = arg; lcb_sockrw_status_t status; lcb_size_t oldnr, newnr; lcb_assert(sock != INVALID_SOCKET); if (which & LCB_WRITE_EVENT) { status = lcb_sockrw_v0_write(conn, conn->output); if (status == LCB_SOCKRW_WROTE) { if ((which & LCB_READ_EVENT) == 0) { lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); } } else if (status == LCB_SOCKRW_WOULDBLOCK) { lcb_sockrw_set_want(conn, LCB_WRITE_EVENT, 0); lcb_sockrw_apply_want(conn); } else { conn->easy.error(conn); return; } } if ( (which & LCB_READ_EVENT) == 0) { return; } oldnr = conn->input->nbytes; status = lcb_sockrw_v0_slurp(conn, conn->input); newnr = conn->input->nbytes; if (status != LCB_SOCKRW_READ && status != LCB_SOCKRW_WOULDBLOCK && oldnr == newnr) { conn->easy.error(conn); } else { conn->easy.read(conn); } }
void lcb_server_connect_handler(lcb_connection_t conn, lcb_error_t err) { lcb_server_t *server = (lcb_server_t *)conn->data; struct nameinfo_common nistrs; int sasl_in_progress; int should_do_sasl = 0; if (err != LCB_SUCCESS) { connection_error(server, err); return; } server->inside_handler = 1; sasl_in_progress = (server->sasl_conn != NULL); if (!get_nameinfo(conn, &nistrs)) { /** This normally shouldn't happen! */ connection_error(server, LCB_NETWORK_ERROR); } if (!sasl_in_progress) { int sasl_ok = cbsasl_client_new("couchbase", conn->host, nistrs.local, nistrs.remote, server->instance->sasl.callbacks, 0, &server->sasl_conn); lcb_assert(sasl_ok == SASL_OK); } if (server->index == -1) { should_do_sasl = 1; } else if (vbucket_config_get_user(server->instance->config.handle) != NULL) { should_do_sasl = 1; } if (should_do_sasl) { if (!sasl_in_progress) { start_sasl_auth_server(server); } } else { /* No SASL AUTH needed */ lcb_server_connected(server); } lcb_connection_cancel_timer(conn); lcb_sockrw_apply_want(conn); server->inside_handler = 0; }
void lcb_server_send_packets(lcb_server_t *server) { if (server->pending.nbytes > 0 || server->connection.output->nbytes > 0) { if (server->connection_ready) { lcb_sockrw_set_want(&server->connection, LCB_WRITE_EVENT, 0); if (!server->inside_handler) { lcb_sockrw_apply_want(&server->connection); if (!lcb_timer_armed(server->io_timer)) { lcb_timer_rearm(server->io_timer, MCSERVER_TIMEOUT(server)); } } } else if (server->connection.state == LCB_CONNSTATE_UNINIT) { lcb_server_connect(server); } } }
static void config_v1_write_handler(lcb_sockdata_t *sockptr, lcb_io_writebuf_t *wbuf, int status) { lcb_t instance; lcb_connection_t conn = sockptr->lcbconn; if (!lcb_sockrw_v1_cb_common(sockptr, wbuf, (void **)&instance)) { return; } lcb_sockrw_v1_onwrite_common(sockptr, wbuf, &conn->output); if (status) { v1_error_common(instance); } lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); }
static void event_complete_common(lcb_server_t *c, lcb_error_t rc) { lcb_t instance = c->instance; if (rc != LCB_SUCCESS) { lcb_failout_server(c, rc); } else { if (c->is_config_node) { c->instance->weird_things = 0; } lcb_sockrw_apply_want(&c->connection); c->inside_handler = 0; } if (instance->compat.type == LCB_CACHED_CONFIG && instance->compat.value.cached.needs_update) { lcb_refresh_config_cache(instance); } lcb_maybe_breakout(instance); lcb_error_handler(instance, rc, NULL); }
static void v1_generic_write_handler(lcb_sockdata_t *sd, lcb_io_writebuf_t *wbuf, int status) { lcb_t instance; lcb_connection_t conn = sd->lcbconn; if (!lcb_sockrw_v1_cb_common(sd, wbuf, (void **)&instance)) { return; } lcb_sockrw_v1_onwrite_common(sd, wbuf, &sd->lcbconn->output); if (status) { conn->easy.error(conn); } else { lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); } }
static void connect_done_handler(lcb_connection_t conn, lcb_error_t err) { lcb_t instance = conn->instance; if (err == LCB_SUCCESS) { /** * Print the URI to the ringbuffer */ ringbuffer_strcat(conn->output, instance->bootstrap.via.http.uri); lcb_assert(conn->output->nbytes > 0); lcb_sockrw_set_want(conn, LCB_RW_EVENT, 0); lcb_sockrw_apply_want(conn); lcb_connection_activate_timer(conn); return; } if (err == LCB_ETIMEDOUT) { timeout_handler(conn, err); } else { lcb_bootstrap_error(instance, err, "Couldn't connect", 0); } }
static void io_read_handler(lcb_connection_t conn) { packet_info pi; cccp_provider *cccp = conn->data; lcb_string jsonstr; lcb_error_t err; int rv; lcb_host_t curhost; memset(&pi, 0, sizeof(pi)); rv = lcb_packet_read_ringbuffer(&pi, conn->input); if (rv < 0) { LOG(cccp, ERR, "Couldn't parse packet!?"); mcio_error(cccp, LCB_EINTERNAL); return; } else if (rv == 0) { lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); return; } if (PACKET_STATUS(&pi) != PROTOCOL_BINARY_RESPONSE_SUCCESS) { lcb_log(LOGARGS(cccp, ERR), "CCCP Packet responded with 0x%x; nkey=%d, nbytes=%lu, cmd=0x%x, seq=0x%x", PACKET_STATUS(&pi), PACKET_NKEY(&pi), PACKET_NBODY(&pi), PACKET_OPCODE(&pi), PACKET_OPAQUE(&pi)); switch (PACKET_STATUS(&pi)) { case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED: case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: mcio_error(cccp, LCB_NOT_SUPPORTED); break; default: mcio_error(cccp, LCB_PROTOCOL_ERROR); break; } return; } if (!PACKET_NBODY(&pi)) { mcio_error(cccp, LCB_PROTOCOL_ERROR); return; } if (lcb_string_init(&jsonstr)) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } if (lcb_string_append(&jsonstr, PACKET_BODY(&pi), PACKET_NBODY(&pi))) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } curhost = *lcb_connection_get_host(&cccp->connection); lcb_packet_release_ringbuffer(&pi, conn->input); release_socket(cccp, 1); err = lcb_cccp_update(&cccp->base, curhost.host, &jsonstr); lcb_string_release(&jsonstr); if (err == LCB_SUCCESS) { lcb_timer_disarm(cccp->timer); cccp->server_active = 0; } else { schedule_next_request(cccp, LCB_PROTOCOL_ERROR, 0); } }
/** * Common function to handle parsing the event loop for both v0 and v1 io * implementations. */ static lcb_error_t handle_vbstream_read(lcb_t instance) { lcb_error_t err; int can_retry = 0; int old_gen = instance->config.generation; struct lcb_http_bootstrap_st *http = &instance->bootstrap.via.http; lcb_connection_t conn = &instance->bootstrap.via.http.connection; err = lcb_parse_vbucket_stream(instance); if (err == LCB_SUCCESS) { if (instance->type == LCB_TYPE_BUCKET) { lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); } if (old_gen != instance->config.generation || instance->type == LCB_TYPE_CLUSTER) { lcb_connection_cancel_timer(conn); conn->timeout.usec = 0; lcb_maybe_breakout(instance); } return LCB_SUCCESS; } else if (err != LCB_BUSY) { /** * XXX: We only want to retry on some errors. Things which signify an * obvious user error should be left out here; we only care about * actual "network" errors */ switch (err) { case LCB_ENOMEM: case LCB_AUTH_ERROR: case LCB_PROTOCOL_ERROR: case LCB_BUCKET_ENOENT: can_retry = 0; break; default: can_retry = 1; } if (http->bummer && (err == LCB_BUCKET_ENOENT || err == LCB_AUTH_ERROR)) { can_retry = 1; } if (can_retry) { const char *msg = "Failed to get configuration"; lcb_bootstrap_error(instance, err, msg, LCB_CONFERR_NO_BREAKOUT); return err; } else { lcb_maybe_breakout(instance); return lcb_error_handler(instance, err, ""); } } lcb_assert(err == LCB_BUSY); lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); if (old_gen != instance->config.generation) { lcb_connection_cancel_timer(conn); conn->timeout.usec = 0; lcb_maybe_breakout(instance); } return LCB_BUSY; }