1 /* $OpenBSD: mio_aucat.c,v 1.12 2016/01/09 08:27:24 ratchov Exp $ */ 2 /* 3 * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/un.h> 21 #include <netinet/in.h> 22 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <poll.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "aucat.h" 32 #include "debug.h" 33 #include "mio_priv.h" 34 35 struct mio_aucat_hdl { 36 struct mio_hdl mio; 37 struct aucat aucat; 38 int events; 39 }; 40 41 static void mio_aucat_close(struct mio_hdl *); 42 static size_t mio_aucat_read(struct mio_hdl *, void *, size_t); 43 static size_t mio_aucat_write(struct mio_hdl *, const void *, size_t); 44 static int mio_aucat_nfds(struct mio_hdl *); 45 static int mio_aucat_pollfd(struct mio_hdl *, struct pollfd *, int); 46 static int mio_aucat_revents(struct mio_hdl *, struct pollfd *); 47 48 static struct mio_ops mio_aucat_ops = { 49 mio_aucat_close, 50 mio_aucat_write, 51 mio_aucat_read, 52 mio_aucat_nfds, 53 mio_aucat_pollfd, 54 mio_aucat_revents 55 }; 56 57 /* 58 * execute the next message, return 0 if blocked 59 */ 60 static int 61 mio_aucat_runmsg(struct mio_aucat_hdl *hdl) 62 { 63 int delta; 64 65 if (!_aucat_rmsg(&hdl->aucat, &hdl->mio.eof)) 66 return 0; 67 switch (ntohl(hdl->aucat.rmsg.cmd)) { 68 case AMSG_DATA: 69 return 1; 70 case AMSG_FLOWCTL: 71 delta = ntohl(hdl->aucat.rmsg.u.ts.delta); 72 hdl->aucat.maxwrite += delta; 73 DPRINTF("aucat: flowctl = %d, maxwrite = %d\n", 74 delta, hdl->aucat.maxwrite); 75 break; 76 default: 77 DPRINTF("mio_aucat_runmsg: unhandled message %u\n", 78 hdl->aucat.rmsg.cmd); 79 hdl->mio.eof = 1; 80 return 0; 81 } 82 hdl->aucat.rstate = RSTATE_MSG; 83 hdl->aucat.rtodo = sizeof(struct amsg); 84 return 1; 85 } 86 87 struct mio_hdl * 88 _mio_aucat_open(const char *str, unsigned int mode, int nbio) 89 { 90 struct mio_aucat_hdl *hdl; 91 92 hdl = malloc(sizeof(struct mio_aucat_hdl)); 93 if (hdl == NULL) 94 return NULL; 95 if (!_aucat_open(&hdl->aucat, str, mode)) 96 goto bad; 97 _mio_create(&hdl->mio, &mio_aucat_ops, mode, nbio); 98 if (!_aucat_setfl(&hdl->aucat, 1, &hdl->mio.eof)) 99 goto bad; 100 return (struct mio_hdl *)hdl; 101 bad: 102 free(hdl); 103 return NULL; 104 } 105 106 static void 107 mio_aucat_close(struct mio_hdl *sh) 108 { 109 struct mio_aucat_hdl *hdl = (struct mio_aucat_hdl *)sh; 110 111 if (!hdl->mio.eof) 112 _aucat_setfl(&hdl->aucat, 0, &hdl->mio.eof); 113 _aucat_close(&hdl->aucat, hdl->mio.eof); 114 free(hdl); 115 } 116 117 static size_t 118 mio_aucat_read(struct mio_hdl *sh, void *buf, size_t len) 119 { 120 struct mio_aucat_hdl *hdl = (struct mio_aucat_hdl *)sh; 121 122 while (hdl->aucat.rstate == RSTATE_MSG) { 123 if (!mio_aucat_runmsg(hdl)) 124 return 0; 125 } 126 return _aucat_rdata(&hdl->aucat, buf, len, &hdl->mio.eof); 127 } 128 129 static size_t 130 mio_aucat_write(struct mio_hdl *sh, const void *buf, size_t len) 131 { 132 struct mio_aucat_hdl *hdl = (struct mio_aucat_hdl *)sh; 133 size_t n; 134 135 if (len <= 0 || hdl->aucat.maxwrite <= 0) 136 return 0; 137 if (len > hdl->aucat.maxwrite) 138 len = hdl->aucat.maxwrite; 139 n = _aucat_wdata(&hdl->aucat, buf, len, 1, &hdl->mio.eof); 140 hdl->aucat.maxwrite -= n; 141 return n; 142 } 143 144 static int 145 mio_aucat_nfds(struct mio_hdl *sh) 146 { 147 return 1; 148 } 149 150 static int 151 mio_aucat_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events) 152 { 153 struct mio_aucat_hdl *hdl = (struct mio_aucat_hdl *)sh; 154 155 hdl->events = events; 156 if (hdl->aucat.maxwrite <= 0) 157 events &= ~POLLOUT; 158 return _aucat_pollfd(&hdl->aucat, pfd, events); 159 } 160 161 static int 162 mio_aucat_revents(struct mio_hdl *sh, struct pollfd *pfd) 163 { 164 struct mio_aucat_hdl *hdl = (struct mio_aucat_hdl *)sh; 165 int revents = pfd->revents; 166 167 if (revents & POLLIN) { 168 while (hdl->aucat.rstate == RSTATE_MSG) { 169 if (!mio_aucat_runmsg(hdl)) 170 break; 171 } 172 if (hdl->aucat.rstate != RSTATE_DATA) 173 revents &= ~POLLIN; 174 } 175 if (revents & POLLOUT) { 176 if (hdl->aucat.maxwrite <= 0) 177 revents &= ~POLLOUT; 178 } 179 if (hdl->mio.eof) 180 return POLLHUP; 181 return revents & (hdl->events | POLLHUP); 182 } 183