flx_demuxconfig


Start data section to config/demux.fpc[1 /1 ]
     1: Name: demux
     2: Description: Event handling
     3: Version: $Id: flx_demuxconfig.pak 1405 2007-04-21 19:31:57Z skaller $
     4: 
     5: provides_dlib: -ldemux_dynamic
     6: provides_slib: -ldemux_static
     7: Requires: flx_pthread
     8: flx_requires_driver: flx_arun
     9: 
End data section to config/demux.fpc[1]
Start python section to spkgs/demux.py[1 /1 ]
     1: #line 31 "./lpsrc/flx_demuxconfig.pak"
     2: 
     3: DEMUXRTL_INTERFACES = [
     4:  'demux/flx_demux.hpp',       # portable
     5:  'demux/demux_demuxer.hpp',       # portable
     6:  'demux/demux_posix_demuxer.hpp', # posix
     7:  'demux/demux_timer_queue.hpp',   # portable
     8:  'demux/demux_quitter.hpp',       # portable
     9:  'demux/demux_posix_timer_queue.hpp',   # posix
    10:  'demux/demux_pfileio.hpp',       # posix
    11:  'demux/demux_select_demuxer.hpp',# posix
    12:  'demux/demux_iocp_demuxer.hpp',  # win32 (monolithic)
    13:  'demux/demux_overlapped.hpp',    # win32
    14:  'demux/demux_win_timer_queue.hpp',  # win32
    15:  'demux/demux_kqueue_demuxer.hpp',# osx(10.3 onwards)/bsd
    16:  'demux/demux_evtport_demuxer.hpp',# solaris (9 onwards?)
    17:  'demux/demux_epoll_demuxer.hpp',# linux (>= 2.6)
    18:  'demux/demux_sockety.hpp',       # posix
    19:  'demux/demux_self_piper.hpp',    # posix
    20:  'demux/demux_wself_piper.hpp',   # win32
    21:  'demux/demux_ts_select_demuxer.hpp',
    22:  'demux/demux_poll_demuxer.hpp',  # linux, 10.3 (select impl), 10.4 real.
    23:  'demux/demux_ts_poll_demuxer.hpp',  # idem
    24: ]
    25: 
    26: DEMUX_CPPS = [
    27:   "demux/flx_demux",
    28:   "demux/demux_demuxer",
    29:   "demux/demux_quitter",
    30: ]
    31: 
    32: POSIX_DEMUX_CPPS = [
    33:   "demux/demux_posix_demuxer",      # posix
    34:   "demux/demux_select_demuxer",     # posix
    35:   "demux/demux_posix_timer_queue",  # posix
    36:   "demux/demux_sockety",            # posix
    37:   "demux/demux_self_piper",         # posix
    38:   "demux/demux_pfileio",            # posix
    39:   'demux/demux_ts_select_demuxer',  # posix
    40: ]
    41: 
    42: POLL_DEMUX_CPPS = [
    43:    # I've seen poll on linux and osx10.4 systems.
    44:    # conditionally compiled and used.
    45:   'demux/demux_poll_demuxer',       # I've seen this on linux and osx10.4
    46:   'demux/demux_ts_poll_demuxer',    # ditto
    47: ]
    48: 
    49: WINDOWS_DEMUX_CPPS = [
    50:   "demux/demux_iocp_demuxer",       # windows
    51:   "demux/demux_overlapped",         # windows
    52:   "demux/demux_wself_piper",        # windows
    53:   "demux/demux_win_timer_queue",    # windows
    54: ]
    55: 
    56: EXTRA_SYS_LIBS = ""
    57: if WIN32:
    58:   DEMUX_CPPS = DEMUX_CPPS + WINDOWS_DEMUX_CPPS
    59:   if HAVE_MSVC:
    60:     EXTRA_SYS_LIBS = "/DEFAULTLIB:ws2_32 /DEFAULTLIB:mswsock "
    61:   else:
    62:     # mingw
    63:     EXTRA_SYS_LIBS = "-lws2_32 -lmswsock "
    64: 
    65: 
    66: if POSIX:
    67:   DEMUX_CPPS = DEMUX_CPPS + POSIX_DEMUX_CPPS
    68: 
    69: if HAVE_KQUEUE_DEMUXER:
    70:   DEMUX_CPPS = DEMUX_CPPS + [ "demux/demux_kqueue_demuxer" ]
    71: 
    72: if HAVE_POLL:
    73:   DEMUX_CPPS = DEMUX_CPPS + POLL_DEMUX_CPPS
    74: 
    75: if HAVE_EPOLL:
    76:   DEMUX_CPPS = DEMUX_CPPS + [ "demux/demux_epoll_demuxer" ] # Linux 2.6 +
    77: 
    78: if HAVE_EVTPORTS:
    79:   DEMUX_CPPS = DEMUX_CPPS + [ "demux/demux_evtport_demuxer"] # solaris 10
    80: 
    81: if SOLARIS:
    82:   # RF: this might not be necessary anymore.
    83:   EXTRA_SYS_LIBS = "-lsocket -lnsl "
    84: 
    85: cpp_cpps = DEMUX_CPPS
    86: rtl_interfaces = DEMUXRTL_INTERFACES
    87: pkg_requires = ['flx_pthread', 'flx_rtl'] # flx_rtl for config .hpp
    88: lib_requires = ['libflx_pthread']  # however libflx not needed
    89: dflags = EXTRA_SYS_LIBS
    90: sflags = EXTRA_SYS_LIBS
    91: iscr_source = [
    92:   "lpsrc/flx_demux.pak",
    93:   "lpsrc/flx_demuxconfig.pak",
    94:   ]
    95: build_macro = "DEMUX"
    96: weaver_directory = 'doc/rtl/flx_demux/'
    97: 
