Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1.  Implementing a toy network proxy (Patrick LeBoutillier)
   2. Re:  Implementing a toy network proxy (Michael Snoyman)
   3.  generating arbitrary parameter lists (Amy de Buitl?ir)
   4. Re:  Implementing a toy network proxy (Patrick LeBoutillier)
   5. Re:  Implementing a toy network proxy (Michael Snoyman)
   6. Re:  generating arbitrary parameter lists (Edward Z. Yang)
   7. Re:  generating arbitrary parameter lists (Amy de Buitl?ir)


----------------------------------------------------------------------

Message: 1
Date: Thu, 23 Sep 2010 13:13:53 -0400
From: Patrick LeBoutillier <[email protected]>
Subject: [Haskell-beginners] Implementing a toy network proxy
To: beginners <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

Hi ,

I'm trying to write a toy generic network proxy that will accept
connections on a port, and for each connection connect
to a remote server and forward the traffic.


Here's what I have do far:


import Network
import System.IO
import Control.Exception
import Control.Concurrent


copy :: Handle -> Handle -> IO ()
copy a b = undefined


redir :: Handle -> Handle -> IO ()
redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()


acceptLoop :: Socket -> HostName -> PortID -> IO ()
acceptLoop sock rhost rport = loop
  where loop = do
         (local, host, port) <- accept sock
         remote <- connectTo rhost rport
         redir local remote
         loop >> return ()


main = do
  let local_port = 8000
  let remote_host = "whatever"
  let remote_port = 80
  server <- listenOn (PortNumber local_port)
  acceptLoop server remote_host (PortNumber remote_port)



Basically I'm stuck at how to implement the copy function. I want it
to block until some data is available on a,
read it and then write it to b.

I think I need to use hGetBufNonBlocking, but I don't know how to get a "Ptr a".

I am on the right track with this?


Patrick
-- 
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada


------------------------------

Message: 2
Date: Thu, 23 Sep 2010 19:26:06 +0200
From: Michael Snoyman <[email protected]>
Subject: Re: [Haskell-beginners] Implementing a toy network proxy
To: Patrick LeBoutillier <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

It might be easier to use bytestrings instead of Ptr (). I think the
relevant function is hGetNonBlocking[1].

Cheers,
Michael

[1] 
http://hackage.haskell.org/packages/archive/bytestring/0.9.1.7/doc/html/Data-ByteString.html#v:hGetNonBlocking

On Thu, Sep 23, 2010 at 7:13 PM, Patrick LeBoutillier
<[email protected]> wrote:
> Hi ,
>
> I'm trying to write a toy generic network proxy that will accept
> connections on a port, and for each connection connect
> to a remote server and forward the traffic.
>
>
> Here's what I have do far:
>
>
> import Network
> import System.IO
> import Control.Exception
> import Control.Concurrent
>
>
> copy :: Handle -> Handle -> IO ()
> copy a b = undefined
>
>
> redir :: Handle -> Handle -> IO ()
> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
>
>
> acceptLoop :: Socket -> HostName -> PortID -> IO ()
> acceptLoop sock rhost rport = loop
>  where loop = do
>         (local, host, port) <- accept sock
>         remote <- connectTo rhost rport
>         redir local remote
>         loop >> return ()
>
>
> main = do
>  let local_port = 8000
>  let remote_host = "whatever"
>  let remote_port = 80
>  server <- listenOn (PortNumber local_port)
>  acceptLoop server remote_host (PortNumber remote_port)
>
>
>
> Basically I'm stuck at how to implement the copy function. I want it
> to block until some data is available on a,
> read it and then write it to b.
>
> I think I need to use hGetBufNonBlocking, but I don't know how to get a "Ptr 
> a".
>
> I am on the right track with this?
>
>
> Patrick
> --
> =====================
> Patrick LeBoutillier
> Rosemère, Québec, Canada
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>


------------------------------

Message: 3
Date: Thu, 23 Sep 2010 22:56:39 +0100
From: Amy de Buitl?ir <[email protected]>
Subject: [Haskell-beginners] generating arbitrary parameter lists
To: beginners <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

