A simple TCP client, adding TLS support

I am writing a little program that needs to fetch some information over the network.

Using Network.Simple.TCP I connect to a host:port and get a Socket back. Using System.IO I can use socketToHandle to get a “file” handle, and I then use hPutStrLn and hGetLine on the handle. Easy.

Now I want to be able to do the same for a server using TLS. With Network.Simple.TCP.TLS I get a Context back instead of a Socket. How can I get a “file” handle from that? I can’t figure that out.

Should I be going about this a completely different way?

I would like to keep the code that sends and receives the same, so I can fetch from non-TLS and TLS with the same “dialogue”.

Should I be using different libraries?

The servers I am talking to talk nntp/nntps, and the back-and-forth is really simple (send “group GROUPNAME”, receive “200 OK”, send “article NUMBER”, receive some lines of text).

2 Likes

It seems that you have to make a wrapper type for Handle to use the server code both for TLS and a plain socket.
Unfortunately, it’s very hard (or maybe impossible) to make such a virtual “Handle” which can be read/write via TLS.
I recommend you to make a wrapper record type of functions to read/write via both Handle and Context. That must be much easier.

E.g.

data MyHandle = MyHandle
  { myRead :: IO ByteString
  , myWrite :: ByteString -> IO ()
  , myClose :: IO ()
  }

myHandleForHandle :: Handle -> MyHandle
myHandleForHandle h = MyHandle
  { myRead = hGetContents h
  , myWrite = hPutStr h
  }

NOTE: You can also achieve your goal by a type class.

Thanks for your reply.

My first goal was to not have to reimplement hGetLine and hPutStrLn for Network.Simple.TCP.TLS’s Context - if I understand you correctly, your suggestion is for solving the follow up goal of not having to write the same code for both with and without TLS. Do you have any ideas about the first?

1 Like