diff options
Diffstat (limited to 'src/Network')
| -rw-r--r-- | src/Network/Protocol.hs | 589 | ||||
| -rw-r--r-- | src/Network/ifaddrs.c | 41 | ||||
| -rw-r--r-- | src/Network/ifaddrs.h | 3 | 
3 files changed, 0 insertions, 633 deletions
| diff --git a/src/Network/Protocol.hs b/src/Network/Protocol.hs deleted file mode 100644 index 1240fde..0000000 --- a/src/Network/Protocol.hs +++ /dev/null @@ -1,589 +0,0 @@ -module Network.Protocol ( -    TransportPacket(..), -    transportToObject, -    TransportHeader(..), -    TransportHeaderItem(..), - -    WaitingRef(..), -    WaitingRefCallback, -    wrDigest, - -    ChannelState(..), - -    ControlRequest(..), -    ControlMessage(..), -    erebosNetworkProtocol, - -    Connection, -    connAddress, -    connData, -    connGetChannel, -    connSetChannel, - -    module Flow, -) where - -import Control.Applicative -import Control.Concurrent -import Control.Concurrent.Async -import Control.Concurrent.STM -import Control.Monad -import Control.Monad.Except - -import Data.Bits -import Data.ByteString (ByteString) -import Data.ByteString qualified as B -import Data.ByteString.Char8 qualified as BC -import Data.ByteString.Lazy qualified as BL -import Data.List -import Data.Maybe -import Data.Text (Text) -import Data.Text qualified as T - -import System.Clock - -import Channel -import Flow -import Identity -import Service -import Storage - - -protocolVersion :: Text -protocolVersion = T.pack "0.1" - -protocolVersions :: [Text] -protocolVersions = [protocolVersion] - - -data TransportPacket a = TransportPacket TransportHeader [a] - -data TransportHeader = TransportHeader [TransportHeaderItem] -    deriving (Show) - -data TransportHeaderItem -    = Acknowledged RefDigest -    | AcknowledgedSingle Integer -    | Rejected RefDigest -    | ProtocolVersion Text -    | Initiation RefDigest -    | CookieSet Cookie -    | CookieEcho Cookie -    | DataRequest RefDigest -    | DataResponse RefDigest -    | AnnounceSelf RefDigest -    | AnnounceUpdate RefDigest -    | TrChannelRequest RefDigest -    | TrChannelAccept RefDigest -    | ServiceType ServiceID -    | ServiceRef RefDigest -    deriving (Eq, Show) - -newtype Cookie = Cookie ByteString -    deriving (Eq, Show) - -isHeaderItemAcknowledged :: TransportHeaderItem -> Bool -isHeaderItemAcknowledged = \case -    Acknowledged {} -> False -    AcknowledgedSingle {} -> False -    Rejected {} -> False -    ProtocolVersion {} -> False -    Initiation {} -> False -    CookieSet {} -> False -    CookieEcho {} -> False -    _ -> True - -transportToObject :: PartialStorage -> TransportHeader -> PartialObject -transportToObject st (TransportHeader items) = Rec $ map single items -    where single = \case -              Acknowledged dgst -> (BC.pack "ACK", RecRef $ partialRefFromDigest st dgst) -              AcknowledgedSingle num -> (BC.pack "ACK", RecInt num) -              Rejected dgst -> (BC.pack "REJ", RecRef $ partialRefFromDigest st dgst) -              ProtocolVersion ver -> (BC.pack "VER", RecText ver) -              Initiation dgst -> (BC.pack "INI", RecRef $ partialRefFromDigest st dgst) -              CookieSet (Cookie bytes) -> (BC.pack "CKS", RecBinary bytes) -              CookieEcho (Cookie bytes) -> (BC.pack "CKE", RecBinary bytes) -              DataRequest dgst -> (BC.pack "REQ", RecRef $ partialRefFromDigest st dgst) -              DataResponse dgst -> (BC.pack "RSP", RecRef $ partialRefFromDigest st dgst) -              AnnounceSelf dgst -> (BC.pack "ANN", RecRef $ partialRefFromDigest st dgst) -              AnnounceUpdate dgst -> (BC.pack "ANU", RecRef $ partialRefFromDigest st dgst) -              TrChannelRequest dgst -> (BC.pack "CRQ", RecRef $ partialRefFromDigest st dgst) -              TrChannelAccept dgst -> (BC.pack "CAC", RecRef $ partialRefFromDigest st dgst) -              ServiceType stype -> (BC.pack "SVT", RecUUID $ toUUID stype) -              ServiceRef dgst -> (BC.pack "SVR", RecRef $ partialRefFromDigest st dgst) - -transportFromObject :: PartialObject -> Maybe TransportHeader -transportFromObject (Rec items) = case catMaybes $ map single items of -                                       [] -> Nothing -                                       titems -> Just $ TransportHeader titems -    where single (name, content) = if -              | name == BC.pack "ACK", RecRef ref <- content -> Just $ Acknowledged $ refDigest ref -              | name == BC.pack "ACK", RecInt num <- content -> Just $ AcknowledgedSingle num -              | name == BC.pack "REJ", RecRef ref <- content -> Just $ Rejected $ refDigest ref -              | name == BC.pack "VER", RecText ver <- content -> Just $ ProtocolVersion ver -              | name == BC.pack "INI", RecRef ref <- content -> Just $ Initiation $ refDigest ref -              | name == BC.pack "CKS", RecBinary bytes <- content -> Just $ CookieSet (Cookie bytes) -              | name == BC.pack "CKE", RecBinary bytes <- content -> Just $ CookieEcho (Cookie bytes) -              | name == BC.pack "REQ", RecRef ref <- content -> Just $ DataRequest $ refDigest ref -              | name == BC.pack "RSP", RecRef ref <- content -> Just $ DataResponse $ refDigest ref -              | name == BC.pack "ANN", RecRef ref <- content -> Just $ AnnounceSelf $ refDigest ref -              | name == BC.pack "ANU", RecRef ref <- content -> Just $ AnnounceUpdate $ refDigest ref -              | name == BC.pack "CRQ", RecRef ref <- content -> Just $ TrChannelRequest $ refDigest ref -              | name == BC.pack "CAC", RecRef ref <- content -> Just $ TrChannelAccept $ refDigest ref -              | name == BC.pack "SVT", RecUUID uuid <- content -> Just $ ServiceType $ fromUUID uuid -              | name == BC.pack "SVR", RecRef ref <- content -> Just $ ServiceRef $ refDigest ref -              | otherwise -> Nothing -transportFromObject _ = Nothing - - -data GlobalState addr = (Eq addr, Show addr) => GlobalState -    { gIdentity :: TVar (UnifiedIdentity, [UnifiedIdentity]) -    , gConnections :: TVar [Connection addr] -    , gDataFlow :: SymFlow (addr, ByteString) -    , gControlFlow :: Flow (ControlRequest addr) (ControlMessage addr) -    , gNextUp :: TMVar (Connection addr, (Bool, TransportPacket PartialObject)) -    , gLog :: String -> STM () -    , gStorage :: PartialStorage -    , gNowVar :: TVar TimeSpec -    , gNextTimeout :: TVar TimeSpec -    , gInitConfig :: Ref -    } - -data Connection addr = Connection -    { cAddress :: addr -    , cDataUp :: Flow (Bool, TransportPacket PartialObject) (Bool, TransportPacket Ref, [TransportHeaderItem]) -    , cDataInternal :: Flow (Bool, TransportPacket Ref, [TransportHeaderItem]) (Bool, TransportPacket PartialObject) -    , cChannel :: TVar ChannelState -    , cSecureOutQueue :: TQueue (Bool, TransportPacket Ref, [TransportHeaderItem]) -    , cSentPackets :: TVar [SentPacket] -    , cToAcknowledge :: TVar [Integer] -    } - -connAddress :: Connection addr -> addr -connAddress = cAddress - -connData :: Connection addr -> Flow (Bool, TransportPacket PartialObject) (Bool, TransportPacket Ref, [TransportHeaderItem]) -connData = cDataUp - -connGetChannel :: Connection addr -> STM ChannelState -connGetChannel Connection {..} = readTVar cChannel - -connSetChannel :: Connection addr -> ChannelState -> STM () -connSetChannel Connection {..} ch = do -    writeTVar cChannel ch - - -data WaitingRef = WaitingRef -    { wrefStorage :: Storage -    , wrefPartial :: PartialRef -    , wrefAction :: Ref -> WaitingRefCallback -    , wrefStatus :: TVar (Either [RefDigest] Ref) -    } - -type WaitingRefCallback = ExceptT String IO () - -wrDigest :: WaitingRef -> RefDigest -wrDigest = refDigest . wrefPartial - - -data ChannelState = ChannelNone -                  | ChannelCookieWait -- sent initiation, waiting for response -                  | ChannelCookieReceived Cookie -- received cookie, but no cookie echo yet -                  | ChannelCookieConfirmed Cookie -- received cookie echo, no need to send from our side -                  | ChannelOurRequest (Maybe Cookie) (Stored ChannelRequest) -                  | ChannelPeerRequest (Maybe Cookie) WaitingRef -                  | ChannelOurAccept (Maybe Cookie) (Stored ChannelAccept) Channel -                  | ChannelEstablished Channel - - -data SentPacket = SentPacket -    { spTime :: TimeSpec -    , spRetryCount :: Int -    , spAckedBy :: Maybe (TransportHeaderItem -> Bool) -    , spData :: BC.ByteString -    } - - -data ControlRequest addr = RequestConnection addr -                         | SendAnnounce addr -                         | UpdateSelfIdentity UnifiedIdentity - -data ControlMessage addr = NewConnection (Connection addr) (Maybe RefDigest) -                         | ReceivedAnnounce addr RefDigest - - -erebosNetworkProtocol :: (Eq addr, Ord addr, Show addr) -                      => UnifiedIdentity -                      -> (String -> STM ()) -                      -> SymFlow (addr, ByteString) -                      -> Flow (ControlRequest addr) (ControlMessage addr) -                      -> IO () -erebosNetworkProtocol initialIdentity gLog gDataFlow gControlFlow = do -    gIdentity <- newTVarIO (initialIdentity, []) -    gConnections <- newTVarIO [] -    gNextUp <- newEmptyTMVarIO -    mStorage <- memoryStorage -    gStorage <- derivePartialStorage mStorage - -    startTime <- getTime MonotonicRaw -    gNowVar <- newTVarIO startTime -    gNextTimeout <- newTVarIO startTime -    gInitConfig <- store mStorage $ (Rec [] :: Object) - -    let gs = GlobalState {..} - -    let signalTimeouts = forever $ do -            now <- getTime MonotonicRaw -            next <- atomically $ do -                writeTVar gNowVar now -                readTVar gNextTimeout - -            let waitTill time -                    | time > now = threadDelay $ fromInteger (toNanoSecs (time - now)) `div` 1000 -                    | otherwise = threadDelay maxBound -                waitForUpdate = atomically $ do -                    next' <- readTVar gNextTimeout -                    when (next' == next) retry - -            race_ (waitTill next) waitForUpdate - -    race_ signalTimeouts $ forever $ join $ atomically $ -        passUpIncoming gs <|> processIncoming gs <|> processOutgoing gs - - -getConnection :: GlobalState addr -> addr -> STM (Connection addr) -getConnection gs addr = do -    maybe (newConnection gs addr) return =<< findConnection gs addr - -findConnection :: GlobalState addr -> addr -> STM (Maybe (Connection addr)) -findConnection GlobalState {..} addr = do -    find ((addr==) . cAddress) <$> readTVar gConnections - -newConnection :: GlobalState addr -> addr -> STM (Connection addr) -newConnection GlobalState {..} addr = do -    conns <- readTVar gConnections - -    let cAddress = addr -    (cDataUp, cDataInternal) <- newFlow -    cChannel <- newTVar ChannelNone -    cSecureOutQueue <- newTQueue -    cSentPackets <- newTVar [] -    cToAcknowledge <- newTVar [] -    let conn = Connection {..} - -    writeTVar gConnections (conn : conns) -    return conn - -passUpIncoming :: GlobalState addr -> STM (IO ()) -passUpIncoming GlobalState {..} = do -    (Connection {..}, up) <- takeTMVar gNextUp -    writeFlow cDataInternal up -    return $ return () - -processIncoming :: GlobalState addr -> STM (IO ()) -processIncoming gs@GlobalState {..} = do -    guard =<< isEmptyTMVar gNextUp -    guard =<< canWriteFlow gControlFlow - -    (addr, msg) <- readFlow gDataFlow -    mbconn <- findConnection gs addr - -    mbch <- case mbconn of -        Nothing -> return Nothing -        Just conn -> readTVar (cChannel conn) >>= return . \case -            ChannelEstablished ch   -> Just ch -            ChannelOurAccept _ _ ch -> Just ch -            _                       -> Nothing - -    return $ do -        let deserialize = liftEither . runExcept . deserializeObjects gStorage . BL.fromStrict -        let parse = case B.uncons msg of -                Just (b, enc) -                    | b .&. 0xE0 == 0x80 -> do -                        ch <- maybe (throwError "unexpected encrypted packet") return mbch -                        (dec, counter) <- channelDecrypt ch enc - -                        case B.uncons dec of -                            Just (0x00, content) -> do -                                objs <- deserialize content -                                return (True, objs, Just counter) - -                            Just (_, _) -> do -                                throwError "streams not implemented" - -                            Nothing -> do -                                throwError "empty decrypted content" - -                    | b .&. 0xE0 == 0x60 -> do -                        objs <- deserialize msg -                        return (False, objs, Nothing) - -                    | otherwise -> throwError "invalid packet" - -                Nothing -> throwError "empty packet" - -        runExceptT parse >>= \case -            Right (secure, objs, mbcounter) -                | hobj:content <- objs -                , Just header@(TransportHeader items) <- transportFromObject hobj -                -> processPacket gs (maybe (Left addr) Right mbconn) secure (TransportPacket header content) >>= \case -                    Just (conn@Connection {..}, mbup) -> atomically $ do -                        case mbcounter of -                            Just counter | any isHeaderItemAcknowledged items -> -                                modifyTVar' cToAcknowledge (fromIntegral counter :) -                            _ -> return () -                        processAcknowledgements gs conn items -                        case mbup of -                            Just up -> putTMVar gNextUp (conn, (secure, up)) -                            Nothing -> return () -                    Nothing -> return () - -                | otherwise -> atomically $ do -                      gLog $ show addr ++ ": invalid objects" -                      gLog $ show objs - -            Left err -> do -                atomically $ gLog $ show addr <> ": failed to parse packet: " <> err - -processPacket :: GlobalState addr -> Either addr (Connection addr) -> Bool -> TransportPacket a -> IO (Maybe (Connection addr, Maybe (TransportPacket a))) -processPacket gs@GlobalState {..} econn secure packet@(TransportPacket (TransportHeader header) _) = if -    -- Established secure communication -    | Right conn <- econn, secure -    -> return $ Just (conn, Just packet) - -    -- Plaintext communication with cookies to prove origin -    | cookie:_ <- mapMaybe (\case CookieEcho x -> Just x; _ -> Nothing) header -    -> verifyCookie gs addr cookie >>= \case -        True -> do -            atomically $ do -                conn@Connection {..} <- getConnection gs addr -                channel <- readTVar cChannel -                let received = listToMaybe $ mapMaybe (\case CookieSet x -> Just x; _ -> Nothing) header -                case received `mplus` channelCurrentCookie channel of -                    Just current -> do -                        cookieEchoReceived gs conn mbpid current -                        return $ Just (conn, Just packet) -                    Nothing -> do -                        gLog $ show addr <> ": missing cookie set, dropping " <> show header -                        return $ Nothing - -        False -> do -            atomically $ gLog $ show addr <> ": cookie verification failed, dropping " <> show header -            return Nothing - -    -- Response to initiation packet -    | cookie:_ <- mapMaybe (\case CookieSet x -> Just x; _ -> Nothing) header -    , Just _ <- version -    , Right conn@Connection {..} <- econn -    -> do -        atomically $ readTVar cChannel >>= \case -            ChannelCookieWait -> do -                writeTVar cChannel $ ChannelCookieReceived cookie -                writeFlow gControlFlow (NewConnection conn mbpid) -                return $ Just (conn, Nothing) -            _ -> return Nothing - -    -- Initiation packet -    | _:_ <- mapMaybe (\case Initiation x -> Just x; _ -> Nothing) header -    , Just ver <- version -    -> do -        cookie <- createCookie gs addr -        atomically $ do -            identity <- fst <$> readTVar gIdentity -            let reply = BL.toStrict $ serializeObject $ transportToObject gStorage $ TransportHeader -                    [ CookieSet cookie -                    , AnnounceSelf $ refDigest $ storedRef $ idData identity -                    , ProtocolVersion ver -                    ] -            writeFlow gDataFlow (addr, reply) -        return Nothing - -    -- Announce packet outside any connection -    | dgst:_ <- mapMaybe (\case AnnounceSelf x -> Just x; _ -> Nothing) header -    , Just _ <- version -    -> do -        atomically $ do -            (cur, past) <- readTVar gIdentity -            when (not $ dgst `elem` map (refDigest . storedRef . idData) (cur : past)) $ do -                writeFlow gControlFlow $ ReceivedAnnounce addr dgst -        return Nothing - -    | otherwise -> do -        atomically $ gLog $ show addr <> ": dropping packet " <> show header -        return Nothing - -  where -    addr = either id cAddress econn -    mbpid = listToMaybe $ mapMaybe (\case AnnounceSelf dgst -> Just dgst; _ -> Nothing) header -    version = listToMaybe $ filter (\v -> ProtocolVersion v `elem` header) protocolVersions - -channelCurrentCookie :: ChannelState -> Maybe Cookie -channelCurrentCookie = \case -    ChannelCookieReceived cookie -> Just cookie -    ChannelCookieConfirmed cookie -> Just cookie -    ChannelOurRequest mbcookie _ -> mbcookie -    ChannelPeerRequest mbcookie _ -> mbcookie -    ChannelOurAccept mbcookie _ _ -> mbcookie -    _ -> Nothing - -cookieEchoReceived :: GlobalState addr -> Connection addr -> Maybe RefDigest -> Cookie -> STM () -cookieEchoReceived GlobalState {..} conn@Connection {..} mbpid cookieSet = do -    readTVar cChannel >>= \case -        ChannelNone -> newConn -        ChannelCookieWait -> newConn -        ChannelCookieReceived {} -> update -        _ -> return () -  where -    update = do -        writeTVar cChannel $ ChannelCookieConfirmed cookieSet -    newConn = do -        update -        writeFlow gControlFlow (NewConnection conn mbpid) - -generateCookieHeaders :: GlobalState addr -> addr -> ChannelState -> IO [TransportHeaderItem] -generateCookieHeaders gs addr ch = catMaybes <$> sequence [ echoHeader, setHeader ] -  where -    echoHeader = return $ CookieEcho <$> channelCurrentCookie ch -    setHeader = case ch of -        ChannelCookieWait {} -> Just . CookieSet <$> createCookie gs addr -        ChannelCookieReceived {} -> Just . CookieSet <$> createCookie gs addr -        _ -> return Nothing - -createCookie :: GlobalState addr -> addr -> IO Cookie -createCookie GlobalState {} addr = return (Cookie $ BC.pack $ show addr) - -verifyCookie :: GlobalState addr -> addr -> Cookie -> IO Bool -verifyCookie GlobalState {} addr (Cookie cookie) = return $ show addr == BC.unpack cookie - -resendBytes :: GlobalState addr -> Connection addr -> SentPacket -> IO () -resendBytes GlobalState {..} Connection {..} sp = do -    now <- getTime MonotonicRaw -    atomically $ do -        when (isJust $ spAckedBy sp) $ do -            modifyTVar' cSentPackets $ (:) sp -                { spTime = now -                , spRetryCount = spRetryCount sp + 1 -                } -        writeFlow gDataFlow (cAddress, spData sp) - -sendBytes :: GlobalState addr -> Connection addr -> ByteString -> Maybe (TransportHeaderItem -> Bool) -> IO () -sendBytes gs conn bs ackedBy = resendBytes gs conn -    SentPacket -        { spTime = undefined -        , spRetryCount = -1 -        , spAckedBy = ackedBy -        , spData = bs -        } - -processOutgoing :: forall addr. GlobalState addr -> STM (IO ()) -processOutgoing gs@GlobalState {..} = do - -    let sendNextPacket :: Connection addr -> STM (IO ()) -        sendNextPacket conn@Connection {..} = do -            channel <- readTVar cChannel -            let mbch = case channel of -                    ChannelEstablished ch -> Just ch -                    _                     -> Nothing - -            let checkOutstanding -                    | isJust mbch = readTQueue cSecureOutQueue -                    | otherwise = retry - -                checkAcknowledgements -                    | isJust mbch = do -                        acks <- readTVar cToAcknowledge -                        if null acks then retry -                                     else return (True, TransportPacket (TransportHeader []) [], []) -                    | otherwise = retry - -            (secure, packet@(TransportPacket (TransportHeader hitems) content), plainAckedBy) <- -                checkOutstanding <|> readFlow cDataInternal <|> checkAcknowledgements - -            when (isNothing mbch && secure) $ do -                writeTQueue cSecureOutQueue (secure, packet, plainAckedBy) - -            acknowledge <- case mbch of -                Nothing -> return [] -                Just _ -> swapTVar cToAcknowledge [] - -            return $ do -                cookieHeaders <- generateCookieHeaders gs cAddress channel -                let header = TransportHeader $ map AcknowledgedSingle acknowledge ++ cookieHeaders ++ hitems - -                let plain = BL.concat $ -                        (serializeObject $ transportToObject gStorage header) -                        : map lazyLoadBytes content - -                mbs <- case mbch of -                    Just ch -> do -                        runExceptT (channelEncrypt ch $ BL.toStrict $ 0x00 `BL.cons` plain) >>= \case -                            Right (ctext, counter) -> do -                                let isAcked = any isHeaderItemAcknowledged hitems -                                return $ Just (0x80 `B.cons` ctext, if isAcked then [ AcknowledgedSingle $ fromIntegral counter ] else []) -                            Left err -> do atomically $ gLog $ "Failed to encrypt data: " ++ err -                                           return Nothing -                    Nothing | secure    -> return Nothing -                            | otherwise -> return $ Just (BL.toStrict plain, plainAckedBy) - -                case mbs of -                    Just (bs, ackedBy) -> sendBytes gs conn bs $ guard (not $ null ackedBy) >> Just (`elem` ackedBy) -                    Nothing -> return () - -    let retransmitPacket :: Connection addr -> STM (IO ()) -        retransmitPacket conn@Connection {..} = do -            now <- readTVar gNowVar -            (sp, rest) <- readTVar cSentPackets >>= \case -                sps@(_:_) -> return (last sps, init sps) -                _         -> retry -            let nextTry = spTime sp + fromNanoSecs 1000000000 -            if now < nextTry -              then do -                nextTimeout <- readTVar gNextTimeout -                if nextTimeout <= now || nextTry < nextTimeout -                   then do writeTVar gNextTimeout nextTry -                           return $ return () -                   else retry -              else do -                writeTVar cSentPackets rest -                return $ resendBytes gs conn sp - -    let handleControlRequests = readFlow gControlFlow >>= \case -            RequestConnection addr -> do -                conn@Connection {..} <- getConnection gs addr -                identity <- fst <$> readTVar gIdentity -                readTVar cChannel >>= \case -                    ChannelNone -> do -                        let packet = BL.toStrict $ BL.concat -                                [ serializeObject $ transportToObject gStorage $ TransportHeader $ -                                    [ Initiation $ refDigest gInitConfig -                                    , AnnounceSelf $ refDigest $ storedRef $ idData identity -                                    ] ++ map ProtocolVersion protocolVersions -                                , lazyLoadBytes gInitConfig -                                ] -                        writeTVar cChannel ChannelCookieWait -                        return $ sendBytes gs conn packet $ Just $ \case CookieSet {} -> True; _ -> False -                    _ -> return $ return () - -            SendAnnounce addr -> do -                identity <- fst <$> readTVar gIdentity -                let packet = BL.toStrict $ serializeObject $ transportToObject gStorage $ TransportHeader $ -                        [ AnnounceSelf $ refDigest $ storedRef $ idData identity -                        ] ++ map ProtocolVersion protocolVersions -                writeFlow gDataFlow (addr, packet) -                return $ return () - -            UpdateSelfIdentity nid -> do -                (cur, past) <- readTVar gIdentity -                writeTVar gIdentity (nid, cur : past) -                return $ return () - -    conns <- readTVar gConnections -    msum $ concat $ -        [ map retransmitPacket conns -        , map sendNextPacket conns -        , [ handleControlRequests ] -        ] - -processAcknowledgements :: GlobalState addr -> Connection addr -> [TransportHeaderItem] -> STM () -processAcknowledgements GlobalState {} Connection {..} = mapM_ $ \hitem -> do -    modifyTVar' cSentPackets $ filter $ \sp -> not (fromJust (spAckedBy sp) hitem) diff --git a/src/Network/ifaddrs.c b/src/Network/ifaddrs.c deleted file mode 100644 index 37c3e00..0000000 --- a/src/Network/ifaddrs.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "ifaddrs.h" - -#include <arpa/inet.h> -#include <ifaddrs.h> -#include <net/if.h> -#include <stdlib.h> -#include <sys/types.h> -#include <endian.h> - -uint32_t * broadcast_addresses(void) -{ -	struct ifaddrs * addrs; -	if (getifaddrs(&addrs) < 0) -		return 0; - -	size_t capacity = 16, count = 0; -	uint32_t * ret = malloc(sizeof(uint32_t) * capacity); - -	for (struct ifaddrs * ifa = addrs; ifa; ifa = ifa->ifa_next) { -		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET && -				ifa->ifa_flags & IFF_BROADCAST) { -			if (count + 2 >= capacity) { -				capacity *= 2; -				uint32_t * nret = realloc(ret, sizeof(uint32_t) * capacity); -				if (nret) { -					ret = nret; -				} else { -					free(ret); -					return 0; -				} -			} - -			ret[count] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr; -			count++; -		} -	} - -	freeifaddrs(addrs); -	ret[count] = 0; -	return ret; -} diff --git a/src/Network/ifaddrs.h b/src/Network/ifaddrs.h deleted file mode 100644 index 06d26ec..0000000 --- a/src/Network/ifaddrs.h +++ /dev/null @@ -1,3 +0,0 @@ -#include <stdint.h> - -uint32_t * broadcast_addresses(void); |