summaryrefslogtreecommitdiff
path: root/Monky/Network/Static.hs
blob: fd05d414db313ac8e5ab330239174d8e2735b873 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
{-
    Copyright 2016 Markus Ongyerth

    This file is part of Monky.

    Monky is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Monky is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Monky.  If not, see <http://www.gnu.org/licenses/>.
-}
{-|
Module      : Monky.Network.Static
Description : Allows access to information about they systems network
Maintainer  : ongy
Stability   : testing
Portability : Linux

This module should be used for static network configurations
-}
module Monky.Network.Static
  ( getReadWrite
  , NetworkHandle
  , getNetworkHandle
  , closeNetworkHandle
  )
where

import Monky.Utility
import Data.Time.Clock.POSIX
import Data.IORef
import System.IO.Error (catchIOError)


-- |Current state of network device
data NetState
  = Down -- ^It is down, consider off
  | Up -- ^It is up, consider on
  | Unknown -- ^Unknown, kernel docu says to consider on
  | Dormant -- ^Dormant, consider off

-- |Get the current network adapter state from kernel
getState :: NetworkHandle -> IO NetState
getState (NetH _ _ statef _ _ _) = do
-- the read can throw an exception if the interface disapperad, we just consider it down
  state <- catchIOError (readLine statef) (\_ -> return "down")
  return $ case state of
    "up" -> Up
    "down" -> Down
    "unknown" -> Unknown
    "dormant" -> Dormant
    _ -> error ("Don't know the network state \"" ++ state ++ "\" yet")


-- |Internal handle represanting exactly one interface
data NetworkHandle = NetH File File File (IORef Int) (IORef Int) (IORef POSIXTime)

basePath :: String
basePath = "/sys/class/net/"


readPath :: String
readPath = "/statistics/rx_bytes"


writePath :: String
writePath = "/statistics/tx_bytes"


statePath :: String
statePath = "/operstate"

-- Pure part of read/write rate calculation
calculateRates :: Int -> Int -> Int -> Int -> POSIXTime -> POSIXTime -> (Int, Int)
calculateRates oread nread owrite nwrite otime ntime =
  let cread = oread - nread
      cwrite = owrite - nwrite
      ctime = otime - ntime in
    ((cread * 8) `sdivBound` round ctime,
     (cwrite * 8) `sdivBound` round ctime)

-- IO Part of read/write rate calculation
getReadWriteReal :: NetworkHandle -> IO (Int, Int)
getReadWriteReal (NetH readf writef _ readref writeref timeref) = do
  nread <- readValue readf
  nwrite <- readValue writef
  ntime <- getPOSIXTime

  oread <- readIORef readref
  owrite <- readIORef writeref
  otime <- readIORef timeref

  writeIORef readref nread
  writeIORef writeref nwrite
  writeIORef timeref ntime

  return $ calculateRates oread nread owrite nwrite otime ntime

-- |Get the (read, write) rate of the network interface. This is averaged over the time between calls
getReadWrite :: NetworkHandle -> IO (Maybe (Int, Int))
getReadWrite h = do
  state <- getState h
  case state of
    Up -> fmap Just . getReadWriteReal $ h
    Unknown -> fmap Just . getReadWriteReal $ h
    _ -> return Nothing

-- |Get a 'NetworkHandle'
getNetworkHandle
  :: String -- ^Name of the interface to monitor
  -> IO NetworkHandle
getNetworkHandle dev = do
  readf <- fopen $path ++ readPath
  writef <- fopen $path ++ writePath
  statef <- fopen $path ++ statePath
  readref <- newIORef (1 :: Int)
  writeref <- newIORef (1 :: Int)
  timeref <- newIORef (0 :: POSIXTime)
  return $NetH readf writef statef readref writeref timeref
  where path = basePath ++ dev

-- |Close a network handle after it is no longer needed (the device disappeared)
closeNetworkHandle :: NetworkHandle -> IO ()
closeNetworkHandle (NetH readf writef statef _ _ _) =
  mapM_ fclose [readf, writef, statef]