Annotation of embedaddon/miniupnpd/upnpevents.c, revision 1.1.1.3

1.1.1.3 ! misho       1: /* $Id: upnpevents.c,v 1.26 2012/10/04 22:11:56 nanard Exp $ */
1.1       misho       2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.3 ! misho       4:  * (c) 2008-2012 Thomas Bernard
1.1       misho       5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: #include <stdio.h>
                      9: #include <string.h>
                     10: #include <syslog.h>
                     11: #include <sys/queue.h>
                     12: #include <stdlib.h>
                     13: #include <unistd.h>
                     14: #include <time.h>
                     15: #include <sys/types.h>
                     16: #include <sys/socket.h>
                     17: #include <netinet/in.h>
                     18: #include <arpa/inet.h>
                     19: #include <errno.h>
                     20: #include "config.h"
                     21: #include "upnpevents.h"
                     22: #include "miniupnpdpath.h"
                     23: #include "upnpglobalvars.h"
                     24: #include "upnpdescgen.h"
1.1.1.3 ! misho      25: #include "upnputils.h"
1.1       misho      26: 
                     27: #ifdef ENABLE_EVENTS
                     28: /*enum subscriber_service_enum {
                     29:  EWanCFG = 1,
                     30:  EWanIPC,
                     31:  EL3F
                     32: };*/
                     33: 
                     34: /* stuctures definitions */
                     35: struct subscriber {
                     36:        LIST_ENTRY(subscriber) entries;
                     37:        struct upnp_event_notify * notify;
                     38:        time_t timeout;
                     39:        uint32_t seq;
                     40:        enum subscriber_service_enum service;
                     41:        char uuid[42];
                     42:        char callback[];
                     43: };
                     44: 
                     45: struct upnp_event_notify {
                     46:        LIST_ENTRY(upnp_event_notify) entries;
                     47:     int s;  /* socket */
                     48:     enum { ECreated=1,
                     49:               EConnecting,
                     50:               ESending,
                     51:               EWaitingForResponse,
                     52:               EFinished,
                     53:               EError } state;
                     54:     struct subscriber * sub;
                     55:     char * buffer;
                     56:     int buffersize;
                     57:        int tosend;
                     58:     int sent;
                     59:        const char * path;
1.1.1.2   misho      60: #ifdef ENABLE_IPV6
                     61:        int ipv6;
                     62:        char addrstr[48];
                     63: #else
1.1       misho      64:        char addrstr[16];
1.1.1.2   misho      65: #endif
1.1       misho      66:        char portstr[8];
                     67: };
                     68: 
                     69: /* prototypes */
                     70: static void
                     71: upnp_event_create_notify(struct subscriber * sub);
                     72: 
                     73: /* Subscriber list */
                     74: LIST_HEAD(listhead, subscriber) subscriberlist = { NULL };
                     75: 
                     76: /* notify list */
                     77: LIST_HEAD(listheadnotif, upnp_event_notify) notifylist = { NULL };
                     78: 
                     79: /* create a new subscriber */
                     80: static struct subscriber *
                     81: newSubscriber(const char * eventurl, const char * callback, int callbacklen)
                     82: {
                     83:        struct subscriber * tmp;
                     84:        if(!eventurl || !callback || !callbacklen)
                     85:                return NULL;
                     86:        tmp = calloc(1, sizeof(struct subscriber)+callbacklen+1);
1.1.1.2   misho      87:        if(!tmp)
                     88:                return NULL;
1.1       misho      89:        if(strcmp(eventurl, WANCFG_EVENTURL)==0)
                     90:                tmp->service = EWanCFG;
                     91:        else if(strcmp(eventurl, WANIPC_EVENTURL)==0)
                     92:                tmp->service = EWanIPC;
                     93: #ifdef ENABLE_L3F_SERVICE
                     94:        else if(strcmp(eventurl, L3F_EVENTURL)==0)
                     95:                tmp->service = EL3F;
                     96: #endif
1.1.1.3 ! misho      97: #ifdef ENABLE_6FC_SERVICE
        !            98:        else if(strcmp(eventurl, WANIP6FC_EVENTURL)==0)
        !            99:                tmp->service = E6FC;
        !           100: #endif
        !           101: #ifdef ENABLE_DP_SERVICE
        !           102:        else if(strcmp(eventurl, DP_EVENTURL)==0)
        !           103:                tmp->service = EDP;
        !           104: #endif
1.1       misho     105:        else {
                    106:                free(tmp);
                    107:                return NULL;
                    108:        }
                    109:        memcpy(tmp->callback, callback, callbacklen);
                    110:        tmp->callback[callbacklen] = '\0';
                    111:        /* make a dummy uuid */
                    112:        /* TODO: improve that */
                    113:        strncpy(tmp->uuid, uuidvalue, sizeof(tmp->uuid));
                    114:        tmp->uuid[sizeof(tmp->uuid)-1] = '\0';
                    115:        snprintf(tmp->uuid+37, 5, "%04lx", random() & 0xffff);
                    116:        return tmp;
                    117: }
                    118: 
                    119: /* creates a new subscriber and adds it to the subscriber list
1.1.1.2   misho     120:  * also initiate 1st notify
                    121:  * TODO : add a check on the number of subscriber in order to
                    122:  * prevent memory overflow... */
