/* * Handles merlin control events inside the module. Control events * that relate to cross-host communication only never reaches this. */ void handle_control(merlin_node *node, merlin_event *pkt) { const char *ctrl; if (!pkt) { lerr("handle_control() called with NULL packet"); return; } ctrl = ctrl_name(pkt->hdr.code); linfo("Received control packet code %d (%s) from %s", pkt->hdr.code, ctrl, node ? node->name : "local Merlin daemon"); /* protect against bogus headers */ if (!node && (pkt->hdr.code == CTRL_INACTIVE || pkt->hdr.code == CTRL_ACTIVE)) { lerr("Received %s with unknown node id %d", ctrl, pkt->hdr.selection); return; } switch (pkt->hdr.code) { case CTRL_INACTIVE: /* * must memset() node->info before the disconnect handler * so we discard it in the peer id calculation dance if * we get data from it before it sends us a CTRL_ACTIVE * packet */ memset(&node->info, 0, sizeof(node->info)); node_set_state(node, STATE_NONE, "Received CTRL_INACTIVE"); break; case CTRL_ACTIVE: /* * Only mark the node as connected if the CTRL_ACTIVE packet * checks out properly and the info is new. If it *is* new, * we must re-do the peer assignment thing. */ if (!handle_ctrl_active(node, pkt)) { node_set_state(node, STATE_CONNECTED, "Received CTRL_ACTIVE"); assign_peer_ids(); } break; case CTRL_STALL: ctrl_stall_start(); break; case CTRL_RESUME: ctrl_stall_stop(); assign_peer_ids(); break; case CTRL_STOP: linfo("Received (and ignoring) CTRL_STOP event. What voodoo is this?"); break; default: lwarn("Unknown control code: %d", pkt->hdr.code); } }
/* * This gets called when a connect() attempt has become writable. * It's entirely possible that the node we're trying to connect * to has connected to us while we were waiting for them, in * which case we need to figure out which of the two connections * we're supposed to use. */ static int conn_writable(int sd, int events, void *node_) { merlin_node *node = (merlin_node *)node_; int result; int sel_sd; /* unregister so we don't peg one cpu at 100% */ ldebug("CONN: In conn_writable(): node=%s; sd=%d; node->conn_sock=%d", node->name, sd, node->conn_sock); iobroker_unregister(nagios_iobs, sd); if (node->sock < 0) { /* no inbound connection accept()'ed yet */ node->sock = sd; node->conn_sock = -1; if (!net_is_connected(node)) { node_disconnect(node, "Connection attempt failed: %s", strerror(errno)); close(sd); return 0; } iobroker_register(nagios_iobs, sd, node, net_input); node_set_state(node, STATE_NEGOTIATING, "Connect completed successfully. Negotiating protocol"); return 0; } sel_sd = net_negotiate_socket(node, node->conn_sock, node->sock); if (sel_sd < 0) { node_disconnect(node, "Failed to negotiate socket"); return 0; } if (sel_sd == node->conn_sock) { iobroker_close(nagios_iobs, node->sock); } else if (sel_sd == node->sock) { iobroker_close(nagios_iobs, node->conn_sock); } node->sock = sel_sd; node->conn_sock = -1; node_set_state(node, STATE_NEGOTIATING, "polled for writability"); /* now re-register for input */ ldebug("IOB: registering %s(%d) for input events", node->name, node->sock); result = iobroker_register(nagios_iobs, node->sock, node, net_input); if (result < 0) { lerr("IOB: Failed to register %s(%d) for input events: %s", node->name, node->sock, iobroker_strerror(result)); } return 0; }
void __init zone_sizes_init(void) { unsigned long zones_size[MAX_NR_ZONES], zholes_size[MAX_NR_ZONES]; unsigned long low, start_pfn; int nid, i; mem_prof_t *mp; for_each_online_node(nid) { mp = &mem_prof[nid]; for (i = 0 ; i < MAX_NR_ZONES ; i++) { zones_size[i] = 0; zholes_size[i] = 0; } start_pfn = START_PFN(nid); low = MAX_LOW_PFN(nid); zones_size[ZONE_DMA] = low - start_pfn; zholes_size[ZONE_DMA] = mp->holes; node_set_state(nid, N_NORMAL_MEMORY); free_area_init_node(nid, zones_size, start_pfn, zholes_size); } /* * For test * Use all area of internal RAM. * see __alloc_pages() */ NODE_DATA(1)->node_zones->watermark[WMARK_MIN] = 0; NODE_DATA(1)->node_zones->watermark[WMARK_LOW] = 0; NODE_DATA(1)->node_zones->watermark[WMARK_HIGH] = 0; }
/* close down the connection to a node and mark it as down */ void node_disconnect(merlin_node *node, const char *fmt, ...) { va_list ap; char *reason = NULL; if (node->state == STATE_CONNECTED) node_log_event_count(node, 1); if (fmt) { va_start(ap, fmt); vasprintf(&reason, fmt, ap); va_end(ap); } node_set_state(node, STATE_NONE, reason); if (reason) free(reason); node->last_recv = 0; /* avoid spurious close() errors while strace/valgrind debugging */ if (node->sock >= 0) close(node->sock); node->sock = -1; iocache_reset(node->ioc); }
/* * Accept an inbound connection from a remote host * Returns 0 on success and -1 on errors */ static int net_accept_one(int sd, int events, void *discard) { int sock, result; merlin_node *node; struct sockaddr_in sain; socklen_t slen = sizeof(struct sockaddr_in); sock = accept(sd, (struct sockaddr *)&sain, &slen); if (sock < 0) { lerr("accept() failed: %s", strerror(errno)); return -1; } node = find_node(&sain); linfo("NODESTATE: %s connected from %s:%d. Current state is %s", node ? node->name : "An unregistered node", inet_ntoa(sain.sin_addr), ntohs(sain.sin_port), node ? node_state_name(node->state) : "unknown"); if (!node) { close(sock); return 0; } switch (node->state) { case STATE_NEGOTIATING: case STATE_CONNECTED: case STATE_PENDING: /* if node->sock >= 0, we must negotiate which one to use */ if (node->sock >= 0) { int sel_sd = net_negotiate_socket(node, node->sock, sock); if (sel_sd != sock) { close(sock); } } break; case STATE_NONE: /* * we must close it unconditionally or we'll leak fd's * for reconnecting nodes that were previously connected */ node_disconnect(node, "fd leak prevention for connecting nodes"); node->sock = sock; break; default: lerr("%s %s has an unknown status", node_type(node), node->name); break; } node_set_state(node, STATE_NEGOTIATING, "Inbound connection accepted. Negotiating protocol version"); result = iobroker_register(nagios_iobs, node->sock, node, net_input); if (result < 0) { lerr("IOB: Failed to register %d for %s node %s for input events: %s", node->sock, node_type(node), node->name, iobroker_strerror(result)); } return sock; }
/* * Accept an inbound connection from a remote host * Returns 0 on success and -1 on errors */ int net_accept_one(void) { int sock; merlin_node *node; struct sockaddr_in sain; socklen_t slen = sizeof(struct sockaddr_in); /* * we get called from polling_loop(). If so, check for readability * to see if anyone has connected and, if not, return early */ if (!io_read_ok(net_sock, 0)) return -1; sock = accept(net_sock, (struct sockaddr *)&sain, &slen); if (sock < 0) { lerr("accept() failed: %s", strerror(errno)); return -1; } node = find_node(&sain, NULL); linfo("%s connected from %s:%d. Current state is %s", node ? node->name : "An unregistered node", inet_ntoa(sain.sin_addr), ntohs(sain.sin_port), node ? node_state_name(node->state) : "unknown"); if (!node) { close(sock); return 0; } switch (node->state) { case STATE_NEGOTIATING: /* this should *NEVER EVER* happen */ lerr("Aieee! Negotiating connection with one attempting inbound. Bad Thing(tm)"); /* fallthrough */ case STATE_CONNECTED: case STATE_PENDING: /* if node->sock >= 0, we must negotiate which one to use */ node->sock = net_negotiate_socket(node, sock); break; case STATE_NONE: /* * we must close it unconditionally or we'll leak fd's * for reconnecting nodes that were previously connected */ node_disconnect(node, "fd leak prevention for connecting nodes"); node->sock = sock; break; default: lerr("%s %s has an unknown status", node_type(node), node->name); break; } node_set_state(node, STATE_CONNECTED, "Inbound connection accepted or negotiated"); return sock; }
/* * Handles polling results from a previous (successful) select(2) * This is where new connections are handled and network input is * scheduled for reading */ int net_handle_polling_results(fd_set *rd, fd_set *wr) { uint i; /* loop the nodes and see which ones have sent something */ for (i = 0; i < num_nodes; i++) { merlin_node *node = node_table[i]; /* skip obviously bogus sockets */ if (node->sock < 0) continue; /* handle new connections first */ if (FD_ISSET(node->sock, wr)) { if (net_is_connected(node)) { node_set_state(node, STATE_CONNECTED, "select()'ed for writing"); if (binlog_has_entries(node->binlog)) { node_send_binlog(node, NULL); } } continue; } /* * handle input, and missing input. All nodes should send * a pulse at least once in a while, so we know it's still OK. * If they fail to do that, we may have to take action. */ if (FD_ISSET(node->sock, rd)) { net_input(node); } } /* check_node_activity(node); */ return 0; }
/* * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. */ void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES] = { 0, }; unsigned long min_addr, max_addr; unsigned long addr, size, end; int i; #ifdef DEBUG printk ("start of paging_init (%p, %lx)\n", kernel_pg_dir, availmem); #endif /* Fix the cache mode in the page descriptors for the 680[46]0. */ if (CPU_IS_040_OR_060) { int i; #ifndef mm_cachebits mm_cachebits = _PAGE_CACHE040; #endif for (i = 0; i < 16; i++) pgprot_val(protection_map[i]) |= _PAGE_CACHE040; } min_addr = m68k_memory[0].addr; max_addr = min_addr + m68k_memory[0].size; for (i = 1; i < m68k_num_memory;) { if (m68k_memory[i].addr < min_addr) { printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n", m68k_memory[i].addr, m68k_memory[i].size); printk("Fix your bootloader or use a memfile to make use of this area!\n"); m68k_num_memory--; memmove(m68k_memory + i, m68k_memory + i + 1, (m68k_num_memory - i) * sizeof(struct mem_info)); continue; } addr = m68k_memory[i].addr + m68k_memory[i].size; if (addr > max_addr) max_addr = addr; i++; } m68k_memoffset = min_addr - PAGE_OFFSET; m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6; module_fixup(NULL, __start_fixup, __stop_fixup); flush_icache(); high_memory = phys_to_virt(max_addr); min_low_pfn = availmem >> PAGE_SHIFT; max_low_pfn = max_addr >> PAGE_SHIFT; for (i = 0; i < m68k_num_memory; i++) { addr = m68k_memory[i].addr; end = addr + m68k_memory[i].size; m68k_setup_node(i); availmem = PAGE_ALIGN(availmem); availmem += init_bootmem_node(NODE_DATA(i), availmem >> PAGE_SHIFT, addr >> PAGE_SHIFT, end >> PAGE_SHIFT); } /* * Map the physical memory available into the kernel virtual * address space. First initialize the bootmem allocator with * the memory we already mapped, so map_node() has something * to allocate. */ addr = m68k_memory[0].addr; size = m68k_memory[0].size; free_bootmem_node(NODE_DATA(0), availmem, min(INIT_MAPPED_SIZE, size) - (availmem - addr)); map_node(0); if (size > INIT_MAPPED_SIZE) free_bootmem_node(NODE_DATA(0), addr + INIT_MAPPED_SIZE, size - INIT_MAPPED_SIZE); for (i = 1; i < m68k_num_memory; i++) map_node(i); flush_tlb_all(); /* * initialize the bad page table and bad page to point * to a couple of allocated pages */ empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); /* * Set up SFC/DFC registers */ set_fs(KERNEL_DS); #ifdef DEBUG printk ("before free_area_init\n"); #endif for (i = 0; i < m68k_num_memory; i++) { zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT; free_area_init_node(i, zones_size, m68k_memory[i].addr >> PAGE_SHIFT, NULL); if (node_present_pages(i)) node_set_state(i, N_NORMAL_MEMORY); } }
int online_pages(unsigned long pfn, unsigned long nr_pages) { unsigned long flags; unsigned long onlined_pages = 0; struct zone *zone; int need_zonelists_rebuild = 0; int nid; int ret; struct memory_notify arg; arg.start_pfn = pfn; arg.nr_pages = nr_pages; arg.status_change_nid = -1; nid = page_to_nid(pfn_to_page(pfn)); if (node_present_pages(nid) == 0) arg.status_change_nid = nid; ret = memory_notify(MEM_GOING_ONLINE, &arg); ret = notifier_to_errno(ret); if (ret) { memory_notify(MEM_CANCEL_ONLINE, &arg); return ret; } /* * This doesn't need a lock to do pfn_to_page(). * The section can't be removed here because of the * memory_block->state_sem. */ zone = page_zone(pfn_to_page(pfn)); pgdat_resize_lock(zone->zone_pgdat, &flags); grow_zone_span(zone, pfn, pfn + nr_pages); grow_pgdat_span(zone->zone_pgdat, pfn, pfn + nr_pages); pgdat_resize_unlock(zone->zone_pgdat, &flags); /* * If this zone is not populated, then it is not in zonelist. * This means the page allocator ignores this zone. * So, zonelist must be updated after online. */ if (!populated_zone(zone)) need_zonelists_rebuild = 1; walk_memory_resource(pfn, nr_pages, &onlined_pages, online_pages_range); zone->present_pages += onlined_pages; zone->zone_pgdat->node_present_pages += onlined_pages; setup_per_zone_pages_min(); if (onlined_pages) { kswapd_run(zone_to_nid(zone)); node_set_state(zone_to_nid(zone), N_HIGH_MEMORY); } if (need_zonelists_rebuild) build_all_zonelists(); vm_total_pages = nr_free_pagecache_pages(); writeback_set_ratelimit(); if (onlined_pages) memory_notify(MEM_ONLINE, &arg); return 0; }
/* * Initiate a connection attempt to a node and mark it as PENDING. * Note that since we're using sockets in non-blocking mode (in order * to be able to effectively multiplex), the connection attempt will * never be completed in this function */ int net_try_connect(merlin_node *node) { int sockopt = 1; struct sockaddr *sa = (struct sockaddr *)&node->sain; int should_log = 0; struct timeval connect_timeout = { MERLIN_CONNECT_TIMEOUT, 0 }; struct sockaddr_in sain; time_t interval = MERLIN_CONNECT_INTERVAL; int result; /* don't log obsessively */ if (node->last_conn_attempt_logged + 30 <= time(NULL)) { should_log = 1; node->last_conn_attempt_logged = time(NULL); } if (!(node->flags & MERLIN_NODE_CONNECT)) { if (should_log) { linfo("CONN: Connect attempt blocked by config to %s node %s", node_type(node), node->name); } return 0; } /* don't bother trying to connect if it's pending or done */ switch (node->state) { case STATE_NEGOTIATING: if (node->conn_sock < 0) break; case STATE_CONNECTED: case STATE_PENDING: ldebug("CONN: node %s state is %s, so bailing", node->name, node_state_name(node->state)); return 0; } /* if it's not yet time to connect, don't even try it */ if (node->last_conn_attempt + interval > time(NULL)) { return 0; } /* mark the time so we can time it out ourselves if need be */ node->last_conn_attempt = time(NULL); /* create the socket if necessary */ if (node->conn_sock < 0) { node_disconnect(node, "struct reset (no real disconnect)"); node->conn_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (node->conn_sock < 0) { lerr("CONN: Failed to obtain connection socket for node %s: %s", node->name, strerror(errno)); lerr("CONN: Aborting connection attempt to %s", node->name); return -1; } } sa->sa_family = AF_INET; if (should_log) { linfo("CONN: Connecting to %s %s@%s:%d", node_type(node), node->name, inet_ntoa(node->sain.sin_addr), ntohs(node->sain.sin_port)); } if (setsockopt(node->conn_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) { ldebug("CONN: Failed to set sockopt SO_REUSEADDR for node %s connect socket %d: %s", node->name, node->conn_sock, strerror(errno)); } if (node->flags & MERLIN_NODE_FIXED_SRCPORT) { ldebug("CONN: Using fixed source port %d for %s node %s", net_source_port(node), node_type(node), node->name); /* * first we bind() to a local port calculated by our own * listening port + the target port. */ sain.sin_family = AF_INET; sain.sin_port = htons(net_source_port(node)); sain.sin_addr.s_addr = 0; if (bind(node->conn_sock, (struct sockaddr *)&sain, sizeof(sain))) { lerr("CONN: Failed to bind() outgoing socket %d for node %s to port %d: %s", node->conn_sock, node->name, ntohs(sain.sin_port), strerror(errno)); if (errno == EBADF || errno == EADDRINUSE) { close(node->conn_sock); node->conn_sock = -1; return -1; } } } if (fcntl(node->conn_sock, F_SETFL, O_NONBLOCK) < 0) { lwarn("CONN: Failed to set socket %d for %s non-blocking: %s", node->conn_sock, node->name, strerror(errno)); } if (setsockopt(node->conn_sock, SOL_SOCKET, SO_RCVTIMEO, &connect_timeout, sizeof(connect_timeout)) < 0) { ldebug("CONN: Failed to set receive timeout for %d, node %s: %s", node->conn_sock, node->name, strerror(errno)); } if (setsockopt(node->conn_sock, SOL_SOCKET, SO_SNDTIMEO, &connect_timeout, sizeof(connect_timeout)) < 0) { ldebug("CONN: Failed to set send timeout for %d, node %s: %s", node->conn_sock, node->name, strerror(errno)); } if (connect(node->conn_sock, sa, sizeof(struct sockaddr_in)) < 0) { if (errno == EINPROGRESS) { /* * non-blocking socket and connect() can't be completed * immediately (ie, the normal case) */ node_set_state(node, STATE_PENDING, "Connecting"); } else if (errno == EALREADY) { ldebug("CONN: Connect already in progress for socket %d to %s. This should never happen", node->conn_sock, node->name); node_set_state(node, STATE_PENDING, "connect() already in progress"); } else { /* a real connection error */ ldebug("CONN: connect() via %d to %s failed: %s", node->conn_sock, node->name, strerror(errno)); close(node->conn_sock); node->conn_sock = -1; if (should_log) { node_disconnect(node, "CONN: connect() failed to %s node '%s' (%s:%d): %s", node_type(node), node->name, inet_ntoa(node->sain.sin_addr), ntohs(node->sain.sin_port), strerror(errno)); } else { node_disconnect(node, NULL); } return -1; } } result = iobroker_register_out(nagios_iobs, node->conn_sock, node, conn_writable); if (result < 0) { node_disconnect(node, "IOB: Failed to register %s connect socket %d with iobroker: %s", node->name, node->conn_sock, iobroker_strerror(result)); close(node->conn_sock); node->conn_sock = -1; return -1; } return 0; }
/* * checks if a socket is connected or not by looking up the ip and port * of the remote host. * Returns 1 if connected and 0 if not. */ int net_is_connected(merlin_node *node) { struct sockaddr_in sain; socklen_t slen; int optval = 0, gsoerr = 0, gsores = 0, gpnres = 0, gpnerr = 0; if (!node || node->sock < 0) return 0; if (node->state == STATE_CONNECTED) return 1; if (node->state != STATE_PENDING) return 0; /* * yes, getpeername() actually has to be here, or getsockopt() * won't return errors when we're not yet connected. It's * important that we read the socket error state though, or * some older kernels will maintain the link in SYN_SENT state * more or less indefinitely, so get all the syscalls taken * care of no matter if they actually work or not. */ errno = 0; slen = sizeof(struct sockaddr_in); gpnres = getpeername(node->sock, (struct sockaddr *)&sain, &slen); gpnerr = errno; slen = sizeof(optval); gsores = getsockopt(node->sock, SOL_SOCKET, SO_ERROR, &optval, &slen); gsoerr = errno; if (!gpnres && !gsores && !optval && !gpnerr && !gsoerr) { node_set_state(node, STATE_CONNECTED, "connect() attempt completed successfully"); return 1; } /* diagnostics first */ ldebug("%s is not connected: gpn/gso: %d:%d/%d:%d; optval: %d", node->name, gpnres, gpnerr, gsores, gsoerr, optval); if (optval) { node_disconnect(node, "connect() to %s node %s failed: %s", node_type(node), node->name, strerror(optval)); return 0; } if (gsores < 0 && gsoerr != ENOTCONN) { node_disconnect(node, "getsockopt(%d) failed for %s node %s: %s", node->sock, node_type(node), node->name, strerror(gsoerr)); } if (gpnres < 0 && gpnerr != ENOTCONN) { lerr("getpeername(%d) failed for %s: %s", node->sock, node->name, strerror(gpnerr)); } /* * if a connection is in progress, we should be getting * ENOTCONN, but we need to give it time to complete * first. 30 seconds should be enough. */ if (node->last_conn_attempt + MERLIN_CONNECT_TIMEOUT < time(NULL)) { node_disconnect(node, "connect() timed out after %d seconds", MERLIN_CONNECT_TIMEOUT); } return 0; }
/* * Initiate a connection attempt to a node and mark it as PENDING. * Note that since we're using sockets in non-blocking mode (in order * to be able to effectively multiplex), the connection attempt will * never be completed in this function */ int net_try_connect(merlin_node *node) { int sockopt = 1; struct sockaddr *sa = (struct sockaddr *)&node->sain; int connected = 0, should_log = 0; struct timeval connect_timeout = { MERLIN_CONNECT_TIMEOUT, 0 }; struct sockaddr_in sain; time_t interval = MERLIN_CONNECT_INTERVAL; /* don't log obsessively */ if (node->last_conn_attempt_logged + 30 <= time(NULL)) { should_log = 1; node->last_conn_attempt_logged = time(NULL); } if (!(node->flags & MERLIN_NODE_CONNECT)) { if (should_log) { linfo("Connect attempt blocked by config to %s node %s", node_type(node), node->name); } return 0; } /* if it's not yet time to connect, don't even try it */ if (node->last_conn_attempt + interval > time(NULL)) { ldebug("connect to %s blocked for %lu more seconds", node->name, node->last_conn_attempt + interval - time(NULL)); return 0; } /* mark the time so we can time it out ourselves if need be */ node->last_conn_attempt = time(NULL); /* create the socket if necessary */ if (node->sock < 0) { node_disconnect(node, "struct reset (no real disconnect)"); node->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (node->sock < 0) { lerr("Failed to obtain socket for node %s: %s", node->name, strerror(errno)); lerr("Aborting connection attempt to %s", node->name); return -1; } } /* * don't try to connect to a node if an attempt is already pending, * but do check if the connection has completed successfully */ if (node->state == STATE_PENDING || node->state == STATE_CONNECTED) { if (net_is_connected(node)) node_set_state(node, STATE_CONNECTED, "Attempted connect completed"); return 0; } sa->sa_family = AF_INET; if (should_log) { linfo("Connecting to %s %s@%s:%d", node_type(node), node->name, inet_ntoa(node->sain.sin_addr), ntohs(node->sain.sin_port)); } (void)setsockopt(node->sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)); if (node->flags & MERLIN_NODE_FIXED_SRCPORT) { ldebug("Using fixed source port for %s node %s", node_type(node), node->name); /* * first we bind() to a local port calculated by our own * listening port + the target port. */ sain.sin_family = AF_INET; sain.sin_port = htons(net_source_port(node)); sain.sin_addr.s_addr = 0; if (bind(node->sock, (struct sockaddr *)&sain, sizeof(sain))) { lerr("Failed to bind() outgoing socket for node %s to port %d: %s", node->name, ntohs(sain.sin_port), strerror(errno)); } } if (fcntl(node->sock, F_SETFL, O_NONBLOCK) < 0) { lwarn("Failed to set socket for %s non-blocking: %s", node->name, strerror(errno)); } if (setsockopt(node->sock, SOL_SOCKET, SO_RCVTIMEO, &connect_timeout, sizeof(connect_timeout)) < 0) { ldebug("Failed to set receive timeout for node %s: %s", node->name, strerror(errno)); } if (setsockopt(node->sock, SOL_SOCKET, SO_SNDTIMEO, &connect_timeout, sizeof(connect_timeout)) < 0) { ldebug("Failed to set send timeout for node %s: %s", node->name, strerror(errno)); } if (connect(node->sock, sa, sizeof(struct sockaddr_in)) < 0) { if (errno == EINPROGRESS || errno == EALREADY) { node_set_state(node, STATE_PENDING, "connect() already in progress"); } else if (errno == EISCONN) { connected = 1; } else { if (should_log) { node_disconnect(node, "connect() failed to %s node '%s' (%s:%d): %s", node_type(node), node->name, inet_ntoa(node->sain.sin_addr), ntohs(node->sain.sin_port), strerror(errno)); } else { node_disconnect(node, NULL); } return -1; } } if (connected || net_is_connected(node)) { linfo("Successfully connected to %s %s@%s:%d", node_type(node), node->name, inet_ntoa(node->sain.sin_addr), ntohs(node->sain.sin_port)); node_set_state(node, STATE_CONNECTED, "connect() successful"); } else { if (should_log) { linfo("Connection pending to %s %s@%s:%d", node_type(node), node->name, inet_ntoa(node->sain.sin_addr), ntohs(node->sain.sin_port)); } node_set_state(node, STATE_PENDING, "connect() in progress"); } return 0; }