jabberd2  2.3.4
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  fcntl(fd, F_SETFL, flags);
114 #elif defined(HAVE_IOCTL)
115  flags = 1;
116  ioctl(fd, FIONBIO, &flags);
117 #endif
118 
119  return mio_fd;
120 }
121 
123 static void _mio_close(mio_t m, mio_fd_t fd)
124 {
125  if(FD(m,fd)->type == type_CLOSED)
126  return;
127 
128  mio_debug(ZONE,"actually closing fd #%d", fd->fd);
129 
130  /* take out of poll sets */
131  MIO_REMOVE_FD(m, FD(m,fd));
132 
133  /* let the app know, it must process any waiting write data it has and free it's arg */
134  if (FD(m,fd)->app != NULL)
135  ACT(m, fd, action_CLOSE, NULL);
136 
137  /* close the socket, and reset all memory */
138  close(fd->fd);
139  FD(m,fd)->type = type_CLOSED;
140  FD(m,fd)->app = NULL;
141  FD(m,fd)->arg = NULL;
142 
143  if (MIO_CAN_FREE(m))
144  {
145  MIO_FREE_FD(m, fd);
146  }
147 }
148 
150 static void _mio_accept(mio_t m, mio_fd_t fd)
151 {
152  struct sockaddr_storage serv_addr;
153  socklen_t addrlen = (socklen_t) sizeof(serv_addr);
154  int newfd;
155  mio_fd_t mio_fd;
156  char ip[INET6_ADDRSTRLEN];
157 
158  mio_debug(ZONE, "accepting on fd #%d", fd->fd);
159 
160  /* pull a socket off the accept queue and check */
161  newfd = accept(fd->fd, (struct sockaddr*)&serv_addr, &addrlen);
162  if(newfd <= 0) return;
163  if(addrlen <= 0) {
164  close(newfd);
165  return;
166  }
167 
168  j_inet_ntop(&serv_addr, ip, sizeof(ip));
169  mio_debug(ZONE, "new socket accepted fd #%d, %s:%d", newfd, ip, j_inet_getport(&serv_addr));
170 
171  /* set up the entry for this new socket */
172  mio_fd = _mio_setup_fd(m, newfd, FD(m,fd)->app, FD(m,fd)->arg);
173 
174  if(!mio_fd) {
175  close(newfd);
176  return;
177  }
178 
179  /* tell the app about the new socket, if they reject it clean up */
180  if (ACT(m, mio_fd, action_ACCEPT, ip))
181  {
182  mio_debug(ZONE, "accept was rejected for %s:%d", ip, newfd);
183  MIO_REMOVE_FD(m, FD(m,mio_fd));
184 
185  /* close the socket, and reset all memory */
186  close(newfd);
187  MIO_FREE_FD(m, mio_fd);
188  }
189 
190  return;
191 }
192 
194 static void _mio__connect(mio_t m, mio_fd_t fd)
195 {
196  mio_type_t type = FD(m,fd)->type;
197 
198  mio_debug(ZONE, "connect processing for fd #%d", fd->fd);
199 
200  /* reset type and clear the "write" event that flags connect() is done */
201  FD(m,fd)->type = type_NORMAL;
202  MIO_UNSET_WRITE(m,FD(m,fd));
203 
204  /* if the app had asked to do anything in the meantime, do those now */
205  if(type & type_CONNECT_READ) mio_read(m,fd);
206  if(type & type_CONNECT_WRITE) mio_write(m,fd);
207 }
208 
210 static void _mio_app(mio_t m, mio_fd_t fd, mio_handler_t app, void *arg)
211 {
212  FD(m,fd)->app = app;
213  FD(m,fd)->arg = arg;
214 }
215 
217 static void _mio_run(mio_t m, int timeout)
218 {
219  int retval;
220  MIO_INIT_ITERATOR(iter);
221 
222  mio_debug(ZONE, "mio running for %d sec", timeout);
223 
224  /* wait for a socket event */
225  retval = MIO_CHECK(m, timeout);
226 
227  /* nothing to do */
228  if(retval == 0) return;
229 
230  /* an error */
231  if(retval < 0)
232  {
233  mio_debug(ZONE, "MIO_CHECK returned an error (%d)", MIO_ERROR);
234 
235  return;
236  }
237 
238  mio_debug(ZONE,"mio processing %d file descriptors", retval);
239 
240  /* loop through the sockets, check for stuff to do */
241  MIO_ITERATE_RESULTS(m, retval, iter)
242  {
243  mio_fd_t fd = MIO_ITERATOR_FD(m,iter);
244  if (fd == NULL) continue;
245 
246  /* skip already dead slots */
247  if(FD(m,fd)->type == type_CLOSED) continue;
248 
249  /* new conns on a listen socket */
250  if(FD(m,fd)->type == type_LISTEN && MIO_CAN_READ(m,iter))
251  {
252  _mio_accept(m, fd);
253  goto deferred;
254  }
255 
256  /* check for connecting sockets */
257  if(FD(m,fd)->type & type_CONNECT &&
258  (MIO_CAN_READ(m,iter) || MIO_CAN_WRITE(m,iter)))
259  {
260  _mio__connect(m, fd);
261  goto deferred;
262  }
263 
264  /* read from ready sockets */
265  if(FD(m,fd)->type == type_NORMAL && MIO_CAN_READ(m,iter))
266  {
267  /* if they don't want to read any more right now */
268  if(ACT(m, fd, action_READ, NULL) == 0)
269  MIO_UNSET_READ(m, FD(m,fd));
270  }
271 
272  /* write to ready sockets */
273  if(FD(m,fd)->type == type_NORMAL && MIO_CAN_WRITE(m,iter))
274  {
275  /* don't wait for writeability if nothing to write anymore */
276  if(ACT(m, fd, action_WRITE, NULL) == 0)
277  MIO_UNSET_WRITE(m, FD(m,fd));
278  }
279 
280  deferred:
281  /* deferred closing fd
282  * one of previous actions might change the state of fd */
283  if(FD(m,fd)->type == type_CLOSED)
284  {
285  MIO_FREE_FD(m, fd);
286  }
287  }
288 }
289 
291 static void _mio_read(mio_t m, mio_fd_t fd)
292 {
293  if(m == NULL || fd == NULL) return;
294 
295  /* if connecting, do this later */
296  if(FD(m,fd)->type & type_CONNECT)
297  {
298  FD(m,fd)->type |= type_CONNECT_READ;
299  return;
300  }
301 
302  MIO_SET_READ(m, FD(m,fd));
303 }
304 
306 static void _mio_write(mio_t m, mio_fd_t fd)
307 {
308  if(m == NULL || fd == NULL) return;
309 
310  /* if connecting, do this later */
311  if(FD(m,fd)->type & type_CONNECT)
312  {
313  FD(m,fd)->type |= type_CONNECT_WRITE;
314  return;
315  }
316 
317  if(FD(m,fd)->type != type_NORMAL)
318  return;
319 
320  if(ACT(m, fd, action_WRITE, NULL) == 0) return;
321 
322  /* not all written, do more l8r */
323  MIO_SET_WRITE(m, FD(m,fd));
324 }
325 
327 static mio_fd_t _mio_listen(mio_t m, int port, const char *sourceip, mio_handler_t app, void *arg)
328 {
329  int fd, flag = 1;
330  mio_fd_t mio_fd;
331  struct sockaddr_storage sa;
332 
333  if(m == NULL) return NULL;
334 
335  mio_debug(ZONE, "mio to listen on %d [%s]", port, sourceip);
336 
337  memset(&sa, 0, sizeof(sa));
338 
339  /* if we specified an ip to bind to */
340  if(sourceip != NULL && !j_inet_pton(sourceip, &sa))
341  return NULL;
342 
343  if(sa.ss_family == 0)
344  sa.ss_family = AF_INET;
345 
346  /* attempt to create a socket */
347  if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL;
348  if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0) return NULL;
349 
350  /* set up and bind address info */
351  j_inet_setport(&sa, port);
352  if(bind(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa)) < 0)
353  {
354  close(fd);
355  return NULL;
356  }
357 
358  /* start listening with a max accept queue specified by kern.ipc.somaxconn sysctl */
359  if(listen(fd, -1) < 0)
360  {
361  close(fd);
362  return NULL;
363  }
364 
365  /* now set us up the bomb */
366  mio_fd = _mio_setup_fd(m, fd, app, arg);
367  if(mio_fd == NULL)
368  {
369  close(fd);
370  return NULL;
371  }
372  FD(m,mio_fd)->type = type_LISTEN;
373  /* by default we read for new sockets */
374  mio_read(m,mio_fd);
375 
376  return mio_fd;
377 }
378 
380 static mio_fd_t _mio_connect(mio_t m, int port, const char *hostip, const char *srcip, mio_handler_t app, void *arg)
381 {
382  int fd, flag, flags;
383  mio_fd_t mio_fd;
384  struct sockaddr_storage sa, src;
385 
386  memset(&sa, 0, sizeof(sa));
387 
388  if(m == NULL || port <= 0 || hostip == NULL) return NULL;
389 
390  mio_debug(ZONE, "mio connecting to %s, port=%d",hostip,port);
391 
392  /* convert the hostip */
393  if(j_inet_pton(hostip, &sa)<=0) {
394  MIO_SETERROR(EFAULT);
395  return NULL;
396  }
397 
398  if(!sa.ss_family) sa.ss_family = AF_INET;
399 
400  /* attempt to create a socket */
401  if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL;
402 
403  /* Bind to the given source IP if it was specified */
404  if (srcip != NULL) {
405  /* convert the srcip */
406  if(j_inet_pton(srcip, &src)<=0) {
407  MIO_SETERROR(EFAULT);
408  return NULL;
409  }
410  if(!src.ss_family) src.ss_family = AF_INET;
411  j_inet_setport(&src, INADDR_ANY);
412  if(bind(fd,(struct sockaddr*)&src,j_inet_addrlen(&src)) < 0) {
413  close(fd);
414  return NULL;
415  }
416  }
417 
418  /* set the socket to non-blocking before connecting */
419 #if defined(HAVE_FCNTL)
420  flags = fcntl(fd, F_GETFL);
421  flags |= O_NONBLOCK;
422  fcntl(fd, F_SETFL, flags);
423 #elif defined(HAVE_IOCTL)
424  flags = 1;
425  ioctl(fd, FIONBIO, &flags);
426 #endif
427 
428  /* set up address info */
429  j_inet_setport(&sa, port);
430 
431  /* try to connect */
432  flag = connect(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa));
433 
434  mio_debug(ZONE, "connect returned %d and %s", flag, MIO_STRERROR(MIO_ERROR));
435 
436  /* already connected? great! */
437  if(flag == 0)
438  {
439  mio_fd = _mio_setup_fd(m,fd,app,arg);
440  if(mio_fd != NULL) return mio_fd;
441  }
442 
443  /* gotta wait till later */
444 #ifdef _WIN32
445  if(flag == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
446 #else
447  if(flag == -1 && errno == EINPROGRESS)
448 #endif
449  {
450  mio_fd = _mio_setup_fd(m,fd,app,arg);
451  if(mio_fd != NULL)
452  {
453  mio_debug(ZONE, "connect processing non-blocking mode");
454 
455  FD(m,mio_fd)->type = type_CONNECT;
456  MIO_SET_WRITE(m,FD(m,mio_fd));
457  return mio_fd;
458  }
459  }
460 
461  /* bummer dude */
462  close(fd);
463  return NULL;
464 }
465 
466 
468 static void _mio_free(mio_t m)
469 {
470  MIO_FREE_VARS(m);
471 
472  free(m);
473 }
474 
476 static mio_t _mio_new(int maxfd)
477 {
478  static struct mio_st mio_impl = {
479  _mio_free,
481  _mio_app,
482  _mio_close,
484  _mio_run
485  };
486  mio_t m;
487 
488  /* init winsock if we are in Windows */
489 #ifdef _WIN32
490  WSADATA wsaData;
491  if (WSAStartup(MAKEWORD( 1, 1 ), &wsaData))
492  return NULL;
493 #endif
494 
495  /* allocate and zero out main memory */
496  if((m = calloc(1, sizeof(struct mio_priv_st))) == NULL) {
497  fprintf(stderr,"Cannot allocate MIO memory! Exiting.\n");
498  exit(EXIT_FAILURE);
499  }
500 
501  /* set up our internal vars */
502  *m = &mio_impl;
503  MIO(m)->maxfd = maxfd;
504 
505  MIO_INIT_VARS(m);
506 
507  return m;
508 }
static void _mio_write(mio_t m, mio_fd_t fd)
try writing to the socket via the app
Definition: mio_impl.h:306
#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:194
#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:327
#define JABBERD2_API
Definition: mio.h:39
static void _mio_run(mio_t m, int timeout)
main select loop runner
Definition: mio_impl.h:217
static void _mio_close(mio_t m, mio_fd_t fd)
internal close function
Definition: mio_impl.h:123
#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:476
#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:291
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:380
static void _mio_free(mio_t m)
adam
Definition: mio_impl.h:468
#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:210
#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:150
#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