1.1       misho     123: const char *
                    124: upnpevents_addSubscriber(const char * eventurl,
                    125:                          const char * callback, int callbacklen,
                    126:                          int timeout)
                    127: {
                    128:        struct subscriber * tmp;
                    129:        /*static char uuid[42];*/
                    130:        /* "uuid:00000000-0000-0000-0000-000000000000"; 5+36+1=42bytes */
                    131:        syslog(LOG_DEBUG, "addSubscriber(%s, %.*s, %d)",
                    132:               eventurl, callbacklen, callback, timeout);
                    133:        /*strncpy(uuid, uuidvalue, sizeof(uuid));
                    134:        uuid[sizeof(uuid)-1] = '\0';*/
                    135:        tmp = newSubscriber(eventurl, callback, callbacklen);
                    136:        if(!tmp)
                    137:                return NULL;
                    138:        if(timeout)
                    139:                tmp->timeout = time(NULL) + timeout;
                    140:        LIST_INSERT_HEAD(&subscriberlist, tmp, entries);
                    141:        upnp_event_create_notify(tmp);
                    142:        return tmp->uuid;
                    143: }
                    144: 
                    145: /* renew a subscription (update the timeout) */
                    146: int
                    147: renewSubscription(const char * sid, int sidlen, int timeout)
                    148: {
                    149:        struct subscriber * sub;
                    150:        for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
1.1.1.3 ! misho     151:                if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) {
1.1       misho     152:                        sub->timeout = (timeout ? time(NULL) + timeout : 0);
                    153:                        return 0;
                    154:                }
                    155:        }
                    156:        return -1;
                    157: }
                    158: 
                    159: int
                    160: upnpevents_removeSubscriber(const char * sid, int sidlen)
                    161: {
                    162:        struct subscriber * sub;
                    163:        if(!sid)
                    164:                return -1;
                    165:        for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
1.1.1.3 ! misho     166:                if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) {
1.1       misho     167:                        if(sub->notify) {
                    168:                                sub->notify->sub = NULL;
                    169:                        }
                    170:                        LIST_REMOVE(sub, entries);
                    171:                        free(sub);
                    172:                        return 0;
                    173:                }
                    174:        }
                    175:        return -1;
                    176: }
                    177: 
                    178: /* notifies all subscriber of a number of port mapping change
                    179:  * or external ip address change */
                    180: void
                    181: upnp_event_var_change_notify(enum subscriber_service_enum service)
                    182: {
                    183:        struct subscriber * sub;
                    184:        for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
                    185:                if(sub->service == service && sub->notify == NULL)
                    186:                        upnp_event_create_notify(sub);
                    187:        }
                    188: }
                    189: 
                    190: /* create and add the notify object to the list */
                    191: static void
                    192: upnp_event_create_notify(struct subscriber * sub)
                    193: {
                    194:        struct upnp_event_notify * obj;
1.1.1.3 ! misho     195: 
1.1       misho     196:        obj = calloc(1, sizeof(struct upnp_event_notify));
                    197:        if(!obj) {
                    198:                syslog(LOG_ERR, "%s: calloc(): %m", "upnp_event_create_notify");
                    199:                return;
                    200:        }
                    201:        obj->sub = sub;
                    202:        obj->state = ECreated;
1.1.1.2   misho     203: #ifdef ENABLE_IPV6
                    204:        obj->s = socket((obj->sub->callback[7] == '[') ? PF_INET6 : PF_INET,
                    205:                        SOCK_STREAM, 0);
                    206: #else
1.1       misho     207:        obj->s = socket(PF_INET, SOCK_STREAM, 0);
1.1.1.2   misho     208: #endif
1.1       misho     209:        if(obj->s<0) {
                    210:                syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify");
                    211:                goto error;
                    212:        }
1.1.1.3 ! misho     213:        if(!set_non_blocking(obj->s)) {
        !           214:                syslog(LOG_ERR, "%s: set_non_blocking(): %m",
1.1       misho     215:                       "upnp_event_create_notify");
                    216:                goto error;
                    217:        }
                    218:        if(sub)
                    219:                sub->notify = obj;
                    220:        LIST_INSERT_HEAD(&notifylist, obj, entries);
                    221:        return;
                    222: error:
                    223:        if(obj->s >= 0)
                    224:                close(obj->s);
                    225:        free(obj);
                    226: }
                    227: 
                    228: static void
                    229: upnp_event_notify_connect(struct upnp_event_notify * obj)
                    230: {
1.1.1.3 ! misho     231:        unsigned int i;
1.1       misho     232:        const char * p;
                    233:        unsigned short port;
1.1.1.2   misho     234: #ifdef ENABLE_IPV6
                    235:        struct sockaddr_storage addr;
                    236: #else
1.1       misho     237:        struct sockaddr_in addr;
1.1.1.2   misho     238: #endif
1.1       misho     239:        if(!obj)
                    240:                return;
                    241:        memset(&addr, 0, sizeof(addr));
                    242:        i = 0;
                    243:        if(obj->sub == NULL) {
                    244:                obj->state = EError;
                    245:                return;
                    246:        }
                    247:        p = obj->sub->callback;
                    248:        p += 7; /* http:// */
1.1.1.2   misho     249: #ifdef ENABLE_IPV6
                    250:        if(*p == '[') { /* ip v6 */
                    251:                p++;
                    252:                obj->ipv6 = 1;
                    253:                while(*p != ']' && i < (sizeof(obj->addrstr)-1))
                    254:                        obj->addrstr[i++] = *(p++);
                    255:                if(*p == ']')
                    256:                        p++;
                    257:        } else {
                    258: #endif
                    259:                while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1))
                    260:                        obj->addrstr[i++] = *(p++);
                    261: #ifdef ENABLE_IPV6
                    262:        }
                    263: #endif
