NineP- 9P2000 in pure Haskell

PortabilityOnly tested on GHC 6.12.1, uses TypeSynonymInstances
MaintainerDavid Leimbach <>
Safe HaskellSafe-Inferred




Module providing Binary serialization of 9P messages to and from lazy ByteStrings.

This library does not currently provide any networking support or wrappers for easy to write clients or servers, though that may come with time as we decide the best way to implement these.

9P2000 messages are sent in little endian byte order rather than network byte order (big endian)

Lightly tested against an Inferno operating system share with no authentication successfully.


Bin - a little endian encode/decode class for Binary

class Bin a whereSource


get :: Get aSource

put :: a -> PutSource

Qid - Server side data type for path tracking ( for details)

data Qid Source

A Plan 9 Qid type. See for more information




Stat - Namespace metadata (somewhat like a unix fstat)

data Stat Source

Provides information on a path entry at a 9P2000 server


Msg - envelope for 9P2000 messages

data Msg Source

The message envelope type for all 9P2000 messages




Tag - A message payload type

data Tag Source

A type that enumerates all the valid (and one invalid) message types in 9P2000


VarMsg - A data type encapsulating the various 9P messages

data VarMsg Source

A variable message type that encapsulates the valid kinds of messages in a 9P2000 payload


putVarMsg - function that can encode all VarMsg types to a lazy ByteString

putVarMsg :: VarMsg -> PutSource

For every lower level VarMsg type, encodes a full wrapper around that type for use with 9P2000 streams

getVarMsg - function to decode all VarMsg types from a lazy ByteString

getVarMsg :: Tag -> Get VarMsgSource

For every messages type, runs a Get parser to decode that type of payload from the 9P2000 stream


Exchanging initial version data with any 9P2000 server

 module Main where
 import Data.Maybe
 import Control.Monad
 import qualified Data.ByteString.Lazy.Char8 as C
 import Network.Socket hiding (send, recv)
 import Network.Socket.ByteString.Lazy
 import Data.Int
 import Data.Binary.Get
 import Data.Binary.Put
 import Debug.Trace
 import Data.NineP
 connector :: IO Socket 
 connector = withSocketsDo $
               ainfo <- getAddrInfo Nothing (Just "") (Just "6872")
               let a = head ainfo
               sock <- socket AF_INET Stream defaultProtocol

At this point we've just created our socket to a machine on where we'd expect to see a 9P2000 server.

               putStrLn "Trying to connect"
               connect sock (addrAddress (traceShow a a))
               putStrLn "connected!"

The socket is connected at this point, build up a TVersion message, asking to speak to the server with the 9P2000 protocol.

The 1024 tells the server the maximum message size we'd like to support.

               let version = Msg TTversion (-1) $ Tversion 1024 "9P2000"
               putStrLn $ "About to send: " ++ show version

We now need to pack the message into a bytestring. This is handled by the Bin class instance Msg, and the serialization is handled by runPut. We send this data to the socket.

               send sock $ runPut (put version) 
               putStrLn "Getting response"

Now wait for a response from the server, evaluated runGet over it to de-serialize it, and show it.

               msg <- recv sock 50
               let response = runGet get msg ::Msg
               putStrLn $ show response
               return sock