Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-18 Thread Gregory Collins
On Tue, Oct 18, 2011 at 3:18 AM, Jason Dusek jason.du...@gmail.com wrote:
 The lazy bridging code, `lazyBridge', blocks (unsurprisingly)
 and does not allow packets to go back and forth. I think I need
 explicit selects/waits here to get the back and forth traffic.
 Maybe there is a some way to leverage GHC's internal async I/O
 but I'm not sure how to do it.

Maybe: forkIO two threads, one for the read end, one for the write
end? I would use a loop over lazy I/O, also.

G
-- 
Gregory Collins g...@gregorycollins.net

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-18 Thread Ertugrul Soeylemez
Jason Dusek jason.du...@gmail.com wrote:

  I don't think you want either of the functions you mentioned.  What
  you probably want instead is to do concurrent programming by
  creating Haskell threads.  A hundred Haskell threads reading from
  Handles are translated to one or more OS threads using whatever
  polling mechanism (select(), poll(), epoll) your operating system
  supports.
 
  I have uploaded a simple concurrent echo server implementation to
  hpaste [1]. It uses one thread for the stdout logger, one thread for
  the server, one thread for each client and finally a main thread
  waiting for you to hit enter to quit the application.
 
  [1] http://hpaste.org/52742 - Concurrent echo server with logger

 I am not sure how to apply the principle you mention to a proxy, which
 must read from and write to both handles in turn (or, ideally, as
 needed).

A proxy server acts a lot like an echo server.  The difference is that
usually before the actual proxying starts you have a negotiation phase,
and instead of echoing back to the same socket, you just write it to a
different one.  Here is an (untested) example:

(clientH, clientHost, clientPort) - accept serverSock
destH - negotiate clientH
doneVar - newEmptyMVar

forkIO (hGetContents clientH = hPutStr destH = putMVar doneVar)
forkIO (hGetContents destH = hPutStr clientH = putMVar doneVar)
replicateM_ 2 (takeMVar doneVar)
mapM_ hClose [clientH, destH]

Of course this code is going to bite you in production for two reasons:
First of all it has no error handling.  If the 'negotiate' function
throws an exception, then nobody will close the client handle.  So view
this is a highly simplified example!

The second reason is that in this lazy I/O framework it is
extraordinarily difficult to write the 'negotiate' function in the first
place, unless you allow yourself to put stuff back into the handle or
process only one byte at a time.  Both options are bad.  A better option
is to use a proper I/O abstraction suitable for protocol processing.
Iteratees [1] come to mind.  They solve this problem elegantly and let
you really just use the parser style destH - negotiate.

My usage of the MVar is actually kind of an abuse.  I just use it to
allow the two forwarder threads to signal their completion.  The main
thread just waits for the two to complete and then closes both handles.
The word abuse is perhaps too strong, because there is essentially
nothing wrong with the approach.  The standard concurrency library
doesn't provide an event primitive, so the more general MVar is often
used for this.

[1] http://www.yesodweb.com/book/enumerator


Greets,
Ertugrul


-- 
nightmare = unsafePerformIO (getWrongWife = sex)
http://ertes.de/



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-18 Thread Ertugrul Soeylemez
Michael Orlitzky mich...@orlitzky.com wrote:

  I have uploaded a simple concurrent echo server implementation to
  hpaste [1].  It uses one thread for the stdout logger, one thread
  for the server, one thread for each client and finally a main thread
  waiting for you to hit enter to quit the application.
 
  [1] http://hpaste.org/52742 - Concurrent echo server with logger

 This is a good example; you should stick it on the wiki somewhere so
 it isn't lost.

It is a good example for concurrent programming, but not a good example
for server programming.  By putting it into the wiki I would discourage
some programmers from using more suitable I/O abstractions/mechanisms.

Better let's keep it away from the wiki.


Greets,
Ertugrul


-- 
nightmare = unsafePerformIO (getWrongWife = sex)
http://ertes.de/



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-18 Thread Jason Dusek
2011/10/18 Ertugrul Soeylemez e...@ertes.de:
 A proxy server acts a lot like an echo server.  The difference is that
 usually before the actual proxying starts you have a negotiation phase,
 and instead of echoing back to the same socket, you just write it to a
 different one.  Here is an (untested) example:

    (clientH, clientHost, clientPort) - accept serverSock
    destH - negotiate clientH
    doneVar - newEmptyMVar

    forkIO (hGetContents clientH = hPutStr destH = putMVar doneVar)
    forkIO (hGetContents destH = hPutStr clientH = putMVar doneVar)
    replicateM_ 2 (takeMVar doneVar)
    mapM_ hClose [clientH, destH]

This code seems like it says:

  Allow the client to write to the server one time.

  Allow the server to write to the client one time.

  Teardown both sides of the connection.

Am I reading this correctly? This is, indeed, a proxy; but I'm
not sure it could support a wide range of protocols.

--
Jason Dusek
()  ascii ribbon campaign - against html e-mail
/\  www.asciiribbon.org   - against proprietary attachments

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-18 Thread Jason Dusek
2011/10/18 Gregory Collins g...@gregorycollins.net:
 On Tue, Oct 18, 2011 at 3:18 AM, Jason Dusek jason.du...@gmail.com wrote:
  The lazy bridging code, `lazyBridge', blocks (unsurprisingly)
  and does not allow packets to go back and forth. I think I need
  explicit selects/waits here to get the back and forth traffic.
  Maybe there is a some way to leverage GHC's internal async I/O
  but I'm not sure how to do it.

 Maybe: forkIO two threads, one for the read end, one for the write
 end? I would use a loop over lazy I/O, also.

This does work, thanks; the new version of lazyBridge is:


  lazyBridge  ::  Handle - Handle - IO ()
  lazyBridge a b   =  do forkIO (flush a b)
 forkIO (flush b a)
 return ()
   where
