/* start listening on a mailslot. talloc_free() the handle to stop listening */ struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock, const char *mailslot_name, dgram_mailslot_handler_t handler, void *private_data) { struct dgram_mailslot_handler *dgmslot; dgmslot = talloc(dgmsock, struct dgram_mailslot_handler); if (dgmslot == NULL) return NULL; dgmslot->dgmsock = dgmsock; dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name); if (dgmslot->mailslot_name == NULL) { talloc_free(dgmslot); return NULL; } dgmslot->handler = handler; dgmslot->private_data = private_data; DLIST_ADD(dgmsock->mailslot_handlers, dgmslot); talloc_set_destructor(dgmslot, dgram_mailslot_destructor); TEVENT_FD_READABLE(dgmsock->fde); return dgmslot; }
/* setup a handler for generic incoming requests */ NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock, void (*handler)(struct nbt_dgram_socket *, struct nbt_dgram_packet *, struct socket_address *), void *private_data) { dgmsock->incoming.handler = handler; dgmsock->incoming.private_data = private_data; TEVENT_FD_READABLE(dgmsock->fde); return NT_STATUS_OK; }
/* 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); } }
/* handle send events on a smb_krb5 socket */ static void smb_krb5_socket_send(struct smb_krb5_socket *smb_krb5) { NTSTATUS status; size_t len; len = smb_krb5->request.length; status = socket_send(smb_krb5->sock, &smb_krb5->request, &len); if (!NT_STATUS_IS_OK(status)) return; TEVENT_FD_READABLE(smb_krb5->fde); TEVENT_FD_NOT_WRITEABLE(smb_krb5->fde); return; }
static void test_event_fd1_finished(struct tevent_context *ev_ctx, struct tevent_timer *te, struct timeval tval, void *private_data) { struct test_event_fd1_state *state = (struct test_event_fd1_state *)private_data; if (state->drain_done) { state->finished = true; return; } if (!state->got_write) { state->finished = true; state->error = __location__; return; } if (!state->got_read) { state->finished = true; state->error = __location__; return; } state->loop_count++; if (state->loop_count > 3) { state->finished = true; state->error = __location__; return; } state->got_write = false; state->got_read = false; tevent_fd_set_flags(state->fde0, TEVENT_FD_WRITE); if (state->loop_count > 2) { state->drain = true; TALLOC_FREE(state->fde1); TEVENT_FD_READABLE(state->fde0); } state->te = tevent_add_timer(state->ev, state->ev, timeval_current_ofs(0,2000), test_event_fd1_finished, state); }
static void client_send(struct cli_ctx *cctx) { int ret; ret = sss_packet_send(cctx->creq->out, cctx->cfd); if (ret == EAGAIN) { /* not all data was sent, loop again */ return; } if (ret != EOK) { DEBUG(0, ("Failed to send data, aborting client!\n")); talloc_free(cctx); return; } /* ok all sent */ TEVENT_FD_NOT_WRITEABLE(cctx->cfde); TEVENT_FD_READABLE(cctx->cfde); talloc_free(cctx->creq); cctx->creq = NULL; return; }
/* 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); }
static void test_event_fd1_fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *fde, uint16_t flags, void *private_data) { struct test_event_fd1_state *state = (struct test_event_fd1_state *)private_data; if (state->drain_done) { state->finished = true; state->error = __location__; return; } if (state->drain) { ssize_t ret; uint8_t c = 0; if (!(flags & TEVENT_FD_READ)) { state->finished = true; state->error = __location__; return; } ret = read(state->sock[0], &c, 1); if (ret == 1) { return; } /* * end of test... */ tevent_fd_set_flags(fde, 0); state->drain_done = true; return; } if (!state->got_write) { uint8_t c = 0; if (flags != TEVENT_FD_WRITE) { state->finished = true; state->error = __location__; return; } state->got_write = true; /* * we write to the other socket... */ write(state->sock[1], &c, 1); TEVENT_FD_NOT_WRITEABLE(fde); TEVENT_FD_READABLE(fde); return; } if (!state->got_read) { if (flags != TEVENT_FD_READ) { state->finished = true; state->error = __location__; return; } state->got_read = true; TEVENT_FD_NOT_READABLE(fde); return; } state->finished = true; state->error = __location__; return; }
/* called when a new socket connection has been established. This is called in the process context of the new process (if appropriate) */ static void stream_new_connection(struct tevent_context *ev, struct loadparm_context *lp_ctx, struct socket_context *sock, struct server_id server_id, void *private_data) { struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket); struct stream_connection *srv_conn; srv_conn = talloc_zero(ev, struct stream_connection); if (!srv_conn) { DEBUG(0,("talloc(mem_ctx, struct stream_connection) failed\n")); return; } talloc_steal(srv_conn, sock); srv_conn->private_data = stream_socket->private_data; srv_conn->model_ops = stream_socket->model_ops; srv_conn->socket = sock; srv_conn->server_id = server_id; srv_conn->ops = stream_socket->ops; srv_conn->event.ctx = ev; srv_conn->lp_ctx = lp_ctx; if (!socket_check_access(sock, "smbd", lpcfg_hostsallow(NULL, lpcfg_default_service(lp_ctx)), lpcfg_hostsdeny(NULL, lpcfg_default_service(lp_ctx)))) { stream_terminate_connection(srv_conn, "denied by access rules"); return; } srv_conn->event.fde = tevent_add_fd(ev, srv_conn, socket_get_fd(sock), 0, stream_io_handler_fde, srv_conn); if (!srv_conn->event.fde) { stream_terminate_connection(srv_conn, "tevent_add_fd() failed"); return; } /* setup to receive internal messages on this connection */ srv_conn->msg_ctx = imessaging_init(srv_conn, lpcfg_imessaging_path(srv_conn, lp_ctx), srv_conn->server_id, ev, false); if (!srv_conn->msg_ctx) { stream_terminate_connection(srv_conn, "imessaging_init() failed"); return; } srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn); if (!srv_conn->remote_address) { stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed"); return; } srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn); if (!srv_conn->local_address) { stream_terminate_connection(srv_conn, "socket_get_local_addr() failed"); return; } { TALLOC_CTX *tmp_ctx; const char *title; tmp_ctx = talloc_new(srv_conn); title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]", stream_socket->ops->name, tsocket_address_string(srv_conn->remote_address, tmp_ctx), tsocket_address_string(srv_conn->local_address, tmp_ctx), server_id_str(tmp_ctx, &server_id)); if (title) { stream_connection_set_title(srv_conn, title); } talloc_free(tmp_ctx); } /* we're now ready to start receiving events on this stream */ TEVENT_FD_READABLE(srv_conn->event.fde); /* call the server specific accept code */ stream_socket->ops->accept_connection(srv_conn); }