Whenever I want to use quickCheck to test some function with multiple
input parameters, I end up writing boilerplate code that looks like
the example below. I have a feeling I'm missing out on some good
Haskell tricks. In particular, writing a function like arbXYZ for
every combination of parameter types that I need to test is a bit
repetitive. Is there a better way?

Thank you in advance,
Amy

----- code example -----

functionIWantToTest :: Double -> Int -> Bool -> Double
functionIWantToTest x y z = 27  -- pretend we're doing something useful

arbXYZ :: Gen (Double, Int, Bool)
arbXYZ = do
  x <- choose (0.0, 1.0)
  y <- choose (1, 10)
  z <- arbitrary
  return (x, y, z)

conditionIWantToCheck :: (Double, Int, Bool) -> Bool
conditionIWantToCheck (x, y, z) = True -- pretend we're checking something

prop_i_want_to_check :: Property
prop_i_want_to_check = forAll arbXYZ conditionIWantToCheck


------------------------------

Message: 4
Date: Thu, 23 Sep 2010 19:18:11 -0400
From: Patrick LeBoutillier <[email protected]>
Subject: Re: [Haskell-beginners] Implementing a toy network proxy
To: Michael Snoyman <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

Ok, finally I wound up with this:

import Network
import System.IO
import Control.Concurrent
import IO (hWaitForInput)
import System.IO.Error (try)
import qualified Data.ByteString as B


copy :: Handle -> Handle -> IO ()
copy a b = do
  r <- try $ hWaitForInput a (-1)
  buf <- case r of
           Right _ -> B.hGetNonBlocking a 4096
           Left err -> return B.empty
  if B.null buf
    then hClose a >> hClose b
    else B.hPut b buf >> copy a b


main = do
  let lport = 8000
  let rhost = "idefix"
  let rport = 80

  listenOn (PortNumber lport) >>= acceptLoop rhost rport

  where
    acceptLoop rhost rport server = do
      (local, _, _) <- accept server
      hSetBuffering local NoBuffering
      forkIO $ do
        remote <- connectTo rhost (PortNumber rport)
        hSetBuffering remote NoBuffering
        redir local remote
      acceptLoop rhost rport server

    redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1)


That seems to do the job, but it feels a bit clunky when I do a manual
telnet through it.
Do I have to compile/run it in a special way to make the forkIOs
really parallelize?

It also feels like the hCloses are not happening immediately. Is there
anything I can do about that?


Thanks a lot,

Patrick



On Thu, Sep 23, 2010 at 1:26 PM, Michael Snoyman <[email protected]> wrote:
> It might be easier to use bytestrings instead of Ptr (). I think the
> relevant function is hGetNonBlocking[1].
>
> Cheers,
> Michael
>
> [1] 
> http://hackage.haskell.org/packages/archive/bytestring/0.9.1.7/doc/html/Data-ByteString.html#v:hGetNonBlocking
>
> On Thu, Sep 23, 2010 at 7:13 PM, Patrick LeBoutillier
> <[email protected]> wrote:
>> Hi ,
>>
>> I'm trying to write a toy generic network proxy that will accept
>> connections on a port, and for each connection connect
>> to a remote server and forward the traffic.
>>
>>
>> Here's what I have do far:
>>
>>
>> import Network
>> import System.IO
>> import Control.Exception
>> import Control.Concurrent
>>
>>
>> copy :: Handle -> Handle -> IO ()
>> copy a b = undefined
>>
>>
>> redir :: Handle -> Handle -> IO ()
>> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
>>
>>
>> acceptLoop :: Socket -> HostName -> PortID -> IO ()
>> acceptLoop sock rhost rport = loop
>>  where loop = do
>>         (local, host, port) <- accept sock
>>         remote <- connectTo rhost rport
>>         redir local remote
>>         loop >> return ()
>>
>>
>> main = do
>>  let local_port = 8000
>>  let remote_host = "whatever"
>>  let remote_port = 80
>>  server <- listenOn (PortNumber local_port)
>>  acceptLoop server remote_host (PortNumber remote_port)
>>
>>
>>
>> Basically I'm stuck at how to implement the copy function. I want it
>> to block until some data is available on a,
>> read it and then write it to b.
>>
>> I think I need to use hGetBufNonBlocking, but I don't know how to get a "Ptr 
>> a".
>>
>> I am on the right track with this?
>>
>>
>> Patrick
>> --
>> =====================
>> Patrick LeBoutillier
>> Rosemère, Québec, Canada
>> _______________________________________________
>> Beginners mailing list
>> [email protected]
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>



