/* startup a copy of smbd as a child daemon */ static void s3fs_task_init(struct task_server *task) { const char *fileserver_conf; struct tevent_req *req; const char *smbd_path; const char *smbd_cmd[2] = { NULL, NULL }; task_server_set_title(task, "task[s3fs_parent]"); /* create a smb.conf for smbd to use */ fileserver_conf = generate_smb_conf(task); smbd_path = talloc_asprintf(task, "%s/smbd", dyn_SBINDIR); smbd_cmd[0] = smbd_path; /* start it as a child process */ req = samba_runcmd_send(task, task->event_ctx, timeval_zero(), 1, 0, smbd_cmd, "--configfile", fileserver_conf, "--foreground", debug_get_output_is_stdout()?"--log-stdout":NULL, NULL); if (req == NULL) { DEBUG(0, ("Failed to start smbd as child daemon\n")); goto failed; } tevent_req_set_callback(req, file_server_smbd_done, task); DEBUG(1,("Started file server smbd with config %s\n", fileserver_conf)); return; failed: task_server_terminate(task, "Failed to startup s3fs smb task", true); }
/* construct an event driven local ctdb_call this is used so that locally processed ctdb_call requests are processed in an event driven manner */ struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, struct ctdb_ltdb_header *header, TDB_DATA *data) { struct ctdb_call_state *state; struct ctdb_context *ctdb = ctdb_db->ctdb; int ret; state = talloc_zero(ctdb_db, struct ctdb_call_state); CTDB_NO_MEMORY_NULL(ctdb, state); talloc_steal(state, data->dptr); state->state = CTDB_CALL_DONE; state->node = ctdb->nodes[ctdb->vnn]; state->call = *call; state->ctdb_db = ctdb_db; ret = ctdb_call_local(ctdb_db, &state->call, header, data, ctdb->vnn); talloc_steal(state, state->call.reply_data.dptr); event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state); return state; }
_PUBLIC_ void composite_done(struct composite_context *ctx) { if (!ctx->used_wait && !ctx->async.fn) { tevent_add_timer(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx); } ctx->state = COMPOSITE_STATE_DONE; if (ctx->async.fn != NULL) { ctx->async.fn(ctx); } }
/* Just try locking/unlocking a single record once */ static void fetch_lock_once(struct ctdb_context *ctdb, struct event_context *ev, uint32_t generation) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA key, data; struct ctdb_record_handle *h; struct ctdb_ltdb_header *header; int ret; key.dptr = discard_const(TESTKEY); key.dsize = strlen(TESTKEY); printf("Trying to fetch lock the record ...\n"); h = ctdb_fetch_readonly_lock(ctdb_db, tmp_ctx, key, &data, false); if (h == NULL) { printf("Failed to fetch record '%s' on node %d\n", (const char *)key.dptr, ctdb_get_pnn(ctdb)); talloc_free(tmp_ctx); exit(10); } printf("Record fetchlocked.\n"); header = talloc_memdup(tmp_ctx, ctdb_header_from_record_handle(h), sizeof(*header)); printf("RSN:%d\n", (int)header->rsn); talloc_free(h); printf("Record released.\n"); printf("Write new record with RSN+10\n"); header->rsn += 10; data.dptr = (void *)talloc_asprintf(tmp_ctx, "%d", (int)header->rsn); data.dsize = strlen((char *)data.dptr); ret = ctdb_ctrl_updaterecord(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, ctdb_db, key, header, data); if (ret != 0) { printf("Failed to writerecord, ret==%d\n", ret); exit(1); } printf("re-fetch the record\n"); h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data); if (h == NULL) { printf("Failed to fetch record '%s' on node %d\n", (const char *)key.dptr, ctdb_get_pnn(ctdb)); talloc_free(tmp_ctx); exit(10); } printf("Record fetchlocked.\n"); header = talloc_memdup(tmp_ctx, ctdb_header_from_record_handle(h), sizeof(*header)); printf("RSN:%d\n", (int)header->rsn); talloc_free(h); printf("Record released.\n"); talloc_free(tmp_ctx); }
static bool recalc_brl_timeout(void) { struct blocking_lock_record *blr; struct timeval next_timeout; TALLOC_FREE(brl_timeout); next_timeout = timeval_zero(); for (blr = blocking_lock_queue; blr; blr = blr->next) { if (timeval_is_zero(&blr->expire_time)) { /* * If we're blocked on pid 0xFFFFFFFF this is * a POSIX lock, so calculate a timeout of * 10 seconds into the future. */ if (blr->blocking_pid == 0xFFFFFFFF) { struct timeval psx_to = timeval_current_ofs(10, 0); next_timeout = timeval_min(&next_timeout, &psx_to); } continue; } if (timeval_is_zero(&next_timeout)) { next_timeout = blr->expire_time; } else { next_timeout = timeval_min(&next_timeout, &blr->expire_time); } } if (timeval_is_zero(&next_timeout)) { DEBUG(10, ("Next timeout = Infinite.\n")); return True; } if (DEBUGLVL(10)) { struct timeval cur, from_now; cur = timeval_current(); from_now = timeval_until(&cur, &next_timeout); DEBUG(10, ("Next timeout = %d.%d seconds from now.\n", (int)from_now.tv_sec, (int)from_now.tv_usec)); } if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL, next_timeout, brl_timeout_fn, NULL))) { return False; } return True; }
/* re-enable receiving */ _PUBLIC_ void packet_recv_enable(struct packet_context *pc) { if (pc->recv_need_enable) { pc->recv_need_enable = false; TEVENT_FD_READABLE(pc->fde); } pc->recv_disable = false; if (pc->num_read != 0 && pc->packet_size >= pc->num_read) { tevent_add_timer(pc->ev, pc, timeval_zero(), packet_next_event, pc); } }
/* shutdown and try to restart a connection to a node after it has been disconnected */ static void ctdb_tcp_restart(struct ctdb_node *node) { struct ctdb_tcp_node *tnode = talloc_get_type( node->private_data, struct ctdb_tcp_node); DEBUG(DEBUG_NOTICE,("Tearing down connection to dead node :%d\n", node->pnn)); ctdb_tcp_stop_connection(node); tnode->connect_te = tevent_add_timer(node->ctdb->ev, tnode, timeval_zero(), ctdb_tcp_node_connect, node); }
_PUBLIC_ struct timeval timeval_until(const struct timeval *tv1, const struct timeval *tv2) { struct timeval t; if (timeval_compare(tv1, tv2) >= 0) { return timeval_zero(); } t.tv_sec = tv2->tv_sec - tv1->tv_sec; if (tv1->tv_usec > tv2->tv_usec) { t.tv_sec--; t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec); } else { t.tv_usec = tv2->tv_usec - tv1->tv_usec; } return t; }
_PUBLIC_ void composite_continue(struct composite_context *ctx, struct composite_context *new_ctx, void (*continuation)(struct composite_context *), void *private_data) { if (composite_nomem(new_ctx, ctx)) return; new_ctx->async.fn = continuation; new_ctx->async.private_data = private_data; /* if we are setting up a continuation, and the context has already finished, then we should run the callback with an immediate event, otherwise we can be stuck forever */ if (new_ctx->state >= COMPOSITE_STATE_DONE && continuation) { tevent_add_timer(new_ctx->event_ctx, new_ctx, timeval_zero(), composite_trigger, new_ctx); } }
_PUBLIC_ void composite_error(struct composite_context *ctx, NTSTATUS status) { /* you are allowed to pass NT_STATUS_OK to composite_error(), in which case it is equivalent to composite_done() */ if (NT_STATUS_IS_OK(status)) { composite_done(ctx); return; } if (!ctx->used_wait && !ctx->async.fn) { tevent_add_timer(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx); } ctx->status = status; ctx->state = COMPOSITE_STATE_ERROR; if (ctx->async.fn != NULL) { ctx->async.fn(ctx); } }
/* start the protocol going */ static int ctdb_tcp_connect_node(struct ctdb_node *node) { struct ctdb_context *ctdb = node->ctdb; struct ctdb_tcp_node *tnode = talloc_get_type( node->private_data, struct ctdb_tcp_node); /* startup connection to the other server - will happen on next event loop */ if (!ctdb_same_address(ctdb->address, &node->address)) { tnode->connect_te = tevent_add_timer(ctdb->ev, tnode, timeval_zero(), ctdb_tcp_node_connect, node); } return 0; }
static void gensec_socket_trigger_read(struct tevent_context *ev, struct tevent_timer *te, struct timeval t, void *private_data) { struct gensec_socket *gensec_socket = talloc_get_type(private_data, struct gensec_socket); gensec_socket->in_extra_read++; gensec_socket->recv_handler(gensec_socket->recv_private, TEVENT_FD_READ); gensec_socket->in_extra_read--; /* It may well be that, having run the recv handler, we still * have even more data waiting for us! */ if (gensec_socket->read_buffer.length > 0) { /* Schedule this funcion to run again */ tevent_add_timer(gensec_socket->ev, gensec_socket, timeval_zero(), gensec_socket_trigger_read, gensec_socket); } }
/* complete an async reconnect */ static void reopen_connection_complete(struct composite_context *ctx) { struct benchlock_state *state = (struct benchlock_state *)ctx->async.private_data; NTSTATUS status; struct smb_composite_connect *io = &state->reconnect; status = smb_composite_connect_recv(ctx, state->mem_ctx); if (!NT_STATUS_IS_OK(status)) { talloc_free(state->te); state->te = event_add_timed(state->ev, state->mem_ctx, timeval_current_ofs(1,0), reopen_connection, state); return; } talloc_free(state->tree); state->tree = io->out.tree; /* do the reopen as a separate event */ event_add_timed(state->ev, state->mem_ctx, timeval_zero(), reopen_file, state); }
/* startup a copy of smbd as a child daemon */ static void s3fs_task_init(struct task_server *task) { struct tevent_req *subreq; const char *smbd_path; const char *smbd_cmd[2] = { NULL, NULL }; task_server_set_title(task, "task[s3fs_parent]"); smbd_path = talloc_asprintf(task, "%s/smbd", dyn_SBINDIR); smbd_cmd[0] = smbd_path; /* the child should be able to call through nss_winbind */ (void)winbind_on(); /* start it as a child process */ subreq = samba_runcmd_send(task, task->event_ctx, timeval_zero(), 1, 0, smbd_cmd, "--option=server role check:inhibit=yes", "--foreground", debug_get_output_is_stdout()?"--log-stdout":NULL, NULL); /* the parent should not be able to call through nss_winbind */ if (!winbind_off()) { DEBUG(0,("Failed to re-disable recursive winbindd calls after forking smbd\n")); task_server_terminate(task, "Failed to re-disable recursive winbindd calls", true); return; } if (subreq == NULL) { DEBUG(0, ("Failed to start smbd as child daemon\n")); task_server_terminate(task, "Failed to startup s3fs smb task", true); return; } tevent_req_set_callback(subreq, file_server_smbd_done, task); DEBUG(5,("Started file server child smbd\n")); }
/* test the TestSleep interface */ static bool test_sleep(struct torture_context *tctx, struct dcerpc_pipe *p) { int i; #define ASYNC_COUNT 3 struct tevent_req *req[ASYNC_COUNT]; struct echo_TestSleep r[ASYNC_COUNT]; bool done1[ASYNC_COUNT]; bool done2[ASYNC_COUNT]; struct timeval snd[ASYNC_COUNT]; struct timeval rcv[ASYNC_COUNT]; struct timeval diff[ASYNC_COUNT]; int total_done = 0; struct dcerpc_binding_handle *b = p->binding_handle; enum dcerpc_transport_t transport; uint32_t assoc_group_id; struct dcerpc_pipe *p2 = NULL; NTSTATUS status; if (torture_setting_bool(tctx, "quick", false)) { torture_skip(tctx, "TestSleep disabled - use \"torture:quick=no\" to enable\n"); } torture_comment(tctx, "Testing TestSleep - use \"torture:quick=yes\" to disable\n"); transport = dcerpc_binding_get_transport(p->binding); assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding); torture_comment(tctx, "connect echo connection 2 with " "DCERPC_CONCURRENT_MULTIPLEX\n"); status = torture_rpc_connection_transport(tctx, &p2, &ndr_table_rpcecho, transport, assoc_group_id, DCERPC_CONCURRENT_MULTIPLEX); torture_assert_ntstatus_ok(tctx, status, "opening echo connection 2"); b = p2->binding_handle; for (i=0;i<ASYNC_COUNT;i++) { done1[i] = false; done2[i] = false; snd[i] = timeval_current(); rcv[i] = timeval_zero(); r[i].in.seconds = ASYNC_COUNT-i; req[i] = dcerpc_echo_TestSleep_r_send(tctx, tctx->ev, b, &r[i]); torture_assert(tctx, req[i], "Failed to send async sleep request\n"); tevent_req_set_callback(req[i], test_sleep_done, &done1[i]); } while (total_done < ASYNC_COUNT) { torture_assert(tctx, tevent_loop_once(tctx->ev) == 0, "Event context loop failed"); for (i=0;i<ASYNC_COUNT;i++) { if (done2[i] == false && done1[i] == true) { int rounded_tdiff; total_done++; done2[i] = true; rcv[i] = timeval_current(); diff[i] = timeval_until(&snd[i], &rcv[i]); rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec)); torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff); torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestSleep_r_recv(req[i], tctx), talloc_asprintf(tctx, "TestSleep(%d) failed", i)); torture_assert(tctx, r[i].out.result == r[i].in.seconds, talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)", r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec)); torture_assert(tctx, r[i].out.result <= rounded_tdiff, talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec)); if (r[i].out.result+1 == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else if (r[i].out.result == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else { torture_fail(tctx, talloc_asprintf(tctx, "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec)); } } } } torture_comment(tctx, "\n"); return true; }
static void print_notify_send_messages_to_printer(struct messaging_context *msg_ctx, const char *printer, unsigned int timeout) { char *buf; struct notify_queue *pq, *pq_next; size_t msg_count = 0, offset = 0; size_t num_pids = 0; size_t i; pid_t *pid_list = NULL; struct timeval end_time = timeval_zero(); /* Count the space needed to send the messages. */ for (pq = notify_queue_head; pq; pq = pq->next) { if (strequal(printer, pq->msg->printer)) { if (!flatten_message(pq)) { DEBUG(0,("print_notify_send_messages: Out of memory\n")); talloc_free_children(send_ctx); num_messages = 0; return; } offset += (pq->buflen + 4); msg_count++; } } offset += 4; /* For count. */ buf = (char *)TALLOC(send_ctx, offset); if (!buf) { DEBUG(0,("print_notify_send_messages: Out of memory\n")); talloc_free_children(send_ctx); num_messages = 0; return; } offset = 0; SIVAL(buf,offset,msg_count); offset += 4; for (pq = notify_queue_head; pq; pq = pq_next) { pq_next = pq->next; if (strequal(printer, pq->msg->printer)) { SIVAL(buf,offset,pq->buflen); offset += 4; memcpy(buf + offset, pq->buf, pq->buflen); offset += pq->buflen; /* Remove from list. */ DLIST_REMOVE(notify_queue_head, pq); } } DEBUG(5, ("print_notify_send_messages_to_printer: sending %lu print notify message%s to printer %s\n", (unsigned long)msg_count, msg_count != 1 ? "s" : "", printer)); /* * Get the list of PID's to send to. */ if (!print_notify_pid_list(printer, send_ctx, &num_pids, &pid_list)) return; if (timeout != 0) { end_time = timeval_current_ofs(timeout, 0); } for (i = 0; i < num_pids; i++) { messaging_send_buf(msg_ctx, pid_to_procid(pid_list[i]), MSG_PRINTER_NOTIFY2 | MSG_FLAG_LOWPRIORITY, (uint8 *)buf, offset); if ((timeout != 0) && timeval_expired(&end_time)) { break; } } }
/* These two routines could be changed to use a circular buffer of * some kind, or linked lists, or ... */ static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf, size_t wantlen, size_t *nread) { struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); if (!gensec_socket->wrap) { return socket_recv(gensec_socket->socket, buf, wantlen, nread); } gensec_socket->error = NT_STATUS_OK; if (gensec_socket->read_buffer.length == 0) { /* Process any data on the socket, into the read buffer. At * this point, the socket is not available for read any * longer */ packet_recv(gensec_socket->packet); if (gensec_socket->eof) { *nread = 0; return NT_STATUS_OK; } if (!NT_STATUS_IS_OK(gensec_socket->error)) { return gensec_socket->error; } if (gensec_socket->read_buffer.length == 0) { /* Clearly we don't have the entire SASL packet yet, * so it has not been written into the buffer */ *nread = 0; return STATUS_MORE_ENTRIES; } } *nread = MIN(wantlen, gensec_socket->read_buffer.length); memcpy(buf, gensec_socket->read_buffer.data, *nread); if (gensec_socket->read_buffer.length > *nread) { memmove(gensec_socket->read_buffer.data, gensec_socket->read_buffer.data + *nread, gensec_socket->read_buffer.length - *nread); } gensec_socket->read_buffer.length -= *nread; gensec_socket->read_buffer.data = talloc_realloc(gensec_socket, gensec_socket->read_buffer.data, uint8_t, gensec_socket->read_buffer.length); if (gensec_socket->read_buffer.length && gensec_socket->in_extra_read == 0 && gensec_socket->recv_handler) { /* Manually call a read event, to get this moving * again (as the socket should be dry, so the normal * event handler won't trigger) */ tevent_add_timer(gensec_socket->ev, gensec_socket, timeval_zero(), gensec_socket_trigger_read, gensec_socket); } return NT_STATUS_OK; }
/* main program */ int main(int argc, const char *argv[]) { struct ctdb_context *ctdb; struct poptOption popt_options[] = { POPT_AUTOHELP POPT_CTDB_CMDLINE POPT_TABLEEND }; int opt; const char **extra_argv; int extra_argc = 0; poptContext pc; struct event_context *ev; struct ctdb_vnn_map *vnnmap=NULL; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { default: fprintf(stderr, "Invalid option %s: %s\n", poptBadOption(pc, 0), poptStrerror(opt)); exit(1); } } /* setup the remaining options for the main program to use */ extra_argv = poptGetArgs(pc); if (extra_argv) { extra_argv++; while (extra_argv[extra_argc]) extra_argc++; } ev = event_context_init(NULL); ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(5, 0)); if (ctdb == NULL) { exit(1); } /* attach to a specific database */ ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(5, 0), "test.tdb", false, 0); if (!ctdb_db) { printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb)); exit(1); } printf("Waiting for cluster\n"); while (1) { uint32_t recmode=1; ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode); if (recmode == 0) break; event_loop_once(ev); } if (ctdb_ctrl_getvnnmap(ctdb, timeval_zero(), CTDB_CURRENT_NODE, ctdb, &vnnmap) != 0) { printf("Unable to get vnnmap from local node\n"); exit(1); } printf("Current Generation %d\n", (int)vnnmap->generation); fetch_lock_once(ctdb, ev, vnnmap->generation); return 0; }
/* main program */ int main(int argc, const char *argv[]) { struct ctdb_context *ctdb; struct ctdb_db_context *ctdb_db; struct poptOption popt_options[] = { POPT_AUTOHELP POPT_CTDB_CMDLINE { "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" }, { "base-rec", 'b', POPT_ARG_INT, &base_rec, 0, "base_rec", "integer" }, POPT_TABLEEND }; int opt; const char **extra_argv; int extra_argc = 0; poptContext pc; struct event_context *ev; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { default: fprintf(stderr, "Invalid option %s: %s\n", poptBadOption(pc, 0), poptStrerror(opt)); exit(1); } } /* talloc_enable_leak_report_full(); */ /* setup the remaining options for the main program to use */ extra_argv = poptGetArgs(pc); if (extra_argv) { extra_argv++; while (extra_argv[extra_argc]) extra_argc++; } ev = event_context_init(NULL); ctdb = ctdb_cmdline_client(ev); /* attach to a specific database */ ctdb_db = ctdb_attach(ctdb, "test.tdb", false, 0); if (!ctdb_db) { printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb)); exit(1); } printf("Waiting for cluster\n"); while (1) { uint32_t recmode=1; ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode); if (recmode == 0) break; event_loop_once(ev); } store_records(ctdb, ev); return 0; }
static bool recalc_brl_timeout(struct smbd_server_connection *sconn) { struct blocking_lock_record *blr; struct timeval next_timeout; int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5); TALLOC_FREE(sconn->smb1.locks.brl_timeout); next_timeout = timeval_zero(); for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) { if (timeval_is_zero(&blr->expire_time)) { /* * If we're blocked on pid 0xFFFFFFFFFFFFFFFFLL this is * a POSIX lock, so calculate a timeout of * 10 seconds into the future. */ if (blr->blocking_smblctx == 0xFFFFFFFFFFFFFFFFLL) { struct timeval psx_to = timeval_current_ofs(10, 0); next_timeout = timeval_brl_min(&next_timeout, &psx_to); } continue; } next_timeout = timeval_brl_min(&next_timeout, &blr->expire_time); } if (timeval_is_zero(&next_timeout)) { DEBUG(10, ("Next timeout = Infinite.\n")); return True; } /* to account for unclean shutdowns by clients we need a maximum timeout that we use for checking pending locks. If we have any pending locks at all, then check if the pending lock can continue at least every brl:recalctime seconds (default 5 seconds). This saves us needing to do a message_send_all() in the SIGCHLD handler in the parent daemon. That message_send_all() caused O(n^2) work to be done when IP failovers happened in clustered Samba, which could make the entire system unusable for many minutes. */ if (max_brl_timeout > 0) { struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0); next_timeout = timeval_min(&next_timeout, &min_to); } if (DEBUGLVL(10)) { struct timeval cur, from_now; cur = timeval_current(); from_now = timeval_until(&cur, &next_timeout); DEBUG(10, ("Next timeout = %d.%d seconds from now.\n", (int)from_now.tv_sec, (int)from_now.tv_usec)); } sconn->smb1.locks.brl_timeout = tevent_add_timer(sconn->ev_ctx, NULL, next_timeout, brl_timeout_fn, sconn); if (sconn->smb1.locks.brl_timeout == NULL) { return False; } return True; }
/* test the TestSleep interface */ static bool test_sleep(struct torture_context *tctx, struct dcerpc_pipe *p) { int i; NTSTATUS status; #define ASYNC_COUNT 3 struct rpc_request *req[ASYNC_COUNT]; struct echo_TestSleep r[ASYNC_COUNT]; bool done[ASYNC_COUNT]; struct timeval snd[ASYNC_COUNT]; struct timeval rcv[ASYNC_COUNT]; struct timeval diff[ASYNC_COUNT]; struct tevent_context *ctx; int total_done = 0; if (torture_setting_bool(tctx, "quick", false)) { torture_skip(tctx, "TestSleep disabled - use \"torture:quick=no\" to enable\n"); } torture_comment(tctx, "Testing TestSleep - use \"torture:quick=yes\" to disable\n"); for (i=0;i<ASYNC_COUNT;i++) { done[i] = false; snd[i] = timeval_current(); rcv[i] = timeval_zero(); r[i].in.seconds = ASYNC_COUNT-i; req[i] = dcerpc_echo_TestSleep_send(p, tctx, &r[i]); torture_assert(tctx, req[i], "Failed to send async sleep request\n"); } ctx = dcerpc_event_context(p); while (total_done < ASYNC_COUNT) { torture_assert(tctx, event_loop_once(ctx) == 0, "Event context loop failed"); for (i=0;i<ASYNC_COUNT;i++) { if (done[i] == false && req[i]->state == RPC_REQUEST_DONE) { int rounded_tdiff; total_done++; done[i] = true; rcv[i] = timeval_current(); diff[i] = timeval_until(&snd[i], &rcv[i]); rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec)); status = dcerpc_ndr_request_recv(req[i]); torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff); torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "TestSleep(%d) failed", i)); torture_assert(tctx, r[i].out.result == r[i].in.seconds, talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)", r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec)); torture_assert(tctx, r[i].out.result <= rounded_tdiff, talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec)); if (r[i].out.result+1 == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else if (r[i].out.result == rounded_tdiff) { torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); } else { torture_comment(tctx, "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)", r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec); /* TODO: let the test fail here, when we support async rpc on ncacn_np */ } } } } torture_comment(tctx, "\n"); return true; }
/* call this when the socket becomes readable to kick off the whole stream parsing process */ _PUBLIC_ void packet_recv(struct packet_context *pc) { size_t npending; NTSTATUS status; size_t nread = 0; DATA_BLOB blob; bool recv_retry = false; if (pc->processing) { TEVENT_FD_NOT_READABLE(pc->fde); pc->processing++; return; } if (pc->recv_disable) { pc->recv_need_enable = true; TEVENT_FD_NOT_READABLE(pc->fde); return; } if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) { goto next_partial; } if (pc->packet_size != 0) { /* we've already worked out how long this next packet is, so skip the socket_pending() call */ npending = pc->packet_size - pc->num_read; } else if (pc->initial_read != 0) { npending = pc->initial_read - pc->num_read; } else { if (pc->sock) { status = socket_pending(pc->sock, &npending); } else { status = NT_STATUS_CONNECTION_DISCONNECTED; } if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; } } if (npending == 0) { packet_eof(pc); return; } again: if (npending + pc->num_read < npending) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } if (npending + pc->num_read < pc->num_read) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } /* possibly expand the partial packet buffer */ if (npending + pc->num_read > pc->partial.length) { if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } } if (pc->partial.length < pc->num_read + npending) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) { packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } status = socket_recv(pc->sock, pc->partial.data + pc->num_read, npending, &nread); if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; } if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { nread = 0; status = NT_STATUS_OK; } if (!NT_STATUS_IS_OK(status)) { return; } if (nread == 0 && !recv_retry) { packet_eof(pc); return; } pc->num_read += nread; if (pc->unreliable_select && nread != 0) { recv_retry = true; status = socket_pending(pc->sock, &npending); if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; } if (npending != 0) { goto again; } } next_partial: if (pc->partial.length != pc->num_read) { if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } } /* see if its a full request */ blob = pc->partial; blob.length = pc->num_read; status = pc->full_request(pc->private_data, blob, &pc->packet_size); if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; } if (!NT_STATUS_IS_OK(status)) { return; } if (pc->packet_size > pc->num_read) { /* the caller made an error */ DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n", (long)pc->packet_size, (long)pc->num_read)); packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } /* it is a full request - give it to the caller */ blob = pc->partial; blob.length = pc->num_read; if (pc->packet_size < pc->num_read) { pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, pc->num_read - pc->packet_size); if (pc->partial.data == NULL) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } /* Trunate the blob sent to the caller to only the packet length */ if (!data_blob_realloc(pc, &blob, pc->packet_size)) { packet_error(pc, NT_STATUS_NO_MEMORY); return; } } else { pc->partial = data_blob(NULL, 0); } pc->num_read -= pc->packet_size; pc->packet_size = 0; if (pc->serialise) { pc->processing = 1; } pc->busy = true; status = pc->callback(pc->private_data, blob); pc->busy = false; if (pc->destructor_called) { talloc_free(pc); return; } if (pc->processing) { if (pc->processing > 1) { TEVENT_FD_READABLE(pc->fde); } pc->processing = 0; } if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; } /* Have we consumed the whole buffer yet? */ if (pc->partial.length == 0) { return; } /* we got multiple packets in one tcp read */ if (pc->ev == NULL) { goto next_partial; } blob = pc->partial; blob.length = pc->num_read; status = pc->full_request(pc->private_data, blob, &pc->packet_size); if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; } if (!NT_STATUS_IS_OK(status)) { return; } tevent_add_timer(pc->ev, pc, timeval_zero(), packet_next_event, pc); }
/* main program */ int main(int argc, const char *argv[]) { struct ctdb_context *ctdb; struct ctdb_db_context *ctdb_db; struct tevent_context *ev; TDB_DATA key; struct poptOption popt_options[] = { POPT_AUTOHELP { "record", 'r', POPT_ARG_STRING, &TESTKEY, 0, "record", "string" }, POPT_TABLEEND }; int opt; const char **extra_argv; int extra_argc = 0; poptContext pc; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { default: fprintf(stderr, "Invalid option %s: %s\n", poptBadOption(pc, 0), poptStrerror(opt)); exit(1); } } /* setup the remaining options for the main program to use */ extra_argv = poptGetArgs(pc); if (extra_argv) { extra_argv++; while (extra_argv[extra_argc]) extra_argc++; } ev = tevent_context_init(NULL); ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0)); if (ctdb == NULL) { printf("failed to connect to ctdb daemon.\n"); exit(1); } key.dptr = discard_const(TESTKEY); key.dsize = strlen(TESTKEY); /* attach to a specific database */ ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(3, 0), "test.tdb", false, 0); if (!ctdb_db) { fprintf(stderr, "ctdb_attach failed - %s\n", ctdb_errstr(ctdb)); exit(10); } printf("Waiting for cluster\n"); while (1) { uint32_t recmode=1; ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode); if (recmode == 0) break; tevent_loop_once(ev); } fetch_readonly_once(ctdb, ctdb_db, key); return 0; }
/* load our replication partners */ NTSTATUS wreplsrv_load_partners(struct wreplsrv_service *service) { struct wreplsrv_partner *partner; struct ldb_result *res = NULL; int ret; TALLOC_CTX *tmp_ctx; int i; uint64_t new_seqnumber; new_seqnumber = wins_config_db_get_seqnumber(service->config.ldb); /* if it's not the first run and nothing changed we're done */ if (service->config.seqnumber != 0 && service->config.seqnumber == new_seqnumber) { return NT_STATUS_OK; } tmp_ctx = talloc_new(service); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); service->config.seqnumber = new_seqnumber; /* find the record in the WINS database */ ret = ldb_search(service->config.ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, service->config.ldb, "CN=PARTNERS"), LDB_SCOPE_SUBTREE, NULL, "(objectClass=wreplPartner)"); if (ret != LDB_SUCCESS) goto failed; /* first disable all existing partners */ for (partner=service->partners; partner; partner = partner->next) { partner->type = WINSREPL_PARTNER_NONE; } for (i=0; i < res->count; i++) { const char *address; address = ldb_msg_find_attr_as_string(res->msgs[i], "address", NULL); if (!address) { goto failed; } partner = wreplsrv_find_partner(service, address); if (partner) { if (partner->name != partner->address) { talloc_free(discard_const(partner->name)); } partner->name = NULL; talloc_free(discard_const(partner->our_address)); partner->our_address = NULL; /* force rescheduling of pulling */ partner->pull.next_run = timeval_zero(); } else { partner = talloc_zero(service, struct wreplsrv_partner); if (partner == NULL) goto failed; partner->service = service; partner->address = address; talloc_steal(partner, partner->address); DLIST_ADD_END(service->partners, partner, struct wreplsrv_partner *); } partner->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", partner->address); talloc_steal(partner, partner->name); partner->our_address = ldb_msg_find_attr_as_string(res->msgs[i], "ourAddress", NULL); talloc_steal(partner, partner->our_address); partner->type = ldb_msg_find_attr_as_uint(res->msgs[i], "type", WINSREPL_PARTNER_BOTH); partner->pull.interval = ldb_msg_find_attr_as_uint(res->msgs[i], "pullInterval", WINSREPL_DEFAULT_PULL_INTERVAL); partner->pull.retry_interval = ldb_msg_find_attr_as_uint(res->msgs[i], "pullRetryInterval", WINSREPL_DEFAULT_PULL_RETRY_INTERVAL); partner->push.change_count = ldb_msg_find_attr_as_uint(res->msgs[i], "pushChangeCount", WINSREPL_DEFAULT_PUSH_CHANGE_COUNT); partner->push.use_inform = ldb_msg_find_attr_as_uint(res->msgs[i], "pushUseInform", true); DEBUG(3,("wreplsrv_load_partners: found partner: %s type: 0x%X\n", partner->address, partner->type)); } DEBUG(2,("wreplsrv_load_partners: %u partners found: wins_config_db seqnumber %llu\n", res->count, (unsigned long long)service->config.seqnumber)); talloc_free(tmp_ctx); return NT_STATUS_OK; failed: talloc_free(tmp_ctx); return NT_STATUS_FOOBAR; }
/* serve up EchoData over the irpc system */ static NTSTATUS irpc_EchoData(struct irpc_message *irpc, struct echo_EchoData *r) { irpc->defer_reply = true; event_add_timed(irpc->ev, irpc, timeval_zero(), deferred_echodata, irpc); return NT_STATUS_OK; }
/* main program */ int main(int argc, const char *argv[]) { struct ctdb_context *ctdb; struct ctdb_db_context *ctdb_db; int unsafe_writes = 0; struct poptOption popt_options[] = { POPT_AUTOHELP POPT_CTDB_CMDLINE { "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" }, { "delay", 'D', POPT_ARG_INT, &delay, 0, "delay (in seconds) between operations", "integer" }, { "verbose", 'v', POPT_ARG_NONE, &verbose, 0, "switch on verbose mode", NULL }, { "unsafe-writes", 'u', POPT_ARG_NONE, &unsafe_writes, 0, "do not use tdb transactions when writing", NULL }, POPT_TABLEEND }; int opt; const char **extra_argv; int extra_argc = 0; poptContext pc; struct event_context *ev; printf("SUCCESS (transaction test disabled while transactions are being rewritten)\n"); exit(0); if (verbose) { setbuf(stdout, (char *)NULL); /* don't buffer */ } else { setlinebuf(stdout); } pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { default: fprintf(stderr, "Invalid option %s: %s\n", poptBadOption(pc, 0), poptStrerror(opt)); exit(1); } } /* setup the remaining options for the main program to use */ extra_argv = poptGetArgs(pc); if (extra_argv) { extra_argv++; while (extra_argv[extra_argc]) extra_argc++; } ev = event_context_init(NULL); ctdb = ctdb_cmdline_client(ev); if (ctdb == NULL) { DEBUG(DEBUG_ERR, ("Could not attach to daemon\n")); return 1; } /* attach to a specific database */ if (unsafe_writes == 1) { ctdb_db = ctdb_attach(ctdb, "transaction.tdb", true, TDB_NOSYNC); } else { ctdb_db = ctdb_attach(ctdb, "transaction.tdb", true, 0); } if (!ctdb_db) { DEBUG(DEBUG_ERR, ("ctdb_attach failed - %s\n", ctdb_errstr(ctdb))); exit(1); } DEBUG(DEBUG_ERR, ("Waiting for cluster\n")); while (1) { uint32_t recmode=1; ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode); if (recmode == 0) break; event_loop_once(ev); } pnn = ctdb_get_pnn(ctdb); printf("Starting test on node %u. running for %u seconds. sleep delay: %u seconds.\n", pnn, timelimit, delay); if (!verbose && (pnn == 0)) { event_add_timed(ev, ctdb, timeval_current_ofs(1, 0), each_second, ctdb); } test_store_records(ctdb, ev); if (verbose || (pnn == 0)) { if (success != true) { printf("The test FAILED\n"); return 1; } else { printf("SUCCESS!\n"); } } return 0; }