Implement a new function GETNODEMAP in libctdb.
[metze/ctdb/wip.git] / libctdb / io_elem.c
1 /*
2    Simple queuing of input and output records for libctdb
3
4    Copyright (C) Rusty Russell 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <sys/types.h>
20 #include <string.h>
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include "io_elem.h"
27 #include <tdb.h>
28 #include <netinet/in.h>
29 #include <ctdb_protocol.h> // For CTDB_DS_ALIGNMENT and ctdb_req_header
30
31 struct io_elem {
32         size_t len, off;
33         char *data;
34 };
35
36 struct io_elem *new_io_elem(size_t len)
37 {
38         struct io_elem *elem;
39         size_t ask = len;
40
41         len = (len + (CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
42
43         elem = malloc(sizeof(*elem));
44         if (!elem)
45                 return NULL;
46         elem->data = malloc(len);
47         if (!elem->data) {
48                 free(elem);
49                 return NULL;
50         }
51
52         /* stamp out any padding to keep valgrind happy */
53         if (ask != len) {
54                 memset(elem->data + ask, 0, len-ask);
55         }
56         elem->len = len;
57         elem->off = 0;
58         return elem;
59 }
60
61 void free_io_elem(struct io_elem *io)
62 {
63         free(io->data);
64         free(io);
65 }
66
67 bool io_elem_finished(const struct io_elem *io)
68 {
69         return io->off == io->len;
70 }
71
72 void io_elem_init_req_header(struct io_elem *io,
73                              uint32_t operation,
74                              uint32_t destnode,
75                              uint32_t reqid)
76 {
77         struct ctdb_req_header *hdr = io_elem_data(io, NULL);
78
79         hdr->length = io->len;
80         hdr->ctdb_magic = CTDB_MAGIC;
81         hdr->ctdb_version = CTDB_VERSION;
82         /* Generation and srcnode only used for inter-ctdbd communication. */
83         hdr->generation = 0;
84         hdr->destnode = destnode;
85         hdr->srcnode = 0;
86         hdr->operation = operation;
87         hdr->reqid = reqid;
88 }
89
90 /* Access to raw data: if len is non-NULL it is filled in. */
91 void *io_elem_data(const struct io_elem *io, size_t *len)
92 {
93         if (len)
94                 *len = io->len;
95         return io->data;
96 }
97
98 /* Returns -1 if we hit an error.  Errno will be set. */
99 int read_io_elem(int fd, struct io_elem *io)
100 {
101         ssize_t ret;
102
103         ret = read(fd, io->data + io->off, io->len - io->off);
104         if (ret < 0)
105                 return ret;
106
107         io->off += ret;
108         if (io_elem_finished(io)) {
109                 struct ctdb_req_header *hdr = (void *)io->data;
110
111                 /* Finished.  But maybe this was just header? */
112                 if (io->len == sizeof(*hdr) && hdr->length > io->len) {
113                         int reret;
114                         void *newdata;
115                         /* Enlarge and re-read. */
116                         io->len = hdr->length;
117                         newdata = realloc(io->data, io->len);
118                         if (!newdata)
119                                 return -1;
120                         io->data = newdata;
121                         /* Try reading again immediately. */
122                         reret = read_io_elem(fd, io);
123                         if (reret >= 0)
124                                 reret += ret;
125                         return reret;
126                 }
127         }
128         return ret;
129 }
130
131 /* Returns -1 if we hit an error.  Errno will be set. */
132 int write_io_elem(int fd, struct io_elem *io)
133 {
134         ssize_t ret;
135
136         ret = write(fd, io->data + io->off, io->len - io->off);
137         if (ret < 0)
138                 return ret;
139
140         io->off += ret;
141         return ret;
142 }
143
144 void io_elem_reset(struct io_elem *io)
145 {
146         io->off = 0;
147 }