2 * 2012+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <sys/types.h>
28 #include "elliptics.h"
29 #include "elliptics/interface.h"
31 static int dnet_discover_loop
= 1;
32 static int dnet_discover_ttl
= 3;
34 static int dnet_discovery_add_v4(struct dnet_node
*n
, struct dnet_addr
*addr
, int s
)
37 struct ip_mreq command
;
39 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &dnet_discover_loop
, sizeof(dnet_discover_loop
));
42 dnet_log_err(n
, "unable to set loopback option");
46 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &dnet_discover_ttl
, sizeof(dnet_discover_ttl
));
49 dnet_log_err(n
, "unable to set %d hop limit", dnet_discover_ttl
);
53 command
.imr_multiaddr
= ((struct sockaddr_in
*)addr
->addr
)->sin_addr
;
54 command
.imr_interface
= ((struct sockaddr_in
*)n
->addr
.addr
)->sin_addr
;
56 err
= setsockopt(s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &command
, sizeof(command
));
59 dnet_log_err(n
, "can not add multicast membership: %s", inet_ntoa(command
.imr_multiaddr
));
67 static int dnet_discovery_add_v6(struct dnet_node
*n
, struct dnet_addr
*addr __unused
, int s
)
71 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &dnet_discover_loop
, sizeof(dnet_discover_loop
));
74 dnet_log_err(n
, "unable to set loopback option");
78 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &dnet_discover_ttl
, sizeof(dnet_discover_ttl
));
81 dnet_log_err(n
, "unable to set %d hop limit", dnet_discover_ttl
);
89 int dnet_discovery_add(struct dnet_node
*n
, struct dnet_config
*cfg
)
91 struct dnet_addr addr
;
95 if (n
->autodiscovery_socket
!= -1)
98 memset(&addr
, 0, sizeof(struct dnet_addr
));
100 cfg
->sock_type
= SOCK_DGRAM
;
101 cfg
->proto
= IPPROTO_IP
;
102 if (cfg
->family
== AF_INET6
)
103 cfg
->proto
= IPPROTO_IPV6
;
104 addr
.addr_len
= sizeof(addr
.addr
);
106 err
= dnet_fill_addr(&addr
, cfg
->addr
, cfg
->port
, cfg
->family
, cfg
->sock_type
, cfg
->proto
);
108 dnet_log(n
, DNET_LOG_ERROR
, "Failed to get address info for %s:%s, family: %d, err: %d: %s.\n",
109 cfg
->addr
, cfg
->port
, cfg
->family
, err
, strerror(-err
));
113 s
= socket(cfg
->family
, cfg
->sock_type
, 0);
116 dnet_log_err(n
, "failed to create multicast socket");
120 if (cfg
->family
== AF_INET6
)
121 err
= dnet_discovery_add_v6(n
, &addr
, s
);
123 err
= dnet_discovery_add_v4(n
, &addr
, s
);
128 n
->autodiscovery_socket
= s
;
129 n
->autodiscovery_addr
= addr
;
138 static int dnet_discovery_send(struct dnet_node
*n
)
140 char buf
[sizeof(struct dnet_cmd
) + sizeof(struct dnet_auth
) + sizeof(struct dnet_addr_attr
)];
141 struct dnet_cmd
*cmd
;
142 struct dnet_addr_attr
*addr
;
143 struct dnet_auth
*auth
;
146 memset(buf
, 0, sizeof(buf
));
148 cmd
= (struct dnet_cmd
*)buf
;
149 addr
= (struct dnet_addr_attr
*)(cmd
+ 1);
150 auth
= (struct dnet_auth
*)(addr
+ 1);
153 cmd
->size
= sizeof(struct dnet_addr_attr
) + sizeof(struct dnet_auth
);
154 dnet_convert_cmd(cmd
);
156 addr
->sock_type
= n
->sock_type
;
157 addr
->proto
= n
->proto
;
158 addr
->family
= n
->family
;
159 addr
->addr
= n
->addr
;
160 dnet_convert_addr_attr(addr
);
162 memcpy(auth
->cookie
, n
->cookie
, DNET_AUTH_COOKIE_SIZE
);
163 dnet_convert_auth(auth
);
165 err
= sendto(n
->autodiscovery_socket
, buf
, sizeof(buf
), 0, (void *)&n
->autodiscovery_addr
, n
->autodiscovery_addr
.addr_len
);
168 dnet_log_err(n
, "autodiscovery sent: %s - %.*s", dnet_server_convert_dnet_addr(&addr
->addr
),
169 (int)sizeof(auth
->cookie
), auth
->cookie
);
171 dnet_log(n
, DNET_LOG_NOTICE
, "autodiscovery sent: %s - %.*s\n", dnet_server_convert_dnet_addr(&addr
->addr
),
172 (int)sizeof(auth
->cookie
), auth
->cookie
);
178 static int dnet_discovery_add_state(struct dnet_node
*n
, struct dnet_addr_attr
*addr
)
180 struct dnet_config cfg
;
182 memset(&cfg
, 0, sizeof(struct dnet_config
));
184 dnet_server_convert_addr_raw((struct sockaddr
*)&addr
->addr
, addr
->addr
.addr_len
, cfg
.addr
, sizeof(cfg
.addr
));
185 snprintf(cfg
.port
, sizeof(cfg
.port
), "%d", dnet_server_convert_port((struct sockaddr
*)&addr
->addr
, addr
->addr
.addr_len
));
186 cfg
.family
= addr
->family
;
187 cfg
.sock_type
= addr
->sock_type
;
188 cfg
.proto
= addr
->proto
;
190 return dnet_add_state(n
, &cfg
);
193 static int dnet_discovery_recv(struct dnet_node
*n
)
195 char buf
[sizeof(struct dnet_cmd
) + sizeof(struct dnet_auth
) + sizeof(struct dnet_addr_attr
)];
196 struct dnet_cmd
*cmd
;
197 struct dnet_addr_attr
*addr
;
198 struct dnet_auth
*auth
;
200 struct dnet_addr remote
;
201 socklen_t len
= n
->autodiscovery_addr
.addr_len
;
203 remote
= n
->autodiscovery_addr
;
205 cmd
= (struct dnet_cmd
*)buf
;
206 addr
= (struct dnet_addr_attr
*)(cmd
+ 1);
207 auth
= (struct dnet_auth
*)(addr
+ 1);
210 err
= recvfrom(n
->autodiscovery_socket
, buf
, sizeof(buf
), MSG_DONTWAIT
, (void *)&remote
, &len
);
211 if (err
!= sizeof(buf
))
214 dnet_convert_cmd(cmd
);
215 dnet_convert_addr_attr(addr
);
216 dnet_convert_auth(auth
);
218 dnet_log(n
, DNET_LOG_NOTICE
, "autodiscovery recv: %s - %.*s\n", dnet_server_convert_dnet_addr(&addr
->addr
),
219 (int)sizeof(auth
->cookie
), auth
->cookie
);
221 if (!memcmp(n
->cookie
, auth
->cookie
, DNET_AUTH_COOKIE_SIZE
)) {
222 dnet_discovery_add_state(n
, addr
);
229 int dnet_discovery(struct dnet_node
*n
)
233 if (n
->autodiscovery_socket
== -1)
236 err
= dnet_discovery_recv(n
);
238 if (n
->flags
& DNET_CFG_JOIN_NETWORK
)
239 err
= dnet_discovery_send(n
);