static entity *create_server (entity_types type, int index, char *pargs) { entity *en; validate_client_server_local_fn (); en = create_local (type, index, pargs); if (en) { validate_client_server_remote_fn (); create_remote (type, get_local_entity_index (en), pargs); } return (en); }
static entity *create_client (entity_types type, int index, char *pargs) { entity *en; if (get_comms_data_flow () == COMMS_DATA_FLOW_TX) { validate_client_server_remote_fn (); en = create_remote (type, index, pargs); } else { validate_client_server_local_fn (); en = create_local (type, index, pargs); } return (en); }
struct remote *add_remote(struct set *ss, char *name) { struct remote *rs; struct remote **tmp; rs = create_remote(name); if(rs == NULL){ return NULL; } tmp = realloc(ss->s_vector, sizeof(struct remote *) * (ss->s_count + 1)); if(tmp == NULL){ destroy_remote(rs); return NULL; } ss->s_vector = tmp; ss->s_vector[ss->s_count] = rs; ss->s_count++; return rs; }
static void server_recv_cb(EV_P_ ev_io *w, int revents) { struct server_ctx *server_recv_ctx = (struct server_ctx *)w; struct server *server = server_recv_ctx->server; struct remote *remote = server->remote; char *buf; if (remote == NULL) { buf = server->buf; } else { buf = remote->buf; } ssize_t r; r = recv(server->fd, buf, BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server_recv_cb_recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } while (1) { // local socks5 server if (server->stage == 5) { if (remote == NULL) { LOGE("invalid remote"); close_and_free_server(EV_A_ server); return; } if (!remote->direct && remote->send_ctx->connected && auth) { remote->buf = ss_gen_hash(remote->buf, &r, &remote->counter, server->e_ctx, BUF_SIZE); } // insert shadowsocks header if (!remote->direct) { remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx); if (remote->buf == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (!remote->send_ctx->connected) { #ifdef ANDROID if (vpn) { if (protect_socket(remote->fd) == -1) { ERROR("protect_socket"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } #endif remote->buf_idx = 0; remote->buf_len = r; if (!fast_open || remote->direct) { // connecting, wait until connected connect(remote->fd, (struct sockaddr *)&(remote->addr), remote->addr_len); // wait on remote connected event ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } else { #ifdef TCP_FASTOPEN int s = sendto(remote->fd, remote->buf, r, MSG_FASTOPEN, (struct sockaddr *)&(remote->addr), remote->addr_len); if (s == -1) { if (errno == EINPROGRESS) { // in progress, wait until connected remote->buf_idx = 0; remote->buf_len = r; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("sendto"); if (errno == ENOTCONN) { LOGE( "fast open is not supported on this platform"); // just turn it off fast_open = 0; } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < r) { remote->buf_len = r - s; remote->buf_idx = s; } // Just connected remote->send_ctx->connected = 1; ev_timer_stop(EV_A_ & remote->send_ctx->watcher); ev_io_start(EV_A_ & remote->recv_ctx->io); #else // if TCP_FASTOPEN is not defined, fast_open will always be 0 LOGE("can't come here"); exit(1); #endif } } else { int s = send(remote->fd, remote->buf, r, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf_idx = 0; remote->buf_len = r; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("server_recv_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < r) { remote->buf_len = r - s; remote->buf_idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } } // all processed return; } else if (server->stage == 0) { struct method_select_response response; response.ver = SVERSION; response.method = 0; char *send_buf = (char *)&response; send(server->fd, send_buf, sizeof(response), 0); server->stage = 1; return; } else if (server->stage == 1) { struct socks5_request *request = (struct socks5_request *)buf; struct sockaddr_in sock_addr; memset(&sock_addr, 0, sizeof(sock_addr)); int udp_assc = 0; if (mode != TCP_ONLY && request->cmd == 3) { udp_assc = 1; socklen_t addr_len = sizeof(sock_addr); getsockname(server->fd, (struct sockaddr *)&sock_addr, &addr_len); if (verbose) { LOGI("udp assc request accepted"); } } else if (request->cmd != 1) { LOGE("unsupported cmd: %d", request->cmd); struct socks5_response response; response.ver = SVERSION; response.rep = CMD_NOT_SUPPORTED; response.rsv = 0; response.atyp = 1; char *send_buf = (char *)&response; send(server->fd, send_buf, 4, 0); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { char host[256], port[16]; char ss_addr_to_send[320]; ssize_t addr_len = 0; ss_addr_to_send[addr_len++] = request->atyp; // get remote addr and port if (request->atyp == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); memcpy(ss_addr_to_send + addr_len, buf + 4, in_addr_len + 2); addr_len += in_addr_len + 2; if (acl || verbose) { uint16_t p = ntohs(*(uint16_t *)(buf + 4 + in_addr_len)); dns_ntop(AF_INET, (const void *)(buf + 4), host, INET_ADDRSTRLEN); sprintf(port, "%d", p); } } else if (request->atyp == 3) { // Domain name uint8_t name_len = *(uint8_t *)(buf + 4); ss_addr_to_send[addr_len++] = name_len; memcpy(ss_addr_to_send + addr_len, buf + 4 + 1, name_len + 2); addr_len += name_len + 2; if (acl || verbose) { uint16_t p = ntohs(*(uint16_t *)(buf + 4 + 1 + name_len)); memcpy(host, buf + 4 + 1, name_len); host[name_len] = '\0'; sprintf(port, "%d", p); } } else if (request->atyp == 4) { // IP V6 size_t in6_addr_len = sizeof(struct in6_addr); memcpy(ss_addr_to_send + addr_len, buf + 4, in6_addr_len + 2); addr_len += in6_addr_len + 2; if (acl || verbose) { uint16_t p = ntohs(*(uint16_t *)(buf + 4 + in6_addr_len)); dns_ntop(AF_INET6, (const void *)(buf + 4), host, INET6_ADDRSTRLEN); sprintf(port, "%d", p); } } else { LOGE("unsupported addrtype: %d", request->atyp); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } server->stage = 5; r -= (3 + addr_len); buf += (3 + addr_len); if (verbose) { LOGI("connect to %s:%s", host, port); } if ((acl && (request->atyp == 1 || request->atyp == 4) && acl_contains_ip(host))) { if (verbose) { LOGI("bypass %s:%s", host, port); } struct sockaddr_storage storage; memset(&storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, &storage, 0) != -1) { remote = create_remote(server->listener, (struct sockaddr *)&storage); remote->direct = 1; } } else { remote = create_remote(server->listener, NULL); } if (remote == NULL) { LOGE("invalid remote addr"); close_and_free_server(EV_A_ server); return; } if (!remote->direct) { if (auth) { ss_addr_to_send[0] |= ONETIMEAUTH_FLAG; ss_onetimeauth(ss_addr_to_send + addr_len, ss_addr_to_send, addr_len, server->e_ctx); addr_len += ONETIMEAUTH_BYTES; } memcpy(remote->buf, ss_addr_to_send, addr_len); if (r > 0) { if (auth) { buf = ss_gen_hash(buf, &r, &remote->counter, server->e_ctx, BUF_SIZE); } memcpy(remote->buf + addr_len, buf, r); } r += addr_len; } else { if (r > 0) { memcpy(remote->buf, buf, r); } } server->remote = remote; remote->server = server; } // Fake reply struct socks5_response response; response.ver = SVERSION; response.rep = 0; response.rsv = 0; response.atyp = 1; memcpy(server->buf, &response, sizeof(struct socks5_response)); memcpy(server->buf + sizeof(struct socks5_response), &sock_addr.sin_addr, sizeof(sock_addr.sin_addr)); memcpy(server->buf + sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr), &sock_addr.sin_port, sizeof(sock_addr.sin_port)); int reply_size = sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port); int s = send(server->fd, server->buf, reply_size, 0); if (s < reply_size) { LOGE("failed to send fake reply"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if (udp_assc) { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } }
static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; buffer_t *buf; if (remote == NULL) { buf = server->buf; } else { buf = remote->buf; } ssize_t r; r = recv(server->fd, buf->array, BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server_recv_cb_recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } buf->len = r; while (1) { // local socks5 server if (server->stage == 5) { if (remote == NULL) { LOGE("invalid remote"); close_and_free_server(EV_A_ server); return; } if (!remote->direct && remote->send_ctx->connected && auth) { ss_gen_hash(remote->buf, &remote->counter, server->e_ctx); } // insert shadowsocks header if (!remote->direct) { // SSR beg if (server->protocol_plugin) { obfs_class *protocol_plugin = server->protocol_plugin; if (protocol_plugin->client_pre_encrypt) { remote->buf->len = protocol_plugin->client_pre_encrypt(server->protocol, &remote->buf->array, remote->buf->len, &remote->buf->capacity); } } int err = ss_encrypt(remote->buf, server->e_ctx); if (err) { LOGE("server invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if (server->obfs_plugin) { obfs_class *obfs_plugin = server->obfs_plugin; if (obfs_plugin->client_encode) { remote->buf->len = obfs_plugin->client_encode(server->obfs, &remote->buf->array, remote->buf->len, &remote->buf->capacity); } } // SSR end #ifdef ANDROID tx += r; #endif } if (!remote->send_ctx->connected) { #ifdef ANDROID if (vpn) { if (protect_socket(remote->fd) == -1) { ERROR("protect_socket"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } #endif remote->buf->idx = 0; if (!fast_open || remote->direct) { // connecting, wait until connected connect(remote->fd, (struct sockaddr *)&(remote->addr), remote->addr_len); // wait on remote connected event ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } else { #ifdef TCP_FASTOPEN #ifdef __APPLE__ ((struct sockaddr_in*)&(remote->addr))->sin_len = sizeof(struct sockaddr_in); sa_endpoints_t endpoints; bzero((char*)&endpoints, sizeof(endpoints)); endpoints.sae_dstaddr = (struct sockaddr*)&(remote->addr); endpoints.sae_dstaddrlen = remote->addr_len; int s = connectx(remote->fd, &endpoints, SAE_ASSOCID_ANY, CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL); if (s == 0) { s = send(remote->fd, remote->buf->array, remote->buf->len, 0); } #else int s = sendto(remote->fd, remote->buf->array, remote->buf->len, MSG_FASTOPEN, (struct sockaddr *)&(remote->addr), remote->addr_len); #endif if (s == -1) { if (errno == EINPROGRESS) { // in progress, wait until connected remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("sendto"); if (errno == ENOTCONN) { LOGE( "fast open is not supported on this platform"); // just turn it off fast_open = 0; } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s <= remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; } // Just connected remote->send_ctx->connected = 1; ev_timer_stop(EV_A_ & remote->send_ctx->watcher); ev_io_start(EV_A_ & remote->recv_ctx->io); #else // if TCP_FASTOPEN is not defined, fast_open will always be 0 LOGE("can't come here"); exit(1); #endif } } else { int s = send(remote->fd, remote->buf->array, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("server_recv_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } } // all processed return; } else if (server->stage == 0) { struct method_select_response response; response.ver = SVERSION; response.method = 0; char *send_buf = (char *)&response; send(server->fd, send_buf, sizeof(response), 0); server->stage = 1; int off = (buf->array[1] & 0xff) + 2; if (buf->array[0] == 0x05 && off < buf->len) { memmove(buf->array, buf->array + off, buf->len - off); buf->len -= off; continue; } return; } else if (server->stage == 1) { struct socks5_request *request = (struct socks5_request *)buf->array; struct sockaddr_in sock_addr; memset(&sock_addr, 0, sizeof(sock_addr)); int udp_assc = 0; if (mode != TCP_ONLY && request->cmd == 3) { udp_assc = 1; socklen_t addr_len = sizeof(sock_addr); getsockname(server->fd, (struct sockaddr *)&sock_addr, &addr_len); if (verbose) { LOGI("udp assc request accepted"); } } else if (request->cmd != 1) { LOGE("unsupported cmd: %d", request->cmd); struct socks5_response response; response.ver = SVERSION; response.rep = CMD_NOT_SUPPORTED; response.rsv = 0; response.atyp = 1; char *send_buf = (char *)&response; send(server->fd, send_buf, 4, 0); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { char host[256], port[16]; buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); abuf->array[abuf->len++] = request->atyp; // get remote addr and port if (request->atyp == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->array + abuf->len, buf->array + 4, in_addr_len + 2); abuf->len += in_addr_len + 2; if (acl || verbose) { uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + in_addr_len)); dns_ntop(AF_INET, (const void *)(buf->array + 4), host, INET_ADDRSTRLEN); sprintf(port, "%d", p); } } else if (request->atyp == 3) { // Domain name uint8_t name_len = *(uint8_t *)(buf->array + 4); abuf->array[abuf->len++] = name_len; memcpy(abuf->array + abuf->len, buf->array + 4 + 1, name_len + 2); abuf->len += name_len + 2; if (acl || verbose) { uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + 1 + name_len)); memcpy(host, buf->array + 4 + 1, name_len); host[name_len] = '\0'; sprintf(port, "%d", p); } } else if (request->atyp == 4) { // IP V6 size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->array + abuf->len, buf->array + 4, in6_addr_len + 2); abuf->len += in6_addr_len + 2; if (acl || verbose) { uint16_t p = ntohs(*(uint16_t *)(buf->array + 4 + in6_addr_len)); dns_ntop(AF_INET6, (const void *)(buf->array + 4), host, INET6_ADDRSTRLEN); sprintf(port, "%d", p); } } else { bfree(abuf); LOGE("unsupported addrtype: %d", request->atyp); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } server->stage = 5; buf->len -= (3 + abuf->len); if (buf->len > 0) { memmove(buf->array, buf->array + 3 + abuf->len, buf->len); } if (verbose) { LOGI("connect to %s:%s", host, port); } if ((acl && (request->atyp == 1 || request->atyp == 4) && acl_match_ip(host))) { if (verbose) { LOGI("bypass %s:%s", host, port); } struct sockaddr_storage storage; memset(&storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, &storage, 0) != -1) { remote = create_remote(server->listener, (struct sockaddr *)&storage); remote->direct = 1; } } else { remote = create_remote(server->listener, NULL); } if (remote == NULL) { bfree(abuf); LOGE("invalid remote addr"); close_and_free_server(EV_A_ server); return; } // SSR beg if (server->listener->list_obfs_global[remote->remote_index] == NULL && server->obfs_plugin) { server->listener->list_obfs_global[remote->remote_index] = server->obfs_plugin->init_data(); } if (server->listener->list_protocol_global[remote->remote_index] == NULL && server->protocol_plugin) { server->listener->list_protocol_global[remote->remote_index] = server->protocol_plugin->init_data(); } server_info _server_info; memset(&_server_info, 0, sizeof(server_info)); strcpy(_server_info.host, inet_ntoa(((struct sockaddr_in*)&remote->addr)->sin_addr)); _server_info.port = ((struct sockaddr_in*)&remote->addr)->sin_port; _server_info.port = _server_info.port >> 8 | _server_info.port << 8; _server_info.param = server->listener->obfs_param; _server_info.g_data = server->listener->list_obfs_global[remote->remote_index]; _server_info.head_len = get_head_size(ss_addr_to_send.array, 320, 30); _server_info.iv = server->e_ctx->evp.iv; _server_info.iv_len = enc_get_iv_len(); _server_info.key = enc_get_key(); _server_info.key_len = enc_get_key_len(); _server_info.tcp_mss = 1440; if (server->obfs_plugin) server->obfs_plugin->set_server_info(server->obfs, &_server_info); _server_info.param = NULL; _server_info.g_data = server->listener->list_protocol_global[remote->remote_index]; if (server->protocol_plugin) server->protocol_plugin->set_server_info(server->protocol, &_server_info); // SSR end if (!remote->direct) { if (auth) { abuf->array[0] |= ONETIMEAUTH_FLAG; ss_onetimeauth(abuf, server->e_ctx->evp.iv); } brealloc(remote->buf, buf->len + abuf->len, BUF_SIZE); memcpy(remote->buf->array, abuf->array, abuf->len); remote->buf->len = buf->len + abuf->len; if (buf->len > 0) { if (auth) { ss_gen_hash(buf, &remote->counter, server->e_ctx); } memcpy(remote->buf->array + abuf->len, buf->array, buf->len); } } else { if (buf->len > 0) { memcpy(remote->buf->array, buf->array, buf->len); remote->buf->len = buf->len; } } server->remote = remote; remote->server = server; bfree(abuf); } // Fake reply struct socks5_response response; response.ver = SVERSION; response.rep = 0; response.rsv = 0; response.atyp = 1; memcpy(server->buf->array, &response, sizeof(struct socks5_response)); memcpy(server->buf->array + sizeof(struct socks5_response), &sock_addr.sin_addr, sizeof(sock_addr.sin_addr)); memcpy(server->buf->array + sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr), &sock_addr.sin_port, sizeof(sock_addr.sin_port)); int reply_size = sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port); int s = send(server->fd, server->buf->array, reply_size, 0); if (s < reply_size) { LOGE("failed to send fake reply"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if (udp_assc) { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } }
nodes_data::ptr start_nodes(std::ostream &debug_stream, const std::vector<config_data> &configs, const std::string &path) { nodes_data::ptr data = std::make_shared<nodes_data>(); std::string base_path; std::string auth_cookie; std::string cocaine_config_template = read_file(COCAINE_CONFIG_PATH); std::string run_path; { char buffer[1024]; snprintf(buffer, sizeof(buffer), "%04x%04x", rand(), rand()); buffer[sizeof(buffer) - 1] = 0; auth_cookie = buffer; snprintf(buffer, sizeof(buffer), "/tmp/elliptics-test-run-%04x/", rand()); buffer[sizeof(buffer) - 1] = 0; run_path = buffer; } const auto ports = generate_ports(configs.size()); if (path.empty()) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "/tmp/elliptics-test-%04x/", rand()); buffer[sizeof(buffer) - 1] = 0; base_path = buffer; create_directory(base_path); data->directory = directory_handler(base_path, true); } else { base_path = path; create_directory(base_path); data->directory = directory_handler(base_path, false); } debug_stream << "Set base directory: \"" << base_path << "\"" << std::endl; create_directory(run_path); data->run_directory = directory_handler(run_path, true); debug_stream << "Set cocaine run directory: \"" << run_path << "\"" << std::endl; std::string cocaine_remotes; for (size_t j = 0; j < configs.size(); ++j) { if (j > 0) cocaine_remotes += ", "; cocaine_remotes += "\"localhost\": " + ports[j]; } const auto cocaine_locator_ports = generate_ports(configs.size()); // client only needs connection to one (any) locator service data->locator_port = std::stoul(cocaine_locator_ports[0]); debug_stream << "Starting " << configs.size() << " servers" << std::endl; for (size_t i = 0; i < configs.size(); ++i) { debug_stream << "Starting server #" << (i + 1) << std::endl; const std::string server_path = base_path + "/server-" + boost::lexical_cast<std::string>(i + 1); create_directory(server_path); create_directory(server_path + "/blob"); create_directory(server_path + "/history"); std::string remotes; for (size_t j = 0; j < configs.size(); ++j) { if (j == i) continue; remotes += create_remote(ports[j]); } config_data config = configs[i]; if (remotes.empty()) config("remote", NULL_VALUE); else config("remote", remotes); if (config.has_value("srw_config")) { create_directory(server_path + "/run"); const substitute_context cocaine_variables = { { "COCAINE_LOCATOR_PORT", cocaine_locator_ports[i] }, { "COCAINE_PLUGINS_PATH", COCAINE_PLUGINS_PATH }, { "ELLIPTICS_REMOTES", cocaine_remotes }, { "ELLIPTICS_GROUPS", "1" }, { "COCAINE_LOG_PATH", server_path + "/cocaine.log" }, { "COCAINE_RUN_PATH", run_path } }; create_cocaine_config(server_path + "/cocaine.conf", cocaine_config_template, cocaine_variables); config("srw_config", server_path + "/cocaine.conf"); } create_config(config, server_path + "/ioserv.conf") ("auth_cookie", auth_cookie) ("log", server_path + "/log.log") ("addr", create_remote(ports[i])) ("history", server_path + "/history") ("data", server_path + "/blob/data") ; server_node server(server_path + "/ioserv.conf", create_remote(ports[i])); server.start(); debug_stream << "Started server #" << (i + 1) << std::endl; data->nodes.emplace_back(std::move(server)); } { std::vector<std::string> remotes; for (size_t i = 0; i < data->nodes.size(); ++i) { remotes.push_back(data->nodes[i].remote()); } start_client_nodes(data, debug_stream, remotes); } return data; }
nodes_data::ptr start_nodes(std::ostream &debug_stream, const std::vector<server_config> &configs, const std::string &path) { nodes_data::ptr data = std::make_shared<nodes_data>(); std::string base_path; std::string auth_cookie; std::string cocaine_config_template = read_file(COCAINE_CONFIG_PATH); std::string run_path; { char buffer[1024]; snprintf(buffer, sizeof(buffer), "%04x%04x", rand(), rand()); buffer[sizeof(buffer) - 1] = 0; auth_cookie = buffer; snprintf(buffer, sizeof(buffer), "/tmp/elliptics-test-run-%04x/", rand()); buffer[sizeof(buffer) - 1] = 0; run_path = buffer; } std::set<std::string> all_ports; const auto ports = generate_ports(configs.size(), all_ports); const auto monitor_ports = generate_ports(configs.size(), all_ports); if (path.empty()) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "/tmp/elliptics-test-%04x/", rand()); buffer[sizeof(buffer) - 1] = 0; base_path = buffer; create_directory(base_path); data->directory = directory_handler(base_path, true); } else { #if BOOST_VERSION >= 104600 boost::filesystem::path boost_path = boost::filesystem::absolute(path); #else boost::filesystem::path boost_path = boost::filesystem::complete(path, boost::filesystem::current_path()); #endif base_path = boost_path.string(); create_directory(base_path); data->directory = directory_handler(base_path, false); } debug_stream << "Set base directory: \"" << base_path << "\"" << std::endl; create_directory(run_path); data->run_directory = directory_handler(run_path, true); debug_stream << "Set cocaine run directory: \"" << run_path << "\"" << std::endl; std::set<std::string> cocaine_unique_groups; std::string cocaine_remotes; std::string cocaine_groups; for (size_t j = 0; j < configs.size(); ++j) { if (j > 0) cocaine_remotes += ", "; cocaine_remotes += "\"localhost:" + ports[j] + ":2\""; const std::string group = configs[j].options.string_value("group"); if (cocaine_unique_groups.find(group) == cocaine_unique_groups.end()) { if (!cocaine_groups.empty()) cocaine_groups += ", "; cocaine_groups += group; } } const auto cocaine_locator_ports = generate_ports(configs.size(), all_ports); // client only needs connection to one (any) locator service data->locator_port = std::stoul(cocaine_locator_ports[0]); debug_stream << "Starting " << configs.size() << " servers" << std::endl; for (size_t i = 0; i < configs.size(); ++i) { debug_stream << "Starting server #" << (i + 1) << std::endl; const std::string server_suffix = "/server-" + boost::lexical_cast<std::string>(i + 1); const std::string server_path = base_path + server_suffix; create_directory(server_path); create_directory(server_path + "/blob"); create_directory(server_path + "/history"); std::vector<std::string> remotes; for (size_t j = 0; j < configs.size(); ++j) { if (j == i) continue; remotes.push_back(create_remote(ports[j])); } server_config config = configs[i]; if (!remotes.empty()) config.options("remote", remotes); if (config.options.has_value("srw_config")) { const std::string server_run_path = run_path + server_suffix; create_directory(server_run_path); const substitute_context cocaine_variables = { { "COCAINE_LOCATOR_PORT", cocaine_locator_ports[i] }, { "COCAINE_PLUGINS_PATH", COCAINE_PLUGINS_PATH }, { "ELLIPTICS_REMOTES", cocaine_remotes }, { "ELLIPTICS_GROUPS", cocaine_groups }, { "COCAINE_LOG_PATH", server_path + "/cocaine.log" }, { "COCAINE_RUN_PATH", server_run_path } }; create_cocaine_config(server_path + "/cocaine.conf", cocaine_config_template, cocaine_variables); config.options("srw_config", server_path + "/cocaine.conf"); } if (config.log_path.empty()) config.log_path = server_path + "/log.log"; config.options ("auth_cookie", auth_cookie) ("address", std::vector<std::string>(1, create_remote(ports[i]))) ("monitor_port", boost::lexical_cast<int>(monitor_ports[i])) ; config.backends[0] ("history", server_path + "/history") ("data", server_path + "/blob/data") ; config.write(server_path + "/ioserv.conf"); server_node server(server_path + "/ioserv.conf", create_remote(ports[i]), boost::lexical_cast<int>(monitor_ports[i])); try { server.start(); } catch (...) { std::ifstream in; in.open(config.log_path.c_str()); try { if (in) { std::string line; while (std::getline(in, line)) debug_stream << line << std::endl; } } catch (...) { } throw; } debug_stream << "Started server #" << (i + 1) << std::endl; data->nodes.emplace_back(std::move(server)); } { std::vector<std::string> remotes; for (size_t i = 0; i < data->nodes.size(); ++i) { remotes.push_back(data->nodes[i].remote()); } start_client_nodes(data, debug_stream, remotes); } return data; }