
I am trying to get a proxy working using the network-conduit package on windows. So I send a request to port 5002 and that gets forwarded to another port 5000 where I have a simple echo server running. I made a stab at it, but get intermittent send errors after the first connection Here is the code: {-# OPTIONS -Wall #-} import Data.Conduit import Data.Conduit.Network import Network (withSocketsDo) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Resource main::IO () main = withSocketsDo $ runTCPClient (ClientSettings 5000 "localhost") $ \src1 sink1 -> do liftIO $ print "in tcpclient section" liftIO $ withSocketsDo $ runTCPServer (ServerSettings 5002 Nothing) $ \src sink -> do liftIO $ print "in tcpserver section" _ <- liftIO $ runResourceT $ resourceForkIO $ do src1 $$ sink return () src $$ sink1 Thanks for any help, Grant

Hello. I'm not expert but first you should not use Network sockets, because everything is included into Data.Conduit.Network, just use high level API. Second, you should use not server inside client but client inside server: so you can make such a code [1]: {-# OPTIONS -Wall #-} import Data.Conduit import Data.Conduit.Network import Control.Monad.IO.Class (liftIO) import Control.Concurrent.Lifted (fork) main::IO () main = runTCPServer (ServerSettings 5002 Nothing) $ \clientSrc clientSink -> do liftIO $ runTCPClient (ClientSettings 5000 "localhost") $ \serverSrc serverSink -> do _ <- liftIO $ fork $ runResourceT $ serverSrc $$ clientSink clientSrc $$ serverSink tested and works [1] https://gist.github.com/2008113 -- Alexander V Vershilov Fri, Mar 09, 2012 at 05:44:29PM +0000, grant wrote
I am trying to get a proxy working using the network-conduit package on windows. So I send a request to port 5002 and that gets forwarded to another port 5000 where I have a simple echo server running.
I made a stab at it, but get intermittent send errors after the first connection
Here is the code: {-# OPTIONS -Wall #-} import Data.Conduit import Data.Conduit.Network import Network (withSocketsDo) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Resource
main::IO () main = withSocketsDo $ runTCPClient (ClientSettings 5000 "localhost") $ \src1 sink1 -> do liftIO $ print "in tcpclient section" liftIO $ withSocketsDo $ runTCPServer (ServerSettings 5002 Nothing) $ \src sink -> do liftIO $ print "in tcpserver section" _ <- liftIO $ runResourceT $ resourceForkIO $ do src1 $$ sink return () src $$ sink1
Thanks for any help, Grant
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

When I run the code you suggested on windows I get the following error: getAddrInfo: does not exist (error 10093) which probably refers to http://trac.haskell.org/network/ticket/32 After adding withSocketsDo I get a little further, but get the following error after sending data through the proxy: netproxy2: Network.Socket.ByteString.recv: failed (Unknown error) Any ideas? Thanks so much for your help with this. Grant

For first error it seems best way will be patching conduit-network as it done it warp [1]. I don't know how to deal with second error. [1] http://hackage.haskell.org/packages/archive/warp/1.1.0.1/doc/html/src/Networ... -- Alexander V Vershilov Fri, Mar 09, 2012 at 07:52:39PM +0000, grant wrote
When I run the code you suggested on windows I get the following error: getAddrInfo: does not exist (error 10093) which probably refers to http://trac.haskell.org/network/ticket/32
After adding withSocketsDo I get a little further, but get the following error after sending data through the proxy:
netproxy2: Network.Socket.ByteString.recv: failed (Unknown error)
Any ideas? Thanks so much for your help with this. Grant
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I've tried running the code with runTCPServer first but I get "recv: invalid argument (Bad file descriptor)" on ubuntu (virtualbox) and when running on windows I get "Network.Socket.ByteString.recv: failed (Unknown error)". Also, it seems odd that when I run this code https://gist.github.com/2010354 that it doesn't print "END serverSrc clientSink". Is this the expected behaviour or are resources not being closed? Again the same thing happens when running on Ubuntu. {- here is the output ... C:\haskell>netproxy4 START clientSrc serverSink START serverSrc clientSink END clientSrc serverSink START serverSrc clientSink START clientSrc serverSink END clientSrc serverSink -} Thanks for any ideas. Grant

As it seems from code runTCPServer registers socket close and TCPClient runs it in bracket so all open resources should be closed. It my last try I add _ <- register $ killThread tId after forking serverSrc $$ clientSink, to kill outter thread explicilty otherwise it closes thread with error.
Is this the expected behaviour or are resources not being closed?
In 'strace' log it seems that both sockets is closed. So I think that computation is closed before reaching the end because src $$ sink closed with error. If you want to run action at the end you can register it -- Alexander V Vershilov Sat, Mar 10, 2012 at 05:43:12AM +0000, grant wrote
I've tried running the code with runTCPServer first but I get "recv: invalid argument (Bad file descriptor)" on ubuntu (virtualbox) and when running on windows I get "Network.Socket.ByteString.recv: failed (Unknown error)".
Also, it seems odd that when I run this code https://gist.github.com/2010354 that it doesn't print "END serverSrc clientSink". Is this the expected behaviour or are resources not being closed? Again the same thing happens when running on Ubuntu.
{- here is the output ... C:\haskell>netproxy4 START clientSrc serverSink START serverSrc clientSink END clientSrc serverSink START serverSrc clientSink START clientSrc serverSink END clientSrc serverSink -}
Thanks for any ideas. Grant
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Excellent. registering killThread works great. Hopefully the library will be fixed correctly. Thanks a lot for your help, Grant

I think I missed something in this thread. What's the bug in
network-conduit? I'd like to have it patched in the next release.
On Sat, Mar 10, 2012 at 9:19 AM, grant
Excellent. registering killThread works great. Hopefully the library will be fixed correctly. Thanks a lot for your help, Grant
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Unfortunately I don't have a solution to this. Here is some code and output that hopefully explains what is happening https://gist.github.com/2012723 The problem is that the clientSrc $$ serverSink appears to run and according to Alexander, the socket closes. But the thread seems to hang inside the "clientSrc $$ serverSink" command and then nothing after that command is run (until the process is terminated). I would have expected the register command to run and the statement "END clientSrc serverSink" to display. When I kill the process on Ubuntu all three exceptions are then thrown at once and the rest of the thread continue. Thanks for taking a look at this, Grant

Seems to work perfectly for me. The statement you're expecting to be
printed won't be printed until the original server (running on 5000)
closes its socket. If I connect it to Warp, this takes about 30
seconds, which is the slowloris timeout period.
On Sat, Mar 10, 2012 at 10:01 PM, grant
Unfortunately I don't have a solution to this.
Here is some code and output that hopefully explains what is happening https://gist.github.com/2012723
The problem is that the clientSrc $$ serverSink appears to run and according to Alexander, the socket closes. But the thread seems to hang inside the "clientSrc $$ serverSink" command and then nothing after that command is run (until the process is terminated).
I would have expected the register command to run and the statement "END clientSrc serverSink" to display. When I kill the process on Ubuntu all three exceptions are then thrown at once and the rest of the thread continue.
Thanks for taking a look at this, Grant
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

The problem is, how would I then go about creating a proxy like tcpmon? I was going to replace this code 'clientSrc $$ serverSink' with this 'clientSrc $$ (sinkFork (sinkFile "randomname") serverSink' and the same for the 'serverSrc $$ clientSink' part. However, since the 'clientSrc $$ serverSink' part will be suspended until the process has ended, I would be holding on to open resources for the whole time. Is there a better way to create this proxy? Thanks, Grant

You're running `clientSrc $$ serverSink` in a separate thread. What
it's doing is blocking for any kind of input from clientSrc before it
can continue. That thread knows nothing about the rest of the program,
including that serverSink is closed. This is inherent to the network
functions involved here.
It seems like this is a perfect time to pull out killThread, as
Alexander mentioned. It's a way to send a signal to a blocked thread,
which is what you have here. All of the conduit libraries have been
designed from the ground up to work correctly with asynchronous
exceptions, and all resources will be freed correctly. Is there a
specific reason why this seems like the wrong approach here?
Michael
On Sat, Mar 10, 2012 at 11:12 PM, grant
The problem is, how would I then go about creating a proxy like tcpmon?
I was going to replace this code 'clientSrc $$ serverSink' with this 'clientSrc $$ (sinkFork (sinkFile "randomname") serverSink' and the same for the 'serverSrc $$ clientSink' part.
However, since the 'clientSrc $$ serverSink' part will be suspended until the process has ended, I would be holding on to open resources for the whole time.
Is there a better way to create this proxy?
Thanks, Grant
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thanks for explaining the problem. I guess I have to ditch my preconceived notions (based on using Java/.Net) that killing a thread is dangerous. Thanks again, Grant

Sun, Mar 11, 2012 at 05:16:06PM +0000, grant wrote
Thanks for explaining the problem. I guess I have to ditch my preconceived notions (based on using Java/.Net) that killing a thread is dangerous. Thanks again, Grant
Don't know if it's a good way, but if you are afraid of killing thread you can use thread communication like you can use asynchronous exceptions or channels. So you can do smth like: (sourceClient $= CL.map Left) >=< (sourceTMChan communicationChannel $= CL.map Right) And have all data in Left and all commands in Right. This is really overkill for such a task but it can be usefull for more complicated ones, where there are communication between threads. -- Alexander V Vershilov

So you can do smth like:
(sourceClient $= CL.map Left) >=< (sourceTMChan communicationChannel $= CL.map Right)
Alexander V Vershilov
That's a great idea, I'll give that a try. I was having an odd problem with killThread on windows where the first character would be lost in the next session straight after the killThread, so your idea looks more appealing. Thanks again, Grant
participants (3)
-
Alexander V Vershilov
-
grant
-
Michael Snoyman