smbd/winbindd: Do an early check if ctdbd is functional
[mat/samba.git] / source3 / lib / ctdbd_conn.c
index dddb41285e5ec4d360a91d29ffc8ac61a366d76e..6ab4bbe70466e5e875fa18d8f27698fe51ec59a6 100644 (file)
@@ -57,7 +57,7 @@ struct ctdbd_connection {
        uint32_t our_vnn;
        uint64_t rand_srvid;
        struct ctdb_packet_context *pkt;
-       struct fd_event *fde;
+       struct tevent_fd *fde;
 
        void (*release_ip_handler)(const char *ip_addr, void *private_data);
        void *release_ip_priv;
@@ -128,7 +128,8 @@ static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32_t *vnn)
                               CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0,
                               tdb_null, NULL, NULL, &cstatus);
        if (!NT_STATUS_IS_OK(status)) {
-               cluster_fatal("ctdbd_control failed\n");
+               DEBUG(1, ("ctdbd_control failed: %s\n", nt_errstr(status)));
+               return status;
        }
        *vnn = (uint32_t)cstatus;
        return status;
@@ -151,7 +152,8 @@ static bool ctdbd_working(struct ctdbd_connection *conn, uint32_t vnn)
                               CTDB_CONTROL_GET_NODEMAP, 0, 0,
                               tdb_null, talloc_tos(), &outdata, &cstatus);
        if (!NT_STATUS_IS_OK(status)) {
-               cluster_fatal("ctdbd_control failed\n");
+               DEBUG(1, ("ctdbd_control failed: %s\n", nt_errstr(status)));
+               return false;
        }
        if ((cstatus != 0) || (outdata.dptr == NULL)) {
                DEBUG(2, ("Received invalid ctdb data\n"));
@@ -201,7 +203,7 @@ static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx,
 {
        struct ctdb_packet_context *result;
        const char *sockname = lp_ctdbd_socket();
-       struct sockaddr_un addr;
+       struct sockaddr_un addr = { 0, };
        int fd;
        socklen_t salen;
 
@@ -211,9 +213,8 @@ static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx,
                return map_nt_error_from_unix(errno);
        }
 
-       ZERO_STRUCT(addr);
        addr.sun_family = AF_UNIX;
-       strncpy(addr.sun_path, sockname, sizeof(addr.sun_path));
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", sockname);
 
        salen = sizeof(struct sockaddr_un);
        if (connect(fd, (struct sockaddr *)(void *)&addr, salen) == -1) {
@@ -279,8 +280,8 @@ struct deferred_msg_state {
  * Timed event handler for the deferred message
  */
 
-static void deferred_message_dispatch(struct event_context *event_ctx,
-                                     struct timed_event *te,
+static void deferred_message_dispatch(struct tevent_context *event_ctx,
+                                     struct tevent_timer *te,
                                      struct timeval now,
                                      void *private_data)
 {
@@ -414,7 +415,7 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid,
        ctdb_packet_dump(hdr);
 
        if (hdr->operation == CTDB_REQ_MESSAGE) {
-               struct timed_event *evt;
+               struct tevent_timer *evt;
                struct deferred_msg_state *msg_state;
                struct ctdb_req_message *msg = (struct ctdb_req_message *)hdr;
 
@@ -476,7 +477,7 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid,
                 * We're waiting for a call reply, but an async message has
                 * crossed. Defer dispatching to the toplevel event loop.
                 */
-               evt = event_add_timed(conn->msg_ctx->event_ctx,
+               evt = tevent_add_timer(conn->msg_ctx->event_ctx,
                                      conn->msg_ctx->event_ctx,
                                      timeval_zero(),
                                      deferred_message_dispatch,
@@ -685,8 +686,8 @@ static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t length,
  * The ctdbd socket is readable asynchronuously
  */
 
-static void ctdbd_socket_handler(struct event_context *event_ctx,
-                                struct fd_event *event,
+static void ctdbd_socket_handler(struct tevent_context *event_ctx,
+                                struct tevent_fd *event,
                                 uint16 flags,
                                 void *private_data)
 {
@@ -721,9 +722,9 @@ NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn,
        SMB_ASSERT(conn->msg_ctx == NULL);
        SMB_ASSERT(conn->fde == NULL);
 
-       if (!(conn->fde = event_add_fd(msg_ctx->event_ctx, conn,
+       if (!(conn->fde = tevent_add_fd(msg_ctx->event_ctx, conn,
                                       ctdb_packet_get_fd(conn->pkt),
-                                      EVENT_FD_READ,
+                                      TEVENT_FD_READ,
                                       ctdbd_socket_handler,
                                       conn))) {
                DEBUG(0, ("event_add_fd failed\n"));
@@ -760,7 +761,7 @@ NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn,
        status = ctdbd_messaging_send_blob(conn, dst_vnn, dst_srvid,
                                           blob.data, blob.length);
        TALLOC_FREE(blob.data);
-       return NT_STATUS_OK;
+       return status;
 }
 
 NTSTATUS ctdbd_messaging_send_blob(struct ctdbd_connection *conn,
@@ -1190,6 +1191,7 @@ bool ctdb_serverids_exist(struct ctdbd_connection *conn,
                struct ctdb_reply_control *reply = NULL;
                struct ctdb_vnn_list *vnn;
                uint32_t reqid;
+               uint8_t *reply_data;
 
                status = ctdb_read_req(conn, 0, talloc_tos(), (void *)&reply);
                if (!NT_STATUS_IS_OK(status)) {
@@ -1227,13 +1229,26 @@ bool ctdb_serverids_exist(struct ctdbd_connection *conn,
                           (unsigned)vnn->vnn, vnn->num_srvids,
                           (unsigned)reply->datalen));
 
-               if (reply->datalen < ((vnn->num_srvids+7)/8)) {
-                       DEBUG(1, ("Received short reply len %d, status %u,"
+               if (reply->datalen >= ((vnn->num_srvids+7)/8)) {
+                       /*
+                        * Got a real reply
+                        */
+                       reply_data = reply->data;
+               } else {
+                       /*
+                        * Got an error reply
+                        */
+                       DEBUG(5, ("Received short reply len %d, status %u, "
                                  "errorlen %u\n",
                                  (unsigned)reply->datalen,
                                  (unsigned)reply->status,
                                  (unsigned)reply->errorlen));
-                       goto fail;
+                       dump_data(5, reply->data, reply->errorlen);
+
+                       /*
+                        * This will trigger everything set to false
+                        */
+                       reply_data = NULL;
                }
 
                for (i=0; i<vnn->num_srvids; i++) {
@@ -1244,7 +1259,9 @@ bool ctdb_serverids_exist(struct ctdbd_connection *conn,
                                results[idx] = true;
                                continue;
                        }
-                       results[idx] = ((reply->data[i/8] & (1<<(i%8))) != 0);
+                       results[idx] =
+                               (reply_data != NULL) &&
+                               ((reply_data[i/8] & (1<<(i%8))) != 0);
                }
 
                TALLOC_FREE(reply);
@@ -1398,11 +1415,13 @@ NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32_t db_id,
 }
 
 /*
- * remotely fetch a record (read-only)
+ * Fetch a record and parse it
  */
-NTSTATUS ctdbd_fetch(struct ctdbd_connection *conn, uint32_t db_id,
-                    TDB_DATA key, TALLOC_CTX *mem_ctx, TDB_DATA *data,
-                    bool local_copy)
+NTSTATUS ctdbd_parse(struct ctdbd_connection *conn, uint32_t db_id,
+                    TDB_DATA key, bool local_copy,
+                    void (*parser)(TDB_DATA key, TDB_DATA data,
+                                   void *private_data),
+                    void *private_data)
 {
        struct ctdb_req_call req;
        struct ctdb_reply_call *reply;
@@ -1457,21 +1476,17 @@ NTSTATUS ctdbd_fetch(struct ctdbd_connection *conn, uint32_t db_id,
                goto fail;
        }
 
-       data->dsize = reply->datalen;
-       if (data->dsize == 0) {
-               data->dptr = NULL;
-               goto done;
-       }
-
-       data->dptr = (uint8 *)talloc_memdup(mem_ctx, &reply->data[0],
-                                           reply->datalen);
-       if (data->dptr == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               status = NT_STATUS_NO_MEMORY;
+       if (reply->datalen == 0) {
+               /*
+                * Treat an empty record as non-existing
+                */
+               status = NT_STATUS_NOT_FOUND;
                goto fail;
        }
 
- done:
+       parser(key, make_tdb_data(&reply->data[0], reply->datalen),
+              private_data);
+
        status = NT_STATUS_OK;
  fail:
        TALLOC_FREE(reply);
@@ -1807,8 +1822,32 @@ NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn)
        return status;
 }
 
+NTSTATUS ctdbd_probe(void)
+{
+       /*
+        * Do a very early check if ctdbd is around to avoid an abort and core
+        * later
+        */
+       struct ctdbd_connection *conn = NULL;
+       NTSTATUS status;
+
+       status = ctdbd_messaging_connection(talloc_tos(), &conn);
+
+       /*
+        * We only care if we can connect.
+        */
+       TALLOC_FREE(conn);
+
+       return status;
+}
+
 #else
 
+NTSTATUS ctdbd_probe(void)
+{
+       return NT_STATUS_OK;
+}
+
 NTSTATUS ctdbd_messaging_send_blob(struct ctdbd_connection *conn,
                                   uint32_t dst_vnn, uint64_t dst_srvid,
                                   const uint8_t *buf, size_t buflen)