Commit 0b9702b7 authored by Michael Hanus 's avatar Michael Hanus

Update CPM, fix bug in binding optimizer w.r.t. hierarchical imported modules

parent 340fd1c7
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
module CPM.Config module CPM.Config
( Config ( Config, packageInstallDir, binInstallDir, repositoryDir ( Config ( Config, packageInstallDir, binInstallDir, repositoryDir
, appPackageDir, packageIndexURL, homePackageDir, curryExec , appPackageDir, packageIndexURL, packageTarFilesURL
, homePackageDir, curryExec
, compilerVersion, compilerBaseVersion, baseVersion ) , compilerVersion, compilerBaseVersion, baseVersion )
, readConfigurationWith, defaultConfig , readConfigurationWith, defaultConfig
, showConfiguration, showCompilerVersion ) where , showConfiguration, showCompilerVersion ) where
...@@ -36,6 +37,11 @@ packageIndexDefaultURL = ...@@ -36,6 +37,11 @@ packageIndexDefaultURL =
-- If you have an ssh access to git.ps.informatik.uni-kiel.de: -- If you have an ssh access to git.ps.informatik.uni-kiel.de:
-- "ssh://git@git.ps.informatik.uni-kiel.de:55055/curry-packages/cpm-index.git" -- "ssh://git@git.ps.informatik.uni-kiel.de:55055/curry-packages/cpm-index.git"
--- The default URL prefix to the directory containing tar files of all packages
packageTarFilesDefaultURL :: String
packageTarFilesDefaultURL =
"https://www-ps.informatik.uni-kiel.de/~pakcs/CPM_PACKAGES/"
--- Data type containing the main configuration of CPM. --- Data type containing the main configuration of CPM.
data Config = Config { data Config = Config {
--- The directory where locally installed packages are stored --- The directory where locally installed packages are stored
...@@ -48,6 +54,8 @@ data Config = Config { ...@@ -48,6 +54,8 @@ data Config = Config {
, appPackageDir :: String , appPackageDir :: String
--- URL to the package index repository --- URL to the package index repository
, packageIndexURL :: String , packageIndexURL :: String
--- URL prefix to the directory containing tar files of all packages
, packageTarFilesURL :: String
--- The directory where the default home package is stored --- The directory where the default home package is stored
, homePackageDir :: String , homePackageDir :: String
--- The executable of the Curry system used to compile and check packages --- The executable of the Curry system used to compile and check packages
...@@ -69,6 +77,7 @@ defaultConfig = Config ...@@ -69,6 +77,7 @@ defaultConfig = Config
, repositoryDir = "$HOME/.cpm/index" , repositoryDir = "$HOME/.cpm/index"
, appPackageDir = "" , appPackageDir = ""
, packageIndexURL = packageIndexDefaultURL , packageIndexURL = packageIndexDefaultURL
, packageTarFilesURL = packageTarFilesDefaultURL
, homePackageDir = "" , homePackageDir = ""
, curryExec = Dist.installDir </> "bin" </> Dist.curryCompiler , curryExec = Dist.installDir </> "bin" </> Dist.curryCompiler
, compilerVersion = ( Dist.curryCompiler , compilerVersion = ( Dist.curryCompiler
...@@ -92,6 +101,7 @@ showConfiguration cfg = unlines ...@@ -92,6 +101,7 @@ showConfiguration cfg = unlines
, "APP_PACKAGE_PATH : " ++ appPackageDir cfg , "APP_PACKAGE_PATH : " ++ appPackageDir cfg
, "HOME_PACKAGE_PATH : " ++ homePackageDir cfg , "HOME_PACKAGE_PATH : " ++ homePackageDir cfg
, "PACKAGE_INDEX_URL : " ++ packageIndexURL cfg , "PACKAGE_INDEX_URL : " ++ packageIndexURL cfg
, "PACKAGE_TARFILES_URL : " ++ packageTarFilesURL cfg
] ]
--- Shows the compiler version in the configuration. --- Shows the compiler version in the configuration.
...@@ -259,14 +269,15 @@ stripProps = map ((map toUpper . filter (/='_') . strip) *** strip) ...@@ -259,14 +269,15 @@ stripProps = map ((map toUpper . filter (/='_') . strip) *** strip)
--- record with a value for that option. --- record with a value for that option.
keySetters :: [(String, String -> Config -> Config)] keySetters :: [(String, String -> Config -> Config)]
keySetters = keySetters =
[ ("APPPACKAGEPATH" , \v c -> c { appPackageDir = v }) [ ("APPPACKAGEPATH" , \v c -> c { appPackageDir = v })
, ("BASEVERSION" , \v c -> c { baseVersion = v }) , ("BASEVERSION" , \v c -> c { baseVersion = v })
, ("BININSTALLPATH" , \v c -> c { binInstallDir = v }) , ("BININSTALLPATH" , \v c -> c { binInstallDir = v })
, ("CURRYBIN" , \v c -> c { curryExec = v }) , ("CURRYBIN" , \v c -> c { curryExec = v })
, ("HOMEPACKAGEPATH" , \v c -> c { homePackageDir = v }) , ("HOMEPACKAGEPATH" , \v c -> c { homePackageDir = v })
, ("PACKAGEINDEXURL" , \v c -> c { packageIndexURL = v }) , ("PACKAGEINDEXURL" , \v c -> c { packageIndexURL = v })
, ("PACKAGEINSTALLPATH" , \v c -> c { packageInstallDir = v }) , ("PACKAGETARFILESURL" , \v c -> c { packageTarFilesURL = v })
, ("REPOSITORYPATH" , \v c -> c { repositoryDir = v }) , ("PACKAGEINSTALLPATH" , \v c -> c { packageInstallDir = v })
, ("REPOSITORYPATH" , \v c -> c { repositoryDir = v })
] ]
--- Sequentially applies a list of functions that transform a value to a value --- Sequentially applies a list of functions that transform a value to a value
......
...@@ -59,7 +59,7 @@ cpmBanner :: String ...@@ -59,7 +59,7 @@ cpmBanner :: String
cpmBanner = unlines [bannerLine,bannerText,bannerLine] cpmBanner = unlines [bannerLine,bannerText,bannerLine]
where where
bannerText = bannerText =
"Curry Package Manager <curry-language.org/tools/cpm> (version of 15/03/2019)" "Curry Package Manager <curry-language.org/tools/cpm> (version of 24/04/2019)"
bannerLine = take (length bannerText) (repeat '-') bannerLine = take (length bannerText) (repeat '-')
main :: IO () main :: IO ()
......
...@@ -15,7 +15,7 @@ module CPM.Package ...@@ -15,7 +15,7 @@ module CPM.Package
, replaceVersionInTag , replaceVersionInTag
, readVersion , readVersion
, packageIdEq , packageIdEq
, showPackageSource , showSourceOfPackage
, readVersionConstraint , readVersionConstraint
, readVersionConstraints , readVersionConstraints
, readPackageSpec , readPackageSpec
...@@ -347,11 +347,12 @@ packageIdEq :: Package -> Package -> Bool ...@@ -347,11 +347,12 @@ packageIdEq :: Package -> Package -> Bool
packageIdEq p1 p2 = name p1 == name p2 && version p1 == version p2 packageIdEq p1 p2 = name p1 == name p2 && version p1 == version p2
--- Shows the package source in human-readable format. --- Shows the package source in human-readable format.
showPackageSource :: Package -> String showSourceOfPackage :: Package -> String
showPackageSource pkg = case source pkg of showSourceOfPackage pkg = case source pkg of
Nothing -> "No source specified" Nothing -> "No source specified"
Just s -> showSource s Just s -> showSource s
where where
showSource :: PackageSource -> String
showSource (Git url rev) = "Git " ++ url ++ showGitRev rev showSource (Git url rev) = "Git " ++ url ++ showGitRev rev
showSource (Http url) = url showSource (Http url) = url
showSource (FileSource url) = "File " ++ url showSource (FileSource url) = "File " ++ url
......
...@@ -14,6 +14,7 @@ module CPM.Package.Helpers ...@@ -14,6 +14,7 @@ module CPM.Package.Helpers
import Directory import Directory
import FilePath import FilePath
import List ( splitOn, nub ) import List ( splitOn, nub )
import System ( getPID )
import System.CurryPath ( addCurrySubdir ) import System.CurryPath ( addCurrySubdir )
import Text.Pretty hiding ( (</>) ) import Text.Pretty hiding ( (</>) )
...@@ -59,16 +60,18 @@ installPackageSourceTo pkg (FileSource zipfile) installdir = ...@@ -59,16 +60,18 @@ installPackageSourceTo pkg (FileSource zipfile) installdir =
installPkgFromFile pkg zipfile (installdir </> packageId pkg) False installPkgFromFile pkg zipfile (installdir </> packageId pkg) False
installPackageSourceTo pkg (Http url) installdir = do installPackageSourceTo pkg (Http url) installdir = do
let pkgDir = installdir </> packageId pkg pid <- getPID
let pkgDir = installdir </> packageId pkg
basepf = "package" ++ show pid
revurl = reverse url revurl = reverse url
pkgfile = if take 4 revurl == "piz." then "package.zip" else pkgfile = if take 4 revurl == "piz." then basepf ++ ".zip" else
if take 7 revurl == "zg.rat." then "package.tar.gz" else "" if take 7 revurl == "zg.rat." then basepf ++ ".tar.gz" else ""
if null pkgfile if null pkgfile
then failIO $ "Illegal URL (only .zip or .tar.gz allowed):\n" ++ url then failIO $ "Illegal URL (only .zip or .tar.gz allowed):\n" ++ url
else do else do
tmpdir <- tempDir tmpdir <- tempDir
let tmppkgfile = tmpdir </> pkgfile let tmppkgfile = tmpdir </> pkgfile
c <- inTempDir $ showExecCmd $ "curl -s -o " ++ tmppkgfile ++ c <- inTempDir $ showExecCmd $ "curl -f -s -S -o " ++ tmppkgfile ++
" " ++ quote url " " ++ quote url
if c == 0 if c == 0
then installPkgFromFile pkg tmppkgfile pkgDir True then installPkgFromFile pkg tmppkgfile pkgDir True
...@@ -226,7 +229,7 @@ renderPackageInfo allinfos plain installed pkg = pPrint doc ...@@ -226,7 +229,7 @@ renderPackageInfo allinfos plain installed pkg = pPrint doc
src = maybe empty src = maybe empty
(\_ -> boldText "Source" <$$> (\_ -> boldText "Source" <$$>
indent 4 (text $ showPackageSource pkg)) indent 4 (text $ showSourceOfPackage pkg))
(source pkg) (source pkg)
srcdirs = srcdirs =
......
...@@ -15,6 +15,7 @@ module CPM.PackageCache.Global ...@@ -15,6 +15,7 @@ module CPM.PackageCache.Global
, copyPackage , copyPackage
, installMissingDependencies , installMissingDependencies
, acquireAndInstallPackage , acquireAndInstallPackage
, acquireAndInstallPackageFromSource
, tryFindPackage , tryFindPackage
, missingPackages , missingPackages
, installFromZip , installFromZip
...@@ -30,7 +31,7 @@ import List ...@@ -30,7 +31,7 @@ import List
import Maybe (isJust) import Maybe (isJust)
import FilePath import FilePath
import CPM.Config ( Config, packageInstallDir ) import CPM.Config ( Config, packageInstallDir, packageTarFilesURL )
import CPM.ErrorLogger import CPM.ErrorLogger
import CPM.FileUtil ( copyDirectory, inTempDir, recreateDirectory, inDirectory import CPM.FileUtil ( copyDirectory, inTempDir, recreateDirectory, inDirectory
, removeDirectoryComplete, tempDir, whenFileExists , removeDirectoryComplete, tempDir, whenFileExists
...@@ -109,10 +110,28 @@ copyPackage cfg pkg dir = do ...@@ -109,10 +110,28 @@ copyPackage cfg pkg dir = do
where where
srcDir = installedPackageDir cfg pkg srcDir = installedPackageDir cfg pkg
--- Acquires a package from the source specified in its specification and --- Acquires a package, either from the global tar file repository
--- or from the source specified in its specification, and
--- installs it to the global package cache. --- installs it to the global package cache.
acquireAndInstallPackage :: Config -> Package -> IO (ErrorLogger ()) acquireAndInstallPackage :: Config -> Package -> IO (ErrorLogger ())
acquireAndInstallPackage cfg reppkg = acquireAndInstallPackage cfg pkg = do
pkgDirExists <- doesDirectoryExist (installedPackageDir cfg pkg)
if pkgDirExists
then log Info $ "Package '" ++ packageId pkg ++
"' already installed, skipping"
else do
let stdurl = packageTarFilesURL cfg ++ packageId pkg ++ ".tar.gz"
infoMessage ("Installing package from " ++ stdurl)
(msgs,err) <- installPackageSourceTo pkg (Http stdurl)
(packageInstallDir cfg)
case err of
Right _ -> return (msgs,err)
Left _ -> acquireAndInstallPackageFromSource cfg pkg
--- Acquires a package from the source specified in its specification and
--- installs it to the global package cache.
acquireAndInstallPackageFromSource :: Config -> Package -> IO (ErrorLogger ())
acquireAndInstallPackageFromSource cfg reppkg =
readPackageFromRepository cfg reppkg |>= \pkg -> readPackageFromRepository cfg reppkg |>= \pkg ->
case source pkg of case source pkg of
Nothing -> failIO $ "No source specified for " ++ packageId pkg Nothing -> failIO $ "No source specified for " ++ packageId pkg
...@@ -128,7 +147,7 @@ installFromSource cfg pkg pkgsource = do ...@@ -128,7 +147,7 @@ installFromSource cfg pkg pkgsource = do
if pkgDirExists if pkgDirExists
then then
log Info $ "Package '" ++ packageId pkg ++ "' already installed, skipping" log Info $ "Package '" ++ packageId pkg ++ "' already installed, skipping"
else log Info ("Installing package from " ++ showPackageSource pkg) |> else log Info ("Installing package from " ++ showSourceOfPackage pkg) |>
installPackageSourceTo pkg pkgsource (packageInstallDir cfg) installPackageSourceTo pkg pkgsource (packageInstallDir cfg)
where where
pkgDir = installedPackageDir cfg pkg pkgDir = installedPackageDir cfg pkg
......
...@@ -3,3 +3,7 @@ socket ...@@ -3,3 +3,7 @@ socket
This package contains the library `Network.Socket` This package contains the library `Network.Socket`
to support network programming with sockets. to support network programming with sockets.
Currently only IPv4 connections are supported
by the KICS2-Compiler (This might be the case with PAKCS too)
...@@ -2,32 +2,36 @@ ...@@ -2,32 +2,36 @@
--- A simple "addition" server to test the Socket library. --- A simple "addition" server to test the Socket library.
--- ---
--- @author Michael Hanus --- @author Michael Hanus
--- @version February 2006 --- @version April 2019
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
import IO import IO
import Read(readInt) import Read ( readInt )
import Network.Socket import Network.Socket
-- Choose a free port number: -- Choose a free port number:
portnr :: Int portnr :: Int
portnr = 32145 portnr = 65502
sendTo :: String -> String -> IO ()
sendTo host msg = do sendTo host msg = do
h <- connectToSocket host portnr h <- connectToSocket host portnr
hPutStr h msg hPutStr h msg
hClose h hClose h
stopServer :: String -> IO ()
stopServer host = sendTo host "TERMINATE\n" stopServer host = sendTo host "TERMINATE\n"
-- An "addition" server: -- An "addition" server:
addServer :: IO ()
addServer = do addServer = do
socket <- listenOn portnr socket <- listenOn portnr
putStrLn $ "Serving port: " ++ show portnr putStrLn $ "Serving port: " ++ show portnr
addServeSocket socket addServeSocket socket
addServeSocket :: Socket -> IO ()
addServeSocket socket = do addServeSocket socket = do
(chost,stream) <- accept socket (chost,stream) <- accept socket
putStrLn $ "Connection from "++chost putStrLn $ "Connection from "++chost
......
...@@ -3,46 +3,51 @@ ...@@ -3,46 +3,51 @@
--- on socket connections. --- on socket connections.
--- ---
--- @author Michael Hanus --- @author Michael Hanus
--- @version March 2006 --- @version April 2019
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
import IO import IO
import Read(readInt) import Read ( readInt )
import Network.Socket import Network.Socket
-- Choose a free port number: -- Choose a free port number:
portnr = 32145 portnr :: Int
portnr = 65502
sendTo :: String -> String -> IO ()
sendTo host msg = do sendTo host msg = do
h <- connectToSocket host portnr h <- connectToSocket host portnr
hPutStr h msg hPutStr h msg
hClose h hClose h
stopServer :: String -> IO ()
stopServer host = sendTo host "TERMINATE\n" stopServer host = sendTo host "TERMINATE\n"
-- An "addition" server: -- An "addition" server:
addServer :: IO ()
addServer = do addServer = do
socket <- listenOn portnr socket <- listenOn portnr
putStrLn $ "Serving port: " ++ show portnr putStrLn $ "Serving port: " ++ show portnr
addServeSocket socket addServeSocket socket
addServeSocket :: Socket -> IO ()
addServeSocket socket = do addServeSocket socket = do
conn <- waitForSocketAccept socket 1000 conn <- waitForSocketAccept socket 1000
addServeSocketTest socket conn addServeSocketTest socket conn
addServeSocketTest :: Socket -> Maybe (String,Handle) -> IO ()
addServeSocketTest socket Nothing = do addServeSocketTest socket Nothing = do
putStrLn "Timeout" putStrLn "Timeout"
addServeSocket socket addServeSocket socket
addServeSocketTest socket (Just (chost,stream)) = do addServeSocketTest socket (Just (chost,stream)) = do
putStrLn $ "Connection from "++chost putStrLn $ "Connection from "++chost
serverLoop stream serverLoop stream
where where
serverLoop h = do serverLoop h = do
l1 <- hGetLine h l1 <- hGetLine h
if l1=="TERMINATE" if l1 == "TERMINATE"
then do hClose h then do hClose h
close socket close socket
else do l2 <- hGetLine h else do l2 <- hGetLine h
...@@ -50,6 +55,7 @@ addServeSocketTest socket (Just (chost,stream)) = do ...@@ -50,6 +55,7 @@ addServeSocketTest socket (Just (chost,stream)) = do
hClose h hClose h
addServeSocket socket addServeSocket socket
addClient :: String -> Int -> Int -> IO ()
addClient host x y = do addClient host x y = do
h <- connectToSocket host portnr h <- connectToSocket host portnr
hPutStr h (unlines (map show [x,y])) hPutStr h (unlines (map show [x,y]))
......
...@@ -40,6 +40,7 @@ listenOnFresh external ...@@ -40,6 +40,7 @@ listenOnFresh external
--- the client (the format of this string is implementation-dependent) --- the client (the format of this string is implementation-dependent)
--- and a handle to a stream communication with the client. --- and a handle to a stream communication with the client.
--- The handle is both readable and writable. --- The handle is both readable and writable.
--- Only IPv4 connections are currently possible.
accept :: Socket -> IO (String,Handle) accept :: Socket -> IO (String,Handle)
accept s = prim_socketAccept $## s accept s = prim_socketAccept $## s
...@@ -74,6 +75,7 @@ prim_sClose external ...@@ -74,6 +75,7 @@ prim_sClose external
-- Client side operations: -- Client side operations:
--- Creates a new connection to a Unix socket. --- Creates a new connection to a Unix socket.
--- Only IPv4 connections are currently possible.
--- @param host - the host name of the connection --- @param host - the host name of the connection
--- @param port - the port number of the connection --- @param port - the port number of the connection
--- @return the handle of the stream (connected to the port port@host) --- @return the handle of the stream (connected to the port port@host)
......
...@@ -33,16 +33,19 @@ external_d_C_listenOnFresh _ _ = toCurry listenOnFreshPort ...@@ -33,16 +33,19 @@ external_d_C_listenOnFresh _ _ = toCurry listenOnFreshPort
------------------------------------------------- -------------------------------------------------
acceptOld :: Socket -> IO (Handle, HostName, PortNumber) acceptOld :: Socket -> IO (Handle, HostName, PortNumber)
acceptOld sock = do (s, addr) <- Network.Socket.accept sock acceptOld sock = do (s, peer) <- Network.Socket.accept sock
h <- socketToHandle s ReadWriteMode
p <- socketPort s p <- socketPort s
n <- getSocketName s h <- socketToHandle s ReadWriteMode
(Just hn, _) <- getNameInfo [] True False n -- s is invalid after this point.
return (h, hn, p) return (h, show peer, p)
listenOn :: PortNumber -> IO Socket listenOn :: PortNumber -> IO Socket
listenOn pn = do listenOn pn = do
let hints = defaultHints { addrFlags = [AI_PASSIVE], addrSocketType = Stream } -- AI_PASSIVE is needed when the address should be used for bind/listenOn
-- AF_INET forces IPv4. This is crucial, because some
-- systems crashed with the old Implementation that allowed IPv6
-- As soon as IPv6 is needed, someone has to look into this issue again.
let hints = defaultHints { addrFlags = [AI_PASSIVE], addrFamily = AF_INET }
addr:_ <- getAddrInfo (Just hints) Nothing (Just (show pn)) addr:_ <- getAddrInfo (Just hints) Nothing (Just (show pn))
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
setSocketOption sock ReuseAddr 1 setSocketOption sock ReuseAddr 1
...@@ -57,7 +60,8 @@ sClose = close ...@@ -57,7 +60,8 @@ sClose = close
connectTo :: HostName -> PortNumber -> IO Handle connectTo :: HostName -> PortNumber -> IO Handle
connectTo s a = do connectTo s a = do
let hints = defaultHints { addrSocketType = Stream } -- for AF_INET see above
let hints = defaultHints { addrFamily = AF_INET }
addr:_ <- getAddrInfo (Just hints) (Just s) (Just (show a)) addr:_ <- getAddrInfo (Just hints) (Just s) (Just (show a))
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
connect sock (addrAddress addr) connect sock (addrAddress addr)
......
...@@ -3,3 +3,7 @@ socket ...@@ -3,3 +3,7 @@ socket
This package contains the library `Network.Socket` This package contains the library `Network.Socket`
to support network programming with sockets. to support network programming with sockets.
Currently only IPv4 connections are supported
by the KICS2-Compiler (This might be the case with PAKCS too)
...@@ -2,32 +2,36 @@ ...@@ -2,32 +2,36 @@
--- A simple "addition" server to test the Socket library. --- A simple "addition" server to test the Socket library.
--- ---
--- @author Michael Hanus --- @author Michael Hanus
--- @version February 2006 --- @version April 2019
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
import IO import IO
import Read(readInt) import Read ( readInt )
import Network.Socket import Network.Socket
-- Choose a free port number: -- Choose a free port number:
portnr :: Int portnr :: Int
portnr = 32145 portnr = 65502
sendTo :: String -> String -> IO ()
sendTo host msg = do sendTo host msg = do
h <- connectToSocket host portnr h <- connectToSocket host portnr
hPutStr h msg hPutStr h msg
hClose h hClose h
stopServer :: String -> IO ()
stopServer host = sendTo host "TERMINATE\n" stopServer host = sendTo host "TERMINATE\n"
-- An "addition" server: -- An "addition" server:
addServer :: IO ()
addServer = do addServer = do
socket <- listenOn portnr socket <- listenOn portnr
putStrLn $ "Serving port: " ++ show portnr putStrLn $ "Serving port: " ++ show portnr
addServeSocket socket addServeSocket socket
addServeSocket :: Socket -> IO ()
addServeSocket socket = do addServeSocket socket = do
(chost,stream) <- accept socket (chost,stream) <- accept socket
putStrLn $ "Connection from "++chost putStrLn $ "Connection from "++chost
......
...@@ -3,46 +3,51 @@ ...@@ -3,46 +3,51 @@
--- on socket connections. --- on socket connections.
--- ---
--- @author Michael Hanus --- @author Michael Hanus
--- @version March 2006 --- @version April 2019
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
import IO import IO
import Read(readInt) import Read ( readInt )
import Network.Socket import Network.Socket
-- Choose a free port number: -- Choose a free port number:
portnr = 32145 portnr :: Int
portnr = 65502
sendTo :: String -> String -> IO ()
sendTo host msg = do sendTo host msg = do
h <- connectToSocket host portnr h <- connectToSocket host portnr