static void _main_loop(Ipmi_Ping_CreatePacket _create, Ipmi_Ping_ParsePacket _parse, Ipmi_Ping_LatePacket _late) { unsigned int sequence_number = 0; time_t last_send = 0; int ret; assert(_create != NULL && _parse != NULL && _late != NULL && _progname != NULL && _end_result != NULL); if (_initial_sequence_number < 0) { int len; if ((len = ipmi_get_random((uint8_t *)&_initial_sequence_number, sizeof(_initial_sequence_number))) < 0) ipmi_ping_err_exit("ipmi_get_random: %s", strerror(errno)); if (len != sizeof(_initial_sequence_number)) ipmi_ping_err_exit("ipmi_get_random: invalid len returned"); } sequence_number = _initial_sequence_number; printf("%s %s (%s)\n", _progname, _dest, _dest_ip); while (_count == -1 || (_pkt_sent < _count)) { int rv, len, received = 0; uint8_t buffer[IPMI_PING_MAX_PKT_LEN]; time_t now; /* wait if necessary */ now = time(NULL); if ((now - last_send) < _interval) { if (_sleep((last_send + _interval - now)) < 0) continue; } if ((len = _create(_dest, (char *)buffer, IPMI_PING_MAX_PKT_LEN, sequence_number, _version, _debug)) < 0) ipmi_ping_err_exit("_create failed: %s", strerror(errno)); rv = ipmi_lan_sendto(_sockfd, buffer, len, 0, (struct sockaddr *)&_destaddr, sizeof(_destaddr)); if (rv < 0) ipmi_ping_err_exit("ipmi_sendto: %s", strerror(errno)); if (rv != len) ipmi_ping_err_exit("ipmi_sendto: wrong bytes written"); last_send = time(NULL); _pkt_sent++; while (((now = time(NULL)) - last_send) < _timeout) { fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(_sockfd, &rset); tv.tv_sec = (last_send + _timeout - now); tv.tv_usec = 0; if ((rv = select(_sockfd+1, &rset, NULL, NULL, &tv)) < 0) ipmi_ping_err_exit("select: %s", strerror(errno)); if (rv == 1) { struct sockaddr_in from; socklen_t fromlen; fromlen = sizeof(from); len = ipmi_lan_recvfrom(_sockfd, buffer, IPMI_PING_MAX_PKT_LEN, 0, (struct sockaddr *)&from, &fromlen); if (len < 0) ipmi_ping_err_exit("ipmi_recvfrom: %s", strerror(errno)); if ((rv = _parse(_dest, (char *)buffer, len, inet_ntoa(from.sin_addr), sequence_number, _verbose, _version, _debug)) < 0) ipmi_ping_err_exit("_parse failed: %s", strerror(errno)); /* If rv == 0, the sequence numbers don't match, so * we'll wait some more for the latest packet we sent * out. */ if (rv == 0) continue; received++; _pkt_recv++; break; } } if (received == 0) _late(sequence_number); sequence_number++; } ret = _end_result(_progname, _dest, _pkt_sent, _pkt_recv); _cleanup(); exit(ret); }
static void _main_loop (Ipmi_Ping_CreatePacket create, Ipmi_Ping_ParsePacket parse, Ipmi_Ping_LatePacket late) { unsigned int sequence_number = 0; time_t last_send = 0; int ret; assert (create); assert (parse); assert (late); assert (pingtool_progname); assert (pingtool_end_result); if (pingtool_initial_sequence_number < 0) { int len; if ((len = ipmi_get_random (&pingtool_initial_sequence_number, sizeof (pingtool_initial_sequence_number))) < 0) ipmi_ping_err_exit ("ipmi_get_random: %s", strerror (errno)); if (len != sizeof (pingtool_initial_sequence_number)) ipmi_ping_err_exit ("ipmi_get_random: invalid len returned"); } sequence_number = pingtool_initial_sequence_number; printf ("%s %s (%s)\n", pingtool_progname, pingtool_dest, pingtool_dest_ip); while (pingtool_count == -1 || (pingtool_pkt_sent < pingtool_count)) { int rv, len, received = 0; uint8_t buf[IPMI_PING_MAX_PKT_LEN]; time_t now; /* wait if necessary */ now = time (NULL); if ((now - last_send) < pingtool_interval) { if (_sleep ((last_send + pingtool_interval - now)) < 0) continue; } if ((len = create (pingtool_dest, buf, IPMI_PING_MAX_PKT_LEN, sequence_number, pingtool_version, pingtool_debug)) < 0) ipmi_ping_err_exit ("_create failed: %s", strerror (errno)); rv = ipmi_lan_sendto (pingtool_sockfd, buf, len, 0, (struct sockaddr *)&pingtool_destaddr, sizeof (pingtool_destaddr)); if (rv < 0) ipmi_ping_err_exit ("ipmi_sendto: %s", strerror (errno)); if (rv != len) ipmi_ping_err_exit ("ipmi_sendto: wrong bytes written"); last_send = time (NULL); pingtool_pkt_sent++; while (((now = time (NULL)) - last_send) < pingtool_timeout) { fd_set rset; struct timeval tv; FD_ZERO (&rset); FD_SET (pingtool_sockfd, &rset); tv.tv_sec = (last_send + pingtool_timeout - now); tv.tv_usec = 0; if ((rv = select (pingtool_sockfd+1, &rset, NULL, NULL, &tv)) < 0) ipmi_ping_err_exit ("select: %s", strerror (errno)); if (rv == 1) { struct sockaddr_in from; socklen_t fromlen; fromlen = sizeof (from); len = ipmi_lan_recvfrom (pingtool_sockfd, buf, IPMI_PING_MAX_PKT_LEN, 0, (struct sockaddr *)&from, &fromlen); /* achu & hliebig: * * Premise from ipmitool (http://ipmitool.sourceforge.net/) * * On some OSes (it seems Unixes), the behavior is to not return * port denied errors up to the client for UDP responses (i.e. you * need to timeout). But on some OSes (it seems Windows), the * behavior is to return port denied errors up to the user for UDP * responses via ECONNRESET or ECONNREFUSED. * * If this were just the case, we could return or handle errors * properly and move on. However, it's not the case. * * According to Ipmitool, on some motherboards, both the OS and the * BMC are capable of responding to an IPMI request. That means you * can get an ECONNRESET or ECONNREFUSED, then later on, get your * real IPMI response. * * Our solution is copied from Ipmitool, we'll ignore some specific * errors and try to read again. * * If the ECONNREFUSED or ECONNRESET is from the OS, but we will get * an IPMI response later, the recvfrom later on gets the packet we * want. * * If the ECONNREFUSED or ECONNRESET is from the OS but there is no * BMC (or IPMI disabled, etc.), just do the recvfrom again to * eventually get a timeout, which is the behavior we'd like. */ if (len < 0 && (errno == ECONNRESET || errno == ECONNREFUSED)) continue; if (len < 0) ipmi_ping_err_exit ("ipmi_recvfrom: %s", strerror (errno)); if ((rv = parse (pingtool_dest, buf, len, inet_ntoa (from.sin_addr), sequence_number, pingtool_verbose, pingtool_version, pingtool_debug)) < 0) ipmi_ping_err_exit ("_parse failed: %s", strerror (errno)); /* If rv == 0, the sequence numbers don't match, so * we'll wait some more for the latest packet we sent * out. */ if (!rv) continue; received++; pingtool_pkt_recv++; break; } } if (!received) late (sequence_number); sequence_number++; } ret = pingtool_end_result (pingtool_progname, pingtool_dest, pingtool_pkt_sent, pingtool_pkt_recv); _cleanup (); exit (ret); }
/* * Return 0 on success * Return -1 on fatal error */ static int _ipmi_sendto (ipmiconsole_ctx_t c) { char buffer[IPMICONSOLE_PACKET_BUFLEN]; ssize_t len; int n; assert (c); assert (c->magic == IPMICONSOLE_CTX_MAGIC); if ((n = scbuf_read (c->connection.ipmi_to_bmc, buffer, IPMICONSOLE_PACKET_BUFLEN)) < 0) { IPMICONSOLE_CTX_DEBUG (c, ("scbuf_read: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR); return (-1); } if (ipmi_is_ipmi_1_5_packet (buffer, n)) { do { len = ipmi_lan_sendto (c->connection.ipmi_fd, buffer, n, 0, (struct sockaddr *)&(c->session.addr), sizeof (struct sockaddr_in)); } while (len < 0 && errno == EINTR); } else { do { len = ipmi_rmcpplus_sendto (c->connection.ipmi_fd, buffer, n, 0, (struct sockaddr *)&(c->session.addr), sizeof (struct sockaddr_in)); } while (len < 0 && errno == EINTR); } if (len < 0) { IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_sendto: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR); return (-1); } #if 0 /* don't check, let bad packet timeout */ if (len != n) { IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_sendto: invalid bytes written; n=%d; len=%d", n, len)); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR); return (-1); } #endif /* scbuf should be empty now */ if (!scbuf_is_empty (c->connection.ipmi_to_bmc)) { IPMICONSOLE_CTX_DEBUG (c, ("ipmi_to_bmc not empty")); /* Note: Not a fatal error, just return*/ return (0); } return (0); }