]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Add ntpq pstats command similar to ntpdc's.
authorDave Hart <hart@ntp.org>
Fri, 24 Dec 2010 08:05:27 +0000 (08:05 +0000)
committerDave Hart <hart@ntp.org>
Fri, 24 Dec 2010 08:05:27 +0000 (08:05 +0000)
Remove ntpq pstatus command, rv/readvar does the same and more.

bk: 4d145447bIiibiF8F2EJ-Zq08sn6KA

ChangeLog
include/ntp_control.h
libntp/statestr.c
ntpd/ntp_control.c
ntpdc/ntpdc_ops.c
ntpq/ntpq-subs.c
ntpq/ntpq.c
ntpq/ntpq.h

index c2f9589bf319d06d7a6f221a7273da16e5dd3ff8..4a66bca85142e135e412285edf0148e6ce7632d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+* Add ntpq pstats command similar to ntpdc's.
+* Remove ntpq pstatus command, rv/readvar does the same and more.
 (4.2.7p102) 2010/12/23 Released by Harlan Stenn <stenn@ntp.org>
 * Allow ntpq &1 associd use without preceding association-fetching.
 * Documentation updates from Dave Mills.
index 63e4155a9c8d03134e794aac5fec0b8f8edb49c1..dd02d9bd522becfb20aa95ac3869a09f39ac4769 100644 (file)
@@ -252,7 +252,15 @@ struct ntp_control {
 #define        CP_RATE                 40
 #define        CP_BIAS                 41
 #define        CP_SRCHOST              42
-#define        CP_MAX_NOAUTOKEY        CP_SRCHOST
+#define        CP_TIMEREC              43
+#define        CP_TIMEREACH            44
+#define        CP_BADAUTH              45
+#define        CP_BOGUSORG             46
+#define        CP_OLDPKT               47
+#define        CP_SELDISP              48
+#define        CP_SELBROKEN            49
+#define        CP_CANDIDATE            50
+#define        CP_MAX_NOAUTOKEY        CP_CANDIDATE
 #ifdef AUTOKEY
 #define        CP_FLAGS                (1 + CP_MAX_NOAUTOKEY)
 #define        CP_HOST                 (2 + CP_MAX_NOAUTOKEY)
index 6edc859fbda4f9d8679f7fba995b1f528092c518..0dbf2abc01e066026c08ed31c045cee035965361 100644 (file)
@@ -237,7 +237,8 @@ statustoa(
        LIB_GETBUF(cb);
 
        switch (type) {
-           case TYPE_SYS:
+
+       case TYPE_SYS:
                strcpy(cb, getcode(CTL_SYS_LI(st), leap_codes));
                strcat(cb, ", ");
                strcat(cb, getcode(CTL_SYS_SOURCE(st), sync_codes));
@@ -247,8 +248,7 @@ statustoa(
                strcat(cb, getcode(CTL_SYS_EVENT(st), sys_codes));
                break;
        
-           case TYPE_PEER:
-
+       case TYPE_PEER:
                /*
                 * Handcraft the bits
                 */
@@ -296,7 +296,7 @@ statustoa(
                }
                break;
        
-           case TYPE_CLOCK:
+       case TYPE_CLOCK:
                strcat(cb, ", ");
                strcat(cb, getevents(CTL_SYS_NEVNT(st)));
                strcat(cb, ", ");
index afa989e823383492fca3a8625e8dc1ab4948f86c..9b64ae11d06b5dda246bad8d84aa82f7ec5d2f77 100644 (file)
@@ -248,12 +248,12 @@ static struct ctl_var peer_var[] = {
        { CP_JITTER,    RO, "jitter" },         /* 26 */
        { CP_DISPERSION, RO, "dispersion" },    /* 27 */
        { CP_KEYID,     RO, "keyid" },          /* 28 */
-       { CP_FILTDELAY, RO, "filtdelay=" },     /* 29 */
-       { CP_FILTOFFSET, RO, "filtoffset=" },   /* 30 */
+       { CP_FILTDELAY, RO, "filtdelay" },      /* 29 */
+       { CP_FILTOFFSET, RO, "filtoffset" },    /* 30 */
        { CP_PMODE,     RO, "pmode" },          /* 31 */
        { CP_RECEIVED,  RO, "received"},        /* 32 */
        { CP_SENT,      RO, "sent" },           /* 33 */
-       { CP_FILTERROR, RO, "filtdisp=" },      /* 34 */
+       { CP_FILTERROR, RO, "filtdisp" },       /* 34 */
        { CP_FLASH,     RO, "flash" },          /* 35 */
        { CP_TTL,       RO, "ttl" },            /* 36 */
        { CP_VARLIST,   RO, "peer_var_list" },  /* 37 */
@@ -262,17 +262,25 @@ static struct ctl_var peer_var[] = {
        { CP_RATE,      RO, "headway" },        /* 40 */
        { CP_BIAS,      RO, "bias" },           /* 41 */
        { CP_SRCHOST,   RO, "srchost" },        /* 42 */
+       { CP_TIMEREC,   RO, "timerec" },        /* 43 */
+       { CP_TIMEREACH, RO, "timereach" },      /* 44 */
+       { CP_BADAUTH,   RO, "badauth" },        /* 45 */
+       { CP_BOGUSORG,  RO, "bogusorg" },       /* 46 */
+       { CP_OLDPKT,    RO, "oldpkt" },         /* 47 */
+       { CP_SELDISP,   RO, "seldisp" },        /* 48 */
+       { CP_SELBROKEN, RO, "selbroken" },      /* 49 */
+       { CP_CANDIDATE, RO, "candidate" },      /* 50 */
 #ifdef AUTOKEY
-       { CP_FLAGS,     RO, "flags" },          /* 43 */
-       { CP_HOST,      RO, "host" },           /* 44 */
-       { CP_VALID,     RO, "valid" },          /* 45 */
-       { CP_INITSEQ,   RO, "initsequence" },   /* 46 */
-       { CP_INITKEY,   RO, "initkey" },        /* 47 */
-       { CP_INITTSP,   RO, "timestamp" },      /* 48 */
-       { CP_SIGNATURE, RO, "signature" },      /* 49 */
-       { CP_IDENT,     RO, "ident" },          /* 44 */
+       { CP_FLAGS,     RO, "flags" },          /* 1 + CP_MAX_NOAUTOKEY */
+       { CP_HOST,      RO, "host" },           /* 2 + CP_MAX_NOAUTOKEY */
+       { CP_VALID,     RO, "valid" },          /* 3 + CP_MAX_NOAUTOKEY */
+       { CP_INITSEQ,   RO, "initsequence" },   /* 4 + CP_MAX_NOAUTOKEY */
+       { CP_INITKEY,   RO, "initkey" },        /* 5 + CP_MAX_NOAUTOKEY */
+       { CP_INITTSP,   RO, "timestamp" },      /* 6 + CP_MAX_NOAUTOKEY */
+       { CP_SIGNATURE, RO, "signature" },      /* 7 + CP_MAX_NOAUTOKEY */
+       { CP_IDENT,     RO, "ident" },          /* 8 + CP_MAX_NOAUTOKEY */
 #endif /* AUTOKEY */
-       { 0,            EOV, "" }               /* 44/51 */
+       { 0,            EOV, "" }               /* 50/58 */
 };
 
 
@@ -1380,6 +1388,7 @@ ctl_putarray(
        cq = tag;
        while (*cq != '\0')
                *cp++ = *cq++;
+       *cp++ = '=';
        i = start;
        do {
                if (i == 0)
@@ -1389,7 +1398,7 @@ ctl_putarray(
                snprintf(cp, sizeof(buffer) - (cp - buffer),
                         " %.2f", arr[i] * 1e3);
                cp += strlen(cp);
-       } while(i != start);
+       } while (i != start);
        ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
 }
 
@@ -1928,17 +1937,17 @@ ctl_putpeer(
 
        case CP_FILTDELAY:
                ctl_putarray(peer_var[id].text, p->filter_delay,
-                            (int)p->filter_nextpt);
+                            p->filter_nextpt);
                break;
 
        case CP_FILTOFFSET:
                ctl_putarray(peer_var[id].text, p->filter_offset,
-                            (int)p->filter_nextpt);
+                            p->filter_nextpt);
                break;
 
        case CP_FILTERROR:
                ctl_putarray(peer_var[id].text, p->filter_disp,
-                            (int)p->filter_nextpt);
+                            p->filter_nextpt);
                break;
 
        case CP_PMODE:
@@ -1979,6 +1988,40 @@ ctl_putpeer(
                        ctl_putdata(buf, (u_int)(s - buf), 0);
                }
                break;
+
+       case CP_TIMEREC:
+               ctl_putuint(peer_var[id].text,
+                           current_time - p->timereceived);
+               break;
+
+       case CP_TIMEREACH:
+               ctl_putuint(peer_var[id].text,
+                           current_time - p->timereachable);
+               break;
+
+       case CP_BADAUTH:
+               ctl_putuint(peer_var[id].text, p->badauth);
+               break;
+
+       case CP_BOGUSORG:
+               ctl_putuint(peer_var[id].text, p->bogusorg);
+               break;
+
+       case CP_OLDPKT:
+               ctl_putuint(peer_var[id].text, p->oldpkt);
+               break;
+
+       case CP_SELDISP:
+               ctl_putuint(peer_var[id].text, p->seldisptoolarge);
+               break;
+
+       case CP_SELBROKEN:
+               ctl_putuint(peer_var[id].text, p->selbroken);
+               break;
+
+       case CP_CANDIDATE:
+               ctl_putuint(peer_var[id].text, p->status);
+               break;
 #ifdef AUTOKEY
        case CP_FLAGS:
                if (p->crypto)
index 134f82eca8fc924d6a5bcc0508e82d499442288f..c28928e86424cbc4228a855ee2bd395658fee4e5 100644 (file)
@@ -550,49 +550,56 @@ refid_string(
 
 static void
 print_pflag(
-           FILE *fp,
-           u_int32 flags
-           )
+       FILE *  fp,
+       u_int32 flags
+       )
 {
-     const char *str;
+       static const char none[] = "";
+       static const char comma[] = ",";
+       const char *dlim;
 
-     if (flags == 0) {
-               (void) fprintf(fp, " none\n");
-       } else {
-               str = "";
-               if (flags & INFO_FLAG_SYSPEER) {
-                       (void) fprintf(fp, " system_peer");
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_CONFIG) {
-                       (void) fprintf(fp, "%s config", str);
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_REFCLOCK) {
-                       (void) fprintf(fp, "%s refclock", str);
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_AUTHENABLE) {
-                       (void) fprintf(fp, "%s auth", str);
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_BCLIENT) {
-                       (void) fprintf(fp, "%s bclient", str);
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_PREFER) {
-                       (void) fprintf(fp, "%s prefer", str);
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_IBURST) {
-                       (void) fprintf(fp, "%s iburst", str);
-                       str = ",";
-               }
-               if (flags & INFO_FLAG_BURST) {
-                       (void) fprintf(fp, "%s burst", str);
-               }
-               (void) fprintf(fp, "\n");
+       if (0 == flags) {
+               fprintf(fp, " none\n");
+               return;
+       }
+       dlim = none;
+       if (flags & INFO_FLAG_SYSPEER) {
+               fprintf(fp, " system_peer");
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_CONFIG) {
+               fprintf(fp, "%s config", dlim);
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_REFCLOCK) {
+               fprintf(fp, "%s refclock", dlim);
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_AUTHENABLE) {
+               fprintf(fp, "%s auth", dlim);
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_PREFER) {
+               fprintf(fp, "%s prefer", dlim);
+               dlim = comma;
        }
+       if (flags & INFO_FLAG_IBURST) {
+               fprintf(fp, "%s iburst", dlim);
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_BURST) {
+               fprintf(fp, "%s burst", dlim);
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_SEL_CANDIDATE) {
+               fprintf(fp, "%s candidate", dlim);
+               dlim = comma;
+       }
+       if (flags & INFO_FLAG_PREFER) {
+               fprintf(fp, "%s shortlist", dlim);
+               dlim = comma;
+       }
+       fprintf(fp, "\n");
 }
 /*
  * printpeer - print detail information for a peer
index aa8f9cd5e745f529a97bd73223ac35181544717d..5049f7376e768e67d55b0c0b5f9f3effa420af37 100644 (file)
@@ -51,7 +51,7 @@ static        void    lpassociations  (struct parse *, FILE *);
 static void    radiostatus (struct parse *, FILE *);
 #endif /* UNUSED */
 
-static void    pstatus         (struct parse *, FILE *);
+static void    pstat         (struct parse *, FILE *);
 static long    when            (l_fp *, l_fp *, l_fp *);
 static char *  prettyinterval  (char *, size_t, long);
 static int     doprintpeers    (struct varlist *, int, int, int, const char *, FILE *, int);
@@ -143,7 +143,7 @@ struct xcmd opcmds[] = {
        { "cv",     clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
          { "assocID", "name=value[,...]", "", "" },
          "read clock variables" },
-       { "pstatus",    pstatus,    { NTP_UINT, NO, NO, NO },
+       { "pstats",    pstats,    { NTP_UINT, NO, NO, NO },
          { "assocID", "", "", "" },
          "print status information returned for a peer" },
        { "peers",  peers,      { OPT|IP_VERSION, NO, NO, NO },
@@ -292,7 +292,8 @@ typedef struct var_display_collection_tag {
        const char * const display;     /* descriptive text */
        u_char type;                    /* NTP_STR, etc */
        union {
-               char *str;
+               char *          str;
+               sockaddr_u      sau;    /* NTP_ADD */
        } v;                            /* retrieved value */
 } vdc;
 
@@ -310,7 +311,7 @@ static int  qcmp_mru_count(const void *, const void *);
 static int     qcmp_mru_r_count(const void *, const void *);
 static void    validate_ifnum(u_int, int, ifstats_row *);
 static void    another_ifstats_field(int *, ifstats_row *, FILE *);
-static void    collect_display_vdc(vdc *vdc_table, FILE *fp);
+static void    collect_display_vdc(associd_t as, vdc *table, FILE *fp);
 
 /*
  * static globals
@@ -667,7 +668,7 @@ dolist(
        }
 
        if (!quiet)
-               fprintf(fp,"associd=%d ",associd);
+               fprintf(fp, "associd=%u ", associd);
        printvars(dsize, datap, (int)rstatus, type, quiet, fp);
        return 1;
 }
@@ -738,7 +739,7 @@ writelist(
        if (dsize == 0)
                (void) fprintf(fp, "done! (no data returned)\n");
        else {
-               (void) fprintf(fp,"associd=%d ",associd);
+               (void) fprintf(fp,"associd=%u ", associd);
                printvars(dsize, datap, (int)rstatus,
                          (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
        }
@@ -823,7 +824,7 @@ writevar(
        if (dsize == 0)
                fprintf(fp, "done! (no data returned)\n");
        else {
-               fprintf(fp,"associd=%d ",associd);
+               fprintf(fp,"associd=%u ", associd);
                type = (0 == associd)
                           ? TYPE_SYS
                           : TYPE_PEER;
@@ -1374,45 +1375,6 @@ radiostatus(
 }
 #endif /* UNUSED */
 
-/*
- * pstatus - print peer status returned by the server
- */
-static void
-pstatus(
-       struct parse *pcmd,
-       FILE *fp
-       )
-{
-       const char *datap;
-       int res;
-       associd_t associd;
-       int dsize;
-       u_short rstatus;
-
-       /* HMS: uval? */
-       if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
-               return;
-
-       res = doquery(CTL_OP_READSTAT, associd, 0, 0, NULL, &rstatus,
-                     &dsize, &datap);
-
-       if (res != 0)
-               return;
-
-       if (numhosts > 1)
-               fprintf(fp, "server=%s ", currenthost);
-       if (dsize == 0) {
-               fprintf(fp,
-                       "No information returned for association %u\n",
-                       associd);
-               return;
-       }
-
-       fprintf(fp, "associd=%u ", associd);
-       printvars(dsize, datap, (int)rstatus, TYPE_PEER, 0, fp);
-}
-
-
 /*
  * when - print how long its been since his last packet arrived
  */
@@ -3240,11 +3202,14 @@ ifstats(
  */
 static void 
 collect_display_vdc(
-       vdc *vdc_table,
-       FILE *fp
+       associd_t       as,
+       vdc *           table,
+       FILE *          fp
        )
 {
+       static const char * const suf[2] = { "adr", "port" };
        struct varlist vl[MAXLIST];
+       char tagbuf[32];
        vdc *pvdc;
        u_short rstatus;
        int rsize;
@@ -3252,14 +3217,26 @@ collect_display_vdc(
        int qres;
        char *tag;
        char *val;
+       u_int n;
+       size_t taglen;
+       int match;
+       u_long ul;
 
        memset(vl, 0, sizeof(vl));
-       for (pvdc = vdc_table; pvdc->tag != NULL; pvdc++) {
+       for (pvdc = table; pvdc->tag != NULL; pvdc++) {
                memset(&pvdc->v, 0, sizeof(pvdc->v));
-               doaddvlist(vl, pvdc->tag);
+               if (NTP_ADD != pvdc->type) {
+                       doaddvlist(vl, pvdc->tag);
+               } else {
+                       for (n = 0; n < COUNTOF(suf); n++) {
+                               snprintf(tagbuf, sizeof(tagbuf), "%s%s",
+                                        pvdc->tag, suf[n]);
+                               doaddvlist(vl, tagbuf);
+                       }
+               }
        }
-       qres = doquerylist(vl, CTL_OP_READVAR, 0, 0, &rstatus, &rsize,
-                         &rdata);
+       qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize,
+                          &rdata);
        doclearvlist(vl);
        if (qres)
                return;         /* error msg already displayed */
@@ -3269,21 +3246,66 @@ collect_display_vdc(
         * the retrieved values.
         */
        while (nextvar(&rsize, &rdata, &tag, &val)) {
-               for (pvdc = vdc_table; pvdc->tag != NULL; pvdc++)
-                       if (!strcmp(tag, pvdc->tag))
+               for (pvdc = table; pvdc->tag != NULL; pvdc++) {
+                       taglen = strlen(pvdc->tag);
+                       if (strncmp(tag, pvdc->tag, taglen))
+                               continue;
+                       if (NTP_ADD != pvdc->type) {
+                               if ('\0' != tag[taglen])
+                                       continue;
                                break;
-               if (pvdc->tag != NULL) {
-                       NTP_INSIST(NTP_STR == pvdc->type);
+                       }
+                       match = FALSE;
+                       for (n = 0; n < COUNTOF(suf); n++) {
+                               if (strcmp(tag + taglen, suf[n]))
+                                       continue;
+                               match = TRUE;
+                               break;
+                       }
+                       if (match)
+                               break;
+               }
+               if (NULL == pvdc->tag)
+                       continue;
+               if (NTP_STR == pvdc->type) {
                        pvdc->v.str = estrdup(val);
+               } else if (NTP_ADD == pvdc->type) {
+                       if (0 == n) {   /* adr */
+                               decodenetnum(val, &pvdc->v.sau);
+                       } else {        /* port */
+                               if (atouint(val, &ul))
+                                       SET_PORT(&pvdc->v.sau, 
+                                                (u_short)ul);
+                       }
                }
        }
 
        /* and display */
-       for (pvdc = vdc_table; pvdc->tag != NULL; pvdc++) {
-               if (pvdc->v.str != NULL) {
+       if (as != 0)
+               fprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus,
+                       statustoa(TYPE_PEER, rstatus));
+
+       for (pvdc = table; pvdc->tag != NULL; pvdc++) {
+               switch (pvdc->type) {
+
+               case NTP_STR:
+                       if (pvdc->v.str != NULL) {
+                               fprintf(fp, "%s  %s\n", pvdc->display,
+                                       pvdc->v.str);
+                               free(pvdc->v.str);
+                               pvdc->v.str = NULL;
+                       }
+                       break;
+
+               case NTP_ADD:
                        fprintf(fp, "%s  %s\n", pvdc->display,
-                               pvdc->v.str);
-                       free(pvdc->v.str);
+                               nntohostp(&pvdc->v.sau));
+                       break;
+
+               default:
+                       fprintf(stderr, "unexpected vdc type %d for %s\n",
+                               pvdc->type, pvdc->tag);
+                       break;
                }
        }
 }
@@ -3314,7 +3336,7 @@ sysstats(
        { NULL,                 NULL,                     0       }
     };
 
-       collect_display_vdc(sysstats_vdc, fp);
+       collect_display_vdc(0, sysstats_vdc, fp);
 }
 
        
@@ -3339,5 +3361,41 @@ monstats(
        { NULL,                 NULL,                    0       }
     };
 
-       collect_display_vdc(monstats_vdc, fp);
+       collect_display_vdc(0, monstats_vdc, fp);
 }
+
+
+/*
+ * pstats - print peer statistics returned by the server
+ */
+static void
+pstats(
+       struct parse *pcmd,
+       FILE *fp
+       )
+{
+    static vdc pstats_vdc[] = {
+       { "src",                "remote host:         ", NTP_ADD },
+       { "dst",                "local address:       ", NTP_ADD },
+       { "timerec",            "time last received:  ", NTP_STR },
+       { "timer",              "time until next send:", NTP_STR },
+       { "timereach",          "reachability change: ", NTP_STR },
+       { "sent",               "packets sent:        ", NTP_STR },
+       { "received",           "packets received:    ", NTP_STR },
+       { "badauth",            "bad authentication:  ", NTP_STR },
+       { "bogusorg",           "bogus origin:        ", NTP_STR },
+       { "oldpkt",             "duplicate:           ", NTP_STR },
+       { "seldisp",            "bad dispersion:      ", NTP_STR },
+       { "selbroken",          "bad reference time:  ", NTP_STR },
+       { "candidate",          "candidate order:     ", NTP_STR },
+       { NULL,                 NULL,                    0       }
+    };
+       associd_t associd;
+
+       associd = checkassocid(pcmd->argval[0].uval);
+       if (0 == associd)
+               return;
+
+       collect_display_vdc(associd, pstats_vdc, fp);
+}
+
index bab61722f5132f451ccc9b89b1fbdf88764aa5f7..6c1eebfaa96e72d692684588337bd8a745e26a59 100644 (file)
@@ -26,6 +26,7 @@
 #include "ntp_calendar.h"
 #include "ntp_select.h"
 #include "ntp_assert.h"
+#include "lib_strbuf.h"
 #include "ntp_lineedit.h"
 #include "ntp_debug.h"
 #ifdef OPENSSL
@@ -1840,6 +1841,29 @@ nntohost(
 }
 
 
+/*
+ * nntohostp() is the same as nntohost() plus a :port suffix
+ */
+char *
+nntohostp(
+       sockaddr_u *netnum
+       )
+{
+       const char *    hostn;
+       char *          buf;
+
+       if (!showhostnames || SOCK_UNSPEC(netnum))
+               return sptoa(netnum);
+       else if (ISREFCLOCKADR(netnum))
+               return refnumtoa(netnum);
+       
+       hostn = socktohost(netnum);
+       LIB_GETBUF(buf);
+       snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
+
+       return buf;
+}
+
 /*
  * rtdatetolfp - decode an RT-11 date into an l_fp
  */
index f3afecac53e4fbd90610ac93d0fad5abcb389709..93b0e10abbf9d6710b63cadbb0db9aa50831c813 100644 (file)
@@ -125,6 +125,7 @@ extern      int     doquery         (int, associd_t, int, int, const char *,
 extern int     doqueryex       (int, associd_t, int, int, const char *,
                                 u_short *, int *, const char **, int);
 extern char *  nntohost        (sockaddr_u *);
+extern char *  nntohostp       (sockaddr_u *);
 extern int     decodets        (char *, l_fp *);
 extern int     decodeuint      (char *, u_long *);
 extern int     nextvar         (int *, const char **, char **, char **);