Author: Ghostwolf <foxxe@wtfs.net>
[ircu2.10.12-pk.git] / ircd / uping.c
index b12fdcb2b1466dcc0dcbefe265ada908f6756ddc..8f8965365d227a5b9646f3bcbcc4f1247c130477 100644 (file)
  *
  * $Id$
  */
+#include "config.h"
+
 #include "uping.h"
 #include "client.h"
 #include "ircd.h"
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "ircd_log.h"
 #include "ircd_osdep.h"
 #include "ircd_string.h"
 #include "match.h"
+#include "msg.h"
 #include "numeric.h"
 #include "numnicks.h"
-#include "res.h"
-#include "s_bsd.h"    /* vserv */
+#include "s_bsd.h"    /* VirtualHost */
 #include "s_conf.h"
 #include "s_debug.h"
 #include "s_misc.h"
 #define INADDR_NONE 0xffffffff
 #endif
 
-static void ping_server(struct UPing*);
-
 static struct UPing* pingList = 0;
-int UPingListener = -1; /* UDP listener socket for upings */
+int UPingFileDescriptor       = -1; /* UDP listener socket for upings */
+
+static struct Socket upingSock;
 
 /*
  * pings_begin - iterator function for ping list 
@@ -77,7 +80,7 @@ static void uping_erase(struct UPing* p)
 
   assert(0 != p);
   
-  for (it = pingList; it; last = it = it->next) {
+  for (it = pingList; it; last = it, it = it->next) {
     if (p == it) {
       if (last)
         last->next = p->next;
@@ -88,67 +91,62 @@ static void uping_erase(struct UPing* p)
   }
 }
 
-/*
- * uping_dns_callback - this gets called when the resolver either
- * succeeds or fails to locate the servers address.
- * If the dns query failed hp will be 0, otherwise it
- * will contain the stuff a hostent normally contains.
- */
-static void uping_dns_callback(void* v, struct DNSReply* r)
+/* Called when the event engine detects activity on the UPing socket */
+static void uping_echo_callback(struct Event* ev)
 {
-  struct UPing* ping = (struct UPing*) v;
-  assert(valid_ptr((void*)ping, sizeof(struct UPing)));
+  assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
 
-  if (r) {
-    memcpy(&ping->sin.sin_addr, r->hp->h_addr, sizeof(struct in_addr));
-    ping_server(ping);
-  }
-  else
-  {
-    sendto_ops("UDP ping to %s failed: host lookup", ping->name);
-    end_ping(ping);
-  }
+  uping_echo();
 }
 
-
 /*
  * Setup a UDP socket and listen for incoming packets
  */
 int uping_init(void)
 {
-  struct sockaddr_in from;
+  struct sockaddr_in from = { 0 };
   int fd;
 
   memset(&from, 0, sizeof(from));
-#ifdef VIRTUAL_HOST
-  from.sin_addr = vserv.sin_addr;
-#else
-  from.sin_addr.s_addr = htonl(INADDR_ANY);
-#endif
+  from.sin_addr = VirtualHost.sin_addr;
   from.sin_port = htons(atoi(UDP_PORT));
   from.sin_family = AF_INET;
 
   if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
-    Debug((DEBUG_ERROR, "UPING: UDP listener socket call failed: %s", strerror(errno)));
+    Debug((DEBUG_ERROR, "UPING: UDP listener socket call failed: %s", 
+           (strerror(errno)) ? strerror(errno) : "Unknown error"));
     return -1;
   }
   if (!os_set_reuseaddr(fd)) {
-    ircd_log(L_ERROR, "UPING: setsockopt UDP listener: fd %d", fd);
-    Debug((DEBUG_ERROR, "UPING: set reuseaddr on UDP listener failed: %s", strerror(errno)));
+    log_write(LS_SOCKET, L_ERROR, 0,
+             "UPING: set reuseaddr on UDP listener failed: %m (fd %d)", fd);
+    Debug((DEBUG_ERROR, "UPING: set reuseaddr on UDP listener failed: %s",
+           (strerror(errno)) ? strerror(errno) : "Unknown error"));
     close(fd);
     return -1;
   }
   if (bind(fd, (struct sockaddr*) &from, sizeof(from)) == -1) {
-    ircd_log(L_ERROR, "UPING: bind UDP listener %d fd %d", htons(from.sin_port), fd);
-    Debug((DEBUG_ERROR, "UPING: bind on UDP listener failed : %s", strerror(errno)));
+    log_write(LS_SOCKET, L_ERROR, 0,
+             "UPING: bind on UDP listener (%d fd %d) failed: %m",
+             htons(from.sin_port), fd);
+    Debug((DEBUG_ERROR, "UPING: bind on UDP listener failed : %s",
+           (strerror(errno)) ? strerror(errno) : "Unknown error"));
     close(fd);
     return -1;
   }
   if (!os_set_nonblocking(fd)) {
-    Debug((DEBUG_ERROR, "UPING: set non-blocking: %s", strerror(errno)));
+    Debug((DEBUG_ERROR, "UPING: set non-blocking: %s",
+           (strerror(errno)) ? strerror(errno) : "Unknown error"));
     close(fd);
     return -1;
   }
