jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris, Christof Meerwald 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 /* 00022 MIO -- Managed Input/Output 00023 --------------------------- 00024 */ 00025 00026 #include "util/inaddr.h" 00027 00028 /* win32 wrappers around strerror */ 00029 #ifdef _WIN32 00030 #define close(x) closesocket(x) 00031 JABBERD2_API char *mio_strerror(int code) 00032 { 00033 static char buff[1024]; 00034 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buff, sizeof(buff), NULL)) 00035 return buff; 00036 return strerror(code); 00037 } 00038 #endif /* _WIN32 */ 00039 00041 typedef enum { 00042 type_CLOSED = 0x00, 00043 type_NORMAL = 0x01, 00044 type_LISTEN = 0x02, 00045 type_CONNECT = 0x10, 00046 type_CONNECT_READ = 0x11, 00047 type_CONNECT_WRITE = 0x12 00048 } mio_type_t; 00049 typedef struct mio_priv_fd_st 00050 { 00051 struct mio_fd_st mio_fd; 00052 00053 mio_type_t type; 00054 /* app event handler and data */ 00055 mio_handler_t app; 00056 void *arg; 00057 00058 MIO_FD_VARS 00059 } *mio_priv_fd_t; 00060 00062 typedef struct mio_priv_st 00063 { 00064 struct mio_st *mio; 00065 00066 int maxfd; 00067 MIO_VARS 00068 } *mio_priv_t; 00069 00070 /* lazy factor */ 00071 #define MIO(m) ((mio_priv_t) m) 00072 #define FD(m,f) ((mio_priv_fd_t) f) 00073 #define ACT(m,f,a,d) (*(FD(m,f)->app))(m,a,&FD(m,f)->mio_fd,d,FD(m,f)->arg) 00074 00075 /* temp debug outputter */ 00076 #define ZONE __LINE__ 00077 #ifndef MIO_DEBUG 00078 #define MIO_DEBUG 0 00079 #endif 00080 #define mio_debug if(MIO_DEBUG) _mio_debug 00081 static void _mio_debug(int line, const char *msgfmt, ...) 00082 { 00083 va_list ap; 00084 va_start(ap,msgfmt); 00085 fprintf(stderr,"mio.c#%d: ",line); 00086 vfprintf(stderr,msgfmt,ap); 00087 va_end(ap); 00088 fprintf(stderr,"\n"); 00089 } 00090 00091 MIO_FUNCS 00092 00094 static mio_fd_t _mio_setup_fd(mio_t m, int fd, mio_handler_t app, void *arg) 00095 { 00096 int flags; 00097 mio_fd_t mio_fd; 00098 00099 mio_debug(ZONE, "adding fd #%d", fd); 00100 00101 mio_fd = MIO_ALLOC_FD(m, fd); 00102 if (mio_fd == NULL) return NULL; 00103 00104 /* ok to process this one, welcome to the family */ 00105 FD(m,mio_fd)->type = type_NORMAL; 00106 FD(m,mio_fd)->app = app; 00107 FD(m,mio_fd)->arg = arg; 00108 00109 /* set the socket to non-blocking */ 00110 #if defined(HAVE_FCNTL) 00111 flags = fcntl(fd, F_GETFL); 00112 flags |= O_NONBLOCK; 00113 fcntl(fd, F_SETFL, flags); 00114 #elif defined(HAVE_IOCTL) 00115 flags = 1; 00116 ioctl(fd, FIONBIO, &flags); 00117 #endif 00118 00119 return mio_fd; 00120 } 00121 00123 static void _mio_close(mio_t m, mio_fd_t fd) 00124 { 00125 if(FD(m,fd)->type == type_CLOSED) 00126 return; 00127 00128 mio_debug(ZONE,"actually closing fd #%d", fd->fd); 00129 00130 /* take out of poll sets */ 00131 MIO_REMOVE_FD(m, FD(m,fd)); 00132 00133 /* let the app know, it must process any waiting write data it has and free it's arg */ 00134 if (FD(m,fd)->app != NULL) 00135 ACT(m, fd, action_CLOSE, NULL); 00136 00137 /* close the socket, and reset all memory */ 00138 close(fd->fd); 00139 FD(m,fd)->type = type_CLOSED; 00140 FD(m,fd)->app = NULL; 00141 FD(m,fd)->arg = NULL; 00142 00143 if (MIO_CAN_FREE(m)) 00144 { 00145 MIO_FREE_FD(m, fd); 00146 } 00147 } 00148 00150 static void _mio_accept(mio_t m, mio_fd_t fd) 00151 { 00152 struct sockaddr_storage serv_addr; 00153 socklen_t addrlen = (socklen_t) sizeof(serv_addr); 00154 int newfd; 00155 mio_fd_t mio_fd; 00156 char ip[INET6_ADDRSTRLEN]; 00157 00158 mio_debug(ZONE, "accepting on fd #%d", fd->fd); 00159 00160 /* pull a socket off the accept queue and check */ 00161 newfd = accept(fd->fd, (struct sockaddr*)&serv_addr, &addrlen); 00162 if(newfd <= 0) return; 00163 if(addrlen <= 0) { 00164 close(newfd); 00165 return; 00166 } 00167 00168 j_inet_ntop(&serv_addr, ip, sizeof(ip)); 00169 mio_debug(ZONE, "new socket accepted fd #%d, %s:%d", newfd, ip, j_inet_getport(&serv_addr)); 00170 00171 /* set up the entry for this new socket */ 00172 mio_fd = _mio_setup_fd(m, newfd, FD(m,fd)->app, FD(m,fd)->arg); 00173 00174 if(!mio_fd) { 00175 close(newfd); 00176 return; 00177 } 00178 00179 /* tell the app about the new socket, if they reject it clean up */ 00180 if (ACT(m, mio_fd, action_ACCEPT, ip)) 00181 { 00182 mio_debug(ZONE, "accept was rejected for %s:%d", ip, newfd); 00183 MIO_REMOVE_FD(m, FD(m,mio_fd)); 00184 00185 /* close the socket, and reset all memory */ 00186 close(newfd); 00187 MIO_FREE_FD(m, mio_fd); 00188 } 00189 00190 return; 00191 } 00192 00194 static void _mio__connect(mio_t m, mio_fd_t fd) 00195 { 00196 mio_type_t type = FD(m,fd)->type; 00197 00198 mio_debug(ZONE, "connect processing for fd #%d", fd->fd); 00199 00200 /* reset type and clear the "write" event that flags connect() is done */ 00201 FD(m,fd)->type = type_NORMAL; 00202 MIO_UNSET_WRITE(m,FD(m,fd)); 00203 00204 /* if the app had asked to do anything in the meantime, do those now */ 00205 if(type & type_CONNECT_READ) mio_read(m,fd); 00206 if(type & type_CONNECT_WRITE) mio_write(m,fd); 00207 } 00208 00210 static void _mio_app(mio_t m, mio_fd_t fd, mio_handler_t app, void *arg) 00211 { 00212 FD(m,fd)->app = app; 00213 FD(m,fd)->arg = arg; 00214 } 00215 00217 static void _mio_run(mio_t m, int timeout) 00218 { 00219 int retval; 00220 MIO_INIT_ITERATOR(iter); 00221 00222 mio_debug(ZONE, "mio running for %d sec", timeout); 00223 00224 /* wait for a socket event */ 00225 retval = MIO_CHECK(m, timeout); 00226 00227 /* nothing to do */ 00228 if(retval == 0) return; 00229 00230 /* an error */ 00231 if(retval < 0) 00232 { 00233 mio_debug(ZONE, "MIO_CHECK returned an error (%d)", MIO_ERROR); 00234 00235 return; 00236 } 00237 00238 mio_debug(ZONE,"mio processing %d file descriptors", retval); 00239 00240 /* loop through the sockets, check for stuff to do */ 00241 MIO_ITERATE_RESULTS(m, retval, iter) 00242 { 00243 mio_fd_t fd = MIO_ITERATOR_FD(m,iter); 00244 if (fd == NULL) continue; 00245 00246 /* skip already dead slots */ 00247 if(FD(m,fd)->type == type_CLOSED) continue; 00248 00249 /* new conns on a listen socket */ 00250 if(FD(m,fd)->type == type_LISTEN && MIO_CAN_READ(m,iter)) 00251 { 00252 _mio_accept(m, fd); 00253 goto deferred; 00254 } 00255 00256 /* check for connecting sockets */ 00257 if(FD(m,fd)->type & type_CONNECT && 00258 (MIO_CAN_READ(m,iter) || MIO_CAN_WRITE(m,iter))) 00259 { 00260 _mio__connect(m, fd); 00261 goto deferred; 00262 } 00263 00264 /* read from ready sockets */ 00265 if(FD(m,fd)->type == type_NORMAL && MIO_CAN_READ(m,iter)) 00266 { 00267 /* if they don't want to read any more right now */ 00268 if(ACT(m, fd, action_READ, NULL) == 0) 00269 MIO_UNSET_READ(m, FD(m,fd)); 00270 } 00271 00272 /* write to ready sockets */ 00273 if(FD(m,fd)->type == type_NORMAL && MIO_CAN_WRITE(m,iter)) 00274 { 00275 /* don't wait for writeability if nothing to write anymore */ 00276 if(ACT(m, fd, action_WRITE, NULL) == 0) 00277 MIO_UNSET_WRITE(m, FD(m,fd)); 00278 } 00279 00280 deferred: 00281 /* deferred closing fd 00282 * one of previous actions might change the state of fd */ 00283 if(FD(m,fd)->type == type_CLOSED) 00284 { 00285 MIO_FREE_FD(m, fd); 00286 } 00287 } 00288 } 00289 00291 static void _mio_read(mio_t m, mio_fd_t fd) 00292 { 00293 if(m == NULL || fd == NULL) return; 00294 00295 /* if connecting, do this later */ 00296 if(FD(m,fd)->type & type_CONNECT) 00297 { 00298 FD(m,fd)->type |= type_CONNECT_READ; 00299 return; 00300 } 00301 00302 MIO_SET_READ(m, FD(m,fd)); 00303 } 00304 00306 static void _mio_write(mio_t m, mio_fd_t fd) 00307 { 00308 if(m == NULL || fd == NULL) return; 00309 00310 /* if connecting, do this later */ 00311 if(FD(m,fd)->type & type_CONNECT) 00312 { 00313 FD(m,fd)->type |= type_CONNECT_WRITE; 00314 return; 00315 } 00316 00317 if(FD(m,fd)->type != type_NORMAL) 00318 return; 00319 00320 if(ACT(m, fd, action_WRITE, NULL) == 0) return; 00321 00322 /* not all written, do more l8r */ 00323 MIO_SET_WRITE(m, FD(m,fd)); 00324 } 00325 00327 static mio_fd_t _mio_listen(mio_t m, int port, char *sourceip, mio_handler_t app, void *arg) 00328 { 00329 int fd, flag = 1; 00330 mio_fd_t mio_fd; 00331 struct sockaddr_storage sa; 00332 00333 if(m == NULL) return NULL; 00334 00335 mio_debug(ZONE, "mio to listen on %d [%s]", port, sourceip); 00336 00337 memset(&sa, 0, sizeof(sa)); 00338 00339 /* if we specified an ip to bind to */ 00340 if(sourceip != NULL && !j_inet_pton(sourceip, &sa)) 00341 return NULL; 00342 00343 if(sa.ss_family == 0) 00344 sa.ss_family = AF_INET; 00345 00346 /* attempt to create a socket */ 00347 if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL; 00348 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0) return NULL; 00349 00350 /* set up and bind address info */ 00351 j_inet_setport(&sa, port); 00352 if(bind(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa)) < 0) 00353 { 00354 close(fd); 00355 return NULL; 00356 } 00357 00358 /* start listening with a max accept queue specified by kern.ipc.somaxconn sysctl */ 00359 if(listen(fd, -1) < 0) 00360 { 00361 close(fd); 00362 return NULL; 00363 } 00364 00365 /* now set us up the bomb */ 00366 mio_fd = _mio_setup_fd(m, fd, app, arg); 00367 if(mio_fd == NULL) 00368 { 00369 close(fd); 00370 return NULL; 00371 } 00372 FD(m,mio_fd)->type = type_LISTEN; 00373 /* by default we read for new sockets */ 00374 mio_read(m,mio_fd); 00375 00376 return mio_fd; 00377 } 00378 00380 static mio_fd_t _mio_connect(mio_t m, int port, char *hostip, char *srcip, mio_handler_t app, void *arg) 00381 { 00382 int fd, flag, flags; 00383 mio_fd_t mio_fd; 00384 struct sockaddr_storage sa, src; 00385 00386 memset(&sa, 0, sizeof(sa)); 00387 00388 if(m == NULL || port <= 0 || hostip == NULL) return NULL; 00389 00390 mio_debug(ZONE, "mio connecting to %s, port=%d",hostip,port); 00391 00392 /* convert the hostip */ 00393 if(j_inet_pton(hostip, &sa)<=0) { 00394 MIO_SETERROR(EFAULT); 00395 return NULL; 00396 } 00397 00398 if(!sa.ss_family) sa.ss_family = AF_INET; 00399 00400 /* attempt to create a socket */ 00401 if((fd = socket(sa.ss_family,SOCK_STREAM,0)) < 0) return NULL; 00402 00403 /* Bind to the given source IP if it was specified */ 00404 if (srcip != NULL) { 00405 /* convert the srcip */ 00406 if(j_inet_pton(srcip, &src)<=0) { 00407 MIO_SETERROR(EFAULT); 00408 return NULL; 00409 } 00410 if(!src.ss_family) src.ss_family = AF_INET; 00411 j_inet_setport(&src, INADDR_ANY); 00412 if(bind(fd,(struct sockaddr*)&src,j_inet_addrlen(&src)) < 0) { 00413 close(fd); 00414 return NULL; 00415 } 00416 } 00417 00418 /* set the socket to non-blocking before connecting */ 00419 #if defined(HAVE_FCNTL) 00420 flags = fcntl(fd, F_GETFL); 00421 flags |= O_NONBLOCK; 00422 fcntl(fd, F_SETFL, flags); 00423 #elif defined(HAVE_IOCTL) 00424 flags = 1; 00425 ioctl(fd, FIONBIO, &flags); 00426 #endif 00427 00428 /* set up address info */ 00429 j_inet_setport(&sa, port); 00430 00431 /* try to connect */ 00432 flag = connect(fd,(struct sockaddr*)&sa,j_inet_addrlen(&sa)); 00433 00434 mio_debug(ZONE, "connect returned %d and %s", flag, MIO_STRERROR(MIO_ERROR)); 00435 00436 /* already connected? great! */ 00437 if(flag == 0) 00438 { 00439 mio_fd = _mio_setup_fd(m,fd,app,arg); 00440 if(mio_fd != NULL) return mio_fd; 00441 } 00442 00443 /* gotta wait till later */ 00444 #ifdef _WIN32 00445 if(flag == -1 && WSAGetLastError() == WSAEWOULDBLOCK) 00446 #else 00447 if(flag == -1 && errno == EINPROGRESS) 00448 #endif 00449 { 00450 mio_fd = _mio_setup_fd(m,fd,app,arg); 00451 if(mio_fd != NULL) 00452 { 00453 mio_debug(ZONE, "connect processing non-blocking mode"); 00454 00455 FD(m,mio_fd)->type = type_CONNECT; 00456 MIO_SET_WRITE(m,FD(m,mio_fd)); 00457 return mio_fd; 00458 } 00459 } 00460 00461 /* bummer dude */ 00462 close(fd); 00463 return NULL; 00464 } 00465 00466 00468 static void _mio_free(mio_t m) 00469 { 00470 MIO_FREE_VARS(m); 00471 00472 free(m); 00473 } 00474 00476 static mio_t _mio_new(int maxfd) 00477 { 00478 static struct mio_st mio_impl = { 00479 _mio_free, 00480 _mio_listen, _mio_connect, _mio_setup_fd, 00481 _mio_app, 00482 _mio_close, 00483 _mio_write, _mio_read, 00484 _mio_run 00485 }; 00486 mio_t m; 00487 00488 /* init winsock if we are in Windows */ 00489 #ifdef _WIN32 00490 WSADATA wsaData; 00491 if (WSAStartup(MAKEWORD( 1, 1 ), &wsaData)) 00492 return NULL; 00493 #endif 00494 00495 /* allocate and zero out main memory */ 00496 if((m = calloc(1, sizeof(struct mio_priv_st))) == NULL) { 00497 fprintf(stderr,"Cannot allocate MIO memory! Exiting.\n"); 00498 exit(EXIT_FAILURE); 00499 } 00500 00501 /* set up our internal vars */ 00502 *m = &mio_impl; 00503 MIO(m)->maxfd = maxfd; 00504 00505 MIO_INIT_VARS(m); 00506 00507 return m; 00508 }