2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/socket.h>
36 static ssize_t mtrecv(struct stdiofd *d, void *buf, size_t len)
46 msg = (struct msghdr){};
47 msg.msg_iov = &bufvec;
49 bufvec.iov_base = buf;
51 msg.msg_control = cbuf;
52 msg.msg_controllen = sizeof(cbuf);
53 if((ret = recvmsg(d->fd, &msg, MSG_DONTWAIT)) < 0)
55 for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
56 if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS)) {
57 fds = (int *)CMSG_DATA(cmsg);
58 clen = (cmsg->cmsg_len - ((char *)fds - (char *)cmsg)) / sizeof(*fds);
59 for(i = 0; i < clen; i++) {
70 static ssize_t mtread(void *cookie, void *buf, size_t len)
72 struct stdiofd *d = cookie;
78 ret = mtrecv(d, buf, len);
80 ret = read(d->fd, buf, len);
81 if((ret < 0) && (errno == EAGAIN)) {
82 ev = block(d->fd, EV_READ, d->timeout);
84 /* If we just go on, we should get the real error. */
98 static ssize_t mtsend(struct stdiofd *d, const void *buf, size_t len)
101 struct cmsghdr *cmsg;
102 char cbuf[CMSG_SPACE(sizeof(int))];
107 msg = (struct msghdr){};
108 msg.msg_iov = &bufvec;
110 bufvec.iov_base = (void *)buf;
111 bufvec.iov_len = len;
113 if(d->sendrights >= 0) {
114 msg.msg_control = cbuf;
115 msg.msg_controllen = sizeof(cbuf);
116 cmsg = CMSG_FIRSTHDR(&msg);
117 cmsg->cmsg_level = SOL_SOCKET;
118 cmsg->cmsg_type = SCM_RIGHTS;
119 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
120 *((int *)CMSG_DATA(cmsg)) = d->sendrights;
123 msg.msg_controllen = cmsg->cmsg_len;
125 ret = sendmsg(d->fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
131 static ssize_t mtwrite(void *cookie, const void *buf, size_t len)
133 struct stdiofd *d = cookie;
139 ret = mtsend(d, buf, len);
141 ret = write(d->fd, buf, len);
142 if((ret < 0) && (errno == EAGAIN)) {
143 ev = block(d->fd, EV_WRITE, d->timeout);
145 /* If we just go on, we should get the real error. */
157 static int mtclose(void *cookie)
159 struct stdiofd *d = cookie;
164 if(d->sendrights >= 0)
165 close(d->sendrights);
170 FILE *mtstdopen(int fd, int issock, int timeout, char *mode, struct stdiofd **infop)
176 if(!strcmp(mode, "r")) {
178 } else if(!strcmp(mode, "w")) {
180 } else if(!strcmp(mode, "r+")) {
188 d->timeout = timeout;
189 d->rights = d->sendrights = -1;
190 if(!(ret = funstdio(d, r?mtread:NULL, w?mtwrite:NULL, NULL, mtclose))) {
194 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
200 struct bufio *mtbioopen(int fd, int issock, int timeout, char *mode, struct stdiofd **infop)
202 static struct bufioops ops = {
203 .read = mtread, .write = mtwrite, .close = mtclose,
208 if(!strcmp(mode, "r")) {
209 } else if(!strcmp(mode, "w")) {
210 } else if(!strcmp(mode, "r+")) {
217 d->timeout = timeout;
218 d->rights = d->sendrights = -1;
219 if(!(ret = bioopen(d, &ops))) {
223 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
236 static void freepipe(struct pipe *p)
242 static ssize_t piperead(void *pdata, void *buf, size_t len)
244 struct pipe *p = pdata;
247 while(p->data.d == 0) {
258 ret = min(len, p->data.d);
259 memcpy(buf, p->data.b, ret);
260 memmove(p->data.b, p->data.b + ret, p->data.d -= ret);
266 static int piperclose(void *pdata)
268 struct pipe *p = pdata;
280 static ssize_t pipewrite(void *pdata, const void *buf, size_t len)
282 struct pipe *p = pdata;
289 while(p->data.d >= p->bufmax) {
302 ret = min(len, p->bufmax - p->data.d);
303 sizebuf(p->data, p->data.d + ret);
304 memcpy(p->data.b + p->data.d, buf, ret);
311 static int pipewclose(void *pdata)
313 struct pipe *p = pdata;
325 void mtiopipe(FILE **read, FILE **write)
331 *read = funstdio(p, piperead, NULL, NULL, piperclose);
332 *write = funstdio(p, NULL, pipewrite, NULL, pipewclose);