+  if (!socket_add(&upingSock, uping_echo_callback, 0, SS_DATAGRAM,
+                 SOCK_EVENT_READABLE, fd)) {
+    Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
+    close(fd);
+    return -1;
+  }
+  UPingFileDescriptor = fd;
   return fd;
 }
 
@@ -156,17 +154,17 @@ int uping_init(void)
 /*
  * max # of pings set to 15/sec.
  */
-void polludp(int udpfd)
+void uping_echo()
 {
-  struct sockaddr_in from;
+  struct sockaddr_in from = { 0 };
   unsigned int       len = 0;
   static time_t      last = 0;
   static int         counter = 0;
   char               buf[BUFSIZE + 1];
 
-  Debug((DEBUG_DEBUG, "UPING: poll"));
+  Debug((DEBUG_DEBUG, "UPING: uping_echo"));
 
-  if (IO_SUCCESS != os_recvfrom_nonb(udpfd, buf, BUFSIZE, &len, &from))
+  if (IO_SUCCESS != os_recvfrom_nonb(UPingFileDescriptor, buf, BUFSIZE, &len, &from))
     return;
   /*
    * count em even if we're getting flooded so we can tell we're getting
@@ -183,75 +181,120 @@ void polludp(int udpfd)
   }
   if (len < 19)
     return;
-  sendto(udpfd, buf, len, 0, (struct sockaddr *)&from, sizeof(from));
+  sendto(UPingFileDescriptor, buf, len, 0, (struct sockaddr*) &from, sizeof(from));
 }
 
 
-/*
- * start_ping
- */
-static void start_ping(struct UPing* pptr)
+/* Callback when socket has data to read */
+static void uping_read_callback(struct Event* ev)
 {
-  assert(valid_ptr((void*) pptr, sizeof(struct UPing)));
-
-  if (MyUser(pptr->client) || Protocol(pptr->client->from) < 10) {
-    sendto_one(pptr->client,
-       ":%s NOTICE %s :Sending %d ping%s to %s[%s] port %d",
-       me.name, pptr->client->name, pptr->count,
-       (pptr->count == 1) ? "" : "s", pptr->name,
-       ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port));
+  struct UPing *pptr;
+
+  assert(0 != ev_socket(ev));
+  assert(0 != s_data(ev_socket(ev)));
+
+  pptr = s_data(ev_socket(ev));
+
+  Debug((DEBUG_SEND, "uping_read_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_SOCKET;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
+
+    uping_read(pptr); /* read uping response */
   }
-  else
-  {
-    sendto_one(pptr->client,
-       "%s NOTICE %s%s :Sending %d ping%s to %s[%s] port %d",
-       NumServ(&me), NumNick(pptr->client), pptr->count,
-       (pptr->count == 1) ? "" : "s", pptr->name,
-       ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port));
+}
+
+/* Callback to send another ping */
+static void uping_sender_callback(struct Event* ev)
+{
+  struct UPing *pptr;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  pptr = t_data(ev_timer(ev));
+
+  Debug((DEBUG_SEND, "uping_sender_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_SENDER;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    pptr->lastsent = CurrentTime; /* store last ping time */
+    uping_send(pptr); /* send a ping */
+
+    if (pptr->sent == pptr->count) /* done sending pings, don't send more */
+      timer_del(ev_timer(ev));
   }
-  pptr->timeout = CurrentTime + UPINGTIMEOUT;
-  pptr->active = 1;
 }
 
-/*
- * ping_server - get the server host address if not valid
- * then call start_ping
- */
-static void ping_server(struct UPing* pptr)
+/* Callback to kill a ping */
+static void uping_killer_callback(struct Event* ev)
 {
-  if (INADDR_NONE == pptr->sin.sin_addr.s_addr) {
-    char *s;
-
-    if ((s = strchr(pptr->name, '@')))
-      ++s;                     
-    else
-      s = pptr->name;
-
-    if (INADDR_NONE == (pptr->sin.sin_addr.s_addr = inet_addr(s))) {
-      struct DNSQuery query;
-      struct DNSReply* rpl;
-
-      query.vptr = (void*) pptr;
-      query.callback = uping_dns_callback;
-      if (0 == (rpl = gethost_byname(s, &query)))
-       return;
-      memcpy(&pptr->sin.sin_addr, rpl->hp->h_addr, sizeof(struct in_addr));
-    }
+  struct UPing *pptr;
+
+  assert(0 != ev_timer(ev));
+  assert(0 != t_data(ev_timer(ev)));
+
+  pptr = t_data(ev_timer(ev));
+
+  Debug((DEBUG_SEND, "uping_killer_callback called, %p (%d)", pptr,
+        ev_type(ev)));
+
+  if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
+    pptr->freeable &= ~UPING_PENDING_KILLER;
+
+    if (!pptr->freeable)
+      MyFree(pptr); /* done with it, finally */
+  } else {
+    assert(ev_type(ev) == ET_EXPIRE);
+
+    uping_end(pptr); /* <FUDD>kill the uping, kill the uping!</FUDD> */
   }
-  start_ping(pptr);
 }
 
+/*
+ * start_ping
+ */
+static void uping_start(struct UPing* pptr)
+{
+  assert(0 != pptr);
+
+  timer_add(timer_init(&pptr->sender), uping_sender_callback, (void*) pptr,
+           TT_PERIODIC, 1);
+  timer_add(timer_init(&pptr->killer), uping_killer_callback, (void*) pptr,
+           TT_RELATIVE, UPINGTIMEOUT);
+  pptr->freeable |= UPING_PENDING_SENDER | UPING_PENDING_KILLER;
+
+  sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :Sending %d ping%s to %s",
+               pptr->client, pptr->count, (pptr->count == 1) ? "" : "s",
+               pptr->name);
+  pptr->active = 1;
+}
 
 /*
- * send_ping
+ * uping_send
  *
  */
-void send_ping(struct UPing* pptr)
+void uping_send(struct UPing* pptr)
 {
   struct timeval tv;
   char buf[BUFSIZE + 1];
 
   assert(0 != pptr);
+  if (pptr->sent == pptr->count)
+    return;
   memset(buf, 0, sizeof(buf));
 
   gettimeofday(&tv, NULL);
@@ -259,28 +302,20 @@ void send_ping(struct UPing* pptr)
 
   Debug((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
          buf, &buf[12],
-         ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port),
+          ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port),
          pptr->fd));
 
   if (sendto(pptr->fd, buf, BUFSIZE, 0, (struct sockaddr*) &pptr->sin,
              sizeof(struct sockaddr_in)) != BUFSIZE)
   {
-    int err = errno;
+    const char* msg = strerror(errno);
+    if (!msg)
+      msg = "Unknown error";
     if (pptr->client)
-    {
-      if (MyUser(pptr->client)
-#ifndef NO_PROTOCOL9
-         || (IsServer(pptr->client->from) && Protocol(pptr->client->from) < 10)
-#endif
-         )
-       sendto_one(pptr->client, ":%s NOTICE %s :UPING: sendto() failed: %s",
-                  me.name, pptr->client->name, strerror(errno));
-      else
-       sendto_one(pptr->client, "%s NOTICE %s%s :UPING: sendto() failed: %s",
-                  NumServ(&me), NumNick(pptr->client), strerror(errno));
-    }
-    Debug((DEBUG_DEBUG, "UPING: send_ping: sendto failed on %d: %s", pptr->fd, strerror(err)));
-    end_ping(pptr);
+      sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: send failed: "
+                   "%s", pptr->client, msg);
+    Debug((DEBUG_DEBUG, "UPING: send_ping: sendto failed on %d: %s", pptr->fd, msg));
+    uping_end(pptr);
     return;
   }
   ++pptr->sent;
