lib: Split epoll and select loops into separate files.
[ashd.git] / lib / mtio.c
1 /*
2     ashd - A Sane HTTP Daemon
3     Copyright (C) 2008  Fredrik Tolf <fredrik@dolda2000.com>
4
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.
9
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.
14
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/>.
17 */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/socket.h>
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 #include <log.h>
30 #include <utils.h>
31 #include <mt.h>
32 #include <mtio.h>
33
34 struct stdiofd {
35     int fd;
36     int sock;
37     int timeout;
38 };
39
40 static ssize_t mtread(void *cookie, char *buf, size_t len)
41 {
42     struct stdiofd *d = cookie;
43     int ev;
44     ssize_t ret;
45     
46     while(1) {
47         ret = read(d->fd, buf, len);
48         if((ret < 0) && (errno == EAGAIN)) {
49             ev = block(d->fd, EV_READ, d->timeout);
50             if(ev < 0) {
51                 /* If we just go on, we should get the real error. */
52                 continue;
53             } else if(ev == 0) {
54                 errno = ETIMEDOUT;
55                 return(-1);
56             } else {
57                 continue;
58             }
59         } else {
60             return(ret);
61         }
62     }
63 }
64
65 static ssize_t mtwrite(void *cookie, const char *buf, size_t len)
66 {
67     struct stdiofd *d = cookie;
68     int ev;
69     size_t off;
70     ssize_t ret;
71     
72     off = 0;
73     while(off < len) {
74         if(d->sock)
75             ret = send(d->fd, buf + off, len - off, MSG_DONTWAIT | MSG_NOSIGNAL);
76         else
77             ret = write(d->fd, buf + off, len - off);
78         if(ret < 0) {
79             if(errno == EAGAIN) {
80                 ev = block(d->fd, EV_WRITE, d->timeout);
81                 if(ev < 0) {
82                     /* If we just go on, we should get the real error. */
83                     continue;
84                 } else if(ev == 0) {
85                     errno = ETIMEDOUT;
86                     return(off);
87                 } else {
88                     continue;
89                 }
90             } else {
91                 return(off);
92             }
93         } else {
94             off += ret;
95         }
96     }
97     return(off);
98 }
99
100 static int mtclose(void *cookie)
101 {
102     struct stdiofd *d = cookie;
103     
104     close(d->fd);
105     free(d);
106     return(0);
107 }
108
109 static cookie_io_functions_t iofuns = {
110     .read = mtread,
111     .write = mtwrite,
112     .close = mtclose,
113 };
114
115 FILE *mtstdopen(int fd, int issock, int timeout, char *mode)
116 {
117     struct stdiofd *d;
118     FILE *ret;
119     
120     omalloc(d);
121     d->fd = fd;
122     d->sock = issock;
123     d->timeout = timeout;
124     ret = fopencookie(d, mode, iofuns);
125     if(!ret)
126         free(d);
127     else
128         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
129     return(ret);
130 }