/*      $NetBSD: eventlib_p.h,v 1.1.1.2 2012/09/09 16:08:02 christos Exp $      */

/*
* Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-1999 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*! \file
* \brief private interfaces for eventlib
* \author vix 09sep95 [initial]
*
* Id: eventlib_p.h,v 1.9 2006/03/09 23:57:56 marka Exp
*/

#ifndef _EVENTLIB_P_H
#define _EVENTLIB_P_H

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>

#define EVENTLIB_DEBUG 1

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <isc/heap.h>
#include <isc/list.h>
#include <isc/memcluster.h>

#define EV_MASK_ALL     (EV_READ | EV_WRITE | EV_EXCEPT)
#define EV_ERR(e)               return (errno = (e), -1)
#define OK(x)           if ((x) < 0) EV_ERR(errno); else (void)NULL
#define OKFREE(x, y)    if ((x) < 0) { FREE((y)); EV_ERR(errno); } \
                       else (void)NULL

#define NEW(p)          if (((p) = memget(sizeof *(p))) != NULL) \
                               FILL(p); \
                       else \
                               (void)NULL;
#define OKNEW(p)        if (!((p) = memget(sizeof *(p)))) { \
                               errno = ENOMEM; \
                               return (-1); \
                       } else \
                               FILL(p)
#define FREE(p)         memput((p), sizeof *(p))

#if EVENTLIB_DEBUG
#define FILL(p)         memset((p), 0xF5, sizeof *(p))
#else
#define FILL(p)
#endif

#ifdef USE_POLL
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <poll.h>
#endif /* USE_POLL */

typedef struct evConn {
       evConnFunc      func;
       void *          uap;
       int             fd;
       int             flags;
#define EV_CONN_LISTEN          0x0001          /*%< Connection is a listener. */
#define EV_CONN_SELECTED        0x0002          /*%< evSelectFD(conn->file). */
#define EV_CONN_BLOCK           0x0004          /*%< Listener fd was blocking. */
       evFileID        file;
       struct evConn * prev;
       struct evConn * next;
} evConn;

typedef struct evAccept {
       int             fd;
       union {
               struct sockaddr         sa;
               struct sockaddr_in      in;
#ifndef NO_SOCKADDR_UN
               struct sockaddr_un      un;
#endif
       }               la;
       ISC_SOCKLEN_T   lalen;
       union {
               struct sockaddr         sa;
               struct sockaddr_in      in;
#ifndef NO_SOCKADDR_UN
               struct sockaddr_un      un;
#endif
       }               ra;
       ISC_SOCKLEN_T   ralen;
       int             ioErrno;
       evConn *        conn;
       LINK(struct evAccept) link;
} evAccept;

typedef struct evFile {
       evFileFunc      func;
       void *          uap;
       int             fd;
       int             eventmask;
       int             preemptive;
       struct evFile * prev;
       struct evFile * next;
       struct evFile * fdprev;
       struct evFile * fdnext;
} evFile;

typedef struct evStream {
       evStreamFunc    func;
       void *          uap;
       evFileID        file;
       evTimerID       timer;
       int             flags;
#define EV_STR_TIMEROK  0x0001  /*%< IFF timer valid. */
       int             fd;
       struct iovec *  iovOrig;
       int             iovOrigCount;
       struct iovec *  iovCur;
       int             iovCurCount;
       int             ioTotal;
       int             ioDone;
       int             ioErrno;
       struct evStream *prevDone, *nextDone;
       struct evStream *prev, *next;
} evStream;

typedef struct evTimer {
       evTimerFunc     func;
       void *          uap;
       struct timespec due, inter;
       int             index;
       int             mode;
#define EV_TMR_RATE     1
} evTimer;

typedef struct evWait {
       evWaitFunc      func;
       void *          uap;
       const void *    tag;
       struct evWait * next;
} evWait;

typedef struct evWaitList {
       evWait *                first;
       evWait *                last;
       struct evWaitList *     prev;
       struct evWaitList *     next;
} evWaitList;