@@ -289,7 +324,7 @@ void send_ping(struct UPing* pptr)
 /*
  * read_ping
  */
-void read_ping(struct UPing* pptr)
+void uping_read(struct UPing* pptr)
 {
   struct sockaddr_in sin;
   struct timeval     tv;
@@ -307,192 +342,66 @@ void read_ping(struct UPing* pptr)
   if (IO_BLOCKED == ior)
     return;
   else if (IO_FAILURE == ior) {
-    int err = errno;
-    if (MyUser(pptr->client)
-#ifndef NO_PROTOCOL9
-        || (IsServer(pptr->client->from) && Protocol(pptr->client->from) < 10)
-#endif
-        )
-      sendto_one(pptr->client, ":%s NOTICE %s :UPING: recvfrom: %s",
-                 me.name, pptr->client->name, strerror(err));
-    else
-      sendto_one(pptr->client, "%s NOTICE %s%s :UPING: recvfrom: %s",
-                 NumServ(&me), NumNick(pptr->client), strerror(err));
-    Debug((DEBUG_SEND, "UPING: read_ping: recvfrom: %d", err));
-    end_ping(pptr);
+    const char* msg = strerror(errno);
+    if (!msg)
+      msg = "Unknown error";
+    sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: receive error: "
+                 "%s", pptr->client, msg);
+    uping_end(pptr);
     return;
   }    
 
   if (len < 19)
     return;                    /* Broken packet */