1.1       misho     264:        obj->addrstr[i] = '\0';
                    265:        if(*p == ':') {
                    266:                obj->portstr[0] = *p;
                    267:                i = 1;
                    268:                p++;
                    269:                port = (unsigned short)atoi(p);
                    270:                while(*p != '/') {
                    271:                        if(i<7) obj->portstr[i++] = *p;
                    272:                        p++;
                    273:                }
                    274:                obj->portstr[i] = 0;
                    275:        } else {
                    276:                port = 80;
                    277:                obj->portstr[0] = '\0';
                    278:        }
                    279:        obj->path = p;
1.1.1.2   misho     280: #ifdef ENABLE_IPV6
                    281:        if(obj->ipv6) {
                    282:                struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&addr;
                    283:                sa->sin6_family = AF_INET6;
                    284:                inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr));
                    285:                sa->sin6_port = htons(port);
                    286:        } else {
                    287:                struct sockaddr_in * sa = (struct sockaddr_in *)&addr;
                    288:                sa->sin_family = AF_INET;
                    289:                inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr));
                    290:                sa->sin_port = htons(port);
                    291:        }
                    292: #else
1.1       misho     293:        addr.sin_family = AF_INET;
                    294:        inet_aton(obj->addrstr, &addr.sin_addr);
                    295:        addr.sin_port = htons(port);
