initial version
[vlendec/samba-autobuild/.git] / ctdb / ctdb_tcp.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 /*
28   initialise the ctdb daemon. 
29
30   if the ctdb dispatcher daemon has already been started then this
31   does nothing. Otherwise it forks the ctdb dispatcher daemon and
32   starts the daemons connecting to each other
33   
34   NOTE: In current code the daemon does not fork. This is for testing purposes only
35   and to simplify the code.
36 */
37
38 struct ctdb_context *ctdb_init(TALLOC_CTX *mem_ctx)
39 {
40         struct ctdb_context *ctdb;
41
42         ctdb = talloc_zero(mem_ctx, struct ctdb_context);
43         return ctdb;
44 }
45
46 const char *ctdb_errstr(struct ctdb_context *ctdb)
47 {
48         return ctdb->err_msg;
49 }
50
51 /*
52   remember an error message
53 */
54 static void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...)
55 {
56         va_list ap;
57         talloc_free(ctdb->err_msg);
58         va_start(ap, fmt);
59         ctdb->err_msg = talloc_vasprintf(ctdb, fmt, ap);
60         va_end(ap);
61 }
62
63 /*
64   called when socket becomes readable
65 */
66 static void ctdb_node_read(struct event_context *ev, struct fd_event *fde, 
67                            uint16_t flags, void *private)
68 {
69         struct ctdb_node *node = talloc_get_type(private, struct ctdb_node);
70         printf("connection to node %s:%u is readable\n", node->address, node->port);
71         event_set_fd_flags(fde, 0);
72 }
73
74 static void ctdb_node_connect(struct event_context *ev, struct timed_event *te, 
75                               struct timeval t, void *private);
76
77 /*
78   called when socket becomes writeable on connect
79 */
80 static void ctdb_node_connect_write(struct event_context *ev, struct fd_event *fde, 
81                                     uint16_t flags, void *private)
82 {
83         struct ctdb_node *node = talloc_get_type(private, struct ctdb_node);
84         struct ctdb_context *ctdb = node->ctdb;
85         int error;
86         socklen_t len;
87
88         if (getsockopt(node->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0 ||
89             errno != 0) {
90                 close(node->fd);
91                 event_add_timed(ctdb->ev, node, timeval_current_ofs(1, 0), 
92                                 ctdb_node_connect, node);
93                 return;
94         }
95
96         printf("Established connection to %s:%u\n", node->address, node->port);
97         talloc_free(fde);
98         event_add_fd(node->ctdb->ev, node, node->fd, EVENT_FD_READ, 
99                      ctdb_node_read, node);
100 }
101
102 /*
103   called when we should try and establish a tcp connection to a node
104 */
105 static void ctdb_node_connect(struct event_context *ev, struct timed_event *te, 
106                               struct timeval t, void *private)
107 {
108         struct ctdb_node *node = talloc_get_type(node, struct ctdb_node);
109         struct ctdb_context *ctdb = node->ctdb;
110         unsigned v;
111         struct sockaddr_in sock_out;
112
113         node->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
114
115         v = fcntl(node->fd, F_GETFL, 0);
116         fcntl(node->fd, F_SETFL, v | O_NONBLOCK);
117
118         inet_pton(AF_INET, node->address, &sock_out.sin_addr);
119         sock_out.sin_port = htons(node->port);
120         sock_out.sin_family = PF_INET;
121         
122         if (connect(node->fd, &sock_out, sizeof(sock_out)) != 0 &&
123             errno != EINPROGRESS) {
124                 /* try again once a second */
125                 close(node->fd);
126                 event_add_timed(ctdb->ev, node, timeval_current_ofs(1, 0), 
127                                 ctdb_node_connect, node);
128                 return;
129         }
130
131         /* non-blocking connect - wait for write event */
132         event_add_fd(node->ctdb->ev, node, node->fd, EVENT_FD_WRITE, 
133                      ctdb_node_connect_write, node);
134 }
135
136
137 /*
138   add a node to the list of active nodes
139 */
140 static int ctdb_add_node(struct ctdb_context *ctdb, char *nstr)
141 {
142         struct ctdb_node *node;
143
144         /* expected to be in IP:port format */
145         char *p;
146         p = strchr(nstr, ':');
147         if (p == NULL) {
148                 ctdb_set_error(ctdb, "Badly formed node '%s'\n", nstr);
149                 return -1;
150         }
151         *p++ = 0;
152
153         node = talloc(ctdb, struct ctdb_node);
154         node->address = talloc_strdup(node, nstr);
155         node->port = strtoul(p, NULL, 0);
156         node->fd = -1;
157         node->ctdb = ctdb;
158
159         DLIST_ADD(ctdb->nodes, node);   
160         event_add_timed(ctdb->ev, node, timeval_zero(), ctdb_node_connect, node);
161         return 0;
162 }
163
164 /*
165   setup the node list from a file
166 */
167 int ctdb_set_nlist(struct ctdb_context *ctdb, const char *nlist)
168 {
169         char **lines;
170         int nlines;
171         int i;
172
173         lines = file_lines_load(nlist, &nlines, ctdb);
174         if (lines == NULL) {
175                 ctdb_set_error(ctdb, "Failed to load nlist '%s'\n", nlist);
176                 return -1;
177         }
178
179         for (i=0;i<nlines;i++) {
180                 if (ctdb_add_node(ctdb, lines[i]) != 0) {
181                         talloc_free(lines);
182                         return -1;
183                 }
184         }
185         
186         talloc_free(lines);
187         return 0;
188 }
189
190 /*
191   add a node to the list of active nodes
192 */
193 int ctdb_set_call(struct ctdb_context *ctdb, ctdb_fn_t fn, int id)
194 {
195         struct ctdb_registered_call *call;
196
197         call = talloc(ctdb, struct ctdb_registered_call);
198         call->fn = fn;
199         call->id = id;
200
201         DLIST_ADD(ctdb->calls, call);   
202         return 0;
203 }
204
205 /*
206   attach to a specific database
207 */
208 int ctdb_attach(struct ctdb_context *ctdb, const char *name, int tdb_flags, 
209                 int open_flags, mode_t mode)
210 {
211         ctdb->ltdb = tdb_open(name, 0, TDB_INTERNAL, 0, 0);
212         if (ctdb->ltdb == NULL) {
213                 ctdb_set_error(ctdb, "Failed to open tdb %s\n", name);
214                 return -1;
215         }
216         return 0;
217 }
218