summaryrefslogtreecommitdiffstats
path: root/src/lib/util/unittests/mock_socketsession.h
blob: 808cddb399dfd591ad0dcb667d00d26368853eb3 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef UTIL_UNITTESTS_MOCKSOCKETSESSION_H
#define UTIL_UNITTESTS_MOCKSOCKETSESSION_H 1

#include <exceptions/exceptions.h>

#include <util/io/socketsession.h>
#include <util/io/sockaddr_util.h>

#include <cassert>
#include <cstring>
#include <vector>

#include <sys/socket.h>
#include <stdint.h>

namespace isc {
namespace util {
namespace unittests {

/// \brief Mock socket session forwarder.
///
/// It emulates the behavior of SocketSessionForwarder without involving
/// network communication, and allowing the tester to customize the behavior
/// and to examine forwarded data afterwards.
class MockSocketSessionForwarder :
    public isc::util::io::BaseSocketSessionForwarder
{
public:
    MockSocketSessionForwarder() :
        is_connected_(false), connect_ok_(true), push_ok_(true),
        close_ok_(true),
        // These are not used until set, but we set them anyway here,
        // partly to silence cppcheck, and partly to be cleaner. Put some
        // invalid values in.
        pushed_sock_(-1), pushed_family_(-1), pushed_type_(-1),
        pushed_protocol_(-1)
    {}

    virtual void connectToReceiver() {
        if (!connect_ok_) {
            isc_throw(isc::util::io::SocketSessionError, "socket session "
                      "forwarding connection disabled for test");
        }
        if (is_connected_) {
            isc_throw(isc::util::io::SocketSessionError, "duplicate connect");
        }
        is_connected_ = true;
    }
    virtual void close() {
        if (!is_connected_) {
            isc_throw(isc::util::io::SocketSessionError, "duplicate close");
        }
        is_connected_ = false;
    }

    // Pushing a socket session.  It copies the given session data
    // so that the test code can check the values later via the getter
    // methods.  Complete deep copy will be created, so the caller doesn't
    // have to keep the parameters valid after the call to this method.
    virtual void push(int sock, int family, int type, int protocol,
                      const struct sockaddr& local_end,
                      const struct sockaddr& remote_end,
                      const void* data, size_t data_len)
    {
        if (!push_ok_) {
            isc_throw(isc::util::io::SocketSessionError,
                       "socket session forwarding is disabled for test");
        }
        if (!is_connected_) {
            isc_throw(isc::util::io::SocketSessionError,
                       "socket session is being pushed before connected");
        }

        // Copy parameters for later checks
        pushed_sock_ = sock;
        pushed_family_ = family;
        pushed_type_ = type;
        pushed_protocol_ = protocol;
        assert(io::internal::getSALength(local_end) <=
               sizeof(pushed_local_end_ss_));
        std::memcpy(&pushed_local_end_ss_, &local_end,
                    io::internal::getSALength(local_end));
        assert(io::internal::getSALength(remote_end) <=
               sizeof(pushed_remote_end_ss_));
        std::memcpy(&pushed_remote_end_ss_, &remote_end,
                    io::internal::getSALength(remote_end));
        pushed_data_.resize(data_len);
        std::memcpy(&pushed_data_[0], data, data_len);
    }

    // Allow the test code to check if the connection is established.
    bool isConnected() const { return (is_connected_); }

    // Allow the test code to customize the forwarder behavior wrt whether
    // a specific operation should succeed or fail.
    void disableConnect() { connect_ok_ = false; }
    void enableConnect() { connect_ok_ = true; }
    void disableClose() { close_ok_ = false; }
    void disablePush() { push_ok_ = false; }
    void enablePush() { push_ok_ = true; }

    // Read-only accessors to recorded parameters to the previous successful
    // call to push().  Return values are undefined if there has been no
    // successful call to push().
    // Note that we use convertSockAddr() to convert sockaddr_storage to
    // sockaddr.  It should be safe since we use the storage in its literal
    // sense; it was originally filled with the binary image of another
    // sockaddr structure, and we are going to return the image opaquely
    // as a sockaddr structure without touching the data.
    int getPushedSock() const { return (pushed_sock_); }
    int getPushedFamily() const { return (pushed_family_); }
    int getPushedType() const { return (pushed_type_); }
    int getPushedProtocol() const { return (pushed_protocol_); }
    const struct sockaddr& getPushedLocalend() const {
        return (*io::internal::convertSockAddr(&pushed_local_end_ss_));
    }
    const struct sockaddr& getPushedRemoteend() const {
        return (*io::internal::convertSockAddr(&pushed_remote_end_ss_));
    }
    const std::vector<uint8_t>& getPushedData() const {
        return (pushed_data_);
    }

private:
    bool is_connected_;
    bool connect_ok_;
    bool push_ok_;
    bool close_ok_;
    int pushed_sock_;
    int pushed_family_;
    int pushed_type_;
    int pushed_protocol_;
    struct sockaddr_storage pushed_local_end_ss_;
    struct sockaddr_storage pushed_remote_end_ss_;
    std::vector<uint8_t> pushed_data_;
};

} // end of unittests
} // end of util
} // end of isc
#endif  // UTIL_UNITTESTS_MOCKSOCKETSESSION_H

// Local Variables:
// mode: c++
// End: