Annotation of 43BSDTahoe/etc/named/ns_forw.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1986 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted
        !             6:  * provided that the above copyright notice and this paragraph are
        !             7:  * duplicated in all such forms and that any documentation,
        !             8:  * advertising materials, and other materials related to such
        !             9:  * distribution and use acknowledge that the software was developed
        !            10:  * by the University of California, Berkeley.  The name of the
        !            11:  * University may not be used to endorse or promote products derived
        !            12:  * from this software without specific prior written permission.
        !            13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            15:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char sccsid[] = "@(#)ns_forw.c  4.27 (Berkeley) 6/18/88";
        !            20: #endif /* not lint */
        !            21: 
        !            22: #include <stdio.h>
        !            23: #include <sys/param.h>
        !            24: #include <sys/time.h>
        !            25: #include <sys/socket.h>
        !            26: #include <netinet/in.h>
        !            27: #include <syslog.h>
        !            28: #include <arpa/nameser.h>
        !            29: #include "ns.h"
        !            30: #include "db.h"
        !            31: 
        !            32: struct qinfo *qhead = QINFO_NULL;      /* head of allocated queries */
        !            33: struct qinfo *retryqp = QINFO_NULL;    /* list of queries to retry */
        !            34: struct fwdinfo *fwdtab;                /* list of forwarding hosts */
        !            35: 
        !            36: int    nsid;                           /* next forwarded query id */
        !            37: extern int forward_only;               /* you are only a slave */
        !            38: extern int errno;
        !            39: extern short ns_port;
        !            40: 
        !            41: time_t retrytime();
        !            42: 
        !            43: /*
        !            44:  * Forward the query to get the answer since its not in the database.
        !            45:  * Returns FW_OK if a request struct is allocated and the query sent.
        !            46:  * Returns FW_DUP if this is a duplicate of a pending request. 
        !            47:  * Returns FW_NOSERVER if there were no addresses for the nameservers.
        !            48:  * Returns FW_SERVFAIL on malloc error.
        !            49:  * (no action is taken on errors and qpp is not filled in.)
        !            50:  */
        !            51: ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
        !            52:        struct databuf *nsp[];
        !            53:        char *msg;
        !            54:        int msglen;
        !            55:        struct sockaddr_in *fp;
        !            56:        struct qstream *qsp;
        !            57:        int dfd;
        !            58:        struct qinfo **qpp;
        !            59: {
        !            60:        register struct qinfo *qp;
        !            61:        HEADER *hp;
        !            62:        u_short id;
        !            63:        extern char *calloc();
        !            64: 
        !            65: #ifdef DEBUG
        !            66:        if (debug >= 3)
        !            67:                fprintf(ddt,"ns_forw()\n");
        !            68: #endif
        !            69: 
        !            70:        /* Don't forward if we're already working on it. */
        !            71:        hp = (HEADER *) msg;
        !            72:        id = hp->id;
        !            73:        hp->rd = 0;
        !            74:        /* Look at them all */
        !            75:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
        !            76:                if (qp->q_id == id &&
        !            77:                    bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
        !            78:                    (qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
        !            79:                     bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
        !            80:                    (qp->q_cmsglen == msglen &&
        !            81:                     bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0)) {
        !            82: #ifdef DEBUG
        !            83:                        if (debug >= 3)
        !            84:                                fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
        !            85: #endif
        !            86: #ifdef STATS
        !            87:                        stats[S_DUPQUERIES].cnt++;
        !            88: #endif
        !            89:                        return (FW_DUP);
        !            90:                }
        !            91:        }
        !            92: 
        !            93:        qp = qnew();
        !            94:        if (nslookup(nsp, qp) == 0) {
        !            95: #ifdef DEBUG
        !            96:                if (debug >= 2)
        !            97:                        fprintf(ddt,"forw: no nameservers found\n");
        !            98: #endif
        !            99:                qfree(qp);
        !           100:                hp->rd = 1;
        !           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:        if (qp->q_fwd)
        !           113:                hp->rd = 1;
        !           114:        else
        !           115:                qp->q_addr[0].stime = tt;
        !           116:        qp->q_from = *fp;
        !           117:        if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
        !           118:                syslog(LOG_ERR, "forw: %m");
        !           119:                qfree(qp);
        !           120:                return (FW_SERVFAIL);
        !           121:        }
        !           122:        bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
        !           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 = 0;
        !           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 = (u_short)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:        while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
        !           302:                qp1 = qp2;
        !           303:        qp1->q_next = qp;
        !           304:        qp->q_next = qp2;
        !           305: }
        !           306: 
        !           307: /*
        !           308:  * Unsched is called to remove a forwarded query entry.
        !           309:  */
        !           310: unsched(qp)
        !           311:        struct qinfo *qp;
        !           312: {
        !           313:        register struct qinfo *np;
        !           314: 
        !           315: #ifdef DEBUG
        !           316:        if (debug > 3) {
        !           317:                fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
        !           318:        }
        !           319: #endif
        !           320:        if( retryqp == qp )  {
        !           321:                retryqp = qp->q_next;
        !           322:        } else {
        !           323:                for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
        !           324:                        if( np->q_next != qp)
        !           325:                                continue;
        !           326:                        np->q_next = qp->q_next;        /* dequeue */
        !           327:                        break;
        !           328:                }
        !           329:        }
        !           330:        qp->q_next = QINFO_NULL;                /* sanity check */
        !           331:        qp->q_time = 0;
        !           332: }
        !           333: 
        !           334: /*
        !           335:  * Retry is called to retransmit query 'qp'.
        !           336:  */
        !           337: retry(qp)
        !           338:        register struct qinfo *qp;
        !           339: {
        !           340:        register int n;
        !           341:        register HEADER *hp;
        !           342: 
        !           343: #ifdef DEBUG
        !           344:        if (debug > 3)
        !           345:                fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
        !           346: #endif
        !           347:        if((HEADER *)qp->q_msg == NULL) {               /*** XXX ***/
        !           348:                qremove(qp);
        !           349:                return;
        !           350:        }                                               /*** XXX ***/
        !           351: 
        !           352:        /* try next address */
        !           353:        n = qp->q_curaddr;
        !           354:        if (qp->q_fwd) {
        !           355:                qp->q_fwd = qp->q_fwd->next;
        !           356:                if (qp->q_fwd)
        !           357:                        goto found;
        !           358:                /* out of forwarders, try direct queries */
        !           359:        } else
        !           360:                ++qp->q_addr[n].nretry;
        !           361:        if (!forward_only) {
        !           362:                do {
        !           363:                        if (++n >= qp->q_naddr)
        !           364:                                n = 0;
        !           365:                        if (qp->q_addr[n].nretry < MAXRETRY)
        !           366:                                goto found;
        !           367:                } while (n != qp->q_curaddr);
        !           368:        }
        !           369:        /*
        !           370:         * Give up. Can't reach destination.
        !           371:         */
        !           372:        hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
        !           373:        if (qp->q_system == PRIMING_CACHE) {
        !           374:                /* Can't give up priming */
        !           375:                unsched(qp);
        !           376:                schedretry(qp, (time_t)60*60);  /* 1 hour */
        !           377:                hp->rcode = NOERROR;    /* Lets be safe, reset the query */
        !           378:                hp->qr = hp->aa = 0;
        !           379:                qp->q_fwd = fwdtab;
        !           380:                for (n = 0; n < qp->q_naddr; n++)
        !           381:                        qp->q_addr[n].nretry = 0;
        !           382:                return;
        !           383:        }
        !           384: #ifdef DEBUG
        !           385:        if (debug >= 5)
        !           386:                fprintf(ddt,"give up\n");
        !           387: #endif
        !           388:        n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
        !           389:        hp->id = qp->q_id;
        !           390:        hp->qr = 1;
        !           391:        hp->ra = 1;
        !           392:        hp->rd = 1;
        !           393:        hp->rcode = SERVFAIL;
        !           394: #ifdef DEBUG
        !           395:        if (debug >= 10)
        !           396:                fp_query(qp->q_msg, ddt);
        !           397: #endif
        !           398:        if (send_msg((char *)hp, n, qp)) {
        !           399: #ifdef DEBUG
        !           400:                if (debug)
        !           401:                        fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
        !           402:                                qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
        !           403: #endif
        !           404:        }
        !           405:        qremove(qp);
        !           406:        return;
        !           407: 
        !           408: found:
        !           409:        if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
        !           410:                qp->q_addr[n].stime = tt;
        !           411:        qp->q_curaddr = n;
        !           412:        hp = (HEADER *)qp->q_msg;
        !           413:        hp->rd = (qp->q_fwd ? 1 : 0);
        !           414: #ifdef DEBUG
        !           415:        if (debug)
        !           416:                fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
        !           417:                        (qp->q_fwd ? "reforw" : "resend"),
        !           418:                        n, qp->q_addr[n].nretry,
        !           419:                        inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
        !           420:                        ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
        !           421:                        ntohs(qp->q_nsid), ntohs(qp->q_id),
        !           422:                        qp->q_addr[n].nsdata->d_nstime);
        !           423:        if ( debug >= 10)
        !           424:                fp_query(qp->q_msg, ddt);
        !           425: #endif
        !           426:        /* NOSTRICT */
        !           427:        if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
        !           428:            (struct sockaddr *)Q_NEXTADDR(qp,n),
        !           429:            sizeof(struct sockaddr_in)) < 0){
        !           430: #ifdef DEBUG
        !           431:                if (debug > 3)
        !           432:                        fprintf(ddt,"error resending msg errno=%d\n",errno);
        !           433: #endif
        !           434:        }
        !           435:        hp->rd = 0;     /* leave set to 0 for dup detection */
        !           436: #ifdef STATS
        !           437:        stats[S_OUTPKTS].cnt++;
        !           438: #endif
        !           439:        unsched(qp);
        !           440:        schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
        !           441: }
        !           442: 
        !           443: /*
        !           444:  * Compute retry time for the next server for a query.
        !           445:  * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
        !           446:  * service time; * back off exponentially on retries, but place a 45-sec.
        !           447:  * ceiling on retry times for now.  (This is because we don't hold a reference
        !           448:  * on servers or their addresses, and we have to finish before they time out.)
        !           449:  */
        !           450: time_t
        !           451: retrytime(qp)
        !           452: register struct qinfo *qp;
        !           453: {
        !           454:        time_t t;
        !           455:        struct qserv *ns = &qp->q_addr[qp->q_curaddr];
        !           456: 
        !           457: #ifdef DEBUG
        !           458:        if (debug > 3)
        !           459:                fprintf(ddt,"retrytime: nstime %dms.\n",
        !           460:                    ns->nsdata->d_nstime / 1000);
        !           461: #endif
        !           462:        t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
        !           463:        t <<= ns->nretry;
        !           464:        t = MIN(t, 45);                 /* max. retry timeout for now */
        !           465: #ifdef notdef
        !           466:        if (qp->q_system)
        !           467:                return ((2 * t) + 5);   /* system queries can wait. */
        !           468: #endif
        !           469:        return (t);
        !           470: }
        !           471: 
        !           472: qflush()
        !           473: {
        !           474:        while (qhead)
        !           475:                qremove(qhead);
        !           476:        qhead = QINFO_NULL;
        !           477: }
        !           478: 
        !           479: qremove(qp)
        !           480: register struct qinfo *qp;
        !           481: {
        !           482: #ifdef DEBUG
        !           483:        if(debug > 3)
        !           484:                fprintf(ddt,"qremove(x%x)\n", qp);
        !           485: #endif
        !           486:        unsched(qp);                    /* get off queue first */
        !           487:        qfree(qp);
        !           488: }
        !           489: 
        !           490: struct qinfo *
        !           491: qfindid(id)
        !           492: register u_short id;
        !           493: {
        !           494:        register struct qinfo *qp;
        !           495: 
        !           496: #ifdef DEBUG
        !           497:        if(debug > 3)
        !           498:                fprintf(ddt,"qfindid(%d)\n", ntohs(id));
        !           499: #endif
        !           500:        for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
        !           501:                if (qp->q_nsid == id)
        !           502:                        return(qp);
        !           503:        }
        !           504: #ifdef DEBUG
        !           505:        if (debug >= 5)
        !           506:                fprintf(ddt,"qp not found\n");
        !           507: #endif
        !           508:        return(NULL);
        !           509: }
        !           510: 
        !           511: struct qinfo *
        !           512: qnew()
        !           513: {
        !           514:        register struct qinfo *qp;
        !           515: 
        !           516:        if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
        !           517: #ifdef DEBUG
        !           518:                if (debug >= 5)
        !           519:                        fprintf(ddt,"qnew: calloc error\n");
        !           520: #endif
        !           521:                syslog(LOG_ERR, "forw: %m");
        !           522:                exit(12);
        !           523:        }
        !           524: #ifdef DEBUG
        !           525:        if (debug >= 5)
        !           526:                fprintf(ddt,"qnew(x%x)\n", qp);
        !           527: #endif
        !           528:        qp->q_link = qhead;
        !           529:        qhead = qp;
        !           530:        return( qp );
        !           531: }
        !           532: 
        !           533: qfree(qp)
        !           534: struct qinfo *qp;
        !           535: {
        !           536:        register struct qinfo *np;
        !           537: 
        !           538: #ifdef DEBUG
        !           539:        if(debug > 3)
        !           540:                fprintf(ddt,"qfree( x%x )\n", qp);
        !           541:        if(debug && qp->q_next)
        !           542:                fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
        !           543: #endif
        !           544:        if (qp->q_msg)
        !           545:                free(qp->q_msg);
        !           546:        if (qp->q_cmsg)
        !           547:                free(qp->q_cmsg);
        !           548:        if( qhead == qp )  {
        !           549:                qhead = qp->q_link;
        !           550:        } else {
        !           551:                for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
        !           552:                        if( np->q_link != qp )  continue;
        !           553:                        np->q_link = qp->q_link;        /* dequeue */
        !           554:                        break;
        !           555:                }
        !           556:        }
        !           557:        (void)free((char *)qp);
        !           558: }

unix.superglobalmegacorp.com

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