Annotation of 43BSDReno/usr.sbin/named/ns_forw.c, revision 1.1

1.1     ! root        1: /*-
        !             2:  * Copyright (c) 1986 The Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted provided
        !             6:  * that: (1) source distributions retain this entire copyright notice and
        !             7:  * comment, and (2) distributions including binaries display the following
        !             8:  * acknowledgement:  ``This product includes software developed by the
        !             9:  * University of California, Berkeley and its contributors'' in the
        !            10:  * documentation or other materials provided with the distribution and in
        !            11:  * all advertising materials mentioning features or use of this software.
        !            12:  * Neither the name of the University nor the names of its contributors may
        !            13:  * be used to endorse or promote products derived from this software without
        !            14:  * specific prior written permission.
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            18:  */
        !            19: 
        !            20: #ifndef lint
        !            21: static char sccsid[] = "@(#)ns_forw.c  4.30 (Berkeley) 6/27/90";
        !            22: #endif /* not lint */
        !            23: 
        !            24: #include <sys/param.h>
        !            25: #include <sys/time.h>
        !            26: #include <sys/socket.h>
        !            27: #include <netinet/in.h>
        !            28: #include <syslog.h>
        !            29: #include <arpa/nameser.h>
        !            30: #include <stdio.h>
        !            31: #include "ns.h"
        !            32: #include "db.h"
        !            33: 
        !            34: struct qinfo *qhead = QINFO_NULL;      /* head of allocated queries */
        !            35: struct qinfo *retryqp = QINFO_NULL;    /* list of queries to retry */
        !            36: struct fwdinfo *fwdtab;                /* list of forwarding hosts */
        !            37: 
        !            38: int    nsid;                           /* next forwarded query id */
        !            39: extern int forward_only;               /* you are only a slave */
        !            40: extern int errno;
        !            41: extern u_short ns_port;
        !            42: 
        !            43: time_t retrytime();
        !            44: 
        !            45: /*
        !            46:  * Forward the query to get the answer since its not in the database.
        !            47:  * Returns FW_OK if a request struct is allocated and the query sent.
        !            48:  * Returns FW_DUP if this is a duplicate of a pending request. 
        !            49:  * Returns FW_NOSERVER if there were no addresses for the nameservers.
        !            50:  * Returns FW_SERVFAIL on malloc error.
        !            51:  * (no action is taken on errors and qpp is not filled in.)
        !            52:  */
        !            53: ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
        !            54:        struct databuf *nsp[];
        !            55:        char *msg;
        !            56:        int msglen;
        !            57:        struct sockaddr_in *fp;
        !            58:        struct qstream *qsp;
        !            59:        int dfd;
        !            60:        struct qinfo **qpp;
        !            61: {
        !            62:        register struct qinfo *qp;
        !            63:        HEADER *hp;
        !            64:        u_short id;
        !            65:        extern char *calloc();
        !            66: 
        !            67: #ifdef DEBUG
        !            68:        if (debug >= 3)
        !            69:                fprintf(ddt,"ns_forw()\n");
        !            70: #endif
        !            71: 
        !            72:        /* Don't forward if we're already working on it. */
        !            73:        hp = (HEADER *) msg;
        !            74:        id = hp->id;
        !            75:        /* Look at them all */
        !            76:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
        !            77:                if (qp->q_id == id &&
        !            78:                    bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
        !            79:                    ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
        !            80:                     bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
        !            81:                    (qp->q_cmsglen == msglen &&
        !            82:                     bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
        !            83: #ifdef DEBUG
        !            84:                        if (debug >= 3)
        !            85:                                fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
        !            86: #endif
        !            87: #ifdef STATS
        !            88:                        stats[S_DUPQUERIES].cnt++;
        !            89: #endif
        !            90:                        return (FW_DUP);
        !            91:                }
        !            92:        }
        !            93: 
        !            94:        qp = qnew();
        !            95:        if (nslookup(nsp, qp) == 0) {
        !            96: #ifdef DEBUG
        !            97:                if (debug >= 2)
        !            98:                        fprintf(ddt,"forw: no nameservers found\n");
        !            99: #endif
        !           100:                qfree(qp);
        !           101:                return (FW_NOSERVER);
        !           102:        }
        !           103:        qp->q_stream = qsp;
        !           104:        qp->q_curaddr = 0;
        !           105:        qp->q_fwd = fwdtab;
        !           106:        qp->q_dfd = dfd;
        !           107:        qp->q_id = id;
        !           108:        hp->id = qp->q_nsid = htons((u_short)++nsid);
        !           109:        hp->ancount = 0;
        !           110:        hp->nscount = 0;
        !           111:        hp->arcount = 0;
        !           112:        qp->q_from = *fp;
        !           113:        if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
        !           114:                syslog(LOG_ERR, "forw: %m");
        !           115:                qfree(qp);
        !           116:                return (FW_SERVFAIL);
        !           117:        }
        !           118:        bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
        !           119:        if (!qp->q_fwd) {
        !           120:                hp->rd = 0;
        !           121:                qp->q_addr[0].stime = tt;
        !           122:        }
        !           123: 
        !           124:        schedretry(qp, retrytime(qp));
        !           125: #ifdef DEBUG
        !           126:        if (debug)
        !           127:                fprintf(ddt,
        !           128:                   "forw: forw -> %s %d (%d) nsid=%d id=%d %dms retry %d sec\n",
        !           129:                        inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
        !           130:                        ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
        !           131:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
        !           132:                        qp->q_addr[0].nsdata->d_nstime,
        !           133:                        qp->q_time - tt.tv_sec);
        !           134:        if ( debug >= 10)
        !           135:                fp_query(msg, ddt);
        !           136: #endif
        !           137:        if (sendto(ds, msg, msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0),
        !           138:                   sizeof(struct sockaddr_in)) < 0){
        !           139: #ifdef DEBUG
        !           140:                if (debug >= 5)
        !           141:                        fprintf(ddt,"error returning msg errno=%d\n",errno);
        !           142: #endif
        !           143:        }
        !           144: #ifdef STATS
        !           145:        stats[S_OUTPKTS].cnt++;
        !           146: #endif
        !           147:        if (qpp)
        !           148:                *qpp = qp;
        !           149:        hp->rd = 1;
        !           150:        return (0);
        !           151: }
        !           152: 
        !           153: /*
        !           154:  * Lookup the address for each nameserver in `nsp' and add it to
        !           155:  * the list saved in the qinfo structure.
        !           156:  */
        !           157: nslookup(nsp, qp)
        !           158:        struct databuf *nsp[];
        !           159:        register struct qinfo *qp;
        !           160: {
        !           161:        register struct namebuf *np;
        !           162:        register struct databuf *dp, *nsdp;
        !           163:        register struct qserv *qs;
        !           164:        register int n, i;
        !           165:        struct hashbuf *tmphtp;
        !           166:        char *dname, *fname;
        !           167:        int oldn, naddr, class, found_arr;
        !           168:        time_t curtime;
        !           169:        int qcomp();
        !           170: 
        !           171: #ifdef DEBUG
        !           172:        if (debug >= 3)
        !           173:                fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp);
        !           174: #endif
        !           175: 
        !           176:        naddr = n = qp->q_naddr;
        !           177:        curtime = (u_long) tt.tv_sec;
        !           178:        while ((nsdp = *nsp++) != NULL) {
        !           179:                class = nsdp->d_class;
        !           180:                dname = nsdp->d_data;
        !           181: #ifdef DEBUG
        !           182:                if (debug >= 3)
        !           183:                        fprintf(ddt,"nslookup: NS %s c%d t%d (x%x)\n",
        !           184:                                dname, class, nsdp->d_type, nsdp->d_flags);
        !           185: #endif
        !           186:                /* don't put in people we have tried */
        !           187:                for (i = 0; i < qp->q_nusedns; i++)
        !           188:                        if (qp->q_usedns[i] == nsdp) {
        !           189: #ifdef DEBUG
        !           190:                                if (debug >= 2)
        !           191: fprintf(ddt, "skipping used NS w/name %s\n", nsdp->d_data);
        !           192: #endif DEBUG
        !           193:                                goto skipserver;
        !           194:                        }
        !           195: 
        !           196:                tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
        !           197:                np = nlookup(dname, &tmphtp, &fname, 1);
        !           198:                if (np == NULL || fname != dname) {
        !           199: #ifdef DEBUG
        !           200:                        if (debug >= 3)
        !           201:                            fprintf(ddt,"%s: not found %s %x\n",dname,fname,np);
        !           202: #endif
        !           203:                        continue;
        !           204:                }
        !           205:                found_arr = 0;
        !           206:                oldn = n;
        !           207:                /* look for name server addresses */
        !           208:                for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
        !           209:                        if (dp->d_type != T_A || dp->d_class != class)
        !           210:                                continue;
        !           211:                        /*
        !           212:                         * Don't use records that may become invalid to
        !           213:                         * reference later when we do the rtt computation.
        !           214:                         * Never delete our safety-belt information!
        !           215:                         */
        !           216:                        if ((dp->d_zone == 0) &&
        !           217:                            (dp->d_ttl < (curtime+900)) &&
        !           218:                            !(dp->d_flags & DB_F_HINT) )
        !           219:                        {
        !           220: #ifdef DEBUG
        !           221:                                if (debug >= 3)
        !           222:                                        fprintf(ddt,"nslookup: stale entry '%s'\n",
        !           223:                                            np->n_dname);
        !           224: #endif
        !           225:                                /* Cache invalidate the NS RR's */
        !           226:                                if (dp->d_ttl < curtime)
        !           227:                                        delete_all(np, class, T_A);
        !           228:                                n = oldn;
        !           229:                                break;
        !           230:                        }
        !           231: 
        !           232:                        found_arr++;
        !           233:                        /* don't put in duplicates */
        !           234:                        qs = qp->q_addr;
        !           235:                        for (i = 0; i < n; i++, qs++)
        !           236:                                if (bcmp((char *)&qs->ns_addr.sin_addr,
        !           237:                                    dp->d_data, sizeof(struct in_addr)) == 0)
        !           238:                                        goto skipaddr;
        !           239:                        qs->ns_addr.sin_family = AF_INET;
        !           240:                        qs->ns_addr.sin_port = ns_port;
        !           241:                        qs->ns_addr.sin_addr = 
        !           242:                                    *(struct in_addr *)dp->d_data;
        !           243:                        qs->ns = nsdp;
        !           244:                        qs->nsdata = dp;
        !           245:                        qp->q_addr[n].nretry = 0;
        !           246:                        n++;
        !           247:                        if (n >= NSMAX)
        !           248:                                goto out;
        !           249:        skipaddr:       ;
        !           250:                }
        !           251: #ifdef DEBUG
        !           252:                if (debug >= 3)
        !           253:                        fprintf(ddt,"nslookup: %d ns addrs\n", n);
        !           254: #endif
        !           255:                if (found_arr == 0 && qp->q_system == 0)
        !           256:                        (void) sysquery(dname, class, T_A);
        !           257: skipserver:    ;
        !           258:        }
        !           259: out:
        !           260: #ifdef DEBUG
        !           261:        if (debug >= 3)
        !           262:                fprintf(ddt,"nslookup: %d ns addrs total\n", n);
        !           263: #endif
        !           264:        qp->q_naddr = n;
        !           265:        if (n > 1)
        !           266:                qsort((char *)qp->q_addr, n, sizeof(struct qserv), qcomp);
        !           267:        return (n - naddr);
        !           268: }
        !           269: 
        !           270: qcomp(qs1, qs2)
        !           271:        struct qserv *qs1, *qs2;
        !           272: {
        !           273: 
        !           274:        return (qs1->nsdata->d_nstime - qs2->nsdata->d_nstime);
        !           275: }
        !           276: 
        !           277: /*
        !           278:  * Arrange that forwarded query (qp) is retried after t seconds.
        !           279:  */
        !           280: schedretry(qp, t)
        !           281:        struct qinfo *qp;
        !           282:        time_t t;
        !           283: {
        !           284:        register struct qinfo *qp1, *qp2;
        !           285: 
        !           286: #ifdef DEBUG
        !           287:        if (debug > 3) {
        !           288:                fprintf(ddt,"schedretry(%#x, %dsec)\n", qp, t);
        !           289:                if (qp->q_time)
        !           290:                   fprintf(ddt,"WARNING: schedretry(%x,%d) q_time already %d\n", qp->q_time);
        !           291:        }
        !           292: #endif
        !           293:        t += (u_long) tt.tv_sec;
        !           294:        qp->q_time = t;
        !           295: 
        !           296:        if ((qp1 = retryqp) == NULL) {
        !           297:                retryqp = qp;
        !           298:                qp->q_next = NULL;
        !           299:                return;
        !           300:        }
        !           301:        if (t < qp1->q_time) {
        !           302:                qp->q_next = qp1;
        !           303:                retryqp = qp;
        !           304:                return;
        !           305:        }
        !           306:        while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
        !           307:                qp1 = qp2;
        !           308:        qp1->q_next = qp;
        !           309:        qp->q_next = qp2;
        !           310: }
        !           311: 
        !           312: /*
        !           313:  * Unsched is called to remove a forwarded query entry.
        !           314:  */
        !           315: unsched(qp)
        !           316:        struct qinfo *qp;
        !           317: {
        !           318:        register struct qinfo *np;
        !           319: 
        !           320: #ifdef DEBUG
        !           321:        if (debug > 3) {
        !           322:                fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
        !           323:        }
        !           324: #endif
        !           325:        if( retryqp == qp )  {
        !           326:                retryqp = qp->q_next;
        !           327:        } else {
        !           328:                for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
        !           329:                        if( np->q_next != qp)
        !           330:                                continue;
        !           331:                        np->q_next = qp->q_next;        /* dequeue */
        !           332:                        break;
        !           333:                }
        !           334:        }
        !           335:        qp->q_next = QINFO_NULL;                /* sanity check */
        !           336:        qp->q_time = 0;
        !           337: }
        !           338: 
        !           339: /*
        !           340:  * Retry is called to retransmit query 'qp'.
        !           341:  */
        !           342: retry(qp)
        !           343:        register struct qinfo *qp;
        !           344: {
        !           345:        register int n;
        !           346:        register HEADER *hp;
        !           347: 
        !           348: #ifdef DEBUG
        !           349:        if (debug > 3)
        !           350:                fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
        !           351: #endif
        !           352:        if((HEADER *)qp->q_msg == NULL) {               /*** XXX ***/
        !           353:                qremove(qp);
        !           354:                return;
        !           355:        }                                               /*** XXX ***/
        !           356: 
        !           357:        /* try next address */
        !           358:        n = qp->q_curaddr;
        !           359:        if (qp->q_fwd) {
        !           360:                qp->q_fwd = qp->q_fwd->next;
        !           361:                if (qp->q_fwd)
        !           362:                        goto found;
        !           363:                /* out of forwarders, try direct queries */
        !           364:        } else
        !           365:                ++qp->q_addr[n].nretry;
        !           366:        if (!forward_only) {
        !           367:                do {
        !           368:                        if (++n >= qp->q_naddr)
        !           369:                                n = 0;
        !           370:                        if (qp->q_addr[n].nretry < MAXRETRY)
        !           371:                                goto found;
        !           372:                } while (n != qp->q_curaddr);
        !           373:        }
        !           374:        /*
        !           375:         * Give up. Can't reach destination.
        !           376:         */
        !           377:        hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
        !           378:        if (qp->q_system == PRIMING_CACHE) {
        !           379:                /* Can't give up priming */
        !           380:                unsched(qp);
        !           381:                schedretry(qp, (time_t)60*60);  /* 1 hour */
        !           382:                hp->rcode = NOERROR;    /* Lets be safe, reset the query */
        !           383:                hp->qr = hp->aa = 0;
        !           384:                qp->q_fwd = fwdtab;
        !           385:                for (n = 0; n < qp->q_naddr; n++)
        !           386:                        qp->q_addr[n].nretry = 0;
        !           387:                return;
        !           388:        }
        !           389: #ifdef DEBUG
        !           390:        if (debug >= 5)
        !           391:                fprintf(ddt,"give up\n");
        !           392: #endif
        !           393:        n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
        !           394:        hp->id = qp->q_id;
        !           395:        hp->qr = 1;
        !           396:        hp->ra = 1;
        !           397:        hp->rd = 1;
        !           398:        hp->rcode = SERVFAIL;
        !           399: #ifdef DEBUG
        !           400:        if (debug >= 10)
        !           401:                fp_query(qp->q_msg, ddt);
        !           402: #endif
        !           403:        if (send_msg((char *)hp, n, qp)) {
        !           404: #ifdef DEBUG
        !           405:                if (debug)
        !           406:                        fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
        !           407:                                qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
        !           408: #endif
        !           409:        }
        !           410:        qremove(qp);
        !           411:        return;
        !           412: 
        !           413: found:
        !           414:        if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
        !           415:                qp->q_addr[n].stime = tt;
        !           416:        qp->q_curaddr = n;
        !           417:        hp = (HEADER *)qp->q_msg;
        !           418:        hp->rd = (qp->q_fwd ? 1 : 0);
        !           419: #ifdef DEBUG
        !           420:        if (debug)
        !           421:                fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
        !           422:                        (qp->q_fwd ? "reforw" : "resend"),
        !           423:                        n, qp->q_addr[n].nretry,
        !           424:                        inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
        !           425:                        ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
        !           426:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
        !           427:                        qp->q_addr[n].nsdata->d_nstime);
        !           428:        if ( debug >= 10)
        !           429:                fp_query(qp->q_msg, ddt);
        !           430: #endif
        !           431:        /* NOSTRICT */
        !           432:        if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
        !           433:            (struct sockaddr *)Q_NEXTADDR(qp,n),
        !           434:            sizeof(struct sockaddr_in)) < 0){
        !           435: #ifdef DEBUG
        !           436:                if (debug > 3)
        !           437:                        fprintf(ddt,"error resending msg errno=%d\n",errno);
        !           438: #endif
        !           439:        }
        !           440:        hp->rd = 1;     /* leave set to 1 for dup detection */
        !           441: #ifdef STATS
        !           442:        stats[S_OUTPKTS].cnt++;
        !           443: #endif
        !           444:        unsched(qp);
        !           445:        schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
        !           446: }
        !           447: 
        !           448: /*
        !           449:  * Compute retry time for the next server for a query.
        !           450:  * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
        !           451:  * service time; * back off exponentially on retries, but place a 45-sec.
        !           452:  * ceiling on retry times for now.  (This is because we don't hold a reference
        !           453:  * on servers or their addresses, and we have to finish before they time out.)
        !           454:  */
        !           455: time_t
        !           456: retrytime(qp)
        !           457: register struct qinfo *qp;
        !           458: {
        !           459:        time_t t;
        !           460:        struct qserv *ns = &qp->q_addr[qp->q_curaddr];
        !           461: 
        !           462: #ifdef DEBUG
        !           463:        if (debug > 3)
        !           464:                fprintf(ddt,"retrytime: nstime %dms.\n",
        !           465:                    ns->nsdata->d_nstime / 1000);
        !           466: #endif
        !           467:        t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
        !           468:        t <<= ns->nretry;
        !           469:        t = MIN(t, 45);                 /* max. retry timeout for now */
        !           470: #ifdef notdef
        !           471:        if (qp->q_system)
        !           472:                return ((2 * t) + 5);   /* system queries can wait. */
        !           473: #endif
        !           474:        return (t);
        !           475: }
        !           476: 
        !           477: qflush()
        !           478: {
        !           479:        while (qhead)
        !           480:                qremove(qhead);
        !           481:        qhead = QINFO_NULL;
        !           482: }
        !           483: 
        !           484: qremove(qp)
        !           485: register struct qinfo *qp;
        !           486: {
        !           487: #ifdef DEBUG
        !           488:        if(debug > 3)
        !           489:                fprintf(ddt,"qremove(x%x)\n", qp);
        !           490: #endif
        !           491:        unsched(qp);                    /* get off queue first */
        !           492:        qfree(qp);
        !           493: }
        !           494: 
        !           495: struct qinfo *
        !           496: qfindid(id)
        !           497: register u_short id;
        !           498: {
        !           499:        register struct qinfo *qp;
        !           500: 
        !           501: #ifdef DEBUG
        !           502:        if(debug > 3)
        !           503:                fprintf(ddt,"qfindid(%d)\n", ntohs(id));
        !           504: #endif
        !           505:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
        !           506:                if (qp->q_nsid == id)
        !           507:                        return(qp);
        !           508:        }
        !           509: #ifdef DEBUG
        !           510:        if (debug >= 5)
        !           511:                fprintf(ddt,"qp not found\n");
        !           512: #endif
        !           513:        return(NULL);
        !           514: }
        !           515: 
        !           516: struct qinfo *
        !           517: qnew()
        !           518: {
        !           519:        register struct qinfo *qp;
        !           520: 
        !           521:        if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
        !           522: #ifdef DEBUG
        !           523:                if (debug >= 5)
        !           524:                        fprintf(ddt,"qnew: calloc error\n");
        !           525: #endif
        !           526:                syslog(LOG_ERR, "forw: %m");
        !           527:                exit(12);
        !           528:        }
        !           529: #ifdef DEBUG
        !           530:        if (debug >= 5)
        !           531:                fprintf(ddt,"qnew(x%x)\n", qp);
        !           532: #endif
        !           533:        qp->q_link = qhead;
        !           534:        qhead = qp;
        !           535:        return( qp );
        !           536: }
        !           537: 
        !           538: qfree(qp)
        !           539: struct qinfo *qp;
        !           540: {
        !           541:        register struct qinfo *np;
        !           542: 
        !           543: #ifdef DEBUG
        !           544:        if(debug > 3)
        !           545:                fprintf(ddt,"qfree( x%x )\n", qp);
        !           546:        if(debug && qp->q_next)
        !           547:                fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
        !           548: #endif
        !           549:        if (qp->q_msg)
        !           550:                free(qp->q_msg);
        !           551:        if (qp->q_cmsg)
        !           552:                free(qp->q_cmsg);
        !           553:        if( qhead == qp )  {
        !           554:                qhead = qp->q_link;
        !           555:        } else {
        !           556:                for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
        !           557:                        if( np->q_link != qp )  continue;
        !           558:                        np->q_link = qp->q_link;        /* dequeue */
        !           559:                        break;
        !           560:                }
        !           561:        }
        !           562:        (void)free((char *)qp);
        !           563: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.