Just some notes! See src/tools/dflx_web.flx! Step 1: Set up server listening socket on PORT.
var PORT=1234; // port to listen on val qlen = 10; // length of queue var listener: Socket::socket_t; // server socket Socket::mk_listener(&listener, &PORT, qlen); Step 2: Listen and spawn forever { var s:Socket:: socket_t; // socket bound to incoming connection Socket::accept(listener, &s); // blocking this fibre (mainline) var h = handler s; // create handler procedure for socket spawn_fthread h; // spawn a fibre to handle the connection }; Step 3: Write the handler noinline proc handler (var k:Socket::socket_t) () { var line: string; get_line(k, &line); // should be the GET line. ..... get_line is mysterious! src/lib/std/io/stream.flx: noinline proc get_line[istr with IByteStream[istr]] ( and we have: proc write_string[ostr with OByteStream[ostr]] ( and in src/lib/std/socket.flx: instance Stream::IByteStream[socket_t] instance Stream::OByteStream[socket_t] So .. sockets provide I/O streams of bytes. Now the hard bit. Yes, you get a rant! Sockets are CRAP. There you go. There's no good way to close a socket. Serious design stupidity. Here's the best I could come up with: //////////////////////////////////////////////////////////// Faio::sleep(clock,DELAY); // give OS time to empty its buffers fprint$ cstderr,"fthread socket "+str k+" shutdown now\n"; // try this: // Advised by: koettermar...@gmx.de, MANY THANKS! gen hack_recv: socket_t * &char * int * int -> int = "recv($1,$2,$3,$4)"; var buf:char ^1025; var counter = 0; var extra = 0; shutdown(k,1); // shutdown read retry:> var b = hack_recv(k,C_hack::cast[&char] (&buf),1024,0); //println$ "Error code " + str b + " from read after shutdown"; if b > 0 do extra += b; if extra > 2000 do println$ "Read too many extraneous bytes from OS buffer"; goto force_close; done; goto retry; elif b == -1 do ++counter; if counter > 200 do println "Timeout waiting for write buffers to be flushed"; goto force_close; done; Faio::sleep(clock,0.1); // 100 ms goto retry; done; assert b==0; force_close:> Socket::shutdown(k,2); ioclose(k); fprint$ cstderr,"fthread "+str k+" terminating!\n"; The basic problem is this. If you just close an async socket the OS is allowed by Posix to simply flush all its buffers. So stuff you write won't go to the client. Indeed Linux really DOES do this stupidity. For synchronous sockets, there is "hang" parameter which makes the close call hang about for a period of time, and return an error if the buffers didn't get flushed, or no error if they are. But this option doesn't work with asynchronous sockets because close always returns immediately. What's more shutdown is a load of crud as well. In fact the whole idea of a bidirectional socket is wrong. What you have to do is shutdown the read side of the socket, then loop around reading until you get 0 bytes. Two other things can happen: you get >0 bytes read, which you ignore (because you're trying to shut down the socket, you don't care what the client is asking for!) Or you get an error code -1, meaning, there are no bytes to read, but it isn't EOF yet either! In that case you sleep a bit and try again. When you get 0 bytes, that's a "for sure the client has shutdown their end of the connection", and its safe to close our end now, even if there are bytes in the OS write buffer, because the client isn't going to read them. So we shutdown our write end then close the socket. The "hack_recv" you see above is a low level asynchronous read operation. Unfortunately we have to therefore sleep. We must not wait about because that would block the pthread. So we sleep which only blocks the fibre. The problem with this crap is that the fibre and socket remain alive for 100ms, even if the buffers were empty 1ms after the sleep starts. This means the server has too many sockets open: more than it needs. Which exposes it to a DNS attack. Note Felix doesn't have proper I/O that is safe. If you read from a socket, you will wait until you get what you ask for (or an error). There is no timed wait. There should be! Generally there are two way to DNS attack a server. 1. FLOOD IT. The server tries to read a file and it gets a lot more than it bargained for. Can be thwarted by a limit. 2. STARVE IT. The server tries to read a file and gets nothing. The client just sends one byte and stops, or sends very slowly. Can be thwarted by a rate monitor. Even with these thwarts, which disconnect unfriendly clients, you have to wait a while to establish the client is unfriendly. So you are wasting resources. So in both cases a DNS attack can be created by the simple expedient of requesting enough unfriendly connections that the server chokes. There is no way around these issues but the problem is that the way of closing a socket as shown above is just crap. Async close should just return and the OS should do the work above. The close should specify the delay the OS is allowed to wait to write its buffers: this is exactly what happens with a synchronous close after all. The parameter controlling this just doesn't work for asynchronous sockets. Sockets kill the stream I/O concepts in Felix. The ioclose function closes the socket, but you have to do the crap above first. There's no way to put that in the ioclose because ioclose is an iclose and an oclose. And note above we actually read off the socket AFTER closing the read side! Shutdown tells the client to stop writing, but the client doesn't have to obey! The client also doesn't have to read the stuff we wrote out of the OS buffers. So we really cannot wait too long for cooperation. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ CenturyLink Cloud: The Leader in Enterprise Cloud Services. Learn Why More Businesses Are Choosing CenturyLink Cloud For Critical Workloads, Development Environments & Everything In Between. Get a Quote or Start a Free Trial Today. http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language