/** * Associate a new session with this instance of the router. * * @param instance The router instance data * @param session The session itself * @return Session specific data for this session */ static void * newSession(ROUTER *instance, SESSION *session) { CLI_INSTANCE *inst = (CLI_INSTANCE *)instance; CLI_SESSION *client; if ((client = (CLI_SESSION *)malloc(sizeof(CLI_SESSION))) == NULL) { return NULL; } client->session = session; memset(client->cmdbuf, 0, 80); spinlock_acquire(&inst->lock); client->next = inst->sessions; inst->sessions = client; spinlock_release(&inst->lock); session->state = SESSION_STATE_READY; dcb_printf(session->client, "Welcome the SkySQL MaxScale Debug Interface (%s).\n", version_str); dcb_printf(session->client, "WARNING: This interface is meant for developer usage,\n"); dcb_printf(session->client, "passing incorrect addresses to commands can endanger your MaxScale server.\n\n"); dcb_printf(session->client, "Type help for a list of available commands.\n\n"); return (void *)client; }
/** * Show a single monitor * * @param dcb DCB for printing output */ void monitorShow(DCB *dcb, MONITOR *monitor) { dcb_printf(dcb, "Monitor: %p\n", monitor); dcb_printf(dcb, "\tName: %s\n", monitor->name); if (monitor->module->diagnostics) monitor->module->diagnostics(dcb, monitor->handle); }
/** * Print all services to a DCB * * Designed to be called within a debugger session in order * to display all active services within the gateway */ void dprintAllServices(DCB *dcb) { SERVICE *ptr; spinlock_acquire(&service_spin); ptr = allServices; while (ptr) { SERVER *server = ptr->databases; dcb_printf(dcb, "Service %p\n", ptr); dcb_printf(dcb, "\tService: %s\n", ptr->name); dcb_printf(dcb, "\tRouter: %s (%p)\n", ptr->routerModule, ptr->router); if (ptr->router) ptr->router->diagnostics(ptr->router_instance, dcb); dcb_printf(dcb, "\tStarted: %s", asctime(localtime(&ptr->stats.started))); dcb_printf(dcb, "\tBackend databases\n"); while (server) { dcb_printf(dcb, "\t\t%s:%d Protocol: %s\n", server->name, server->port, server->protocol); server = server->nextdb; } dcb_printf(dcb, "\tUsers data: %p\n", ptr->users); dcb_printf(dcb, "\tTotal connections: %d\n", ptr->stats.n_sessions); dcb_printf(dcb, "\tCurrently connected: %d\n", ptr->stats.n_current); ptr = ptr->next; } spinlock_release(&service_spin); }
/** * Diagnostics routine * * If fsession is NULL then print diagnostics on the filter * instance as a whole, otherwise print diagnostics for the * particular session. * * @param instance The filter instance * @param fsession Filter session, may be NULL * @param dcb The DCB for diagnostic output */ static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { TEST_INSTANCE *my_instance = (TEST_INSTANCE *)instance; TEST_SESSION *my_session = (TEST_SESSION *)fsession; if (my_session) dcb_printf(dcb, "\t\tNo. of queries routed by filter: %d\n", my_session->count); else dcb_printf(dcb, "\t\tNo. of sessions created: %d\n", my_instance->sessions); }
/** * List all filters in a tabular form to a DCB * */ void dListFilters(DCB *dcb) { FILTER_DEF *ptr; int i; spinlock_acquire(&filter_spin); ptr = allFilters; if (ptr) { dcb_printf(dcb, "Filters\n"); dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); dcb_printf(dcb, "%-19s | %-15s | Options\n", "Filter", "Module"); dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); } while (ptr) { dcb_printf(dcb, "%-19s | %-15s | ", ptr->name, ptr->module); for (i = 0; ptr->options && ptr->options[i]; i++) dcb_printf(dcb, "%s ", ptr->options[i]); dcb_printf(dcb, "\n"); ptr = ptr->next; } if (allFilters) dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n\n"); spinlock_release(&filter_spin); }
/** * Print Modules to a DCB * * Diagnostic routine to display all the loaded modules */ void dprintAllModules(DCB *dcb) { MODULES *ptr = registered; dcb_printf(dcb, "Modules.\n"); dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); dcb_printf(dcb, "%-15s | %-11s | Version | API | Status\n", "Module Name", "Module Type"); dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); while (ptr) { dcb_printf(dcb, "%-15s | %-11s | %-7s ", ptr->module, ptr->type, ptr->version); if (ptr->info) dcb_printf(dcb, "| %d.%d.%d | %s", ptr->info->api_version.major, ptr->info->api_version.minor, ptr->info->api_version.patch, ptr->info->status == MODULE_IN_DEVELOPMENT ? "In Development" : (ptr->info->status == MODULE_ALPHA_RELEASE ? "Alpha" : (ptr->info->status == MODULE_BETA_RELEASE ? "Beta" : (ptr->info->status == MODULE_GA ? "GA" : (ptr->info->status == MODULE_EXPERIMENTAL ? "Experimental" : "Unknown"))))); dcb_printf(dcb, "\n"); ptr = ptr->next; } dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n\n"); }
/** * Send the monitors page. This iterates on all the monitors and send * the rows via the monitor_monitor. * * @param session The router session */ static void send_monitors(WEB_SESSION *session) { DCB *dcb = session->session->client; send_html_header(dcb); dcb_printf(dcb, "<HTML><HEAD>"); dcb_printf(dcb, "<LINK REL=\"stylesheet\" type=\"text/css\" href=\"styles.css\">"); dcb_printf(dcb, "<BODY><H2>Monitors</H2><P>"); dcb_printf(dcb, "<TABLE><TR><TH>Monitor</TH><TH>State</TH></TR>\n"); monitorIterate(monitor_row, dcb); dcb_printf(dcb, "</TABLE></BODY></HTML>\n"); dcb_close(dcb); }
/** * Send the standard HTTP headers for an HTML file */ static void send_html_header(DCB *dcb) { char date[64] = ""; const char *fmt = "%a, %d %b %Y %H:%M:%S GMT"; time_t httpd_current_time = time(NULL); strftime(date, sizeof(date), fmt, localtime(&httpd_current_time)); dcb_printf(dcb, "HTTP/1.1 200 OK\r\nDate: %s\r\nServer: %s\r\nConnection: close\r\nContent-Type: text/html\r\n", date, "MaxScale"); dcb_printf(dcb, "\r\n"); }
/** * Add a new maxscale admin user * * @param dcb The DCB for messages * @param user The user name * @param passwd The Password of the user */ static void telnetdAddUser(DCB *dcb, char *user, char *passwd) { char *err; if (admin_search_user(user)) { dcb_printf(dcb, "User %s already exists.\n", user); return; } if ((err = admin_add_user(user, passwd)) == NULL) dcb_printf(dcb, "User %s has been successfully added.\n", user); else dcb_printf(dcb, "Failed to add new user. %s\n", err); }
/** * Diagnostics routine * * If fsession is NULL then print diagnostics on the filter * instance as a whole, otherwise print diagnostics for the * particular session. * * @param instance The filter instance * @param fsession Filter session, may be NULL * @param dcb The DCB for diagnostic output */ static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { TOPN_INSTANCE *my_instance = (TOPN_INSTANCE *) instance; TOPN_SESSION *my_session = (TOPN_SESSION *) fsession; int i; dcb_printf(dcb, "\t\tReport size %d\n", my_instance->topN); if (my_instance->source) { dcb_printf(dcb, "\t\tLimit logging to connections from %s\n", my_instance->source); } if (my_instance->user) { dcb_printf(dcb, "\t\tLimit logging to user %s\n", my_instance->user); } if (my_instance->match) { dcb_printf(dcb, "\t\tInclude queries that match %s\n", my_instance->match); } if (my_instance->exclude) { dcb_printf(dcb, "\t\tExclude queries that match %s\n", my_instance->exclude); } if (my_session) { dcb_printf(dcb, "\t\tLogging to file %s.\n", my_session->filename); dcb_printf(dcb, "\t\tCurrent Top %d:\n", my_instance->topN); for (i = 0; i < my_instance->topN; i++) { if (my_session->top[i]->sql) { dcb_printf(dcb, "\t\t%d place:\n", i + 1); dcb_printf(dcb, "\t\t\tExecution time: %.3f seconds\n", (double) ((my_session->top[i]->duration.tv_sec * 1000) + (my_session->top[i]->duration.tv_usec / 1000)) / 1000); dcb_printf(dcb, "\t\t\tSQL: %s\n", my_session->top[i]->sql); } } } }
/** * Print a table row for the monitors table * * @param monitor The monitor to print * @param dcb The DCB to print to */ static void monitor_row(MONITOR *monitor, DCB *dcb) { dcb_printf(dcb, "<TR><TD>%s</TD><TD>%s</TD></TR>\n", monitor->name, monitor->state & MONITOR_STATE_RUNNING ? "Running" : "Stopped"); }
/** * Display a table row for a particular server. This is called via the * serverIterate call in send_servers. * * @param server The server to print * @param dcb The DCB to send the HTML to */ static void server_row(SERVER *server, DCB *dcb) { dcb_printf(dcb, "<TR><TD>%s</TD><TD>%s</TD><TD>%d</TD><TD>%s</TD><TD>%d</TD></TR>\n", server->unique_name, server->name, server->port, server_status(server), server->stats.n_current); }
/** * Write a table row for a service. This is called using the service * iterator function * * @param service The service to display * @param dcb The DCB to print the HTML to */ static void service_row(SERVICE *service, DCB *dcb) { dcb_printf(dcb, "<TR><TD>%s</TD><TD>%s</TD><TD>%d</TD><TD>%d</TD></TR>\n", service->name, service->routerModule, service->stats.n_current, service->stats.n_sessions); }
static void fail_accept( DCB* dcb, char* arg1, char* arg2) { int failcount = MIN(atoi(arg2), 100); fail_accept_errno = atoi(arg1); switch(fail_accept_errno) { case EAGAIN: // case EWOULDBLOCK: case EBADF: case EINTR: case EINVAL: case EMFILE: case ENFILE: case ENOTSOCK: case EOPNOTSUPP: case ENOBUFS: case ENOMEM: case EPROTO: fail_next_accept = failcount; break; default: dcb_printf(dcb, "[%d, %s] is not valid errno for accept.\n", fail_accept_errno, strerror(fail_accept_errno)); return ; } }
/** * Show all monitors * * @param dcb DCB for printing output */ void monitorShowAll(DCB *dcb) { MONITOR *ptr; spinlock_acquire(&monLock); ptr = allMonitors; while (ptr) { dcb_printf(dcb, "Monitor: %p\n", ptr); dcb_printf(dcb, "\tName: %s\n", ptr->name); if (ptr->module->diagnostics) ptr->module->diagnostics(dcb, ptr->handle); ptr = ptr->next; } spinlock_release(&monLock); }
/** * Print filter details to a DCB * * Designed to be called within a debug CLI in order * to display all active filters in MaxScale */ void dprintFilter(DCB *dcb, FILTER_DEF *filter) { int i; dcb_printf(dcb, "Filter %p (%s)\n", filter, filter->name); dcb_printf(dcb, "\tModule: %s\n", filter->module); if (filter->options) { dcb_printf(dcb, "\tOptions: "); for (i = 0; filter->options && filter->options[i]; i++) dcb_printf(dcb, "%s ", filter->options[i]); dcb_printf(dcb, "\n"); } if (filter->obj && filter->filter) filter->obj->diagnostics(filter->filter, NULL, dcb); }
/** * Print the statistics and user names of the administration users * * @param dcb A DCB to send the output to */ void dcb_PrintAdminUsers(DCB *dcb) { if (users) dcb_usersPrint(dcb, users); else dcb_printf(dcb, "No administration users have been defined.\n"); }
/** * Diagnostic interface * * @param dcb DCB to send output * @param arg The monitor handle */ static void diagnostics(DCB *dcb, void *arg) { MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; MONITOR_SERVERS *db; char *sep; switch (handle->status) { case MONITOR_RUNNING: dcb_printf(dcb, "\tMonitor running\n"); break; case MONITOR_STOPPING: dcb_printf(dcb, "\tMonitor stopping\n"); break; case MONITOR_STOPPED: dcb_printf(dcb, "\tMonitor stopped\n"); break; } dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval); dcb_printf(dcb, "\tMonitored servers: "); db = handle->databases; sep = ""; while (db) { dcb_printf(dcb, "%s%s:%d", sep, db->server->name, db->server->port); sep = ", "; db = db->next; } dcb_printf(dcb, "\n"); }
/** * Diagnostics routine * * If fsession is NULL then print diagnostics on the filter * instance as a whole, otherwise print diagnostics for the * particular session. * * @param instance The filter instance * @param fsession Filter session, may be NULL * @param dcb The DCB for diagnostic output */ static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { TEE_INSTANCE *my_instance = (TEE_INSTANCE *)instance; TEE_SESSION *my_session = (TEE_SESSION *)fsession; if (my_instance->source) dcb_printf(dcb, "\t\tLimit to connections from %s\n", my_instance->source); dcb_printf(dcb, "\t\tDuplicate statements to service %s\n", my_instance->service->name); if (my_instance->userName) dcb_printf(dcb, "\t\tLimit to user %s\n", my_instance->userName); if (my_instance->match) dcb_printf(dcb, "\t\tInclude queries that match %s\n", my_instance->match); if (my_instance->nomatch) dcb_printf(dcb, "\t\tExclude queries that match %s\n", my_instance->nomatch); if (my_session) { dcb_printf(dcb, "\t\tNo. of statements duplicated: %d.\n", my_session->n_duped); dcb_printf(dcb, "\t\tNo. of statements rejected: %d.\n", my_session->n_rejected); } }
/** * Print a particular session to a DCB * * Designed to be called within a debugger session in order * to display all active sessions within the gateway * * @param dcb The DCB to print to * @param ptr The session to print */ void dprintSession(DCB *dcb, SESSION *ptr) { int i; dcb_printf(dcb, "Session %p\n", ptr); dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state)); dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service); dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client); if (ptr->client && ptr->client->remote) dcb_printf(dcb, "\tClient Address: %s\n", ptr->client->remote); dcb_printf(dcb, "\tConnected: %s", asctime(localtime(&ptr->stats.connect))); if (ptr->n_filters) { for (i = 0; i < ptr->n_filters; i++) { dcb_printf(dcb, "\tFilter: %s\n", ptr->filters[i].filter->name); ptr->filters[i].filter->obj->diagnostics( ptr->filters[i].instance, ptr->filters[i].session, dcb); } } }
/** * Handler for the EPOLLIN event when the DCB refers to the listening * socket for the protocol. * * @param dcb The descriptor control block * @return The number of new connections created */ static int telnetd_accept(DCB *dcb) { int n_connect = 0; while (1) { int so; struct sockaddr_in addr; socklen_t addrlen = sizeof(struct sockaddr); DCB *client_dcb; TELNETD* telnetd_pr = NULL; dcb_state_t old_state = DCB_STATE_UNDEFINED; bool succp = FALSE; so = accept(dcb->fd, (struct sockaddr *)&addr, &addrlen); if (so == -1) return n_connect; else { atomic_add(&dcb->stats.n_accepts, 1); client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER); if (client_dcb == NULL) { return n_connect; } client_dcb->fd = so; client_dcb->remote = strdup(inet_ntoa(addr.sin_addr)); memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); client_dcb->session = session_alloc(dcb->session->service, client_dcb); telnetd_pr = (TELNETD *)malloc(sizeof(TELNETD)); client_dcb->protocol = (void *)telnetd_pr; if (telnetd_pr == NULL) { dcb_add_to_zombieslist(client_dcb); return n_connect; } if (poll_add_dcb(client_dcb) == -1) { dcb_add_to_zombieslist(dcb); return n_connect; } n_connect++; telnetd_pr->state = TELNETD_STATE_LOGIN; telnetd_pr->username = NULL; dcb_printf(client_dcb, "MaxScale login: "); } } return n_connect; }
/** * Send the standard HTTP headers for an HTML file */ static void send_html_header(DCB *dcb) { char date[64] = ""; const char *fmt = "%a, %d %b %Y %H:%M:%S GMT"; time_t httpd_current_time = time(NULL); struct tm tm; char buffer[32]; // asctime_r documentation requires 26 localtime_r(&http_current_time, &tm); asctime_r(&tm, buffer); strftime(date, sizeof(date), fmt, buffer); dcb_printf(dcb, "HTTP/1.1 200 OK\r\nDate: %s\r\nServer: %s\r\nConnection: close\r\nContent-Type: text/html\r\n", date, "MaxScale"); dcb_printf(dcb, "\r\n"); }
/** * Write a session row for a session. this is called using the session * iterator function * * @param session The session to display * @param dcb The DCB to send the HTML to */ static void session_row(SESSION *session, DCB *dcb) { dcb_printf(dcb, "<TR><TD>%-16p</TD><TD>%s</TD><TD>%s</TD><TD>%s</TD></TR>\n", session, ((session->client && session->client->remote) ? session->client->remote : ""), (session->service && session->service->name ? session->service->name : ""), session_state(session->state)); }
/** * Clear the status bit of a server * * @param dcb DCB to send output to * @param server The server to set the status of * @param bit String representation of the status bit */ static void clear_server(DCB *dcb, SERVER *server, char *bit) { unsigned int bitvalue; if ((bitvalue = server_map_status(bit)) != 0) server_clear_status(server, bitvalue); else dcb_printf(dcb, "Unknown status bit %s\n", bit); }
/** * List all the monitors * * @param dcb DCB for printing output */ void monitorList(DCB *dcb) { MONITOR *ptr; spinlock_acquire(&monLock); ptr = allMonitors; dcb_printf(dcb, "---------------------+---------------------\n"); dcb_printf(dcb, "%-20s | Status\n", "Monitor"); dcb_printf(dcb, "---------------------+---------------------\n"); while (ptr) { dcb_printf(dcb, "%-20s | %s\n", ptr->name, ptr->state & MONITOR_STATE_RUNNING ? "Running" : "Stopped"); ptr = ptr->next; } dcb_printf(dcb, "---------------------+---------------------\n"); spinlock_release(&monLock); }
/** * Diagnostics routine * * Prints the connection details and the names of the exchange, * queue and the routing key. * * @param instance The filter instance * @param fsession Filter session, may be NULL * @param dcb The DCB for diagnostic output */ static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { MQ_INSTANCE *my_instance = (MQ_INSTANCE *)instance; if (my_instance) { dcb_printf(dcb, "Connecting to %s:%d as '%s'.\nVhost: %s\tExchange: %s\nKey: %s\tQueue: %s\n\n", my_instance->hostname,my_instance->port, my_instance->username, my_instance->vhost, my_instance->exchange, my_instance->key, my_instance->queue ); dcb_printf(dcb, "%-16s%-16s%-16s\n", "Messages","Queued","Sent"); dcb_printf(dcb, "%-16d%-16d%-16d\n", my_instance->stats.n_msg, my_instance->stats.n_queued, my_instance->stats.n_sent); } }
/** * Print all filters to a DCB * * Designed to be called within a debugger session in order * to display all active filters within MaxScale */ void dprintAllFilters(DCB *dcb) { FILTER_DEF *ptr; int i; spinlock_acquire(&filter_spin); ptr = allFilters; while (ptr) { dcb_printf(dcb, "Filter %p (%s)\n", ptr, ptr->name); dcb_printf(dcb, "\tModule: %s\n", ptr->module); if (ptr->options) { dcb_printf(dcb, "\tOptions: "); for (i = 0; ptr->options && ptr->options[i]; i++) dcb_printf(dcb, "%s ", ptr->options[i]); dcb_printf(dcb, "\n"); } if (ptr->obj && ptr->filter) ptr->obj->diagnostics(ptr->filter, NULL, dcb); else dcb_printf(dcb, "\tModule not loaded.\n"); ptr = ptr->next; } spinlock_release(&filter_spin); }
/** * List all sessions in tabular form to a DCB * * Designed to be called within a debugger session in order * to display all active sessions within the gateway * * @param dcb The DCB to print to */ void dListSessions(DCB *dcb) { SESSION *list_session; spinlock_acquire(&session_spin); list_session = allSessions; if (list_session) { dcb_printf(dcb, "Sessions.\n"); dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n"); dcb_printf(dcb, "Session | Client | Service | State\n"); dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n"); } while (list_session) { dcb_printf(dcb, "%-16p | %-15s | %-14s | %s\n", list_session, ((list_session->client_dcb && list_session->client_dcb->remote) ? list_session->client_dcb->remote : ""), (list_session->service && list_session->service->name ? list_session->service->name : ""), session_state(list_session->state)); list_session = list_session->next; } if (allSessions) { dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n\n"); } spinlock_release(&session_spin); }
/** * List all sessions in tabular form to a DCB * * Designed to be called within a debugger session in order * to display all active sessions within the gateway * * @param dcb The DCB to print to */ void dListSessions(DCB *dcb) { SESSION *ptr; spinlock_acquire(&session_spin); ptr = allSessions; if (ptr) { dcb_printf(dcb, "Sessions.\n"); dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n"); dcb_printf(dcb, "Session | Client | Service | State\n"); dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n"); } while (ptr) { dcb_printf(dcb, "%-16p | %-15s | %-14s | %s\n", ptr, ((ptr->client && ptr->client->remote) ? ptr->client->remote : ""), (ptr->service && ptr->service->name ? ptr->service->name : ""), session_state(ptr->state)); ptr = ptr->next; } if (allSessions) dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n\n"); spinlock_release(&session_spin); }
/** * List the defined services in a tabular format. * * @param dcb DCB to print the service list to. */ void dListServices(DCB *dcb) { SERVICE *ptr; spinlock_acquire(&service_spin); ptr = allServices; if (ptr) { dcb_printf(dcb, "Services.\n"); dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); dcb_printf(dcb, "%-25s | %-20s | #Users | Total Sessions\n", "Service Name", "Router Module"); dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); } while (ptr) { dcb_printf(dcb, "%-25s | %-20s | %6d | %5d\n", ptr->name, ptr->routerModule, ptr->stats.n_current, ptr->stats.n_sessions); ptr = ptr->next; } if (allServices) dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n\n"); spinlock_release(&service_spin); }