flush a b  =  LazyB.hGetContents a = LazyB.hPut b

  -- http://hpaste.org/52814

I am kind of surprised that this works at all, actually.

The strict version has this problem where it lets each socket
takes turns sending and receiving, if you try to send and it's
not your turn, it waits for the other one to send before sending
your data. The lazy version just sends bytes as they become
available, the desired behaviour.

I guess if I wanted to instrument the proxying, to keep a tally
of how much traffic there was (to GC little used connections,
for example), I would need to move up to enumerators?

--
Jason Dusek
()  ascii ribbon campaign - against html e-mail
/\  www.asciiribbon.org   - against proprietary attachments

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-18 Thread Jason Dusek
2011/10/18 Jason Dusek jason.du...@gmail.com:
 2011/10/18 Ertugrul Soeylemez e...@ertes.de:
  A proxy server acts a lot like an echo server.  The difference is that
  usually before the actual proxying starts you have a negotiation phase,
  and instead of echoing back to the same socket, you just write it to a
  different one.  Here is an (untested) example:
 
     (clientH, clientHost, clientPort) - accept serverSock
     destH - negotiate clientH
     doneVar - newEmptyMVar
 
     forkIO (hGetContents clientH = hPutStr destH = putMVar doneVar)
     forkIO (hGetContents destH = hPutStr clientH = putMVar doneVar)
     replicateM_ 2 (takeMVar doneVar)
     mapM_ hClose [clientH, destH]

 This code seems like it says: [...]

After working through Gregory Collins suggestion, above, I see
that I was not reading your code correctly.

--
Jason Dusek
()  ascii ribbon campaign - against html e-mail
/\  www.asciiribbon.org   - against proprietary attachments

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-17 Thread Ertugrul Soeylemez
Jason Dusek jason.du...@gmail.com wrote:

 I would like to use evented I/O for a proxying application. My present
 thinking is to fork a thread for each new connection and then to wait
 for data on either socket in this thread, writing to one or the other
 socket as needed.

 [...]

 Ideally, I'd get something like select() on handles, just saying
 whether there are bytes or not. However, I haven't managed to find
 anything like that in the standard libraries.

I don't think you want either of the functions you mentioned.  What you
probably want instead is to do concurrent programming by creating
Haskell threads.  A hundred Haskell threads reading from Handles are
translated to one or more OS threads using whatever polling mechanism
(select(), poll(), epoll) your operating system supports.

I have uploaded a simple concurrent echo server implementation to hpaste
[1].  It uses one thread for the stdout logger, one thread for the
server, one thread for each client and finally a main thread waiting for
you to hit enter to quit the application.

[1] http://hpaste.org/52742 - Concurrent echo server with logger


Greets,
Ertugrul


-- 
nightmare = unsafePerformIO (getWrongWife = sex)
http://ertes.de/



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-17 Thread Michael Orlitzky
On 10/17/11 04:58, Ertugrul Soeylemez wrote:
 
 I have uploaded a simple concurrent echo server implementation to hpaste
 [1].  It uses one thread for the stdout logger, one thread for the
 server, one thread for each client and finally a main thread waiting for
 you to hit enter to quit the application.
 
 [1] http://hpaste.org/52742 - Concurrent echo server with logger
 

This is a good example; you should stick it on the wiki somewhere so it
isn't lost.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-17 Thread Jason Dusek
2011/10/17 Ertugrul Soeylemez e...@ertes.de:
 Jason Dusek jason.du...@gmail.com wrote:
 I would like to use evented I/O for a proxying application.
 My present thinking is to fork a thread for each new
 connection and then to wait for data on either socket in this
 thread, writing to one or the other socket as needed.

 [...]

 Ideally, I'd get something like select() on handles, just
 saying whether there are bytes or not. However, I haven't
 managed to find anything like that in the standard libraries.

 I don't think you want either of the functions you mentioned.
 What you probably want instead is to do concurrent
 programming by creating Haskell threads.  A hundred Haskell
 threads reading from Handles are translated to one or more OS
 threads using whatever polling mechanism (select(), poll(),
 epoll) your operating system supports.

 I have uploaded a simple concurrent echo server implementation
 to hpaste [1]. It uses one thread for the stdout logger, one
 thread for the server, one thread for each client and finally
 a main thread waiting for you to hit enter to quit the
 application.

 [1] http://hpaste.org/52742 - Concurrent echo server with logger

I am not sure how to apply the principle you mention to a proxy,
which must read from and write to both handles in turn (or,
ideally, as needed).

Here's a little demo that uses hWaitForInput and strict
ByteStrings as well as plain hGetContents with lazy ByteStrings:

  http://hpaste.org/52777

You can load it in GHC and try out the strict/hWaitForInput
version like this:

   proxy (PortNumber 9001) (PortNumber 9000) strictBridge

Then run, in this order, in two terminals:

 :; nc -l -k 9000  # The proxied backend server.
 :; nc localhost 9001  # The nominal client.

Now you can type text on the client side, hit return and see it
on the server side and then vice versa.

The lazy bridging code, `lazyBridge', blocks (unsurprisingly)
and does not allow packets to go back and forth. I think I need
explicit selects/waits here to get the back and forth traffic.
Maybe there is a some way to leverage GHC's internal async I/O
but I'm not sure how to do it.

--
Jason Dusek
()  ascii ribbon campaign - against html e-mail
/\  www.asciiribbon.org   - against proprietary attachments

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Waiting on input with `hWaitForInput' or `threadWaitRead'

2011-10-17 Thread Jason Dusek
2011/10/18 Jason Dusek jason.du...@gmail.com:
 ...load it in GHC and...

s/GHC/GHCi/

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe