/* setup a handler for incoming requests */ NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c, void (*handler)(struct cldap_socket *, void *private_data, struct cldap_incoming *), void *private_data) { if (c->connected) { return NT_STATUS_PIPE_CONNECTED; } /* if sync requests are allowed, we don't allow an incoming handler */ if (c->event.allow_poll) { return NT_STATUS_INVALID_PIPE_STATE; } c->incoming.handler = handler; c->incoming.private_data = private_data; if (!cldap_recvfrom_setup(c)) { ZERO_STRUCT(c->incoming); return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; }
static void cldap_recvfrom_done(struct tevent_req *subreq) { struct cldap_socket *c = tevent_req_callback_data(subreq, struct cldap_socket); struct cldap_incoming *in = NULL; ssize_t ret; c->recv_subreq = NULL; in = talloc_zero(c, struct cldap_incoming); if (!in) { goto nomem; } ret = tdgram_recvfrom_recv(subreq, &in->recv_errno, in, &in->buf, &in->src); talloc_free(subreq); subreq = NULL; if (ret >= 0) { in->len = ret; } if (ret == -1 && in->recv_errno == 0) { in->recv_errno = EIO; } /* this function should free or steal 'in' */ cldap_socket_recv_dgram(c, in); in = NULL; if (!cldap_recvfrom_setup(c)) { goto nomem; } return; nomem: talloc_free(subreq); talloc_free(in); /*TODO: call a dead socket handler */ return; }
/* setup a handler for incoming requests */ NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c, struct tevent_context *ev, void (*handler)(struct cldap_socket *, void *private_data, struct cldap_incoming *), void *private_data) { if (c->connected) { return NT_STATUS_PIPE_CONNECTED; } c->incoming.ev = ev; c->incoming.handler = handler; c->incoming.private_data = private_data; if (!cldap_recvfrom_setup(c)) { ZERO_STRUCT(c->incoming); return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; }
/* handle recv events on a cldap socket */ static bool cldap_socket_recv_dgram(struct cldap_socket *c, struct cldap_incoming *in) { DATA_BLOB blob; struct asn1_data *asn1; void *p; struct cldap_search_state *search; NTSTATUS status; if (in->recv_errno != 0) { goto error; } blob = data_blob_const(in->buf, in->len); asn1 = asn1_init(in); if (!asn1) { goto nomem; } if (!asn1_load(asn1, blob)) { goto nomem; } in->ldap_msg = talloc(in, struct ldap_message); if (in->ldap_msg == NULL) { goto nomem; } /* this initial decode is used to find the message id */ status = ldap_decode(asn1, NULL, in->ldap_msg); if (!NT_STATUS_IS_OK(status)) { goto nterror; } /* find the pending request */ p = idr_find(c->searches.idr, in->ldap_msg->messageid); if (p == NULL) { if (!c->incoming.handler) { TALLOC_FREE(in); return true; } /* this function should free or steal 'in' */ c->incoming.handler(c, c->incoming.private_data, in); return false; } search = talloc_get_type_abort(p, struct cldap_search_state); search->response.in = talloc_move(search, &in); search->response.asn1 = asn1; search->response.asn1->ofs = 0; DLIST_REMOVE(c->searches.list, search); if (cldap_recvfrom_setup(c)) { tevent_req_done(search->req); return true; } /* * This request was ok, just defer the notify of the caller * and then just fail the next request if needed */ tevent_req_defer_callback(search->req, search->caller.ev); tevent_req_done(search->req); status = NT_STATUS_NO_MEMORY; /* in is NULL it this point */ goto nterror; nomem: in->recv_errno = ENOMEM; error: status = map_nt_error_from_unix_common(in->recv_errno); nterror: TALLOC_FREE(in); /* in connected mode the first pending search gets the error */ if (!c->connected) { /* otherwise we just ignore the error */ return false; } if (!c->searches.list) { return false; } /* * We might called tevent_req_done() for a successful * search before, so we better deliver the failure * after the success, that is why we better also * use tevent_req_defer_callback() here. */ tevent_req_defer_callback(c->searches.list->req, c->searches.list->caller.ev); tevent_req_nterror(c->searches.list->req, status); return false; }