-
+   
   ++pptr->received;
+
+  buf[len] = 0;
   pingtime = (tv.tv_sec - atol(&buf[1])) * 1000
              + (tv.tv_usec - atol(buf + strlen(buf) + 1)) / 1000;
 
   pptr->ms_ave += pingtime;
-  if (!(pptr->ms_min) || (pptr->ms_min > pingtime))
+  if (!pptr->ms_min || pptr->ms_min > pingtime)
     pptr->ms_min = pingtime;
   if (pingtime > pptr->ms_max)
     pptr->ms_max = pingtime;
-  
-  pptr->timeout = CurrentTime + UPINGTIMEOUT;
 
-  Debug((DEBUG_SEND, "read_ping: %d bytes, ti %lu: [%s %s] %lu ms",
-      len, pptr->timeout, buf, (buf + strlen(buf) + 1), pingtime));
+  timer_chg(&pptr->killer, TT_RELATIVE, UPINGTIMEOUT);
 
   s = pptr->buf + strlen(pptr->buf);
   sprintf(s, " %u", pingtime);
 
   if (pptr->received == pptr->count)
-    end_ping(pptr);
+    uping_end(pptr);
   return;
 }
 
-
-/*
- * m_uping  -- by Run
- *
- * parv[0] = sender prefix
- * parv[1] = pinged server
- * parv[2] = port
- * parv[3] = hunted server
- * parv[4] = number of requested pings
- */
-int m_uping(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
+int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count)
 {
-  struct ConfItem *aconf;
-  int port;
   int fd;
-  struct UPing* pptr = 0;
+  struct UPing* pptr;
 
-  if (!IsPrivileged(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return -1;
-  }
+  assert(0 != sptr);
+  assert(0 != aconf);
 
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "UPING");
-    return 0;
-  }
-
-  if (MyUser(sptr))
-  {
-    if (parc == 2)
-    {
-      parv[parc++] = UDP_PORT;
-      parv[parc++] = me.name;
-      parv[parc++] = "5";
-    }
-    else if (parc == 3)
-    {
-      if (IsDigit(*parv[2]))
-       parv[parc++] = me.name;
-      else
-      {
-       parv[parc++] = parv[2];
-       parv[2] = UDP_PORT;
-      }
-      parv[parc++] = "5";
-    }
-    else if (parc == 4)
-    {
-      if (IsDigit(*parv[2]))
-      {
-       if (IsDigit(*parv[3]))
-       {
-         parv[parc++] = parv[3];
-         parv[3] = me.name;
-       }
-       else
-         parv[parc++] = "5";
-      }
-      else
-      {
-       parv[parc++] = parv[3];
-       parv[3] = parv[2];
-       parv[2] = UDP_PORT;
-      }
-    }
-  }
-  if (hunt_server(1, cptr, sptr,
-      ":%s UPING %s %s %s %s", 3, parc, parv) != HUNTED_ISME)
-    return 0;
-
-  if (BadPtr(parv[4]) || atoi(parv[4]) <= 0)
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Illegal number of packets: %s",
-         me.name, parv[0], parv[4]);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :UPING: Illegal number of packets: %s",
-         NumServ(&me), NumNick(sptr), parv[4]);
-    return 0;
-  }
-
-  /* Check if a CONNECT would be possible at all (adapted from m_connect) */
-  for (aconf = GlobalConfList; aconf; aconf = aconf->next)
-  {
-    if (aconf->status == CONF_SERVER &&
-       match(parv[1], aconf->name) == 0)
-      break;
-  }
-  if (!aconf)
-  {
-    for (aconf = GlobalConfList; aconf; aconf = aconf->next)
-    {
-      if (aconf->status == CONF_SERVER &&
-         (match(parv[1], aconf->host) == 0 ||
-          match(parv[1], strchr(aconf->host, '@') + 1) == 0))
-       break;
-    }
-  }
-  if (!aconf)
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Host %s not listed in ircd.conf",
-         me.name, parv[0], parv[1]);
-    else
-      sendto_one(sptr,
-         "%s NOTICE %s%s :UPING: Host %s not listed in ircd.conf",
-         NumServ(&me), NumNick(sptr), parv[1]);
+  if (INADDR_NONE == aconf->ipnum.s_addr) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host lookup failed for "
+                 "%s", sptr, aconf->name);
     return 0;
   }
 
   if (IsUPing(sptr))
-    cancel_ping(sptr, sptr);  /* Cancel previous ping request */
-
-  /*
-   * Determine port: First user supplied, then default : 7007
-   */
-  if (BadPtr(parv[2]) || (port = atoi(parv[2])) <= 0)
-    port = atoi(UDP_PORT);
+    uping_cancel(sptr, sptr);  /* Cancel previous ping request */
 
   if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
-    int err = errno;
-    sendto_ops("m_uping: socket: %s", (err != EMFILE) 
-                ? strerror(err) : "No more sockets");
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, 
-                 ":%s NOTICE %s :UPING: Unable to create udp ping socket",
-                 me.name, parv[0]);
-    else
-      sendto_one(sptr,
-                 "%s NOTICE %s%s :UPING: Unable to create udp ping socket",
-                 NumServ(&me), NumNick(sptr));
-    ircd_log(L_ERROR, "UPING: Unable to create UDP socket");
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Unable to create udp "
+                 "ping socket", sptr);
     return 0;
   }
 
   if (!os_set_nonblocking(fd)) {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Can't set fd non-blocking",
-            me.name, parv[0]);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :UPING: Can't set fd non-blocking",
-            NumServ(&me), NumNick(sptr));
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't set fd non-"
+                 "blocking", sptr);
     close(fd);
     return 0;
   }
@@ -500,109 +409,83 @@ int m_uping(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
   assert(0 != pptr);
   memset(pptr, 0, sizeof(struct UPing));
 
-  pptr->fd = fd;
-  pptr->sin.sin_port = htons(port);
+  if (!socket_add(&pptr->socket, uping_read_callback, (void*) pptr,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) {
+    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Can't queue fd for "
+                 "reading", sptr);
+    close(fd);
+    MyFree(pptr);
+    return 0;
+  }
+
+  pptr->fd                  = fd;
+  pptr->sin.sin_port        = htons(port);
   pptr->sin.sin_addr.s_addr = aconf->ipnum.s_addr;
-  pptr->sin.sin_family = AF_INET;
-  pptr->count = IRCD_MIN(20, atoi(parv[4]));
-  strcpy(pptr->name, aconf->host);
-  pptr->client = sptr;
-  pptr->index = -1;
+  pptr->sin.sin_family      = AF_INET;
+  pptr->count               = IRCD_MIN(20, count);
+  pptr->client              = sptr;
+  pptr->index               = -1;
+  pptr->freeable            = UPING_PENDING_SOCKET;
+  strcpy(pptr->name, aconf->name);
 
   pptr->next = pingList;
-  pingList = pptr;
+  pingList   = pptr;
 
   SetUPing(sptr);
-  ping_server(pptr);
+  uping_start(pptr);
   return 0;
 }
 
