summaryrefslogtreecommitdiff
path: root/nfp/net/driver/connection.h
blob: 6ab900e08df815cb9ae77a2dfe4582e1d0ffe121 (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
/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

Abstract:

    Defines a simple NearFieldProximity Provider implementation using the network
    for use in selfhosting. 
    
Author:

    Travis Martin (TravM) 06-24-2010
    
--*/
#pragma once

#include "SocketListener.h"

class CConnection;

struct MESSAGE;

interface IConnectionCallback
{
    virtual void HandleReceivedMessage(_In_ MESSAGE* pMessage) = 0;
    virtual void ConnectionEstablished(_In_ CConnection* pConnection) = 0;
    virtual BOOL ConnectionTerminated(_In_ CConnection* pConnection) = 0;
};

class CConnection : public IValidateAccept
{
private:
    CConnection(_In_ IConnectionCallback* pCallback) :
        _State(INITIAL),
        _Socket(INVALID_SOCKET),
        _pCallback(pCallback),
        _ThreadpoolWork(NULL),
        _fInboundConnection(false)
    {
    }
    
public:
    
    virtual ~CConnection()
    {
        Terminate();
        
        if (_ThreadpoolWork != NULL)
        {
            // Don't wait for threadpool callbacks when this thread is actually the threadpool callback
            if (_ThreadpoolThreadId != GetCurrentThreadId())
            {
                WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false);
            }
            CloseThreadpoolWork(_ThreadpoolWork);
            _ThreadpoolWork = NULL;
        }
    }
    
    static HRESULT Create(_In_ IConnectionCallback* pCallback, _Outptr_ CConnection** ppConnection);

    void SetInboundConnection() { _fInboundConnection = true; }
    bool IsInboundConnection() { return _fInboundConnection; }

    //IValidateAccept
    void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket);
    
    HRESULT FinalizeEstablish(_In_ SOCKET Socket);
    
    HRESULT InitializeAsClient(_In_ BEGIN_PROXIMITY_ARGS* pArgs);

    HRESULT TransmitMessage(_In_ MESSAGE* pMessage);

    BOOL ReceiveThreadProc();
    static VOID CALLBACK s_ReceiveThreadProc(
        _Inout_     PTP_CALLBACK_INSTANCE Instance,
        _Inout_     PVOID                 Context,
        _Inout_     PTP_WORK              /*Work*/)
    {
        CallbackMayRunLong(Instance);
        
        CConnection* pConnection = (CConnection*)Context;
        pConnection->_ThreadpoolThreadId = GetCurrentThreadId();
        BOOL fConnectionDeleted = pConnection->ReceiveThreadProc();

        if (!fConnectionDeleted)
        {
            // Only clear the member variable if the connection object wasn't deleted.
            pConnection->_ThreadpoolThreadId = 0;
        }
    }

    LIST_ENTRY* GetListEntry() { return &_ListEntry; }
    static CConnection* FromListEntry(LIST_ENTRY* pListEntry)
    {
        return (CConnection*) CONTAINING_RECORD(pListEntry, CConnection, _ListEntry);
    }
    
private:

    void Terminate();
    
private:

    enum STATE
    {
        INITIAL = 0,
        ESTABLISHED,
        TERMINATED
    };

    volatile STATE _State;

    SOCKET _Socket;
    
    PTP_WORK _ThreadpoolWork;
    DWORD    _ThreadpoolThreadId;
    
    IConnectionCallback* _pCallback;

    bool _fInboundConnection;
    
    LIST_ENTRY _ListEntry;

};