/* setup the local node address */ int ctdb_set_address(struct ctdb_context *ctdb, const char *address) { ctdb->address = talloc(ctdb, ctdb_sock_addr); CTDB_NO_MEMORY(ctdb, ctdb->address); if (ctdb_parse_address(ctdb, address, ctdb->address) != 0) { return -1; } ctdb->name = talloc_asprintf(ctdb, "%s:%u", ctdb_addr_to_str(ctdb->address), ctdb_addr_to_port(ctdb->address)); return 0; }
/* Load a nodes list file into a nodes array */ static int convert_node_map_to_list(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_node_map_old *node_map, struct ctdb_node ***nodes, uint32_t *num_nodes) { int i; *nodes = talloc_zero_array(mem_ctx, struct ctdb_node *, node_map->num); CTDB_NO_MEMORY(ctdb, *nodes); *num_nodes = node_map->num; for (i = 0; i < node_map->num; i++) { struct ctdb_node *node; node = talloc_zero(*nodes, struct ctdb_node); CTDB_NO_MEMORY(ctdb, node); (*nodes)[i] = node; node->address = node_map->nodes[i].addr; node->name = talloc_asprintf(node, "%s:%u", ctdb_addr_to_str(&node->address), ctdb_addr_to_port(&node->address)); node->flags = node_map->nodes[i].flags; if (!(node->flags & NODE_FLAGS_DELETED)) { node->flags = NODE_FLAGS_UNHEALTHY; } node->flags |= NODE_FLAGS_DISCONNECTED; node->pnn = i; node->ctdb = ctdb; node->dead_count = 0; } return 0; }
/* automatically find which address to listen on */ static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb) { struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data, struct ctdb_tcp); ctdb_sock_addr sock; int lock_fd, i; const char *lock_path = CTDB_RUNDIR "/.socket_lock"; struct flock lock; int one = 1; int sock_size; struct tevent_fd *fde; /* If there are no nodes, then it won't be possible to find * the first one. Log a failure and short circuit the whole * process. */ if (ctdb->num_nodes == 0) { DEBUG(DEBUG_CRIT,("No nodes available to attempt bind to - is the nodes file empty?\n")); return -1; } /* in order to ensure that we don't get two nodes with the same adddress, we must make the bind() and listen() calls atomic. The SO_REUSEADDR setsockopt only prevents double binds if the first socket is in LISTEN state */ lock_fd = open(lock_path, O_RDWR|O_CREAT, 0666); if (lock_fd == -1) { DEBUG(DEBUG_CRIT,("Unable to open %s\n", lock_path)); return -1; } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 1; lock.l_pid = 0; if (fcntl(lock_fd, F_SETLKW, &lock) != 0) { DEBUG(DEBUG_CRIT,("Unable to lock %s\n", lock_path)); close(lock_fd); return -1; } for (i=0; i < ctdb->num_nodes; i++) { if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) { continue; } sock = ctdb->nodes[i]->address; switch (sock.sa.sa_family) { case AF_INET: sock_size = sizeof(sock.ip); break; case AF_INET6: sock_size = sizeof(sock.ip6); break; default: DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n", sock.sa.sa_family)); continue; } ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); if (ctcp->listen_fd == -1) { ctdb_set_error(ctdb, "socket failed\n"); continue; } set_close_on_exec(ctcp->listen_fd); if (setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR, (char *)&one,sizeof(one)) == -1) { DEBUG(DEBUG_WARNING, ("Failed to set REUSEADDR on fd - %s\n", strerror(errno))); } if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) == 0) { break; } if (errno == EADDRNOTAVAIL) { DEBUG(DEBUG_DEBUG,(__location__ " Failed to bind() to socket. %s(%d)\n", strerror(errno), errno)); } else { DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n", strerror(errno), errno)); } close(ctcp->listen_fd); ctcp->listen_fd = -1; } if (i == ctdb->num_nodes) { DEBUG(DEBUG_CRIT,("Unable to bind to any of the node addresses - giving up\n")); goto failed; } ctdb->address = talloc_memdup(ctdb, &ctdb->nodes[i]->address, sizeof(ctdb_sock_addr)); if (ctdb->address == NULL) { ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); goto failed; } ctdb->name = talloc_asprintf(ctdb, "%s:%u", ctdb_addr_to_str(ctdb->address), ctdb_addr_to_port(ctdb->address)); if (ctdb->name == NULL) { ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); goto failed; } DEBUG(DEBUG_INFO,("ctdb chose network address %s\n", ctdb->name)); if (listen(ctcp->listen_fd, 10) == -1) { goto failed; } fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ, ctdb_listen_event, ctdb); tevent_fd_set_auto_close(fde); close(lock_fd); return 0; failed: close(lock_fd); if (ctcp->listen_fd != -1) { close(ctcp->listen_fd); ctcp->listen_fd = -1; } return -1; }