/** * Create the filter chain for this session. * * Filters must be setup in reverse order, starting with the last * filter in the chain and working back towards the client connection * Each filter is passed the current session head of the filter chain * this head becomes the destination for the filter. The newly created * filter becomes the new head of the filter chain. * * @param session The session that requires the chain * @return 0 if filter creation fails */ static int session_setup_filters(SESSION *session) { SERVICE *service = session->service; DOWNSTREAM *head; UPSTREAM *tail; int i; if ((session->filters = calloc(service->n_filters, sizeof(SESSION_FILTER))) == NULL) { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Insufficient memory to allocate session filter " "tracking.\n"))); return 0; } session->n_filters = service->n_filters; for (i = service->n_filters - 1; i >= 0; i--) { if ((head = filterApply(service->filters[i], session, &session->head)) == NULL) { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Failed to create filter '%s' for service '%s'.\n", service->filters[i]->name, service->name))); return 0; } session->filters[i].filter = service->filters[i]; session->filters[i].session = head->session; session->filters[i].instance = head->instance; session->head = *head; } for (i = 0; i < service->n_filters; i++) { if ((tail = filterUpstream(service->filters[i], session->filters[i].session, &session->tail)) == NULL) { LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Failed to create filter '%s' for service '%s'.\n", service->filters[i]->name, service->name))); return 0; } session->tail = *tail; } return 1; }
/** * Create the filter chain for this session. * * Filters must be setup in reverse order, starting with the last * filter in the chain and working back towards the client connection * Each filter is passed the current session head of the filter chain * this head becomes the destination for the filter. The newly created * filter becomes the new head of the filter chain. * * @param session The session that requires the chain * @return 0 if filter creation fails */ static int session_setup_filters(SESSION *session) { SERVICE *service = session->service; DOWNSTREAM *head; UPSTREAM *tail; int i; if ((session->filters = calloc(service->n_filters, sizeof(SESSION_FILTER))) == NULL) { MXS_ERROR("Insufficient memory to allocate session filter " "tracking.\n"); return 0; } session->n_filters = service->n_filters; for (i = service->n_filters - 1; i >= 0; i--) { if (service->filters[i] == NULL) { MXS_ERROR("Service '%s' contians an unresolved filter.", service->name); return 0; } if ((head = filterApply(service->filters[i], session, &session->head)) == NULL) { MXS_ERROR("Failed to create filter '%s' for " "service '%s'.\n", service->filters[i]->name, service->name); return 0; } session->filters[i].filter = service->filters[i]; session->filters[i].session = head->session; session->filters[i].instance = head->instance; session->head = *head; free(head); } for (i = 0; i < service->n_filters; i++) { if ((tail = filterUpstream(service->filters[i], session->filters[i].session, &session->tail)) == NULL) { MXS_ERROR("Failed to create filter '%s' for service '%s'.", service->filters[i]->name, service->name); return 0; } /* * filterUpstream may simply return the 3 parameter if * the filter has no upstream entry point. So no need * to copy the contents or free tail in this case. */ if (tail != &session->tail) { session->tail = *tail; free(tail); } } return 1; }
/** * Associate a new session with this instance of the filter. * * Create the file to log to and open it. * * @param instance The filter instance data * @param session The session itself * @return Session specific data for this session */ static void * newSession(FILTER *instance, SESSION *session) { TEE_INSTANCE *my_instance = (TEE_INSTANCE *) instance; TEE_SESSION *my_session; char *remote, *userName; if (strcmp(my_instance->service->name, session->service->name) == 0) { MXS_ERROR("%s: Recursive use of tee filter in service.", session->service->name); my_session = NULL; goto retblock; } HASHTABLE* ht = hashtable_alloc(100, simple_str_hash, strcmp); bool is_loop = detect_loops(my_instance, ht, session->service); hashtable_free(ht); if (is_loop) { MXS_ERROR("%s: Recursive use of tee filter in service.", session->service->name); my_session = NULL; goto retblock; } if ((my_session = calloc(1, sizeof(TEE_SESSION))) != NULL) { my_session->active = 1; my_session->residual = 0; my_session->tee_replybuf = NULL; my_session->client_dcb = session->client; my_session->instance = my_instance; my_session->client_multistatement = false; my_session->queue = NULL; spinlock_init(&my_session->tee_lock); if (my_instance->source && (remote = session_get_remote(session)) != NULL) { if (strcmp(remote, my_instance->source)) { my_session->active = 0; MXS_WARNING("Tee filter is not active."); } } userName = session_getUser(session); if (my_instance->userName && userName && strcmp(userName, my_instance->userName)) { my_session->active = 0; MXS_WARNING("Tee filter is not active."); } if (my_session->active) { DCB* dcb; SESSION* ses; FILTER_DEF* dummy; UPSTREAM* dummy_upstream; if ((dcb = dcb_clone(session->client)) == NULL) { freeSession(instance, (void *) my_session); my_session = NULL; MXS_ERROR("Creating client DCB for Tee " "filter failed. Terminating session."); goto retblock; } if ((dummy = filter_alloc("tee_dummy", "tee_dummy")) == NULL) { dcb_close(dcb); freeSession(instance, (void *) my_session); my_session = NULL; MXS_ERROR("tee: Allocating memory for " "dummy filter definition failed." " Terminating session."); goto retblock; } if ((ses = session_alloc(my_instance->service, dcb)) == NULL) { filter_free(dummy); dcb_close(dcb); freeSession(instance, (void *) my_session); my_session = NULL; MXS_ERROR("Creating client session for Tee " "filter failed. Terminating session."); goto retblock; } ss_dassert(ses->ses_is_child); dummy->obj = GetModuleObject(); dummy->filter = NULL; my_session->branch_session = ses; my_session->branch_dcb = dcb; my_session->dummy_filterdef = dummy; if ((dummy_upstream = filterUpstream( dummy, my_session, &ses->tail)) == NULL) { filter_free(dummy); closeSession(instance, (void*) my_session); dcb_close(dcb); free(my_session); MXS_ERROR("tee: Allocating memory for" "dummy upstream failed." " Terminating session."); return NULL; } ses->tail = *dummy_upstream; MySQLProtocol* protocol = (MySQLProtocol*) session->client->protocol; my_session->use_ok = protocol->client_capabilities & (1 << 6); free(dummy_upstream); } } retblock: return my_session; }