/* * Unix style ping command for inetd. * Written by Alcides@T'Mud */ #define DEBUG(xx) if (find_player("alcides")) \ tell_object(find_player("alcides"), xx) #include mapping pings = ([ ]); #define PING_MUDNAME 0 #define PING_TOTAL 1 #define PING_SOFAR 2 #define PING_PACKET_LOSS 3 #define PING_TOTAL_TIME 4 #define PING_MIN_TIME 5 #define PING_MAX_TIME 6 #define PING_TIME_OUTS 7 #define PING_ACTUAL_SENT 8 #define PING_DATA_SIZE 9 #define PING_MAX 100 #define PING_DEFAULT "10" int cmd_ping(string str) { string retval, name, mudname; string *args, *names; mixed *data; mapping hosts; name = this_player()->query_real_name(); notify_fail("Syntax: Ping [-s] mudname [number of packets]\n"); if (!str) return 0; args = explode(str, " "); switch(args[0]) { case "-abort": case "-a": if (!pings[name]) { notify_fail("You are not currently pinging.\n"); return 0; } pings = m_delete(pings, name); write("Pinging aborted!\n"); break; case "-s": if (sizeof(args) < 2 || sizeof(args) > 3) return 0; if (sizeof(args) == 2) args += ({ PING_DEFAULT, }); if (to_int(args[2]) > PING_MAX) { notify_fail("Maximum allowed number of packets is " +PING_MAX+"\n"); return 0; } if (to_int(args[2]) == 0) { notify_fail("Sending no packets is meaningless.\n"); return 0; } mudname = lower_case(args[1]); hosts = INETD->query("hosts"); if (!hosts[mudname]) { if (sizeof(names = filter_array( m_indices(hosts), "match_mud_name", this_object(), mudname)) == 1) mudname = names[0]; else { notify_fail("Unknown mud.\n"); return 0; } } if (pings[name]) { notify_fail("Sorry, you may only ping one mud at a time!\n"); return 0; } data = allocate(PING_DATA_SIZE); data[PING_MUDNAME] = mudname; data[PING_TOTAL] = data[PING_ACTUAL_SENT] = to_int(args[2]); data[PING_SOFAR] = data[PING_PACKET_LOSS] = data[PING_TOTAL_TIME] = data[PING_TIME_OUTS] = data[PING_MAX_TIME] = 0; data[PING_MIN_TIME] = 1000; /* Should be long enough... */ pings[name] = data; remove_call_out("do_pings"); call_out("do_pings", 1); write("PING - Sending packets to "+capitalize(mudname)+"..\n"); break; default: /* * Unknown options produce a 'unknown mud' error ;-) */ if (retval = INETD->send_udp(args[0], ([ REQUEST: "ping", SENDER: this_player()->query_real_name(), ]), 1)) { notify_fail(retval); return 0; } write("Request Transmitted.\n"); } return 1; } int match_mud_name(string mudname, string match_str) { return mudname[0..strlen(match_str)-1] == match_str; } void do_pings() { int i; if (!m_sizeof(pings)) return; for(i = m_sizeof(pings); i--; ) INETD->send_udp((m_values(pings)[i])[PING_MUDNAME], ([ REQUEST: "ping", SENDER: this_object(), ]) , 1); call_out("do_pings", 1); } void udp_reply(mapping rdata) { mixed *data; string who; object ob; int i; for (i = m_sizeof(pings); i--; ) { who = m_indices(pings)[i]; data = m_values(pings)[i]; if (data[PING_MUDNAME] != lower_case(rdata[NAME])) continue; if (!(ob = find_player(who))) { pings = m_delete(pings, who); i--; continue; } data[PING_SOFAR]++; data[PING_PACKET_LOSS] += rdata[PACKET_LOSS]; data[PING_ACTUAL_SENT] += rdata[PACKET_LOSS]; data[PING_TOTAL_TIME] += rdata[RESPONSE_TIME]; if (rdata[RESPONSE_TIME] > data[PING_MAX_TIME]) data[PING_MAX_TIME] = rdata[RESPONSE_TIME]; if (rdata[RESPONSE_TIME] < data[PING_MIN_TIME]) data[PING_MIN_TIME] = rdata[RESPONSE_TIME]; pings = m_delete(pings, who); if (rdata[SYSTEM] == TIME_OUT) data[PING_ACTUAL_SENT]--; if (data[PING_SOFAR] == data[PING_TOTAL]) call_out("do_summary", 1, data+({ who, })); else pings[who] = data; if (rdata[SYSTEM] == TIME_OUT) data[PING_TIME_OUTS]++; else tell_object(ob, sprintf("Packet from %s (%s) id: %d. "+ "time: %ds.\n", rdata[NAME], rdata[HOST], rdata[ID], rdata[RESPONSE_TIME])); } } void do_summary(mixed *data) { object ob; if (!(ob = find_player(data[PING_DATA_SIZE]))) return; tell_object(ob, sprintf("---%s ping statistics---\n", capitalize(data[PING_MUDNAME]))); tell_object(ob, sprintf("%d packets transmitted. %d%% packet loss." + " (%d packets).\n" + "Total time taken: %d. Timed out packets - %d\n" + "round-trip (s) min/avg/max = %d/%d/%d.\n", data[PING_ACTUAL_SENT], (data[PING_PACKET_LOSS]*100) / data[PING_ACTUAL_SENT], data[PING_PACKET_LOSS], data[PING_TOTAL_TIME], data[PING_TIME_OUTS], data[PING_MIN_TIME], data[PING_TOTAL_TIME] / data[PING_TOTAL], data[PING_MAX_TIME])); }