jabberd2  2.7.0
mio_impl.h
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris, Christof Meerwald
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 /*
22  MIO -- Managed Input/Output
23  ---------------------------
24 */
25 
26 #include "util/inaddr.h"
27 
28 /* win32 wrappers around strerror */
29 #ifdef _WIN32
30 #define close(x) closesocket(x)
31 JABBERD2_API char *mio_strerror(int code)
32 {
33  static char buff[1024];
34  if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buff, sizeof(buff), NULL))
35  return buff;
36  return strerror(code);
37 }
38 #endif /* _WIN32 */
39 
41 typedef enum {
42  type_CLOSED = 0x00,
43  type_NORMAL = 0x01,
44  type_LISTEN = 0x02,
45  type_CONNECT = 0x10,
48 } mio_type_t;
49 typedef struct mio_priv_fd_st
50 {
51  struct mio_fd_st mio_fd;
52 
54  /* app event handler and data */
56  void *arg;
57 
59 } *mio_priv_fd_t;
60 
62 typedef struct mio_priv_st
63 {
64  struct mio_st *mio;
65 
66  int maxfd;
67  MIO_VARS
68 } *mio_priv_t;
69 
70 /* lazy factor */
71 #define MIO(m) ((mio_priv_t) m)
72 #define FD(m,f) ((mio_priv_fd_t) f)
73 #define ACT(m,f,a,d) (*(FD(m,f)->app))(m,a,&FD(m,f)->mio_fd,d,FD(m,f)->arg)
74 
75 /* temp debug outputter */
76 #define ZONE __LINE__
77 #ifndef MIO_DEBUG
78 #define MIO_DEBUG 0
79 #endif
80 #define mio_debug if(MIO_DEBUG) _mio_debug
81 static void _mio_debug(int line, const char *msgfmt, ...)
82 {
83  va_list ap;
84  va_start(ap,msgfmt);
85  fprintf(stderr,"mio.c#%d: ",line);
86  vfprintf(stderr,msgfmt,ap);
87  va_end(ap);
88  fprintf(stderr,"\n");
89 }
90 
92 
94 static mio_fd_t _mio_setup_fd(mio_t m, int fd, mio_handler_t app, void *arg)
95 {
96  int flags;
97  mio_fd_t mio_fd;
98 
99  mio_debug(ZONE, "adding fd #%d", fd);
100 
101  mio_fd = MIO_ALLOC_FD(m, fd);
102  if (mio_fd == NULL) return NULL;
103 
104  /* ok to process this one, welcome to the family */
105  FD(m,mio_fd)->type = type_NORMAL;
106  FD(m,mio_fd)->app = app;
107  FD(m,mio_fd)->arg = arg;
108 
109  /* set the socket to non-blocking */
110 #if defined(HAVE_FCNTL)
111  flags = fcntl(fd, F_GETFL);
112  flags |= O_NONBLOCK;
113  if(fcntl(fd, F_SETFL, flags) == -1) {
114  MIO_FREE_FD(m, mio_fd);
115  return NULL;
116  }
117 #elif defined(HAVE_IOCTL)
118  flags = 1;
119  if(ioctl(fd, FIONBIO, &flags) == -1) {
120  MIO_FREE_FD(m, mio_fd);
121  return NULL;
122  }
123 #endif
124 
125  return mio_fd;
126 }
127 
129 static void _mio_close(mio_t m, mio_fd_t fd)
130 {
131  if(FD(m,fd)->type == type_CLOSED)
132  return;
133 
134  mio_debug(ZONE,"actually closing fd #%d", fd->fd);
135 
136  /* take out of poll sets */
137  MIO_REMOVE_FD(m, FD(m,fd));
138 
139  /* let the app know, it must process any waiting write data it has and free it's arg */
140  if (FD(m,fd)->app != NULL)
141  ACT(m, fd, action_CLOSE, NULL);
142 
143  /* close the socket, and reset all memory */
144  close(fd->fd);
145  FD(m,fd)->type = type_CLOSED;
146  FD(m,fd)->app = NULL;
147  FD(m,fd)->arg = NULL;
148 
149  if (MIO_CAN_FREE(m))
150  {
151  MIO_FREE_FD(m, fd);
152  }
153 }
154 
156 static void _mio_accept(mio_t m, mio_fd_t fd)
157 {
158  struct sockaddr_storage serv_addr;
159  socklen_t addrlen = (socklen_t) sizeof(serv_addr);
160  int newfd;
161  mio_fd_t mio_fd;
162  char ip[INET6_ADDRSTRLEN];
163 
164  mio_debug(ZONE, "accepting on fd #%d", fd->fd);
165 
166  /* pull a socket off the accept queue and check */
167  newfd = accept(fd->fd, (struct sockaddr*)&serv_addr, &addrlen);
168  if(newfd < 0) return;
169  if(addrlen <= 0) {
170  close(newfd);
171  return;
172  }
173 
174  j_inet_ntop(&serv_addr, ip, sizeof(ip));
175  mio_debug(ZONE, "new socket accepted fd #%d, %s:%d", newfd, ip, j_inet_getport(&serv_addr));
176 
177  /* set up the entry for this new socket */
178  mio_fd = _mio_setup_fd(m, newfd, FD(m,fd)->app, FD(m,fd)->arg);
179 
180  if(!mio_fd) {
181  close(newfd);
182  return;
183  }
184 
185  /* tell the app about the new socket, if they reject it clean up */
186  if (ACT(m, mio_fd, action_ACCEPT, ip))
187  {
188  mio_debug(ZONE, "accept was rejected for %s:%d", ip, newfd);
189  MIO_REMOVE_FD(m, FD(m,mio_fd));
190 
191  /* close the socket, and reset all memory */
192  close(newfd);
193  MIO_FREE_FD(m, mio_fd);
194  }
195 
196  return;
197 }
198 
200 static void _mio__connect(mio_t m, mio_fd_t fd)
201 {
202  mio_type_t type = FD(m,fd)->type;
203 
204  mio_debug(ZONE, "connect processing for fd #%d", fd->fd);
205 
206  /* reset type and clear the "write" event that flags connect() is done */
207  FD(m,fd)->type = type_NORMAL;
208  MIO_UNSET_WRITE(m,FD(m,fd));
209 
210  /* if the app had asked to do anything in the meantime, do those now */
211  if(type & type_CONNECT_READ) mio_read(m,fd);
212  if(type & type_CONNECT_WRITE) mio_write(m,fd);
213 }
214 
216 static void _mio_app(mio_t m, mio_fd_t fd, mio_handler_t app, void *arg)
217 {
218  FD(m,fd)->app = app;
219  FD(m,fd)->arg = arg;
220 }
221 
223 static void _mio_run(mio_t m, int timeout)
224 {
225  int retval;
226  MIO_INIT_ITERATOR(iter);
227 
228  mio_debug(ZONE, "mio running for %d sec", timeout);
229 
230  /* wait for a socket event */
231  retval = MIO_CHECK(m, timeout);
232 
233  /* nothing to do */
234  if(retval == 0) return;
235 
236  /* an error */
237  if(retval < 0)
238  {
239  mio_debug(ZONE, "MIO_CHECK returned an error (%d)", MIO_ERROR);
240 
241  return;
242  }
243 
244  mio_debug(ZONE,"mio processing %d file descriptors", retval);
245 
246  /* loop through the sockets, check for stuff to do */
247  MIO_ITERATE_RESULTS(m, retval, iter)
248  {
249  mio_fd_t fd = MIO_ITERATOR_FD(m,iter);
250  if (fd == NULL) continue;
251 
252  /* skip already dead slots */
253  if(FD(m,fd)->type == type_CLOSED) continue;
254 
255  /* new conns on a listen socket */
256  if(FD(m,fd)->type == type_LISTEN && MIO_CAN_READ(m,iter))
257  {
258  _mio_accept(m, fd);
259  goto deferred;
260  }
261 
262  /* check for connecting sockets */
263  if(FD(m,fd)->type & type_CONNECT &&
264  (MIO_CAN_READ(m,iter) || MIO_CAN_WRITE(m,iter)))
265  {
266  _mio__connect(m, fd);
267  goto deferred;
268  }
269 
270  /* read from ready sockets */
271  if(FD(m,fd)->type == type_NORMAL && MIO_CAN_READ(m,iter))
272  {
273  /* if they don't want to read any more right now */
274  if(ACT(m, fd, action_READ, NULL) == 0)
275  MIO_UNSET_READ(m, FD(m,fd));
276  }
277 
278  /* write to ready sockets */
279  if(FD(m,fd)->type == type_NORMAL && MIO_CAN_WRITE(m,iter))
280  {
281  /* don't wait for writeability if nothing to write anymore */
282  if(ACT(m, fd, action_WRITE, NULL) == 0)
283  MIO_UNSET_WRITE(m, FD(m,fd));
284  }
285 
286  deferred:
287  /* deferred closing fd
288  * one of previous actions might change the state of fd */
289  if(FD(m,fd)->type == type_CLOSED)
290  {
291  MIO_FREE_FD(m, fd);
292  }
293  }
294 }
295 
297 static void _mio_read(mio_t m, mio_fd_t fd)
298 {
299  if(m == NULL || fd == NULL) return;
300 
301  /* if connecting, do this later */
302  if(FD(m,fd)->type & type_CONNECT)
303  {
304  FD(m,fd)->type |= type_CONNECT_READ;
305  return;
306  }
307 
308  MIO_SET_READ(m, FD(m,fd));
309 }
310 
312 static void _mio_write(mio_t m, mio_fd_t fd)
313 {
314  if(m == NULL || fd == NULL) return;
315 
316  /* if connecting, do this later */
317  if(FD(m,fd)->type & type_CONNECT)
318  {
319  FD(m,fd)->type |= type_CONNECT_WRITE;
320  return;
321  }
322 
323  if(FD(m,fd)->type != type_NORMAL)
324  return;
325 
326  if(ACT(m, fd, action_WRITE, NULL) == 0) return;
327 
328  /* not all written, do more l8r */
329  MIO_SET_WRITE(m, FD(m,fd));
330 }
331 
333 static mio_fd_t _mio_listen(mio_t m, int port, const char *sourceip, mio_handler_t app, void *arg)
334 {
335  int fd, flag = 1;
336  mio_fd_t mio_fd;
337  struct sockaddr_storage sa;
338 
339  if(m == NULL) return NULL;
340 
341  mio_debug(ZONE, "mio to listen on %d [%s]", port, sourceip);
342 
343  memset(&sa, 0, sizeof(sa));
344 
345  /* if we specified an ip to bind to */
346  if(sourceip != NULL && !j_inet_pton(sourceip, &sa))
347  return NULL;
348 
349  if(sa.ss_family == 0)
350  sa.ss_family = AF_INET;
351 
352  /* attempt to create a socket */
353  if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL;
354  if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0)
355  {
356  close(fd);
357  return NULL;
358  }
359 
360  /* set up and bind address info */
361  j_inet_setport(&sa, port);
362  if(bind(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa)) < 0)
363  {
364  close(fd);
365  return NULL;
366  }
367 
368  /* start listening with a max accept queue specified by kern.ipc.somaxconn sysctl */
369  if(listen(fd, -1) < 0)
370  {
371  close(fd);
372  return NULL;
373  }
374 
375  /* now set us up the bomb */
376  mio_fd = _mio_setup_fd(m, fd, app, arg);
377  if(mio_fd == NULL)
378  {
379  close(fd);
380  return NULL;
381  }
382  FD(m,mio_fd)->type = type_LISTEN;
383  /* by default we read for new sockets */
384  mio_read(m,mio_fd);
385 
386  return mio_fd;
387 }
388 
390 static mio_fd_t _mio_connect(mio_t m, int port, const char *hostip, const char *srcip, mio_handler_t app, void *arg)
391 {
392  int fd, flag, flags;
393  mio_fd_t mio_fd;
394  struct sockaddr_storage sa, src;
395 
396  memset(&sa, 0, sizeof(sa));
397 
398  if(m == NULL || port <= 0 || hostip == NULL) return NULL;
399 
400  mio_debug(ZONE, "mio connecting to %s, port=%d",hostip,port);
401 
402  /* convert the hostip */
403  if(j_inet_pton(hostip, &sa)<=0) {
404  MIO_SETERROR(EAFNOSUPPORT);
405  return NULL;
406  }
407 
408  if(!sa.ss_family) sa.ss_family = AF_INET;
409 
410  /* attempt to create a socket */
411  if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL;
412 
413  /* Bind to the given source IP if it was specified */
414  if (srcip != NULL) {
415  /* convert the srcip */
416  if(j_inet_pton(srcip, &src)<=0) {
417  MIO_SETERROR(EAFNOSUPPORT);
418  close(fd);
419  return NULL;
420  }
421  if(!src.ss_family) src.ss_family = AF_INET;
422  j_inet_setport(&src, INADDR_ANY);
423  if(bind(fd,(struct sockaddr*)&src,j_inet_addrlen(&src)) < 0) {
424  close(fd);
425  return NULL;
426  }
427  }
428 
429  /* set the socket to non-blocking before connecting */
430 #if defined(HAVE_FCNTL)
431  flags = fcntl(fd, F_GETFL);
432  flags |= O_NONBLOCK;
433  if(fcntl(fd, F_SETFL, flags) == -1) {
434  close(fd);
435  return NULL;
436  }
437 #elif defined(HAVE_IOCTL)
438  flags = 1;
439  if(ioctl(fd, FIONBIO, &flags) == -1) {
440  close(fd);
441  return NULL;
442  }
443 #endif
444 
445  /* set up address info */
446  j_inet_setport(&sa, port);
447 
448  /* try to connect */
449  flag = connect(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa));
450 
451  mio_debug(ZONE, "connect returned %d and %s", flag, MIO_STRERROR(MIO_ERROR));
452 
453  /* already connected? great! */
454  if(flag == 0)
455  {
456  mio_fd = _mio_setup_fd(m,fd,app,arg);
457  if(mio_fd != NULL) return mio_fd;
458  }
459 
460  /* gotta wait till later */
461 #ifdef _WIN32
462  if(flag == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
463 #else
464  if(flag == -1 && errno == EINPROGRESS)
465 #endif
466  {
467  mio_fd = _mio_setup_fd(m,fd,app,arg);
468  if(mio_fd != NULL)
469  {
470  mio_debug(ZONE, "connect processing non-blocking mode");
471 
472  FD(m,mio_fd)->type = type_CONNECT;
473  MIO_SET_WRITE(m,FD(m,mio_fd));
474  return mio_fd;
475  }
476  }
477 
478  /* bummer dude */
479  close(fd);
480  return NULL;
481 }
482 
483 
485 static void _mio_free(mio_t m)
486 {
487  MIO_FREE_VARS(m);
488 
489  free(m);
490 }
491 
493 static mio_t _mio_new(int maxfd)
494 {
495  static struct mio_st mio_impl = {
496  _mio_free,
498  _mio_app,
499  _mio_close,
501  _mio_run
502  };
503  mio_t m;
504 
505  /* init winsock if we are in Windows */
506 #ifdef _WIN32
507  WSADATA wsaData;
508  if (WSAStartup(MAKEWORD( 1, 1 ), &wsaData))
509  return NULL;
510 #endif
511 
512  /* allocate and zero out main memory */
513  if((m = calloc(1, sizeof(struct mio_priv_st))) == NULL) {
514  fprintf(stderr,"Cannot allocate MIO memory! Exiting.\n");
515  exit(EXIT_FAILURE);
516  }
517 
518  /* set up our internal vars */
519  *m = &mio_impl;
520  MIO(m)->maxfd = maxfd;
521 
522  MIO_INIT_VARS(m);
523 
524  return m;
525 }
static void _mio_write(mio_t m, mio_fd_t fd)
try writing to the socket via the app
Definition: mio_impl.h:312
#define INET6_ADDRSTRLEN
maximum length of the string representation of an IPv6 address
Definition: util_compat.h:46
#define MIO_VARS
Definition: mio_epoll.h:53
socklen_t j_inet_addrlen(struct sockaddr_storage *sa)
calculate the size of an address structure (on some unices the stdlibc functions for socket handling ...
Definition: inaddr.c:203
#define FD(m, f)
Definition: mio_impl.h:72
int j_inet_pton(const char *src, struct sockaddr_storage *dst)
set the address of a struct sockaddr_storage (modeled after the stdlib function inet_pton) ...
Definition: inaddr.c:46
#define MIO_INIT_VARS(m)
Definition: mio_epoll.h:58
static void _mio__connect(mio_t m, mio_fd_t fd)
internally change a connecting socket to a normal one
Definition: mio_impl.h:200
#define MIO_CHECK(m, t)
Definition: mio_epoll.h:88
static void _mio_debug(int line, const char *msgfmt,...)
Definition: mio_impl.h:81
#define MIO_SET_WRITE(m, mfd)
Definition: mio_epoll.h:104
#define mio_debug
Definition: mio_impl.h:80
static mio_fd_t _mio_listen(mio_t m, int port, const char *sourceip, mio_handler_t app, void *arg)
set up a listener in this mio w/ this default app/arg
Definition: mio_impl.h:333
#define JABBERD2_API
Definition: mio.h:39
static void _mio_run(mio_t m, int timeout)
main select loop runner
Definition: mio_impl.h:223
static void _mio_close(mio_t m, mio_fd_t fd)
internal close function
Definition: mio_impl.h:129
#define MIO_INIT_ITERATOR(iter)
Definition: mio_epoll.h:155
sa_family_t ss_family
address family
Definition: util_compat.h:99
#define MIO_STRERROR(e)
Definition: mio.h:170
mio_type_t type
Definition: mio_impl.h:53
#define MIO_SET_READ(m, mfd)
Definition: mio_epoll.h:90
Definition: mio.h:109
int maxfd
Definition: mio_impl.h:66
#define MIO(m)
Definition: mio_impl.h:71
static mio_t _mio_new(int maxfd)
eve
Definition: mio_impl.h:493
#define mio_read(m, fd)
process read events for this fd
Definition: mio.h:161
#define MIO_FREE_FD(m, mfd)
Definition: mio_epoll.h:76
#define MIO_UNSET_WRITE(m, mfd)
Definition: mio_epoll.h:132
#define MIO_ERROR
all MIO related routines should use those for error reporting
Definition: mio.h:168
#define MIO_REMOVE_FD(m, mfd)
Definition: mio_epoll.h:78
mio_type_t
our internal wrapper around a fd
Definition: mio_impl.h:41
struct mio_priv_st * mio_priv_t
now define our master data type
struct mio_fd_st mio_fd
Definition: mio_impl.h:51
int j_inet_getport(struct sockaddr_storage *sa)
get the port number out of a struct sockaddr_storage
Definition: inaddr.c:148
static void _mio_read(mio_t m, mio_fd_t fd)
start processing read events
Definition: mio_impl.h:297
mio_handler_t app
Definition: mio_impl.h:55
void * arg
Definition: mio_impl.h:56
static mio_fd_t _mio_connect(mio_t m, int port, const char *hostip, const char *srcip, mio_handler_t app, void *arg)
create an fd and connect to the given ip/port
Definition: mio_impl.h:390
static void _mio_free(mio_t m)
adam
Definition: mio_impl.h:485
#define MIO_CAN_FREE(m)
Definition: mio_epoll.h:153
now define our master data type
Definition: mio_impl.h:62
#define MIO_SETERROR(e)
Definition: mio.h:169
struct mio_priv_fd_st * mio_priv_fd_t
#define MIO_FREE_VARS(m)
Definition: mio_epoll.h:69
int(* mio_handler_t)(struct mio_st **m, mio_action_t a, struct mio_fd_st *fd, void *data, void *arg)
Definition: mio.h:107
#define MIO_FD_VARS
Definition: mio_epoll.h:50
#define MIO_ITERATOR_FD(m, iter)
Definition: mio_epoll.h:161
#define MIO_FUNCS
Definition: mio_epoll.h:25
int fd
Definition: mio.h:102
struct mio_st * mio
Definition: mio_impl.h:64
static void _mio_app(mio_t m, mio_fd_t fd, mio_handler_t app, void *arg)
reset app stuff for this fd
Definition: mio_impl.h:216
#define MIO_ALLOC_FD(m, rfd)
Definition: mio_epoll.h:75
Definition: mio.h:100
#define ACT(m, f, a, d)
Definition: mio_impl.h:73
#define mio_write(m, fd)
mio should try the write action on this fd now
Definition: mio.h:158
#define ZONE
Definition: mio_impl.h:76
#define MIO_CAN_READ(m, iter)
Definition: mio_epoll.h:147
static MIO_FUNCS mio_fd_t _mio_setup_fd(mio_t m, int fd, mio_handler_t app, void *arg)
add and set up this fd to this mio
Definition: mio_impl.h:94
const char * j_inet_ntop(struct sockaddr_storage *src, char *dst, size_t size)
get the string representation of an address in struct sockaddr_storage (modeled after the stdlib func...
Definition: inaddr.c:97
#define MIO_UNSET_READ(m, mfd)
Definition: mio_epoll.h:118
static void _mio_accept(mio_t m, mio_fd_t fd)
internally accept an incoming connection from a listen sock
Definition: mio_impl.h:156
#define MIO_CAN_WRITE(m, iter)
Definition: mio_epoll.h:150
int j_inet_setport(struct sockaddr_storage *sa, in_port_t port)
set the port number in a struct sockaddr_storage
Definition: inaddr.c:173
#define MIO_ITERATE_RESULTS(m, retval, iter)
Definition: mio_epoll.h:158