-void end_ping(struct UPing* pptr)
+
+void uping_end(struct UPing* pptr)
 {
-  Debug((DEBUG_DEBUG, "end_ping: %p", pptr));
-  delete_resolver_queries((void*) pptr);
-  if (pptr->client)
-  {
-    if (MyUser(pptr->client)
-        || (IsServer(pptr->client->from) && Protocol(pptr->client->from) < 10))
-    {
-      if (pptr->lastsent)      /* Started at all ? */
-      {
-       if (0 < pptr->received) /* Received any pings at all? */
-       {
-         sendto_one(pptr->client, ":%s NOTICE %s :UPING %s%s",
-             me.name, pptr->client->name, pptr->name, pptr->buf);
-          /* XXX - warning long unsigned int format, unsigned int arg (7, 8, 9) */
-         sendto_one(pptr->client,
-             ":%s NOTICE %s :UPING Stats: sent %d recvd %d ; "
-             "min/avg/max = %1lu/%1lu/%1lu ms",
-             me.name, pptr->client->name, pptr->sent,
-             pptr->received, pptr->ms_min,
-             (2 * pptr->ms_ave) / (2 * pptr->received), 
-              pptr->ms_max);
-       }
-       else
-         sendto_one(pptr->client,
-             ":%s NOTICE %s :UPING: no response from %s within %d seconds",
-             me.name, pptr->client->name, pptr->name,
-             UPINGTIMEOUT);
-      }
-      else
-       sendto_one(pptr->client,
-           ":%s NOTICE %s :UPING: Could not start ping to %s %d",
-           me.name, pptr->client->name, pptr->name, ntohs(pptr->sin.sin_port));
-    }
-    else
-    {
-      if (pptr->lastsent)      /* Started at all ? */
-      {
-       if (0 < pptr->received) /* Received any pings at all? */
-       {
-         sendto_one(pptr->client, "%s NOTICE %s%s :UPING %s%s",
-             NumServ(&me), NumNick(pptr->client), pptr->name, pptr->buf);
-          /* XXX - warning: long unsigned int format, unsigned int arg(9, 10, 11) */
-         sendto_one(pptr->client,
-             "%s NOTICE %s%s :UPING Stats: sent %d recvd %d ; "
-             "min/avg/max = %1lu/%1lu/%1lu ms",
-             NumServ(&me), NumNick(pptr->client), pptr->sent,
-             pptr->received, pptr->ms_min,
-             (2 * pptr->ms_ave) / (2 * pptr->received), 
-              pptr->ms_max);
-       }
-       else
-         sendto_one(pptr->client,
-             "%s NOTICE %s%s :UPING: no response from %s within %d seconds",
-             NumServ(&me), NumNick(pptr->client), pptr->name,
-             UPINGTIMEOUT);
-      }
-      else
-       sendto_one(pptr->client,
-           "%s NOTICE %s%s :UPING: Could not start ping to %s %d",
-           NumServ(&me), NumNick(pptr->client), pptr->name, 
-            ntohs(pptr->sin.sin_port));
-    }
+  Debug((DEBUG_DEBUG, "uping_end: %p", pptr));
+
+  if (pptr->client) {
+    if (pptr->lastsent) {
+      if (0 < pptr->received) {
+       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING %s%s",
+                     pptr->client, pptr->name, pptr->buf);
+       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING Stats: "
+                     "sent %d recvd %d ; min/avg/max = %1lu/%1lu/%1lu ms",
+                     pptr->client, pptr->sent, pptr->received, pptr->ms_min,
+                     (2 * pptr->ms_ave) / (2 * pptr->received), pptr->ms_max);
+      } else
+       sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: no response "
+                     "from %s within %d seconds", pptr->client, pptr->name,
+                     UPINGTIMEOUT);
+    } else
+      sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING: Could not "
+                   "start ping to %s", pptr->client, pptr->name);
   }
+
   close(pptr->fd);
   pptr->fd = -1;
   uping_erase(pptr);
   if (pptr->client)
     ClearUPing(pptr->client);
-  MyFree(pptr);
+  if (pptr->freeable & UPING_PENDING_SOCKET)
+    socket_del(&pptr->socket);
+  if (pptr->freeable & UPING_PENDING_SENDER)
+    timer_del(&pptr->sender);
+  if (pptr->freeable & UPING_PENDING_KILLER)
+    timer_del(&pptr->killer);
 }
 
-void cancel_ping(struct Client *sptr, struct Client* acptr)
+void uping_cancel(struct Client *sptr, struct Client* acptr)
 {
   struct UPing* ping;
   struct UPing* ping_next;
 
-  Debug((DEBUG_DEBUG, "UPING: cancelling uping for %s", sptr->name));
+  Debug((DEBUG_DEBUG, "UPING: cancelling uping for %s", cli_name(sptr)));
   for (ping = pingList; ping; ping = ping_next) {
     ping_next = ping->next;
     if (sptr == ping->client) {
       ping->client = acptr;
-      end_ping(ping);
+      uping_end(ping);
     }
   }
   ClearUPing(sptr);
 }
 
+