| 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 |  |  | } |