1: #line 31 "./lpsrc/flx_demuxconfig.pak"
2:
3: DEMUXRTL_INTERFACES = [
4: 'demux/flx_demux.hpp',
5: 'demux/demux_demuxer.hpp',
6: 'demux/demux_posix_demuxer.hpp',
7: 'demux/demux_timer_queue.hpp',
8: 'demux/demux_quitter.hpp',
9: 'demux/demux_posix_timer_queue.hpp',
10: 'demux/demux_pfileio.hpp',
11: 'demux/demux_select_demuxer.hpp',
12: 'demux/demux_iocp_demuxer.hpp',
13: 'demux/demux_overlapped.hpp',
14: 'demux/demux_win_timer_queue.hpp',
15: 'demux/demux_kqueue_demuxer.hpp',
16: 'demux/demux_evtport_demuxer.hpp',
17: 'demux/demux_epoll_demuxer.hpp',
18: 'demux/demux_sockety.hpp',
19: 'demux/demux_self_piper.hpp',
20: 'demux/demux_wself_piper.hpp',
21: 'demux/demux_ts_select_demuxer.hpp',
22: 'demux/demux_poll_demuxer.hpp',
23: 'demux/demux_ts_poll_demuxer.hpp',
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",
34: "demux/demux_select_demuxer",
35: "demux/demux_posix_timer_queue",
36: "demux/demux_sockety",
37: "demux/demux_self_piper",
38: "demux/demux_pfileio",
39: 'demux/demux_ts_select_demuxer',
40: ]
41:
42: POLL_DEMUX_CPPS = [
43:
44:
45: 'demux/demux_poll_demuxer',
46: 'demux/demux_ts_poll_demuxer',
47: ]
48:
49: WINDOWS_DEMUX_CPPS = [
50: "demux/demux_iocp_demuxer",
51: "demux/demux_overlapped",
52: "demux/demux_wself_piper",
53: "demux/demux_win_timer_queue",
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:
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" ]
77:
78: if HAVE_EVTPORTS:
79: DEMUX_CPPS = DEMUX_CPPS + [ "demux/demux_evtport_demuxer"]
80:
81: if SOLARIS:
82:
83: EXTRA_SYS_LIBS = "-lsocket -lnsl "
84:
85: cpp_cpps = DEMUX_CPPS
86: rtl_interfaces = DEMUXRTL_INTERFACES
87: pkg_requires = ['flx_pthread', 'flx_rtl']
88: lib_requires = ['libflx_pthread']
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:
1: #line 129 "./lpsrc/flx_demuxconfig.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
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:
118: else if(make_linger(newfd, 30) == -1)
119: {
120: *err = errno;
121:
122:
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;
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:
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;
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: