- setup a convenience name field for nodes
[vlendec/samba-autobuild/.git] / ctdb / common / ctdb.c
1 /* 
2    ctdb over TCP
3
4    Copyright (C) Andrew Tridgell  2006
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10
11    This library 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 GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "includes.h"
22 #include "lib/events/events.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "ctdb_private.h"
26
27 const char *ctdb_errstr(struct ctdb_context *ctdb)
28 {
29         return ctdb->err_msg;
30 }
31
32
33 /*
34   remember an error message
35 */
36 void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...)
37 {
38         va_list ap;
39         talloc_free(ctdb->err_msg);
40         va_start(ap, fmt);
41         ctdb->err_msg = talloc_vasprintf(ctdb, fmt, ap);
42         va_end(ap);
43 }
44
45 /*
46   choose the transport we will use
47 */
48 int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport)
49 {
50         int ctdb_tcp_init(struct ctdb_context *ctdb);
51
52         if (strcmp(transport, "tcp") == 0) {
53                 return ctdb_tcp_init(ctdb);
54         }
55         ctdb_set_error(ctdb, "Unknown transport '%s'\n", transport);
56         return -1;
57 }
58
59
60 /*
61   parse a IP:port pair
62 */
63 static int ctdb_parse_address(struct ctdb_context *ctdb,
64                              TALLOC_CTX *mem_ctx, const char *str,
65                              struct ctdb_address *address)
66 {
67         char *p;
68         p = strchr(str, ':');
69         if (p == NULL) {
70                 ctdb_set_error(ctdb, "Badly formed node '%s'\n", str);
71                 return -1;
72         }
73         
74         address->address = talloc_strndup(mem_ctx, str, p-str);
75         address->port = strtoul(p+1, NULL, 0);
76         return 0;
77 }
78
79
80 /*
81   add a node to the list of active nodes
82 */
83 static int ctdb_add_node(struct ctdb_context *ctdb, char *nstr)
84 {
85         struct ctdb_node *node;
86
87         node = talloc(ctdb, struct ctdb_node);
88         if (ctdb_parse_address(ctdb, node, nstr, &node->address) != 0) {
89                 return -1;
90         }
91         node->ctdb = ctdb;
92         node->name = talloc_asprintf(node, "%s:%u", 
93                                      node->address.address, 
94                                      node->address.port);
95
96         if (ctdb->methods->add_node(node) != 0) {
97                 talloc_free(node);
98                 return -1;
99         }
100
101         DLIST_ADD(ctdb->nodes, node);   
102         return 0;
103 }
104
105 /*
106   setup the node list from a file
107 */
108 int ctdb_set_nlist(struct ctdb_context *ctdb, const char *nlist)
109 {
110         char **lines;
111         int nlines;
112         int i;
113
114         lines = file_lines_load(nlist, &nlines, ctdb);
115         if (lines == NULL) {
116                 ctdb_set_error(ctdb, "Failed to load nlist '%s'\n", nlist);
117                 return -1;
118         }
119
120         for (i=0;i<nlines;i++) {
121                 if (ctdb_add_node(ctdb, lines[i]) != 0) {
122                         talloc_free(lines);
123                         return -1;
124                 }
125         }
126         
127         talloc_free(lines);
128         return 0;
129 }
130
131 /*
132   setup the local node address
133 */
134 int ctdb_set_address(struct ctdb_context *ctdb, const char *address)
135 {
136         return ctdb_parse_address(ctdb, ctdb, address, &ctdb->address);
137 }
138
139 /*
140   add a node to the list of active nodes
141 */
142 int ctdb_set_call(struct ctdb_context *ctdb, ctdb_fn_t fn, int id)
143 {
144         struct ctdb_registered_call *call;
145
146         call = talloc(ctdb, struct ctdb_registered_call);
147         call->fn = fn;
148         call->id = id;
149
150         DLIST_ADD(ctdb->calls, call);   
151         return 0;
152 }
153
154 /*
155   attach to a specific database
156 */
157 int ctdb_attach(struct ctdb_context *ctdb, const char *name, int tdb_flags, 
158                 int open_flags, mode_t mode)
159 {
160         /* when we have a separate daemon this will need to be a real
161            file, not a TDB_INTERNAL, so the parent can access it to
162            for ltdb bypass */
163         ctdb->ltdb = tdb_open(name, 0, TDB_INTERNAL, 0, 0);
164         if (ctdb->ltdb == NULL) {
165                 ctdb_set_error(ctdb, "Failed to open tdb %s\n", name);
166                 return -1;
167         }
168         return 0;
169 }
170
171 /*
172   start the protocol going
173 */
174 int ctdb_start(struct ctdb_context *ctdb)
175 {
176         return ctdb->methods->start(ctdb);
177 }
178
179 /*
180   make a remote ctdb call
181 */
182 int ctdb_call(struct ctdb_context *ctdb, TDB_DATA key, int call_id, 
183               TDB_DATA *call_data, TDB_DATA *reply_data)
184 {
185         printf("ctdb_call not implemented\n");
186         return -1;
187 }
188
189 /*
190   check if two addresses are the same
191 */
192 bool ctdb_same_address(struct ctdb_address *a1, struct ctdb_address *a2)
193 {
194         return strcmp(a1->address, a2->address) == 0 && a1->port == a2->port;
195 }
196
197 /*
198   called by the transport layer when a packet comes in
199 */
200 static void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
201 {
202         printf("received pkt of length %d\n", length);
203 }
204
205 /*
206   called by the transport layer when a node is dead
207 */
208 static void ctdb_node_dead(struct ctdb_node *node)
209 {
210         printf("node %s is dead\n", node->name);
211 }
212
213 static const struct ctdb_upcalls ctdb_upcalls = {
214         .recv_pkt  = ctdb_recv_pkt,
215         .node_dead = ctdb_node_dead
216 };
217
218 /*
219   initialise the ctdb daemon. 
220
221   NOTE: In current code the daemon does not fork. This is for testing purposes only
222   and to simplify the code.
223 */
224 struct ctdb_context *ctdb_init(struct event_context *ev)
225 {
226         struct ctdb_context *ctdb;
227
228         ctdb = talloc_zero(ev, struct ctdb_context);
229         ctdb->ev = ev;
230         ctdb->upcalls = &ctdb_upcalls;
231
232         return ctdb;
233 }
234