summaryrefslogtreecommitdiff
path: root/indra/llmessage/lliopipe.h
blob: b40539f38c45aa32e6097da7e0cb8935781eddba (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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/**
 * @file lliopipe.h
 * @author Phoenix
 * @date 2004-11-18
 * @brief Declaration of base IO class
 *
 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library 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;
 * version 2.1 of the License only.
 *
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLIOPIPE_H
#define LL_LLIOPIPE_H

#include <boost/intrusive_ptr.hpp>
#include "llwin32headers.h"
#include "apr_poll.h"

#include "llsd.h"

class LLIOPipe;
class LLPumpIO;
class LLBufferArray;
class LLChannelDescriptors;

// Debugging schmutz for deadlocks
//#define LL_DEBUG_PUMPS
#ifdef LL_DEBUG_PUMPS
void pump_debug(const char *file, S32 line);
#define PUMP_DEBUG pump_debug(__FILE__, __LINE__);
#define END_PUMP_DEBUG pump_debug("none", 0);
#else /* LL_DEBUG_PUMPS */
#define PUMP_DEBUG
#define END_PUMP_DEBUG
#endif


/**
 * intrusive pointer support
 */
void intrusive_ptr_add_ref(LLIOPipe* p);
void intrusive_ptr_release(LLIOPipe* p);

/**
 * @class LLIOPipe
 * @brief This class is an abstract base class for data processing units
 * @see LLPumpIO
 *
 * The LLIOPipe is a base class for implementing the basic non-blocking
 * processing of data subsystem in our system.
 *
 * Implementations of this class should behave like a stateful or
 * stateless signal processor. Each call to <code>process()</code>
 * hands the pipe implementation a buffer and a set of channels in the
 * buffer to process, and the pipe returns the status of the
 * operation. This is an abstract base class and developer created
 * concrete implementations provide block or stream based processing
 * of data to implement a particular protocol.
 */
class LLIOPipe
{
public:
    /**
     * @brief I have decided that IO objects should have a reference
     * count. In general, you can pass bald LLIOPipe pointers around
     * as you need, but if you need to maintain a reference to one,
     * you need to hold a ptr_t.
     */
    typedef boost::intrusive_ptr<LLIOPipe> ptr_t;

    /**
     * @brief Scattered memory container.
     */
    typedef std::shared_ptr<LLBufferArray> buffer_ptr_t;

    /**
     * @brief Enumeration for IO return codes
     *
     * A status code a positive integer value is considered a success,
     * but may indicate special handling for future calls, for
     * example, issuing a STATUS_STOP to an LLIOSocketReader instance
     * will tell the instance to stop reading the socket. A status
     * code with a negative value means that a problem has been
     * encountered which will require further action on the caller or
     * a developer to correct. Some mechanisms, such as the LLPumpIO
     * may depend on this definition of success and failure.
     */
    enum EStatus
    {
        // Processing occurred normally, future calls will be accepted.
        STATUS_OK = 0,

        // Processing occured normally, but stop unsolicited calls to
        // process.
        STATUS_STOP = 1,

        // This pipe is done with the processing. Future calls to
        // process will be accepted as long as new data is available.
        STATUS_DONE = 2,

        // This pipe is requesting that it become the head in a process.
        STATUS_BREAK = 3,

        // This pipe is requesting that it become the head in a process.
        STATUS_NEED_PROCESS = 4,

        // Keep track of the highest number of success codes here.
        STATUS_SUCCESS_COUNT = 5,

        // A generic error code.
        STATUS_ERROR = -1,

        // This method has not yet been implemented. This usually
        // indicates the programmer working on the pipe is not yet
        // done.
        STATUS_NOT_IMPLEMENTED = -2,

        // This indicates that a pipe precondition was not met. For
        // example, many pipes require an element to appear after them
        // in a chain (ie, mNext is not null) and will return this in
        // response to method calls. To recover from this, it will
        // require the caller to adjust the pipe state or may require
        // a dev to adjust the code to satisfy the preconditions.
        STATUS_PRECONDITION_NOT_MET = -3,

        // This means we could not connect to a remote host.
        STATUS_NO_CONNECTION = -4,

        // The connection was lost.
        STATUS_LOST_CONNECTION = -5,

        // The totoal process time has exceeded the timeout.
        STATUS_EXPIRED = -6,

        // Keep track of the count of codes here.
        STATUS_ERROR_COUNT = 6,
    };

    /**
     * @brief Helper function to check status.
     *
     * When writing code to check status codes, if you do not
     * specifically check a particular value, use this method for
     * checking an error condition.
     * @param status The status to check.
     * @return Returns true if the code indicates an error occurred.
     */
    inline static bool isError(EStatus status)
    {
        return ((S32)status < 0);
    }

    /**
     * @brief Helper function to check status.
     *
     * When writing code to check status codes, if you do not
     * specifically check a particular value, use this method for
     * checking an error condition.
     * @param status The status to check.
     * @return Returns true if the code indicates no error was generated.
     */
    inline static bool isSuccess(EStatus status)
    {
        return ((S32)status >= 0);
    }

    /**
     * @brief Helper function to turn status into a string.
     *
     * @param status The status to check.
     * @return Returns the name of the status code or empty string on failure.
     */
    static std::string lookupStatusString(EStatus status);

    /**
     * @brief Process the data in buffer.
     *
     * @param data The data processed
     * @param eos True if this function call is the last because end of stream.
     * @param pump The pump which is calling process. May be NULL.
     * @param context Shared meta-data for the process.
     * @return Returns a status code from the operation.
     */
    EStatus process(
        const LLChannelDescriptors& channels,
        buffer_ptr_t& buffer,
        bool& eos,
        LLSD& context,
        LLPumpIO* pump);

    /**
     * @brief Give this pipe a chance to handle a generated error
     *
     * If this pipe is in a chain being processed by a pump, and one
     * of the pipes generates an error, the pump will rewind through
     * the chain to see if any of the links can handle the error. For
     * example, if a connection is refused in a socket connection, the
     * socket client can try to find a new destination host. Return an
     * error code if this pipe does not handle the error passed in.
     * @param status The status code for the error
     * @param pump The pump which was calling process before the error
     * was generated.
     * @return Returns a status code from the operation. Returns an
     * error code if the error passed in was not handled. Returns
     * STATUS_OK to indicate the error has been handled.
     */
    virtual EStatus handleError(EStatus status, LLPumpIO* pump);

    /**
     * @brief Base Destructor - do not call <code>delete</code> directly.
     */
    virtual ~LLIOPipe();

    virtual bool isValid() ;

protected:
    /**
     * @brief Base Constructor.
     */
    LLIOPipe();

    /**
     * @brief Process the data in buffer
     */
    virtual EStatus process_impl(
        const LLChannelDescriptors& channels,
        buffer_ptr_t& buffer,
        bool& eos,
        LLSD& context,
        LLPumpIO* pump) = 0;

private:
    friend void intrusive_ptr_add_ref(LLIOPipe* p);
    friend void intrusive_ptr_release(LLIOPipe* p);
    U32 mReferenceCount;
};

inline void intrusive_ptr_add_ref(LLIOPipe* p)
{
    ++p->mReferenceCount;
}
inline void intrusive_ptr_release(LLIOPipe* p)
{
    if(p && 0 == --p->mReferenceCount)
    {
        delete p;
    }
}

#endif // LL_LLIOPIPE_H