End python section to spkgs/demux.py[1]
Start cpp section to demux/demux_sockety.cpp[1 /1 ]
     1: #line 129 "./lpsrc/flx_demuxconfig.pak"
     2: #include "demux_sockety.hpp" /* for this stuff */
     3: 
     4: #include <stdio.h>        /* for perror */
     5: #include <fcntl.h>        /* for making non blocking sockets */
     6: #include <netinet/in.h>     /* for sockaddr_in */
     7: #include <arpa/inet.h>      /* for inet_addr */
     8: #include <unistd.h>       /* for close */
     9: 
    10: #include <netinet/in.h>     /* IPPROTO_TCP and sockaddr_in */
    11: #include <netinet/tcp.h>    /* TCP_NODELAY */
    12: 
    13: #include <sys/types.h>      /* for accept */
    14: #include <sys/socket.h>
    15: //#include <sys/errno.h>    /* EINPROGRESS (GUSI doesn't like both this and errno.h)*/
    16: 
    17: #include <errno.h>        /* errno */
    18: 
    19: #include <string.h>       /* for memset */
    20: 
    21: typedef socklen_t FLX_SOCKLEN_T;
    22: 
    23: namespace flx { namespace demux {
    24: 
    25: /*
    26:  returns a socket ready for listening (AF_INET, SOCK_STREAM for now).
    27:  0 in for port means let kernel decide, result in *io_port
    28:  portable, can be factored out. listens on all NICs.
    29:  returns -1 on failure, sometimes eats errno.
    30:  p.s. sets SO_REUSEADDR.
    31: */
    32: int
    33: create_listener_socket(int* io_port, int q_len)
    34: {
    35:   int         listener;
    36:   int         yes = 1;  /* for address reuse */
    37: 
    38:   if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    39:     return -1;
    40: 
    41:   /* get rid of those *pesky* "address already in use" errors. */
    42:   /* for when you don't cleanly shutdown the server */
    43:   if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
    44:     goto listener_fail;
    45: 
    46:   /* bind listener to local interface (ANY) */
    47:   if(bind_sock(listener, io_port) == -1)
    48:     goto listener_fail;
    49: 
    50:   /* set listen queue length for socket */
    51:   if(listen(listener, q_len) == -1)
    52:     goto listener_fail;
    53: 
    54:   return listener;
    55: 
    56: listener_fail:
    57:   perror("create_listener_socket"); /* eats errno! */
    58:   if(close(listener) == -1)
    59:     perror("create_listener_socket close");
    60:   return -1;
    61: }
    62: 
    63: /* create listener, make it non-blocking */
    64: /* duh, sometimes eats errno...*/
    65: int
    66: create_async_listener(int* io_port, int q_len)
    67: {
    68:   int   listener;
    69: 
    70:   listener = create_listener_socket(io_port, q_len);
    71: 
    72:   if(-1 == listener) return -1;
    73: 
    74:   if(make_nonblock(listener) == -1)
    75:   {
    76:     if(close(listener) != 0)
    77:       perror("create_async_listener close");
    78:     return -1;
    79:   }
    80: 
    81:   return listener;
    82: }
    83: 
    84: /* ps, sets resulting socket to non-block. some people would say that */
    85: /* this WASN'T nice, so change the name some time. returns socket or -1 */
    86: /* on failure, with *err containing the error code. on success returns 0 */
    87: /* with zero (= no error) in *err */
    88: int
    89: nice_accept(int listener, int* err)
    90: {
    91:   struct sockaddr_in  remoteaddr;
    92:   /*socklen_t     addrlen = sizeof(remoteaddr);*/
    93:   /* os x 10.2.8 doesn't have socklen_t. will this work elsewhere? */
    94:   /* 10.4 (gcc 4.0) complains about signedeness, so now unsigned */
    95:   FLX_SOCKLEN_T addrlen = sizeof(remoteaddr);
    96:   int         newfd;
    97: 
    98:   *err = 0;     /* assume all good */
    99: 
   100:   newfd = accept(listener, (struct sockaddr*)&remoteaddr, &addrlen);
   101:   if(-1 == newfd) {
   102:     *err = errno;
   103:     return -1;
   104:   }
   105:   else
   106:   {
   107:     /*I think 0's the result I want*/
   108:     if(make_nonblock(newfd) == -1)
   109:     {
   110:       *err = errno;
   111: 
   112:       /* bizarre case, note that close's errno is lost */
   113:       if(close(newfd) == -1)
   114:         perror("nice_accept can't set non-block");
   115:       newfd = -1;
   116:     }
   117:     // Linger does nothing good in non-blocking mode
   118:     else if(make_linger(newfd, 30) == -1)
   119:     {
   120:       *err = errno;
   121: 
   122:       // bizarre case, note that close's errno is lost
   123:       if(close(newfd) == -1)
   124:         perror("nice_accept can't set linger");
   125:       newfd = -1;
   126:     }
   127:   }
   128:   return newfd;
   129: }
   130: 
   131: /* call this connect_ipv4? would its interface work for ipv6? */
   132: /* this connect can be either asynchronous or synchronous, */
   133: /* depending on whether or not the socket is non blocking */
   134: /* returns -1 with err in errno on failure */
   135: int
   136: connect_sock(int s, const char* addr, int port)
   137: {
   138:   struct sockaddr_in  sock_addr;
   139: 
   140:   memset(&sock_addr, 0, sizeof(sock_addr));
   141:   sock_addr.sin_family = AF_INET;     /* host byte order */
   142:   sock_addr.sin_addr.s_addr = inet_addr(addr);
   143:   sock_addr.sin_port = htons(port);
   144: 
   145:   return connect(s, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
   146: }
   147: 
   148: /* bind s to local address with given port number, or zero to let OS */
   149: /* choose. can you bind to non-local addresses? not sure, but you might */
   150: /* like to choose which local interface... (ADD OTHER INTERFACES HERE) */
   151: /* returns -1 on failure with error code in errno */
   152: int
   153: bind_sock(int s, int* io_port)
   154: {
   155:   struct sockaddr_in  addr;
   156:   FLX_SOCKLEN_T namelen = sizeof(addr);
   157: 
   158:   memset(&addr, 0, sizeof(addr));
   159:   addr.sin_family = AF_INET;      /* host byte order */
   160:   /* make the NIC an argument */
   161:   addr.sin_addr.s_addr = htonl(INADDR_ANY); /* allow multihomed */
   162:   addr.sin_port = htons(*io_port);
   163: 
   164:   /* bind to port */
   165:   if (bind(s, (struct sockaddr *)&addr, namelen) < 0)
   166:   {
   167:     return -1;
   168:   }
   169: 
   170:   /* we don't need to do this when the port was specified */
   171:   if(0 == *io_port)
   172:   {
   173:     /* Find out what port number was chosen */
   174:     if (getsockname(s, (struct sockaddr *)&addr, &namelen) < 0)
   175:     {
   176:       return -1;
   177:     }
   178: 
   179:     *io_port = ntohs(addr.sin_port);
   180:   }
   181: 
   182:   return 0; /* success! */
   183: }
   184: 
   185: /* simple wrapper for fcntl for those too lazy to look it up */
   186: /* returns -1 on failure with errno set or non -1  otherwise */
   187: int
   188: make_nonblock(int s)
   189: {
   190:   int old = fcntl(s, F_GETFL,0);
   191:   if (old == -1) return old;
   192:   return fcntl(s, F_SETFL, O_NONBLOCK | old );
   193: }
   194: 
   195: int
   196: make_linger(int s, int t)
   197: {
   198:   return 0;
   199:   /*
   200:   struct linger ling;
   201:   ling.l_onoff = 1; // on
   202:   ling.l_linger = t;
   203:   return setsockopt(s, SOL_SOCKET, SO_LINGER,&ling, sizeof(ling));
   204:   */
   205: }
   206: 
   207: 
   208: /* returns -1 on failure with errno set or 0 otherwise */
   209: int
   210: set_tcp_nodelay(int s, int disable_nagle)
   211: {
   212:   return setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
   213:     (char*)&disable_nagle, sizeof(disable_nagle));
   214: }
   215: 
   216: /*
   217:     Getting the determining if the async connect succeeded and if not,
   218:     its error, can actually be quite hairy on some systems, see
   219:     http://cr.yp.to/docs/connect.html
   220:     for suggestions (none of which I follow at this point)
   221:   returns 0 on success and socket error in *socket_err
   222:   on failure returns -1 and *socket_err errno
   223: */
   224: int
   225: get_socket_error(int s, int* socket_err)
   226: {
   227:   int       res;
   228:     FLX_SOCKLEN_T len = sizeof(*socket_err);
   229:     /* god knows what the level should be. socket level seems sensible. */
   230:     res = getsockopt(s, SOL_SOCKET, SO_ERROR, socket_err, &len);
   231: 
   232:     /* I've heard of impls of getsockopt(SO_ERROR) acting as they they */
   233:     /* had the socket error (i.e. returning -1 and the sock err in errno) */
   234:     if(-1 == res)
   235:     {
   236:         *socket_err = errno;     // don't think its ours
   237:         fprintf(stderr, "getsockopt failed - is that our error? (%i)\n",
   238:             *socket_err);
   239:     }
   240: 
   241:   return res;
   242: }
   243: 
   244: /* also make non-blocking AFTER connect, that is, */
   245: /* this is a synchronous connect */
   246: /* is eating errno, fix */
   247: int
   248: nice_connect(const char* addr, int port)
   249: {
   250:   int     s;
   251: 
   252:   if((s = socket(AF_INET, SOCK_STREAM, 0)) != -1
   253:     && connect_sock(s, addr, port) == 0
   254:     && make_nonblock(s) != -1)
   255:   {
   256:     return s;   /* success! */
   257:   }
   258: 
   259:   /* something happened (not as good as catch 22) */
   260:   perror("nice_connect");
   261: 
   262:   if(-1 != s && close(s) != 0)
   263:     perror("nice close");
   264: 
   265:   return -1;
   266: }
   267: 
   268: /* makes the socket non-blocking BEFORE connect, returns result */
   269: /* from which can be determined if it finished immediately */
   270: /* returns the socket & finished flag or -1 on failure, with the */
   271: /* error returned in *err */
   272: int
   273: async_connect(const char* addr, int port, int* finished, int* err)
   274: {
   275:   int     s = -1;
   276: 
   277:   if((s = socket(AF_INET, SOCK_STREAM, 0)) != -1 && make_nonblock(s) != -1)
   278:   {
   279:     /* no error we now have s, a non-blocking socket */
   280:     if(connect_sock(s, addr, port) == 0)
   281:     {
   282:       *err = 0;         /* no error */
   283:       *finished = 1;        /* finished */
   284:       return s;
   285:     }
   286: 
   287:     *err = errno;         /* connect failed or in-progress */
   288: 
   289:     /* this can apparently be EWOULDBLOCK or even EAGAIN on some systems */
   290:     /* any info? on some systems they're the same, on some they're not */
   291:     if(EINPROGRESS == *err)
   292:     {
   293:       *finished = 0;        /* not finished, in progress */
   294:       return s;
   295:     }
   296:     /* some other failure, fall through and clean up */
   297:   }
   298: 
   299:   /* hope you can read same errno twice in threaded apps! */
   300:   *err = errno;           /* pass back error */
   301: 
   302:   if(-1 != s && close(s) != 0)    /* we lose the close error */
   303:     perror("async_connect close");
   304: 
   305:   *finished = 1;            /* for completeness */
   306:   return -1;
   307: }
   308: }}
   309: 
End cpp section to demux/demux_sockety.cpp[1]