-- 
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada


------------------------------

Message: 5
Date: Fri, 24 Sep 2010 02:33:56 +0200
From: Michael Snoyman <[email protected]>
Subject: Re: [Haskell-beginners] Implementing a toy network proxy
To: Patrick LeBoutillier <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

I just tried the code on my system; worked great for an SSH session.
Maybe you want to try with the multithreaded runtime, ie:

ghc --make -threaded filename.hs

On Fri, Sep 24, 2010 at 1:18 AM, Patrick LeBoutillier
<[email protected]> wrote:
> Ok, finally I wound up with this:
>
> import Network
> import System.IO
> import Control.Concurrent
> import IO (hWaitForInput)
> import System.IO.Error (try)
> import qualified Data.ByteString as B
>
>
> copy :: Handle -> Handle -> IO ()
> copy a b = do
>  r <- try $ hWaitForInput a (-1)
>  buf <- case r of
>           Right _ -> B.hGetNonBlocking a 4096
>           Left err -> return B.empty
>  if B.null buf
>    then hClose a >> hClose b
>    else B.hPut b buf >> copy a b
>
>
> main = do
>  let lport = 8000
>  let rhost = "idefix"
>  let rport = 80
>
>  listenOn (PortNumber lport) >>= acceptLoop rhost rport
>
>  where
>    acceptLoop rhost rport server = do
>      (local, _, _) <- accept server
>      hSetBuffering local NoBuffering
>      forkIO $ do
>        remote <- connectTo rhost (PortNumber rport)
>        hSetBuffering remote NoBuffering
>        redir local remote
>      acceptLoop rhost rport server
>
>    redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1)
>
>
> That seems to do the job, but it feels a bit clunky when I do a manual
> telnet through it.
> Do I have to compile/run it in a special way to make the forkIOs
> really parallelize?
>
> It also feels like the hCloses are not happening immediately. Is there
> anything I can do about that?
>
>
> Thanks a lot,
>
> Patrick
>
>
>
> On Thu, Sep 23, 2010 at 1:26 PM, Michael Snoyman <[email protected]> wrote:
>> It might be easier to use bytestrings instead of Ptr (). I think the
>> relevant function is hGetNonBlocking[1].
>>
>> Cheers,
>> Michael
>>
>> [1] 
>> http://hackage.haskell.org/packages/archive/bytestring/0.9.1.7/doc/html/Data-ByteString.html#v:hGetNonBlocking
>>
>> On Thu, Sep 23, 2010 at 7:13 PM, Patrick LeBoutillier
>> <[email protected]> wrote:
>>> Hi ,
>>>
>>> I'm trying to write a toy generic network proxy that will accept
>>> connections on a port, and for each connection connect
>>> to a remote server and forward the traffic.
>>>
>>>
>>> Here's what I have do far:
>>>
>>>
>>> import Network
>>> import System.IO
>>> import Control.Exception
>>> import Control.Concurrent
>>>
>>>
>>> copy :: Handle -> Handle -> IO ()
>>> copy a b = undefined
>>>
>>>
>>> redir :: Handle -> Handle -> IO ()
>>> redir h1 h2 = forkIO (copy h1 h2) >> forkIO (copy h2 h1) >> return ()
>>>
>>>
>>> acceptLoop :: Socket -> HostName -> PortID -> IO ()
>>> acceptLoop sock rhost rport = loop
>>>  where loop = do
>>>         (local, host, port) <- accept sock
>>>         remote <- connectTo rhost rport
>>>         redir local remote
>>>         loop >> return ()
>>>
>>>
>>> main = do
>>>  let local_port = 8000
>>>  let remote_host = "whatever"
>>>  let remote_port = 80
>>>  server <- listenOn (PortNumber local_port)
>>>  acceptLoop server remote_host (PortNumber remote_port)
>>>
>>>
>>>
>>> Basically I'm stuck at how to implement the copy function. I want it
>>> to block until some data is available on a,
>>> read it and then write it to b.
>>>
>>> I think I need to use hGetBufNonBlocking, but I don't know how to get a 
>>> "Ptr a".
>>>
>>> I am on the right track with this?
>>>
>>>
>>> Patrick
>>> --
>>> =====================
>>> Patrick LeBoutillier
>>> Rosemère, Québec, Canada
>>> _______________________________________________
>>> Beginners mailing list
>>> [email protected]
>>> http://www.haskell.org/mailman/listinfo/beginners
>>>
>>
>
>
>
> --
> =====================
> Patrick LeBoutillier
> Rosemère, Québec, Canada
>


