apr_status_t server_init_child_stat(dav_rawx_server_conf *conf, apr_pool_t *pool, apr_pool_t *plog) { char buff[256]; apr_status_t rc; DAV_XDEBUG_POOL(plog, 0, "%s()", __FUNCTION__); /* Attaches the mutex */ DAV_DEBUG_POOL(plog, 0, "%s : Attaching the SHM global_mutex at [%s]", __FUNCTION__, conf->shm.path); rc = apr_global_mutex_child_init(&(conf->lock.handle), conf->shm.path, pool); if (APR_SUCCESS != rc) { DAV_ERROR_POOL(plog, 0, "%s : Failed to attach the SHM global_mutex at [%s] rc=%d : %s", __FUNCTION__, conf->shm.path, rc, apr_strerror(rc, buff, sizeof(buff))); return rc; } DAV_DEBUG_POOL(plog, 0, "%s : globalmutex attached at [%s]", __FUNCTION__, conf->shm.path); /* Atatches the SHM */ if (!conf->shm.handle) { DAV_DEBUG_POOL(plog, 0, "%s : Attaching the SHM segment at [%s]", __FUNCTION__, conf->shm.path); rc = apr_shm_attach(&(conf->shm.handle), conf->shm.path, pool); if (APR_SUCCESS != rc) { DAV_ERROR_POOL(plog, 0, "%s : Failed to attach the SHM segment at [%s] rc=%d : %s", __FUNCTION__, conf->shm.path, rc, apr_strerror(rc, buff, sizeof(buff))); conf->shm.handle = NULL; return rc; } } DAV_DEBUG_POOL(plog, 0, "%s : SHM segment attached at [%s]", __FUNCTION__, conf->shm.path); return APR_SUCCESS; }
static const char * dav_rainx_cmd_gridconfig_sock_timeout(cmd_parms *cmd, void *config, const char *arg1) { dav_rainx_server_conf *conf; apr_int64_t socket_timeout; char *endstr; (void) config; DAV_XDEBUG_POOL(cmd->pool, 0, "%s()", __FUNCTION__); conf = ap_get_module_config(cmd->server->module_config, &dav_rainx_module); socket_timeout = apr_strtoi64(arg1, &endstr, 10); if (errno == 0 && *endstr == '\0') { conf->socket_timeout = socket_timeout; } else { DAV_ERROR_POOL(cmd->pool, 0, "Invalid socket timeout, default value will be used"); } DAV_DEBUG_POOL(cmd->pool, 0, "Socket timeout for rawx request is %" APR_TIME_T_FMT " microseconds", conf->socket_timeout); return NULL; }
apr_status_t server_init_master_stat(dav_rawx_server_conf *conf, apr_pool_t *pool, apr_pool_t *plog) { char buff[256]; apr_status_t rc; DAV_XDEBUG_POOL(plog, 0, "%s()", __FUNCTION__); /* Try to attach to the already existing SHM segment */ rc = apr_shm_attach(&(conf->shm.handle), conf->shm.path, pool); if (APR_SUCCESS != rc) { DAV_DEBUG_POOL(plog, 0, "%s: Failed to attach to SHM segment at [%s]: %s", __FUNCTION__, conf->shm.path, apr_strerror(rc, buff, sizeof(buff))); conf->shm.handle = NULL; return rc; } DAV_DEBUG_POOL(plog, 0, "%s: Attached to existing SHM segment at [%s]", __FUNCTION__, conf->shm.path); /* Create a processus lock*/ rc = apr_global_mutex_create(&(conf->lock.handle), conf->shm.path, APR_LOCK_DEFAULT, pool); if (rc != APR_SUCCESS) { DAV_ERROR_POOL(plog, 0, "%s : Cannot create a global_mutex at [%s] rc=%d : %s", __FUNCTION__, conf->shm.path, rc, apr_strerror(rc, buff, sizeof(buff))); (void) apr_shm_destroy(conf->shm.handle); conf->shm.handle = NULL; return rc; } DAV_DEBUG_POOL(plog, 0, "%s : globalmutex created at [%s]", __FUNCTION__, conf->shm.path); return APR_SUCCESS; }
apr_status_t server_init_master_stat(dav_rainx_server_conf *conf, apr_pool_t *pool, apr_pool_t *plog) { char buff[256]; apr_status_t rc; DAV_XDEBUG_POOL(plog, 0, "%s()", __FUNCTION__); /* Create and attach the segment */ rc = apr_shm_create(&(conf->shm.handle), sizeof(struct shm_stats_s), conf->shm.path, pool); if (APR_SUCCESS != rc) { DAV_ERROR_POOL(plog, 0, "%s : Cannot create a SHM segment at [%s] rc=%d : %s", __FUNCTION__, conf->shm.path, rc, apr_strerror(rc, buff, sizeof(buff))); conf->shm.handle = NULL; return rc; } DAV_DEBUG_POOL(plog, 0, "%s : SHM segment created at [%s]", __FUNCTION__, conf->shm.path); /* Create a processus lock*/ rc = apr_global_mutex_create(&(conf->lock.handle), conf->lock.path, APR_LOCK_DEFAULT, pool); if (rc != APR_SUCCESS) { DAV_ERROR_POOL(plog, 0, "%s : Cannot create a global_mutex at [%s] rc=%d : %s", __FUNCTION__, conf->lock.path, rc, apr_strerror(rc, buff, sizeof(buff))); (void) apr_shm_destroy(conf->shm.handle); conf->shm.handle = NULL; return rc; } DAV_DEBUG_POOL(plog, 0, "%s : globalmutex created at [%s]", __FUNCTION__, conf->lock.path); /* Init the SHM */ void *ptr_counter = apr_shm_baseaddr_get(conf->shm.handle); if (ptr_counter) { bzero(ptr_counter, sizeof(struct shm_stats_s)); /* init rrd's */ rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_sec)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_duration)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_put_sec)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_put_duration)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_get_sec)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_get_duration)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_del_sec)); rainx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_del_duration)); } return APR_SUCCESS; }
void server_master_stat_fini(dav_rawx_server_conf *conf, apr_pool_t *plog) { DAV_XDEBUG_POOL(plog, 0, "%s()", __FUNCTION__); if (conf->lock.handle) { DAV_DEBUG_POOL(plog, 0, "%s: Destroying the globalmutex at [%s]", __FUNCTION__, conf->shm.path); if (APR_SUCCESS != apr_global_mutex_destroy(conf->lock.handle)) { DAV_ERROR_POOL(plog, 0, "Failed to destroy the global_mutex"); } conf->lock.handle = NULL; } if (conf->shm.handle) { DAV_DEBUG_POOL(plog, 0, "%s: Detaching the SHM segment at [%s]", __FUNCTION__, conf->shm.path); if (APR_SUCCESS != apr_shm_detach(conf->shm.handle)) { DAV_ERROR_POOL(plog, 0, "Failed to detach the SHM segment"); } conf->shm.handle = NULL; } }
static void rainx_hook_child_init(apr_pool_t *pchild, server_rec *s) { apr_status_t status; dav_rainx_server_conf *conf; DAV_XDEBUG_POOL(pchild, 0, "%s()", __FUNCTION__); conf = ap_get_module_config(s->module_config, &dav_rainx_module); conf->cleanup = _stat_cleanup_child; status = server_init_child_stat(conf, pchild, pchild); if (APR_SUCCESS != status) DAV_ERROR_POOL(pchild, 0, "Failed to attach the RAWX statistics support"); conf->cleanup = _stat_cleanup_child; }
static apr_status_t _create_shm_if_needed(char *shm_path, server_rec *server, apr_pool_t *plog) { apr_pool_t *ppool = server->process->pool; apr_shm_t *shm = NULL; apr_status_t rc; // Test if an SHM segment already exists apr_pool_userdata_get((void**)&shm, SHM_HANDLE_KEY, ppool); if (shm == NULL) { DAV_DEBUG_POOL(plog, 0, "%s: Creating SHM segment at [%s]", __FUNCTION__, shm_path); // Create a new SHM segment rc = apr_shm_create(&shm, sizeof(struct shm_stats_s), shm_path, ppool); if (rc != APR_SUCCESS) { char buff[256]; DAV_ERROR_POOL(plog, 0, "Failed to create the SHM segment at [%s]: %s", shm_path, apr_strerror(rc, buff, sizeof(buff))); return rc; } /* Init the SHM */ void *ptr_counter = apr_shm_baseaddr_get(shm); if (ptr_counter) { memset(ptr_counter, 0, sizeof(struct shm_stats_s)); /* init rrd's */ rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_sec)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_duration)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_put_sec)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_put_duration)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_get_sec)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_get_duration)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_req_del_sec)); rawx_stats_rrd_init(&(((struct shm_stats_s *) ptr_counter)->body.rrd_del_duration)); } // Save the SHM handle in the process' pool, without cleanup callback apr_pool_userdata_set(shm, SHM_HANDLE_KEY, NULL, ppool); // Register the cleanup callback to be executed BEFORE pool cleanup apr_pool_pre_cleanup_register(ppool, shm, _destroy_shm_cb); } else { DAV_DEBUG_POOL(plog, 0, "%s: Found an already created SHM segment", __FUNCTION__); } return APR_SUCCESS; }
apr_status_t server_child_stat_fini(dav_rawx_server_conf *conf, apr_pool_t *plog) { char buff[256]; apr_status_t rc; DAV_XDEBUG_POOL(plog, 0, "%s()", __FUNCTION__); /* Detaches the segment */ if (conf->shm.handle) { rc = apr_shm_detach(conf->shm.handle); if (APR_SUCCESS != rc) { DAV_ERROR_POOL(plog, 0, "Failed to detach SHM segment at [%s] rc=%d : %s", conf->shm.path, rc, apr_strerror(rc, buff, sizeof(buff))); return rc; } conf->shm.handle = NULL; } DAV_DEBUG_POOL(plog, 0, "%s: SHM segment at [%s] detached", __FUNCTION__, conf->shm.path); return APR_SUCCESS; }
apr_status_t rainx_http_req(struct req_params_store* rps) { const dav_resource* resource = rps->resource; char* remote_uri = rps->service_address; char* req_type = rps->req_type; char* header = rps->header; char* data = rps->data_to_send; int data_length = rps->data_to_send_size; char** reply = &(rps->reply); apr_pool_t *local_pool = rps->pool; dav_rainx_server_conf *server_conf = resource_get_server_config(resource); if (NULL == resource || NULL == remote_uri || NULL == req_type || NULL == server_conf) { DAV_ERROR_POOL(local_pool, APR_EINVAL, "One of these params is wrong: " "remote_uri=%p, req_type=%p, server_conf=%p" " (__FILE__:__LINE__)", remote_uri, req_type, server_conf); return APR_EINVAL; } const gboolean is_get = (0 == g_strcmp0(req_type, "GET")); /* Isolating Rawx IP and port */ char *temp_remote_uri = apr_pstrdup(local_pool, remote_uri); char* last; char* full_remote_url = apr_strtok(temp_remote_uri, "/", &last); char* content_hexid = apr_pstrdup(local_pool, remote_uri + strlen(full_remote_url)); char* remote_ip = NULL; char* scope_id = NULL; apr_port_t remote_port; apr_parse_addr_port(&remote_ip, &scope_id, &remote_port, full_remote_url, local_pool); /* ------- */ /* Preparing the socket */ apr_socket_t* sock; apr_sockaddr_t* sockaddr; apr_status_t status; if ((status = apr_sockaddr_info_get(&sockaddr, remote_ip, APR_INET, remote_port, 0, local_pool)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to connect to the rawx %s", full_remote_url); return status; } if ((status = apr_socket_create(&sock, sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, local_pool)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to create a socket to the rawx %s", full_remote_url); return status; } if ((status = apr_socket_timeout_set(sock, server_conf->socket_timeout)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to set timeout for the socket to the rawx %s", full_remote_url); return status; } if ((status = apr_socket_connect(sock, sockaddr)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to establish the connection to the rawx %s", full_remote_url); return status; } /* ------- */ /* Forging the message */ char* forged_header = apr_psprintf(local_pool, "%s %s HTTP/1.1\nHost: %s", req_type, content_hexid, full_remote_url); if (header) forged_header = apr_psprintf(local_pool, "%s\n%s", forged_header, header); if (data) forged_header = apr_psprintf(local_pool, "%s\nContent-Length: %d\n\n", forged_header, data_length); else forged_header = apr_psprintf(local_pool, "%s\n\n", forged_header); /* ------- */ /* Sending the message */ int remaining_to_send = strlen(forged_header); char* ptr_start = forged_header; apr_size_t send_buffer_size; while (remaining_to_send > 0) { if (remaining_to_send < REQUEST_BUFFER_SIZE) send_buffer_size = (apr_size_t)remaining_to_send; else send_buffer_size = REQUEST_BUFFER_SIZE; if ((status = apr_socket_send(sock, ptr_start, &send_buffer_size)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "failed to send the %s request to the rawx %s", req_type, full_remote_url); apr_status_t status_sav = status; apr_socket_close(sock); return status_sav; } remaining_to_send -= send_buffer_size; ptr_start = ptr_start + send_buffer_size; } if (NULL != data) { remaining_to_send = data_length; ptr_start = data; while (remaining_to_send > 0) { if (remaining_to_send < REQUEST_BUFFER_SIZE) send_buffer_size = (apr_size_t)remaining_to_send; else send_buffer_size = REQUEST_BUFFER_SIZE; if ((status = apr_socket_send(sock, ptr_start, &send_buffer_size)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "failed to send the %s request to the rawx %s", req_type, full_remote_url); apr_status_t status_sav = status; apr_socket_close(sock); return status_sav; } remaining_to_send -= send_buffer_size; ptr_start = ptr_start + send_buffer_size; } } if (is_get) { /* This avoids a ~5s delay in the communication */ apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE); } DAV_DEBUG_REQ(resource->info->request, 0, "%s request to the rawx %s sent for the content %s", req_type, full_remote_url, content_hexid); /* ------ */ /* Getting the reply */ char* reply_ptr = *reply; apr_size_t total_size; if (!is_get) total_size = REPLY_BUFFER_SIZE; // PUT or DELETE else total_size = MAX_REPLY_HEADER_SIZE + data_length; // GET apr_size_t reply_size = (apr_size_t)total_size; apr_size_t total_replied_size; do { status = apr_socket_recv(sock, reply_ptr, &reply_size); reply_ptr += reply_size; total_replied_size = reply_ptr - *reply; /* Leave when OK, or error != timeout, or buffer full */ if (status == APR_EOF || (status == APR_SUCCESS && !is_get) || (reply_size == 0) || total_replied_size >= total_size) { break; } /* Take care of overflows! */ reply_size = total_size - total_replied_size; } while (total_replied_size < total_size); /* ------- */ apr_socket_close(sock); return status; }
static int rainx_hook_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server) { apr_status_t status; server_rec *s; server_addr_rec *a; dav_rainx_server_conf *conf; GError *gerr; (void) ptemp; DAV_XDEBUG_POOL(plog, 0, "%s(%lx)", __FUNCTION__, (long)server); if (__rainx_is_first_call(server)) { DAV_DEBUG_POOL(plog, 0, "First call detected"); return OK; } DAV_DEBUG_POOL(plog, 0, "Second call detected"); gerr = NULL; conf = ap_get_module_config(server->module_config, &dav_rainx_module); /* perform some options consistency checks */ if (!(conf->headers_scheme & HEADER_SCHEME_V1) && !(conf->headers_scheme & HEADER_SCHEME_V2)) { DAV_ERROR_POOL(plog, 0, "You cannot disable both V1 and V2 header scheme"); return DONE; } DAV_XDEBUG_POOL(plog, 0, "Checking the docroot XATTR lock for [%s]", conf->docroot); /* Runs the configured servers and check they do not serve * the grid docroot with an unauthorized IP:PORT couple */ for (s = server ; s ; s = s->next) { for (a = s->addrs ; a ; a = a->next) { char *host = NULL, url[512]; if (gerr) g_clear_error(&gerr); if (a->host_port == 0) continue; host = NULL; status = apr_getnameinfo(&host, a->host_addr, NI_NUMERICSERV|NI_NUMERICHOST|NI_NOFQDN); if (status != APR_SUCCESS || host == NULL) { DAV_ERROR_POOL(plog, 0, "getnameinfo() failed : %d", status); continue; } apr_snprintf(url, sizeof(url), "%s:%d", host, a->host_port); DAV_DEBUG_POOL(plog, 0, "xattr-lock : testing addr [%s]", url); } } if (gerr) g_clear_error(&gerr); /* Init the stat support : doing this so late avoids letting orphan * SHM segments in the nature in case of previous errors */ status = server_init_master_stat(conf, pconf, plog); if (APR_SUCCESS != status) { DAV_ERROR_POOL(plog, 0, "Failed to init the RAINX statistics support"); return DONE; } else { /* This will be overwritten by the child_init */ conf->cleanup = _stat_cleanup_master; apr_pool_userdata_set(conf, apr_psprintf(pconf, "RAINX-config-to-be-cleaned-%d", i++), _stat_cleanup_to_register, pconf); } return OK; }
static int rawx_hook_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server) { apr_status_t status; enum lock_state_e state; server_rec *s; server_addr_rec *a; dav_rawx_server_conf *conf; GError *gerr; int volume_validated = 0; (void) ptemp; DAV_XDEBUG_POOL(plog, 0, "%s(%lx)", __FUNCTION__, (long)server); if (__rawx_is_first_call(server)) { DAV_DEBUG_POOL(plog, 0, "First call detected"); return OK; } DAV_DEBUG_POOL(plog, 0, "Second call detected"); gerr = NULL; conf = ap_get_module_config(server->module_config, &dav_rawx_module); DAV_XDEBUG_POOL(plog, 0, "Checking the docroot XATTR lock for [%s]", conf->docroot); /* Runs the configured servers and check they do not serve * the grid docroot with an unauthorized IP:PORT couple */ for (s = server ; s ; s = s->next) { for (a = s->addrs ; a ; a = a->next) { apr_status_t status2; char *host = NULL, url[512]; if (gerr) g_clear_error(&gerr); if (a->host_port == 0) continue; host = NULL; status2 = apr_getnameinfo(&host, a->host_addr, NI_NUMERICSERV|NI_NUMERICHOST|NI_NOFQDN); if (status2 != APR_SUCCESS || host == NULL) { DAV_ERROR_POOL(plog, 0, "getnameinfo() failed : %d", status2); continue; } apr_snprintf(url, sizeof(url), "%s:%d", host, a->host_port); DAV_DEBUG_POOL(plog, 0, "xattr-lock : testing addr [%s]", url); state = rawx_get_volume_lock_state(conf->docroot, conf->ns_name, url, &gerr); switch (state) { case ERROR_LS: DAV_ERROR_POOL(plog, 0, "Failed to check the docroot ownership: %s", gerror_get_message(gerr)); goto label_error; case NOLOCK_LS: if (!rawx_lock_volume(conf->docroot, conf->ns_name, url, 0, &gerr)) { DAV_ERROR_POOL(plog, 0, "Failed to grab the docroot ownership: %s", gerror_get_message(gerr)); goto label_error; } DAV_DEBUG_POOL(plog, 0, "Docroot now owned"); volume_validated = ~0; break; case OWN_LS: DAV_DEBUG_POOL(plog, 0, "Docroot already owned by the current server"); if (!rawx_lock_volume(conf->docroot, conf->ns_name, url, RAWXLOCK_FLAG_OVERWRITE, &gerr)) DAV_ERROR_POOL(plog, 0, "Failed to complete the docroot ownership: %s", gerror_get_message(gerr)); volume_validated = ~0; break; case OTHER_LS: DAV_ERROR_POOL(plog, 0, "Another RAWX already used the docroot (see XATTR)" " : %s", gerror_get_message(gerr)); goto label_error; } } } if (gerr) g_clear_error(&gerr); if (!volume_validated) { DAV_ERROR_POOL(plog, 0, "No server found, could not validate the RAWX volume. " "Did you declare at least one VirtualHost ?"); goto label_error; } if (_create_shm_if_needed(conf->shm.path, server, plog) != APR_SUCCESS) { DAV_ERROR_POOL(plog, 0, "Failed to init the RAWX statistics support"); return DONE; } /* Init the stat support : doing this so late avoids letting orphan * SHM segments in the nature in case of previous errors */ status = server_init_master_stat(conf, pconf, plog); if (APR_SUCCESS != status) { DAV_ERROR_POOL(plog, 0, "Failed to init the RAWX statistics support"); return DONE; } else { /* This will be overwritten by the child_init */ conf->cleanup = _stat_cleanup_master; apr_pool_userdata_set(conf, apr_psprintf(pconf, "RAWX-config-to-be-cleaned-%d", i++), _stat_cleanup_to_register, pconf); } return OK; label_error: if (gerr) g_clear_error(&gerr); return DONE; }