chiark / gitweb /
util: Break out pollbadbit()
[secnet.git] / util.h
diff --git a/util.h b/util.h
index 33b2b2bd865e0cb81c3e2d2d5c4a2a4706da7296..63ceef69b9581165d3aaaf7e9dad8b09f40a6205 100644 (file)
--- a/util.h
+++ b/util.h
@@ -23,6 +23,7 @@ extern void buffer_assert_used(struct buffer_if *buffer, cstring_t file,
                               int line);
 extern void buffer_new(struct buffer_if *buffer, int32_t len);
 extern void buffer_init(struct buffer_if *buffer, int32_t max_start_pad);
+extern void buffer_destroy(struct buffer_if *buffer);
 extern void buffer_copy(struct buffer_if *dst, const struct buffer_if *src);
 extern void *buf_append(struct buffer_if *buf, int32_t amount);
 extern void *buf_prepend(struct buffer_if *buf, int32_t amount);
@@ -87,6 +88,74 @@ int iaddr_socklen(const union iaddr *ia);
 void string_item_to_iaddr(const item_t *item, uint16_t port, union iaddr *ia,
                          const char *desc);
 
+
+/*----- line-buffered asynch input -----*/
+
+enum async_linebuf_result {
+    async_linebuf_nothing,
+    async_linebuf_ok,
+    async_linebuf_eof,
+    async_linebuf_broken,
+};
+
+const char *pollbadbit(int revents); /* returns 0, or bad bit description */
+
+enum async_linebuf_result
+async_linebuf_read(struct pollfd *pfd, struct buffer_if *buf,
+                  const char **emsg_out);
+   /* Implements reading whole lines, asynchronously.  Use like
+    * this:
+    *   - set up the fd, which should be readable, O_NONBLOCK
+    *   - set up and initialise buffer, which should be big enough
+    *     for one line plus its trailing newline, and be empty
+    *     with start==base
+    *   - in your beforepoll_fn, be interested in POLLIN
+    *   - in your afterpoll_fn, repeatedly call this function
+    *     until it doesn't return `nothing'
+    *   - after you're done, simply close fd and free or reset buf
+    * State on return from async_linebuf_read depends on return value:
+    *
+    *   async_linebuf_nothing:
+    *
+    *      No complete lines available right now.  You should return
+    *      from afterpoll.  buf should be left untouched until the
+    *      next call to async_linebuf_read.
+    *
+    *   async_linebuf_ok:
+    *
+    *      buf->base contains a input line as a nul-terminated string
+    *      (\n replaced by \0); *emsg_out==0.  You must call
+    *      async_linebuf_read again before returning from afterpoll.
+    *
+    *   async_linebuf_eof:
+    *
+    *      EOF on stream.  buf->base contains any partial
+    *      (non-newline-terminated) line; *emsg_out!=0 iff there was
+    *      such a partial line.  You can call async_linebuf_read again
+    *      if you like but it will probably just return eof again.
+    *
+    *   broken:
+    *
+    *      Fatal problem (might be overly long lines, nuls in input
+    *      data, bad bits in pfd->revents, errors from read, etc.)
+    *
+    *      *emsg_out is the error message describing the problem;
+    *      this message might be stored in buf, might be from
+    *      strerror, or might be a constant.
+    *
+    *      You must not call async_linebuf_read again.  buf contents
+    *      is undefined: it is only safe to reset or free.
+    *
+    * While using this function, do not look at buf->start or ->size
+    * or anything after the first '\0' in buf.
+    *
+    * If you decide to stop reading with async_linebuf_read that's
+    * fine and you can reset or free buf, but you risk missing some
+    * read-but-not-reported data.
+    */
+
+/*----- some handy macros -----*/
+
 #define MINMAX(ae,be,op) ({                    \
        typeof((ae)) a=(ae);                    \
        typeof((be)) b=(be);                    \
@@ -95,4 +164,10 @@ void string_item_to_iaddr(const item_t *item, uint16_t port, union iaddr *ia,
 #define MAX(a,b) MINMAX((a),(b),>)
 #define MIN(a,b) MINMAX((a),(b),<)
 
+#define MAX_RAW(a,b) ((a)>(b)?(a):(b))
+#define MIN_RAW(a,b) ((a)<(b)?(a):(b))
+
+static inline bool_t iswouldblock(int e)
+    { return e==EWOULDBLOCK || e==EAGAIN; }
+
 #endif /* util_h */