------------------------------

Message: 6
Date: Thu, 23 Sep 2010 23:57:19 -0400
From: "Edward Z. Yang" <[email protected]>
Subject: Re: [Haskell-beginners] generating arbitrary parameter lists
To: Amy de Buitl?ir <[email protected]>
Cc: beginners <[email protected]>
Message-ID: <1285300447-sup-2...@ezyang>
Content-Type: text/plain; charset=UTF-8

Hello Andy,

Gen is a funny typeclass, in particular I can write something like:

prop_foo x y z = {- do something with x y z -}

and QuickCheck will automatically fill in x, y, z using arbitrary from
the inferred type classes.  This will work fine for z but no so much
for x and y in your example, in which case you can create newtypes
that encodes things like [bounded from 0.0 to 1.0], etc.

I often find hanging lambda style with forAll to be quite palatable,
so I frequently find myself writing things like:

conditionIWantToCheck z =
    forAll (choose (0.0, 1.0)) $ \x ->
    forAll (choose (1, 10)) $ \y ->
    {- condition -}

Especially when the inner forAlls have dependencies on earlier forAlls,
this style is quite natural.

Cheers,
Edward

Excerpts from Amy de Buitléir's message of Thu Sep 23 17:56:39 -0400 2010:
> Whenever I want to use quickCheck to test some function with multiple
> input parameters, I end up writing boilerplate code that looks like
> the example below. I have a feeling I'm missing out on some good
> Haskell tricks. In particular, writing a function like arbXYZ for
> every combination of parameter types that I need to test is a bit
> repetitive. Is there a better way?
> 
> Thank you in advance,
> Amy
> 
> ----- code example -----
> 
> functionIWantToTest :: Double -> Int -> Bool -> Double
> functionIWantToTest x y z = 27  -- pretend we're doing something useful
> 
> arbXYZ :: Gen (Double, Int, Bool)
> arbXYZ = do
>   x <- choose (0.0, 1.0)
>   y <- choose (1, 10)
>   z <- arbitrary
>   return (x, y, z)
> 
> conditionIWantToCheck :: (Double, Int, Bool) -> Bool
> conditionIWantToCheck (x, y, z) = True -- pretend we're checking something
> 
> prop_i_want_to_check :: Property
> prop_i_want_to_check = forAll arbXYZ conditionIWantToCheck


------------------------------

Message: 7
Date: Fri, 24 Sep 2010 17:33:57 +0100
From: Amy de Buitl?ir <[email protected]>
Subject: Re: [Haskell-beginners] generating arbitrary parameter lists
To: "Edward Z. Yang" <[email protected]>
Cc: beginners <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

Thank you, Edward. That hanging lambda style looks particularly useful
for my purposes.


------------------------------

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 27, Issue 52
*****************************************

Reply via email to