fixed some warnings
[metze/ctdb/wip.git] / common / ctdb_client.c
index 2e3725c449eed7dd16ed2c75e91a68f7756acc65..f3f3adb9bb5af032953a042df7dc6cf77f26a59a 100644 (file)
@@ -45,6 +45,7 @@ static void ctdb_reply_connect_wait(struct ctdb_context *ctdb,
                                    struct ctdb_req_header *hdr)
 {
        struct ctdb_reply_connect_wait *r = (struct ctdb_reply_connect_wait *)hdr;
+       ctdb->vnn = r->vnn;
        ctdb->num_connected = r->num_connected;
 }
 
@@ -69,9 +70,15 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he
        struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
        struct ctdb_client_call_state *state;
 
-       state = idr_find_type(ctdb->idr, hdr->reqid, struct ctdb_client_call_state);
+       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state);
        if (state == NULL) {
-               DEBUG(0, ("reqid %d not found\n", hdr->reqid));
+               DEBUG(0,(__location__ " reqid %d not found\n", hdr->reqid));
+               return;
+       }
+
+       if (hdr->reqid != state->reqid) {
+               /* we found a record  but it was the wrong one */
+               DEBUG(0, ("Dropped orphaned reply with reqid:%d\n",hdr->reqid));
                return;
        }
 
@@ -84,6 +91,8 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he
        state->state = CTDB_CALL_DONE;
 }
 
+static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+
 /*
   this is called in the client, when data comes in from the daemon
  */
@@ -110,8 +119,8 @@ static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
                goto done;
        }
        if (cnt != hdr->length) {
-               ctdb_set_error(ctdb, "Bad header length %d expected %d in client\n", 
-                              hdr->length, cnt);
+               ctdb_set_error(ctdb, "Bad header length %u expected %u in client\n", 
+                              (unsigned)hdr->length, (unsigned)cnt);
                goto done;
        }
 
@@ -138,6 +147,10 @@ static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
                ctdb_reply_connect_wait(ctdb, hdr);
                break;
 
+       case CTDB_REPLY_CONTROL:
+               ctdb_client_reply_control(ctdb, hdr);
+               break;
+
        default:
                DEBUG(0,("bogus operation code:%d\n",hdr->operation));
        }
@@ -149,7 +162,7 @@ done:
 /*
   connect to a unix domain socket
 */
-static int ux_socket_connect(struct ctdb_context *ctdb)
+int ctdb_socket_connect(struct ctdb_context *ctdb)
 {
        struct sockaddr_un addr;
 
@@ -223,7 +236,7 @@ int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
 */
 static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)   
 {
-       idr_remove(state->ctdb_db->ctdb->idr, state->reqid);
+       ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
        return 0;
 }
 
@@ -276,7 +289,7 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
 
        /* if the domain socket is not yet open, open it */
        if (ctdb->daemon.sd==-1) {
-               ux_socket_connect(ctdb);
+               ctdb_socket_connect(ctdb);
        }
 
        ret = ctdb_ltdb_lock(ctdb_db, call->key);
@@ -309,20 +322,14 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db,
        }
 
        len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
-       c = ctdbd_allocate_pkt(state, len);
+       c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call);
        if (c == NULL) {
                DEBUG(0, (__location__ " failed to allocate packet\n"));
                return NULL;
        }
-       talloc_set_name_const(c, "ctdb client req_call packet");
-       memset(c, 0, offsetof(struct ctdb_req_call, data));
 
-       c->hdr.length    = len;
-       c->hdr.ctdb_magic = CTDB_MAGIC;
-       c->hdr.ctdb_version = CTDB_VERSION;
-       c->hdr.operation = CTDB_REQ_CALL;
        /* this limits us to 16k outstanding messages - not unreasonable */
-       c->hdr.reqid     = idr_get_new(ctdb->idr, state, 0xFFFF);
+       c->hdr.reqid     = ctdb_reqid_new(ctdb, state);
        c->flags         = call->flags;
        c->db_id         = ctdb_db->db_id;
        c->callid        = call->call_id;
@@ -363,28 +370,26 @@ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call)
   tell the daemon what messaging srvid we will use, and register the message
   handler function in the client
 */
-int ctdb_set_message_handler(struct ctdb_context *ctdb, uint32_t srvid, 
+int ctdb_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, 
                             ctdb_message_fn_t handler,
                             void *private_data)
                                    
 {
-       struct ctdb_req_register c;
+       struct ctdb_req_register *c;
        int res;
 
        /* if the domain socket is not yet open, open it */
        if (ctdb->daemon.sd==-1) {
-               ux_socket_connect(ctdb);
+               ctdb_socket_connect(ctdb);
        }
 
-       ZERO_STRUCT(c);
-
-       c.hdr.length       = sizeof(c);
-       c.hdr.ctdb_magic   = CTDB_MAGIC;
-       c.hdr.ctdb_version = CTDB_VERSION;
-       c.hdr.operation    = CTDB_REQ_REGISTER;
-       c.srvid            = srvid;
+       c = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_REGISTER, sizeof(*c), 
+                              struct ctdb_req_register);
+       CTDB_NO_MEMORY(ctdb, c);
+       c->srvid            = srvid;
 
-       res = ctdb_client_queue_pkt(ctdb, &c.hdr);
+       res = ctdb_client_queue_pkt(ctdb, &c->hdr);
+       talloc_free(c);
        if (res != 0) {
                return res;
        }
@@ -398,23 +403,18 @@ int ctdb_set_message_handler(struct ctdb_context *ctdb, uint32_t srvid,
   send a message - from client context
  */
 int ctdb_send_message(struct ctdb_context *ctdb, uint32_t vnn,
-                     uint32_t srvid, TDB_DATA data)
+                     uint64_t srvid, TDB_DATA data)
 {
        struct ctdb_req_message *r;
        int len, res;
 
        len = offsetof(struct ctdb_req_message, data) + data.dsize;
-       r = ctdb->methods->allocate_pkt(ctdb, len);
+       r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, 
+                              len, struct ctdb_req_message);
        CTDB_NO_MEMORY(ctdb, r);
-       talloc_set_name_const(r, "req_message packet");
 
-       r->hdr.length    = len;
-       r->hdr.ctdb_magic = CTDB_MAGIC;
-       r->hdr.ctdb_version = CTDB_VERSION;
-       r->hdr.operation = CTDB_REQ_MESSAGE;
        r->hdr.destnode  = vnn;
        r->hdr.srcnode   = ctdb->vnn;
-       r->hdr.reqid     = 0;
        r->srvid         = srvid;
        r->datalen       = data.dsize;
        memcpy(&r->data[0], data.dptr, data.dsize);
@@ -433,24 +433,22 @@ int ctdb_send_message(struct ctdb_context *ctdb, uint32_t vnn,
  */
 void ctdb_connect_wait(struct ctdb_context *ctdb)
 {
-       struct ctdb_req_connect_wait r;
+       struct ctdb_req_connect_wait *r;
        int res;
 
-       ZERO_STRUCT(r);
-
-       r.hdr.length     = sizeof(r);
-       r.hdr.ctdb_magic = CTDB_MAGIC;
-       r.hdr.ctdb_version = CTDB_VERSION;
-       r.hdr.operation = CTDB_REQ_CONNECT_WAIT;
+       r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_CONNECT_WAIT, sizeof(*r), 
+                              struct ctdb_req_connect_wait);
+       CTDB_NO_MEMORY_VOID(ctdb, r);
 
        DEBUG(3,("ctdb_connect_wait: sending to ctdbd\n"));
 
        /* if the domain socket is not yet open, open it */
        if (ctdb->daemon.sd==-1) {
-               ux_socket_connect(ctdb);
+               ctdb_socket_connect(ctdb);
        }
        
-       res = ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)&r.hdr, r.hdr.length);
+       res = ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)&r->hdr, r->hdr.length);
+       talloc_free(r);
        if (res != 0) {
                DEBUG(0,(__location__ " Failed to queue a connect wait request\n"));
                return;
@@ -461,6 +459,9 @@ void ctdb_connect_wait(struct ctdb_context *ctdb)
        /* now we can go into the normal wait routine, as the reply packet
           will update the ctdb->num_connected variable */
        ctdb_daemon_connect_wait(ctdb);
+
+       /* get other config variables */
+       ctdb_get_config(ctdb);
 }
 
 /*
@@ -542,6 +543,13 @@ again:
                return NULL;
        }
 
+       /* when torturing, ensure we test the remote path */
+       if ((ctdb_db->ctdb->flags & CTDB_FLAG_TORTURE) &&
+           random() % 5 == 0) {
+               h->header.dmaster = (uint32_t)-1;
+       }
+
+
        DEBUG(4,("ctdb_fetch_lock: done local fetch\n"));
 
        if (h->header.dmaster != ctdb_db->ctdb->vnn) {
@@ -573,23 +581,20 @@ int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data)
 */
 void ctdb_shutdown(struct ctdb_context *ctdb)
 {
-       struct ctdb_req_shutdown r;
-       int len;
+       struct ctdb_req_shutdown *r;
 
        /* if the domain socket is not yet open, open it */
        if (ctdb->daemon.sd==-1) {
-               ux_socket_connect(ctdb);
+               ctdb_socket_connect(ctdb);
        }
 
-       len = sizeof(struct ctdb_req_shutdown);
-       ZERO_STRUCT(r);
-       r.hdr.length       = len;
-       r.hdr.ctdb_magic   = CTDB_MAGIC;
-       r.hdr.ctdb_version = CTDB_VERSION;
-       r.hdr.operation    = CTDB_REQ_SHUTDOWN;
-       r.hdr.reqid        = 0;
+       r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_SHUTDOWN, sizeof(*r), 
+                              struct ctdb_req_shutdown);
+       CTDB_NO_MEMORY_VOID(ctdb, r);
 
-       ctdb_client_queue_pkt(ctdb, &(r.hdr));
+       ctdb_client_queue_pkt(ctdb, &(r->hdr));
+
+       talloc_free(r);
 
        /* this event loop will terminate once we receive the reply */
        while (1) {
@@ -598,3 +603,348 @@ void ctdb_shutdown(struct ctdb_context *ctdb)
 }
 
 
