/** Use work_send() to place work on another thread's work queue. * The receiving thread will invoke the given function with * the given callback data. * * Returns true on success. */ bool work_send(work_queue *m, void (*func)(void *data0, void *data1), void *data0, void *data1) { cb_assert(m != NULL); cb_assert(m->recv_fd >= 0); cb_assert(m->send_fd >= 0); cb_assert(m->event_base != NULL); cb_assert(func != NULL); bool rv = false; /* TODO: Add a free-list of work_items. */ work_item *w = calloc(1, sizeof(work_item)); if (w != NULL) { w->func = func; w->data0 = data0; w->data1 = data1; w->next = NULL; cb_mutex_enter(&m->work_lock); if (m->work_tail != NULL) m->work_tail->next = w; m->work_tail = w; if (m->work_head == NULL) m->work_head = w; if (send(m->send_fd, "", 1, 0) == 1) { m->num_items++; m->tot_sends++; #ifdef WORK_DEBUG moxi_log_write("work_send %x %x %x %d %d %d %llu %llu\n", (int) cb_thread_self(), (int) m, (int) m->event_base, m->send_fd, m->recv_fd, m->work_head != NULL, m->num_items, m->tot_sends); #endif rv = true; } cb_mutex_exit(&m->work_lock); } return rv; }
static void setup_dispatcher(struct event_base *main_base, void (*dispatcher_callback)(evutil_socket_t, short, void *)) { memset(&dispatcher_thread, 0, sizeof(dispatcher_thread)); dispatcher_thread.type = DISPATCHER; dispatcher_thread.base = main_base; dispatcher_thread.thread_id = cb_thread_self(); if (!create_notification_pipe(&dispatcher_thread)) { exit(1); } /* Listen for notifications from other threads */ event_set(&dispatcher_thread.notify_event, dispatcher_thread.notify[0], EV_READ | EV_PERSIST, dispatcher_callback, &dispatcher_callback); event_base_set(dispatcher_thread.base, &dispatcher_thread.notify_event); if (event_add(&dispatcher_thread.notify_event, 0) == -1) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "Can't monitor libevent notify pipe\n"); exit(1); } }
static void cproxy_sasl_plain_auth(conn *c, char *req_bytes) { protocol_binary_request_header *req; char *key; int keylen; int bodylen; char *clientin; unsigned int clientinlen; proxy_td *ptd = c->extra; cb_assert(ptd != NULL); cb_assert(ptd->proxy != NULL); cb_assert(ptd->proxy->main != NULL); /* Authenticate an upstream connection. */ req = (protocol_binary_request_header *) req_bytes; key = ((char *) req) + sizeof(*req) + req->request.extlen; keylen = ntohs(req->request.keylen); bodylen = ntohl(req->request.bodylen); /* The key is the sasl mech. */ if (keylen != 5 || memcmp(key, "PLAIN", 5) != 0) { /* 5 == strlen("PLAIN"). */ write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, 0); return; } clientin = key + keylen; clientinlen = bodylen - keylen - req->request.extlen; /* The clientin string looks like "[authzid]\0username\0password". */ while (clientinlen > 0 && clientin[0] != '\0') { /* Skip authzid. */ clientin++; clientinlen--; } if (clientinlen > 2 && clientinlen < 128 && clientin[0] == '\0') { const char *username = clientin + 1; char password[256]; int uslen = strlen(username); int pwlen = clientinlen - 2 - uslen; if (pwlen < (int) sizeof(password)) { proxy *p; memcpy(password, clientin + 2 + uslen, pwlen); password[pwlen] = '\0'; p = cproxy_find_proxy_by_auth(ptd->proxy->main, username, password); if (p != NULL) { proxy_td *ptd_target = cproxy_find_thread_data(p, cb_thread_self()); if (ptd_target != NULL) { c->extra = ptd_target; write_bin_response(c, "Authenticated", 0, 0, strlen("Authenticated")); if (settings.verbose > 2) { moxi_log_write("<%d sasl authenticated for %s\n", c->sfd, username); } return; } else { if (settings.verbose > 2) { moxi_log_write("<%d sasl auth failed on ptd for %s\n", c->sfd, username); } } } else { if (settings.verbose > 2) { moxi_log_write("<%d sasl auth failed for %s (%d)\n", c->sfd, username, pwlen); } } } else { if (settings.verbose > 2) { moxi_log_write("<%d sasl auth failed for %s with empty password\n", c->sfd, username); } } } else { if (settings.verbose > 2) { moxi_log_write("<%d sasl auth failed with malformed PLAIN data\n", c->sfd); } } /* TODO: If authentication failed, we should consider */ /* reassigning the connection to the NULL_BUCKET. */ write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, 0); }
/* * Returns true if this is the thread that listens for new TCP connections. */ int is_listen_thread() { return dispatcher_thread.thread_id == cb_thread_self(); }