1 /* this header file comes from libowfat, http://www.fefe.de/libowfat/ */
2 #ifndef IO_H
3 #define IO_H
4 
5 /* http://cr.yp.to/lib/io.html */
6 
7 #include "uint64.h"
8 #include "taia.h"
9 
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13 
14 /* like open(s,O_RDONLY) */
15 /* return 1 if ok, 0 on error */
16 int io_readfile(int64* d,const char* s);
17 /* like open(s,O_WRONLY|O_CREAT|O_TRUNC,0600) */
18 /* return 1 if ok, 0 on error */
19 int io_createfile(int64* d,const char* s);
20 /* like open(s,O_RDWR) */
21 /* return 1 if ok, 0 on error */
22 int io_readwritefile(int64* d,const char* s);
23 /* like open(s,O_WRONLY|O_APPEND|O_CREAT,0600) */
24 /* return 1 if ok, 0 on error */
25 int io_appendfile(int64* d,const char* s);
26 /* like pipe(d) */
27 /* return 1 if ok, 0 on error */
28 int io_pipe(int64* d);
29 /* like socketpair() */
30 /* return 1 if ok, 0 on error */
31 int io_socketpair(int64* d);
32 
33 /* non-blocking read(), -1 for EAGAIN and -3+errno for other errors */
34 int64 io_tryread(int64 d,char* buf,int64 len);
35 
36 /* blocking read(), with -3 instead of -1 for errors */
37 int64 io_waitread(int64 d,char* buf,int64 len);
38 
39 /* non-blocking write(), -1 for EAGAIN and -3+errno for other errors */
40 int64 io_trywrite(int64 d,const char* buf,int64 len);
41 
42 /* blocking write(), with -3 instead of -1 for errors */
43 int64 io_waitwrite(int64 d,const char* buf,int64 len);
44 
45 /* modify timeout attribute of file descriptor */
46 void io_timeout(int64 d,tai6464 t);
47 
48 /* like io_tryread but will return -2,errno=ETIMEDOUT if d has a timeout
49  * associated and it is passed without input being there */
50 int64 io_tryreadtimeout(int64 d,char* buf,int64 len);
51 
52 /* like io_trywrite but will return -2,errno=ETIMEDOUT if d has a timeout
53  * associated and it is passed without being able to write */
54 int64 io_trywritetimeout(int64 d,const char* buf,int64 len);
55 
56 void io_wantread(int64 d);
57 void io_wantwrite(int64 d);
58 void io_dontwantread(int64 d);
59 void io_dontwantwrite(int64 d);
60 
61 void io_wait();
62 void io_waituntil(tai6464 t);
63 int64 io_waituntil2(int64 milliseconds);
64 void io_check();
65 
66 /* signal that read/accept/whatever returned EAGAIN */
67 /* needed for SIGIO and epoll */
68 void io_eagain(int64 d);  /* do not use, API was a bad idea */
69 #define HAVE_EAGAIN_READWRITE
70 void io_eagain_read(int64 d);	/* use these ones */
71 void io_eagain_write(int64 d);
72 
73 /* return next descriptor from io_wait that can be read from */
74 int64 io_canread();
75 /* return next descriptor from io_wait that can be written to */
76 int64 io_canwrite();
77 
78 /* return next descriptor with expired timeout */
79 int64 io_timeouted();
80 
81 /* is this fd over its timeout? */
82 int io_timedout(int64 d);
83 
84 /* 1 means: have IO_FD_CANWRITE, IO_FD_BLOCK and IO_FD_NONBLOCK,
85  * will be incremented if API is extended in the future */
86 #define HAVE_IO_FD_FLAGS 1
87 enum io_fd_flags {
88   IO_FD_CANWRITE=1,	/* new TCP connection, we know it's writable */
89   IO_FD_BLOCK=2,	/* skip the fcntl, assume fd is set to blocking */
90   IO_FD_NONBLOCK=4,	/* skip the fcntl, assume fd is set to non-blocking */
91 };
92 
93 /* put d on internal data structure, return 1 on success, 0 on error */
94 int io_fd(int64 d);		/* use this for sockets before you called connect() or accept() */
95 int io_fd_canwrite(int64 d);	/* use this for connected sockets (assumes socket is writable) */
96 int io_fd_flags(int64 d,int flags);	/* can be used to tell io_fd to skip one syscall */
97 
98 void io_setcookie(int64 d,void* cookie);
99 void* io_getcookie(int64 d);
100 
101 /* put descriptor in non-blocking mode */
102 void io_nonblock(int64 d);
103 /* put descriptor in blocking mode */
104 void io_block(int64 d);
105 /* put descriptor in close-on-exec mode */
106 void io_closeonexec(int64 d);
107 
108 void io_close(int64 d);
109 
110 /* Free the internal data structures from libio.
111  * This only makes sense if you run your program in a malloc checker and
112  * these produce false alarms.  Your OS will free these automatically on
113  * process termination. */
114 void io_finishandshutdown(void);
115 
116 /* send n bytes from file fd starting at offset off to socket s */
117 /* return number of bytes written */
118 int64 io_sendfile(int64 s,int64 fd,uint64 off,uint64 n);
119 
120 /* Pass fd over sock (must be a unix domain socket) to other process.
121  * Return 0 if ok, -1 on error, setting errno. */
122 int io_passfd(int64 sock,int64 fd);
123 
124 /* Receive fd over sock (must be a unix domain socket) from other
125  * process.  Return sock if ok, -1 on error, setting errno. */
126 int64 io_receivefd(int64 sock);
127 
128 int io_starteventloopthread(unsigned int threads);
129 
130 #define HAVE_IO_QUEUEFORREAD
131 /* Artificially queue a file descriptor as readable.
132  * The next call to io_canread will return this descriptor. */
133 int io_queueforread(int64 d);
134 /* Artificially queue a file descriptor as writable.
135  * The next call to io_canread will return this descriptor. */
136 int io_queueforwrite(int64 d);
137 
138 typedef int64 (*io_write_callback)(int64 s,const void* buf,uint64 n);
139 
140 /* used internally, but hey, who knows */
141 int64 io_mmapwritefile(int64 out,int64 in,uint64 off,uint64 bytes,io_write_callback writecb);
142 
143 /* only needed for debugging, will print some stats into the buffer to
144  * aid in debugging the state machine if a descriptor loops or so */
145 unsigned int io_debugstring(int64 s,char* buf,unsigned int bufsize);
146 
147 #ifdef __dietlibc__
148 #include <threads.h>
149 #else
150 #include <pthread.h>
151 #include <semaphore.h>
152 #endif
153 
154 enum { SLOTS=128 };
155 typedef struct iomux {
156   int ctx;
157   int working;	/* used to synchronize who is filling the queue */
158   unsigned int h,l; /* high, low */
159   struct {
160     int fd, events;
161   } q[SLOTS];
162 #ifdef __dietlibc__
163   mtx_t mtx;
164   cnd_t sem;
165 #else
166   sem_t sem;
167 #endif
168 } iomux_t;
169 
170 
171 /* Init master context */
172 int iom_init(iomux_t* c);
173 
174 /* Add socket to iomux */
175 enum {
176   IOM_READ=1,
177   IOM_WRITE=2,
178   IOM_ERROR=4
179 };
180 /* return -1 if error, events can be IOM_READ or IOM_WRITE */
181 int iom_add(iomux_t* c,int64 s,unsigned int events);
182 
183 /* Blocking wait for single event, timeout in milliseconds */
184 /* return -1 if error, 0 if ok; s set to fd, revents set to known events on that fd */
185 /* when done with the fd, call iom_add on it again! */
186 /* This can be called by multiple threads in parallel */
187 int iom_wait(iomux_t* c,int64* s,unsigned int* revents,unsigned long timeout);
188 
189 /* Call this to terminate all threads waiting in iom_wait */
190 int iom_abort(iomux_t* c);
191 
192 #ifdef __cplusplus
193 }
194 #endif
195 
196 #endif
197