+struct ctdb_client_control_state {
+       uint32_t reqid;
+       int32_t status;
+       TDB_DATA outdata;
+       enum call_state state;
+};
+
+/*
+  called when a CTDB_REPLY_CONTROL packet comes in in the client
+
+  This packet comes in response to a CTDB_REQ_CONTROL request packet. It
+  contains any reply data from the control
+*/
+static void ctdb_client_reply_control(struct ctdb_context *ctdb, 
+                                     struct ctdb_req_header *hdr)
+{
+       struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+       struct ctdb_client_control_state *state;
+
+       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state);
+       if (state == NULL) {
+               DEBUG(0,(__location__ " reqid %d not found\n", hdr->reqid));
+               return;
+       }
+
+       if (hdr->reqid != state->reqid) {
+               /* we found a record  but it was the wrong one */
+               DEBUG(0, ("Dropped orphaned reply control with reqid:%d\n",hdr->reqid));
+               return;
+       }
+
+       state->outdata.dptr = c->data;
+       state->outdata.dsize = c->datalen;
+       state->status = c->status;
+
+       talloc_steal(state, c);
+
+       state->state = CTDB_CALL_DONE;
+}
+
+
+/*
+  send a ctdb control message
+ */
+int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, 
+                uint32_t opcode, TDB_DATA data, 
+                TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status)
+{
+       struct ctdb_client_control_state *state;
+       struct ctdb_req_control *c;
+       size_t len;
+       int ret;
+
+       /* if the domain socket is not yet open, open it */
+       if (ctdb->daemon.sd==-1) {
+               ctdb_socket_connect(ctdb);
+       }
+
+       state = talloc_zero(ctdb, struct ctdb_client_control_state);
+       CTDB_NO_MEMORY(ctdb, state);
+
+       state->reqid = ctdb_reqid_new(ctdb, state);
+       state->state = CTDB_CALL_WAIT;
+
+       len = offsetof(struct ctdb_req_control, data) + data.dsize;
+       c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL, 
+                              len, struct ctdb_req_control);
+       CTDB_NO_MEMORY(ctdb, c);
+       
+       c->hdr.reqid        = state->reqid;
+       c->hdr.destnode     = destnode;
+       c->hdr.srcnode      = ctdb->vnn;
+       c->hdr.reqid        = state->reqid;
+       c->opcode           = opcode;
+       c->srvid            = srvid;
+       c->datalen          = data.dsize;
+       if (data.dsize) {
+               memcpy(&c->data[0], data.dptr, data.dsize);
+       }
+
+       ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
+       if (ret != 0) {
+               talloc_free(state);
+               return -1;
+       }
+
+       /* semi-async operation */
+       while (state->state == CTDB_CALL_WAIT) {
+               event_loop_once(ctdb->ev);
+       }
+
+       if (outdata) {
+               *outdata = state->outdata;
+               outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize);
+       }
+
+       *status = state->status;
+
+       talloc_free(state);
+
+       return 0;       
+}
+
+
+
+/*
+  a process exists call. Returns 0 if process exists, -1 otherwise
+ */
+int ctdb_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid)
+{
+       int ret;
+       TDB_DATA data;
+       int32_t status;
+
+       data.dptr = (uint8_t*)&pid;
+       data.dsize = sizeof(pid);
+
+       ret = ctdb_control(ctdb, destnode, 0, 
+                          CTDB_CONTROL_PROCESS_EXISTS, data, 
+                          NULL, NULL, &status);
+       if (ret != 0) {
+               DEBUG(0,(__location__ " ctdb_control for process_exists failed\n"));
+               return -1;
+       }
+
+       return status;
+}
+
+/*
+  get remote status
+ */
+int ctdb_status(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_status *status)
+{
+       int ret;
+       TDB_DATA data;
+       int32_t res;
+
+       ZERO_STRUCT(data);
+       ret = ctdb_control(ctdb, destnode, 0, 
+                          CTDB_CONTROL_STATUS, data, 
+                          ctdb, &data, &res);
+       if (ret != 0 || res != 0) {
+               DEBUG(0,(__location__ " ctdb_control for status failed\n"));
+               return -1;
+       }
+
+       if (data.dsize != sizeof(struct ctdb_status)) {
+               DEBUG(0,(__location__ " Wrong status size %u - expected %u\n",
+                        data.dsize, sizeof(struct ctdb_status)));
+                     return -1;
+       }
+
+       *status = *(struct ctdb_status *)data.dptr;
+       talloc_free(data.dptr);
+                       
+       return 0;
+}
+
+/*
+  get vnn map from a remote node
+ */
+int ctdb_getvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap)
+{
+       int ret;
+       TDB_DATA data, outdata;
+       int32_t i, res;
+
+       ZERO_STRUCT(data);
+       ret = ctdb_control(ctdb, destnode, 0, 
+                          CTDB_CONTROL_GETVNNMAP, data, 
+                          ctdb, &outdata, &res);
+       if (ret != 0 || res != 0) {
+               DEBUG(0,(__location__ " ctdb_control for getvnnmap failed\n"));
+               return -1;
+       }
+
+       vnnmap->generation = ((uint32_t *)outdata.dptr)[0];
+       vnnmap->size = ((uint32_t *)outdata.dptr)[1];
+       if (vnnmap->map) {
+               talloc_free(vnnmap->map);
+               vnnmap->map = NULL;
+       }
+       vnnmap->map = talloc_array(vnnmap, uint32_t, vnnmap->size);
+       for (i=0;i<vnnmap->size;i++) {
+               vnnmap->map[i] = ((uint32_t *)outdata.dptr)[i+2];
+       }
+                   
+       return 0;
+}
+
+
+/*
+  set vnn map on a node
+ */
+int ctdb_setvnnmap(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_vnn_map *vnnmap)
+{
+       int ret;
+       TDB_DATA *data, outdata;
+       int32_t i, res;
+
+       data = talloc_zero(ctdb, TDB_DATA);
+       data->dsize = (vnnmap->size+2)*sizeof(uint32_t);
+       data->dptr = (unsigned char *)talloc_array(data, uint32_t, vnnmap->size+2);
+
+       ((uint32_t *)&data->dptr[0])[0] = vnnmap->generation;
+       ((uint32_t *)&data->dptr[0])[1] = vnnmap->size;
+       for (i=0;i<vnnmap->size;i++) {
+               ((uint32_t *)&data->dptr[0])[i+2] = vnnmap->map[i];
+       }
+
+       ret = ctdb_control(ctdb, destnode, 0, 
+                          CTDB_CONTROL_SETVNNMAP, *data, 
+                          ctdb, &outdata, &res);
+       if (ret != 0 || res != 0) {
+               DEBUG(0,(__location__ " ctdb_control for setvnnmap failed\n"));
+               return -1;
+       }
+
+       talloc_free(data);                  
+       return 0;
+}
+
+/*
+  ping a node
+ */
+int ctdb_ping(struct ctdb_context *ctdb, uint32_t destnode)
+{
+       int ret;
+       int32_t res;
+       TDB_DATA data;
+
+       ZERO_STRUCT(data);
+       ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PING, data, NULL, NULL, &res);
+       if (ret != 0 || res != 0) {
+               return -1;
+       }
+       return 0;
+}
+
+/*
+  get ctdb config
+ */
+int ctdb_get_config(struct ctdb_context *ctdb)
+{
+       int ret;
+       int32_t res;
+       TDB_DATA data;
+       struct ctdb_context c;
+
+       ZERO_STRUCT(data);
+       ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_CONFIG, data, 
+                          ctdb, &data, &res);
+       if (ret != 0 || res != 0) {
+               return -1;
+       }
+       if (data.dsize != sizeof(c)) {
+               DEBUG(0,("Bad config size %u - expected %u\n", data.dsize, sizeof(c)));
+               return -1;
+       }
+
+       c = *(struct ctdb_context *)data.dptr;
+       talloc_free(data.dptr);
+
+       ctdb->num_nodes = c.num_nodes;
+       ctdb->num_connected = c.num_connected;
+       ctdb->vnn = c.vnn;
+       ctdb->max_lacount = c.max_lacount;
+       
+       return 0;
+}
+
+/*
+  find the real path to a ltdb 
+ */
+int ctdb_getdbpath(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, 
+                  const char **path)
+{
+       int ret;
+       int32_t res;
+       TDB_DATA data;
+
+       data.dptr = (uint8_t *)&ctdb_db->db_id;
+       data.dsize = sizeof(ctdb_db->db_id);
+
+       ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, 
+                          CTDB_CONTROL_GETDBPATH, data, 
+                          ctdb_db, &data, &res);
+       if (ret != 0 || res != 0) {
+               return -1;
+       }
+
+       (*path) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize);
+       if ((*path) == NULL) {
+               return -1;
+       }
+
+       talloc_free(data.dptr);
+
+       return 0;
+}
+
+/*
+  get debug level on a node
+ */
+int ctdb_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, uint32_t *level)
+{
+       int ret;
+       int32_t res;
+       TDB_DATA data;
+
+       ZERO_STRUCT(data);
+       ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DEBUG, data, 
+                          ctdb, &data, &res);
+       if (ret != 0 || res != 0) {
+               return -1;
+       }
+       if (data.dsize != sizeof(uint32_t)) {
+               DEBUG(0,("Bad control reply size in ctdb_get_debuglevel (got %u)\n",
+                             data.dsize));
+               return -1;
+       }
+       *level = *(uint32_t *)data.dptr;
+       talloc_free(data.dptr);
+       return 0;
+}
+
+/*
+  set debug level on a node
+ */
+int ctdb_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, uint32_t level)
+{
+       int ret;
+       int32_t res;
+       TDB_DATA data;
+
+       data.dptr = (uint8_t *)&level;
+       data.dsize = sizeof(level);
+
+       ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DEBUG, data, 
+                          NULL, NULL, &res);
+       if (ret != 0 || res != 0) {
+               return -1;
+       }
+       return 0;
+}