typedef struct evEvent_p {
       enum {  Accept, File, Stream, Timer, Wait, Free, Null  } type;
       union {
               struct {  evAccept *this;  }                    accept;
               struct {  evFile *this; int eventmask;  }       file;
               struct {  evStream *this;  }                    stream;
               struct {  evTimer *this;  }                     timer;
               struct {  evWait *this;  }                      wait;
               struct {  struct evEvent_p *next;  }            free;
               struct {  const void *placeholder;  }           null;
       } u;
} evEvent_p;

#ifdef USE_POLL
typedef struct {
       void            *ctx;   /* pointer to the evContext_p   */
       uint32_t        type;   /* READ, WRITE, EXCEPT, nonblk  */
       uint32_t        result; /* 1 => revents, 0 => events    */
} __evEmulMask;

#define emulMaskInit(ctx, field, ev, lastnext) \
       ctx->field.ctx = ctx; \
       ctx->field.type = ev; \
       ctx->field.result = lastnext;

extern short    *__fd_eventfield(int fd, __evEmulMask *maskp);
extern short    __poll_event(__evEmulMask *maskp);
extern void             __fd_clr(int fd, __evEmulMask *maskp);
extern void             __fd_set(int fd, __evEmulMask *maskp);

#undef  FD_ZERO
#define FD_ZERO(maskp)

#undef  FD_SET
#define FD_SET(fd, maskp) \
       __fd_set(fd, maskp)

#undef  FD_CLR
#define FD_CLR(fd, maskp) \
       __fd_clr(fd, maskp)

#undef  FD_ISSET
#define FD_ISSET(fd, maskp) \
       ((*__fd_eventfield(fd, maskp) & __poll_event(maskp)) != 0)

#endif /* USE_POLL */

typedef struct {
       /* Global. */
       const evEvent_p *cur;
       /* Debugging. */
       int             debug;
       FILE            *output;
       /* Connections. */
       evConn          *conns;
       LIST(evAccept)  accepts;
       /* Files. */
       evFile          *files, *fdNext;
#ifndef USE_POLL
       fd_set          rdLast, rdNext;
       fd_set          wrLast, wrNext;
       fd_set          exLast, exNext;
       fd_set          nonblockBefore;
       int             fdMax, fdCount, highestFD;
       evFile          *fdTable[FD_SETSIZE];
#else
       struct pollfd   *pollfds;       /* Allocated as needed  */
       evFile          **fdTable;      /* Ditto                */
       int             maxnfds;        /* # elements in above  */
       int             firstfd;        /* First active fd      */
       int             fdMax;          /* Last active fd       */
       int             fdCount;        /* # fd:s with I/O      */
       int             highestFD;      /* max fd allowed by OS */
       __evEmulMask    rdLast, rdNext;
       __evEmulMask    wrLast, wrNext;
       __evEmulMask    exLast, exNext;
       __evEmulMask    nonblockBefore;
#endif /* USE_POLL */
#ifdef EVENTLIB_TIME_CHECKS
       struct timespec lastSelectTime;
       int             lastFdCount;
#endif
       /* Streams. */
       evStream        *streams;
       evStream        *strDone, *strLast;
       /* Timers. */
       struct timespec lastEventTime;
       heap_context    timers;
       /* Waits. */
       evWaitList      *waitLists;
       evWaitList      waitDone;
} evContext_p;

/* eventlib.c */
#define evPrintf __evPrintf
void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...)
    ISC_FORMAT_PRINTF(3, 4);

#ifdef USE_POLL
extern int evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd);
#endif /* USE_POLL */

/* ev_timers.c */
#define evCreateTimers __evCreateTimers
heap_context evCreateTimers(const evContext_p *);
#define evDestroyTimers __evDestroyTimers
void evDestroyTimers(const evContext_p *);

/* ev_waits.c */
#define evFreeWait __evFreeWait
evWait *evFreeWait(evContext_p *ctx, evWait *old);

/* Global options */
extern int      __evOptMonoTime;

#endif /*_EVENTLIB_P_H*/