1.1.1.2   misho     296: #endif
1.1       misho     297:        syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect",
                    298:               obj->addrstr, port, obj->path);
                    299:        obj->state = EConnecting;
                    300:        if(connect(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                    301:                if(errno != EINPROGRESS && errno != EWOULDBLOCK) {
                    302:                        syslog(LOG_ERR, "%s: connect(): %m", "upnp_event_notify_connect");
                    303:                        obj->state = EError;
                    304:                }
                    305:        }
                    306: }
                    307: 
                    308: static void upnp_event_prepare(struct upnp_event_notify * obj)
                    309: {
1.1.1.3 ! misho     310:        static const char notifymsg[] =
1.1       misho     311:                "NOTIFY %s HTTP/1.1\r\n"
                    312:                "Host: %s%s\r\n"
                    313:                "Content-Type: text/xml\r\n"
                    314:                "Content-Length: %d\r\n"
                    315:                "NT: upnp:event\r\n"
                    316:                "NTS: upnp:propchange\r\n"
                    317:                "SID: %s\r\n"
                    318:                "SEQ: %u\r\n"
                    319:                "Connection: close\r\n"
                    320:                "Cache-Control: no-cache\r\n"
                    321:                "\r\n"
                    322:                "%.*s\r\n";
                    323:        char * xml;
                    324:        int l;
                    325:        if(obj->sub == NULL) {
                    326:                obj->state = EError;
                    327:                return;
                    328:        }
                    329:        switch(obj->sub->service) {
                    330:        case EWanCFG:
                    331:                xml = getVarsWANCfg(&l);
                    332:                break;
                    333:        case EWanIPC:
                    334:                xml = getVarsWANIPCn(&l);
                    335:                break;
                    336: #ifdef ENABLE_L3F_SERVICE
                    337:        case EL3F:
                    338:                xml = getVarsL3F(&l);
                    339:                break;
                    340: #endif
1.1.1.2   misho     341: #ifdef ENABLE_6FC_SERVICE
                    342:        case E6FC:
                    343:                xml = getVars6FC(&l);
                    344:                break;
                    345: #endif
                    346: #ifdef ENABLE_DP_SERVICE
                    347:        case EDP:
                    348:                xml = getVarsDP(&l);
                    349:                break;
                    350: #endif
1.1       misho     351:        default:
                    352:                xml = NULL;
                    353:                l = 0;
                    354:        }
                    355:        obj->buffersize = 1024;
                    356:        obj->buffer = malloc(obj->buffersize);
1.1.1.3 ! misho     357:        if(!obj->buffer) {
        !           358:                syslog(LOG_ERR, "%s: malloc returned NULL", "upnp_event_prepare");
        !           359:                if(xml) {
        !           360:                        free(xml);
        !           361:                }
        !           362:                obj->state = EError;
        !           363:                return;
        !           364:        }
1.1       misho     365:        obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg,
                    366:                               obj->path, obj->addrstr, obj->portstr, l+2,
                    367:                               obj->sub->uuid, obj->sub->seq,
                    368:                               l, xml);
                    369:        if(xml) {
                    370:                free(xml);
                    371:                xml = NULL;
                    372:        }
                    373:        obj->state = ESending;
                    374: }
                    375: 
                    376: static void upnp_event_send(struct upnp_event_notify * obj)
                    377: {
                    378:        int i;
1.1.1.3 ! misho     379: 
1.1       misho     380:        syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s",
                    381:               "upnp_event_send", obj->addrstr, obj->portstr);
                    382:        syslog(LOG_DEBUG, "%s: msg: %s",
                    383:               "upnp_event_send", obj->buffer + obj->sent);
                    384:        i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
                    385:        if(i<0) {
1.1.1.3 ! misho     386:                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
        !           387:                        syslog(LOG_NOTICE, "%s: send(): %m", "upnp_event_send");
        !           388:                        obj->state = EError;
        !           389:                        return;
        !           390:                } else {
        !           391:                        /* EAGAIN or EWOULDBLOCK or EINTR : no data sent */
        !           392:                        i = 0;
        !           393:                }
1.1       misho     394:        }
1.1.1.3 ! misho     395:        if(i != (obj->tosend - obj->sent))
1.1       misho     396:                syslog(LOG_NOTICE, "%s: %d bytes send out of %d",
                    397:                       "upnp_event_send", i, obj->tosend - obj->sent);
                    398:        obj->sent += i;
                    399:        if(obj->sent == obj->tosend)
                    400:                obj->state = EWaitingForResponse;
                    401: }
                    402: 
                    403: static void upnp_event_recv(struct upnp_event_notify * obj)
                    404: {
                    405:        int n;
                    406:        n = recv(obj->s, obj->buffer, obj->buffersize, 0);
                    407:        if(n<0) {
1.1.1.3 ! misho     408:                if(errno != EAGAIN &&
        !           409:                   errno != EWOULDBLOCK &&
        !           410:                   errno != EINTR) {
        !           411:                        syslog(LOG_ERR, "%s: recv(): %m", "upnp_event_recv");
        !           412:                        obj->state = EError;
        !           413:                }
1.1       misho     414:                return;
                    415:        }
                    416:        syslog(LOG_DEBUG, "%s: (%dbytes) %.*s", "upnp_event_recv",
                    417:               n, n, obj->buffer);
1.1.1.3 ! misho     418:        /* TODO : do something with the data recevied ?
        !           419:         * right now, n (number of bytes received) is ignored
        !           420:         * We may need to recv() more bytes. */
1.1       misho     421:        obj->state = EFinished;
                    422:        if(obj->sub)
                    423:                obj->sub->seq++;
                    424: }
                    425: 
                    426: static void
                    427: upnp_event_process_notify(struct upnp_event_notify * obj)
                    428: {
1.1.1.3 ! misho     429:        int err;
        !           430:        socklen_t len;
1.1       misho     431:        switch(obj->state) {
                    432:        case EConnecting:
                    433:                /* now connected or failed to connect */
1.1.1.3 ! misho     434:                len = sizeof(err);
        !           435:                if(getsockopt(obj->s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
        !           436:                        syslog(LOG_ERR, "%s: getsockopt: %m", "upnp_event_process_notify");
        !           437:                        obj->state = EError;
        !           438:                        break;
        !           439:                }
        !           440:                if(err != 0) {
        !           441:                        errno = err;
        !           442:                        syslog(LOG_WARNING, "%s: connect failed: %m", "upnp_event_process_notify");
        !           443:                        obj->state = EError;
        !           444:                        break;
        !           445:                }
1.1       misho     446:                upnp_event_prepare(obj);
1.1.1.3 ! misho     447:                if(obj->state == ESending)
        !           448:                        upnp_event_send(obj);
1.1       misho     449:                break;
                    450:        case ESending:
                    451:                upnp_event_send(obj);
                    452:                break;
                    453:        case EWaitingForResponse:
                    454:                upnp_event_recv(obj);
                    455:                break;
                    456:        case EFinished:
                    457:                close(obj->s);
                    458:                obj->s = -1;
                    459:                break;
                    460:        default:
1.1.1.3 ! misho     461:                syslog(LOG_ERR, "%s: unknown state", "upnp_event_process_notify");
1.1       misho     462:        }
                    463: }
                    464: 
                    465: void upnpevents_selectfds(fd_set *readset, fd_set *writeset, int * max_fd)
                    466: {
                    467:        struct upnp_event_notify * obj;
                    468:        for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
                    469:                syslog(LOG_DEBUG, "upnpevents_selectfds: %p %d %d",
                    470:                       obj, obj->state, obj->s);
                    471:                if(obj->s >= 0) {
                    472:                        switch(obj->state) {
                    473:                        case ECreated:
                    474:                                upnp_event_notify_connect(obj);
                    475:                                if(obj->state != EConnecting)
                    476:                                        break;
                    477:                        case EConnecting:
                    478:                        case ESending:
                    479:                                FD_SET(obj->s, writeset);
                    480:                                if(obj->s > *max_fd)
                    481:                                        *max_fd = obj->s;
                    482:                                break;
                    483:                        case EWaitingForResponse:
                    484:                                FD_SET(obj->s, readset);
                    485:                                if(obj->s > *max_fd)
                    486:                                        *max_fd = obj->s;
                    487:                                break;
1.1.1.2   misho     488:                        default:
                    489:                                ;
1.1       misho     490:                        }
                    491:                }
                    492:        }
                    493: }
                    494: 
                    495: void upnpevents_processfds(fd_set *readset, fd_set *writeset)
                    496: {
                    497:        struct upnp_event_notify * obj;
                    498:        struct upnp_event_notify * next;
                    499:        struct subscriber * sub;
                    500:        struct subscriber * subnext;
                    501:        time_t curtime;
                    502:        for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
                    503:                syslog(LOG_DEBUG, "%s: %p %d %d %d %d",
                    504:                       "upnpevents_processfds", obj, obj->state, obj->s,
                    505:                       FD_ISSET(obj->s, readset), FD_ISSET(obj->s, writeset));
                    506:                if(obj->s >= 0) {
                    507:                        if(FD_ISSET(obj->s, readset) || FD_ISSET(obj->s, writeset))
                    508:                                upnp_event_process_notify(obj);
                    509:                }
                    510:        }
                    511:        obj = notifylist.lh_first;
                    512:        while(obj != NULL) {
                    513:                next = obj->entries.le_next;
                    514:                if(obj->state == EError || obj->state == EFinished) {
                    515:                        if(obj->s >= 0) {
                    516:                                close(obj->s);
                    517:                        }
                    518:                        if(obj->sub)
                    519:                                obj->sub->notify = NULL;
                    520:                        /* remove also the subscriber from the list if there was an error */
                    521:                        if(obj->state == EError && obj->sub) {
                    522:                                LIST_REMOVE(obj->sub, entries);
                    523:                                free(obj->sub);
                    524:                        }
                    525:                        if(obj->buffer) {
                    526:                                free(obj->buffer);
                    527:                        }
                    528:                        LIST_REMOVE(obj, entries);
                    529:                        free(obj);
                    530:                }
                    531:                obj = next;
                    532:        }
                    533:        /* remove timeouted subscribers */
                    534:        curtime = time(NULL);
                    535:        for(sub = subscriberlist.lh_first; sub != NULL; ) {
                    536:                subnext = sub->entries.le_next;
                    537:                if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) {
                    538:                        LIST_REMOVE(sub, entries);
                    539:                        free(sub);
                    540:                }
                    541:                sub = subnext;
                    542:        }
                    543: }
                    544: 
                    545: #ifdef USE_MINIUPNPDCTL
                    546: void write_events_details(int s) {
                    547:        int n;
                    548:        char buff[80];
                    549:        struct upnp_event_notify * obj;
                    550:        struct subscriber * sub;
                    551:        write(s, "Events details :\n", 17);
                    552:        for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
                    553:                n = snprintf(buff, sizeof(buff), " %p sub=%p state=%d s=%d\n",
                    554:                             obj, obj->sub, obj->state, obj->s);
                    555:                write(s, buff, n);
                    556:        }
                    557:        write(s, "Subscribers :\n", 14);
                    558:        for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
                    559:                n = snprintf(buff, sizeof(buff), " %p timeout=%d seq=%u service=%d\n",
1.1.1.2   misho     560:                             sub, (int)sub->timeout, sub->seq, sub->service);
1.1       misho     561:                write(s, buff, n);
                    562:                n = snprintf(buff, sizeof(buff), "   notify=%p %s\n",
                    563:                             sub->notify, sub->uuid);
                    564:                write(s, buff, n);
                    565:                n = snprintf(buff, sizeof(buff), "   %s\n",
                    566:                             sub->callback);
                    567:                write(s, buff, n);
                    568:        }
                    569: }
                    570: #endif
                    571: 
                    572: #endif
                    573: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>