source: trunk/sources/thelib/src/protocols/baseprotocol.cpp @ 768

Revision 768, 11.3 KB checked in by josh, 7 days ago (diff)

-- Don't double-enqueue packets for delete.

This may lead to an infinite loop in some cases,
especially with dependent protocols that are not chained.

Line 
1/*
2 *  Copyright (c) 2010,
3 *  Gavriloaie Eugen-Andrei (shiretu@gmail.com)
4 *
5 *  This file is part of crtmpserver.
6 *  crtmpserver is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  crtmpserver is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with crtmpserver.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21#include "protocols/baseprotocol.h"
22#include "netio/netio.h"
23#include "protocols/protocolmanager.h"
24#include "application/baseclientapplication.h"
25#include "protocols/tcpprotocol.h"
26
27//#define LOG_CONSTRUCTOR_DESTRUCTOR
28
29uint32_t BaseProtocol::_idGenerator = 0;
30
31BaseProtocol::BaseProtocol(uint64_t type) {
32        _id = ++_idGenerator;
33        _type = type;
34        _pFarProtocol = NULL;
35        _pNearProtocol = NULL;
36        _deleteFar = true;
37        _deleteNear = true;
38        _enqueueForDelete = false;
39        _gracefullyEnqueueForDelete = false;
40        _pApplication = NULL;
41#ifdef LOG_CONSTRUCTOR_DESTRUCTOR
42        FINEST("Protocol with id %u of type %s created; F: %p,N: %p, DF: %hhu, DN: %hhu",
43                        _id, STR(tagToString(_type)),
44                        _pFarProtocol, _pNearProtocol, _deleteFar, _deleteNear);
45#endif
46        ProtocolManager::RegisterProtocol(this);
47        GETCLOCKS(_creationTimestamp);
48        _creationTimestamp /= (double) CLOCKS_PER_SECOND;
49        _creationTimestamp *= 1000.00;
50}
51
52BaseProtocol::~BaseProtocol() {
53#ifdef LOG_CONSTRUCTOR_DESTRUCTOR
54        FINEST("Protocol with id %"PRIu32"(%p) of type %s going to be deleted; F: %p,N: %p, DF: %"PRIu8", DN: %"PRIu8,
55                        _id,
56                        this,
57                        STR(tagToString(_type)),
58                        _pFarProtocol,
59                        _pNearProtocol,
60                        _deleteFar,
61                        _deleteNear);
62#endif
63        BaseProtocol *pFar = _pFarProtocol;
64        BaseProtocol *pNear = _pNearProtocol;
65
66        _pFarProtocol = NULL;
67        _pNearProtocol = NULL;
68        if (pFar != NULL) {
69                pFar->_pNearProtocol = NULL;
70                if (_deleteFar) {
71                        pFar->EnqueueForDelete();
72                }
73        }
74        if (pNear != NULL) {
75                pNear->_pFarProtocol = NULL;
76                if (_deleteNear) {
77                        pNear->EnqueueForDelete();
78                }
79        }
80#ifdef LOG_CONSTRUCTOR_DESTRUCTOR
81        FINEST("Protocol with id %"PRIu32"(%p) of type %s deleted; F: %p,N: %p, DF: %"PRIu8", DN: %"PRIu8,
82                        _id,
83                        this,
84                        STR(tagToString(_type)),
85                        _pFarProtocol,
86                        _pNearProtocol,
87                        _deleteFar,
88                        _deleteNear);
89#endif
90        ProtocolManager::UnRegisterProtocol(this);
91}
92
93uint64_t BaseProtocol::GetType() {
94        return _type;
95}
96
97uint32_t BaseProtocol::GetId() {
98        return _id;
99}
100
101double BaseProtocol::GetSpawnTimestamp() {
102        return _creationTimestamp;
103}
104
105BaseProtocol *BaseProtocol::GetFarProtocol() {
106        return _pFarProtocol;
107}
108
109void BaseProtocol::SetFarProtocol(BaseProtocol *pProtocol) {
110        if (!AllowFarProtocol(pProtocol->_type)) {
111                ASSERT("Protocol %s can't accept a far protocol of type: %s",
112                                STR(tagToString(_type)),
113                                STR(tagToString(pProtocol->_type)));
114        }
115        if (!pProtocol->AllowNearProtocol(_type)) {
116                ASSERT("Protocol %s can't accept a near protocol of type: %s",
117                                STR(tagToString(pProtocol->_type)),
118                                STR(tagToString(_type)));
119        }
120        if (_pFarProtocol == NULL) {
121                _pFarProtocol = pProtocol;
122                pProtocol->SetNearProtocol(this);
123#ifdef LOG_CONSTRUCTOR_DESTRUCTOR
124                FINEST("Protocol with id %u of type %s setted up; F: %p,N: %p, DF: %hhu, DN: %hhu",
125                                _id, STR(tagToString(_type)),
126                                _pFarProtocol, _pNearProtocol, _deleteFar, _deleteNear);
127#endif
128        } else {
129                if (_pFarProtocol != pProtocol) {
130                        ASSERT("Far protocol already present");
131                }
132        }
133}
134
135void BaseProtocol::ResetFarProtocol() {
136        if (_pFarProtocol != NULL) {
137                _pFarProtocol->_pNearProtocol = NULL;
138        }
139        _pFarProtocol = NULL;
140}
141
142BaseProtocol *BaseProtocol::GetNearProtocol() {
143        return _pNearProtocol;
144}
145
146void BaseProtocol::SetNearProtocol(BaseProtocol *pProtocol) {
147        if (!AllowNearProtocol(pProtocol->_type)) {
148                ASSERT("Protocol %s can't accept a near protocol of type: %s",
149                                STR(tagToString(_type)),
150                                STR(tagToString(pProtocol->_type)));
151        }
152        if (!pProtocol->AllowFarProtocol(_type)) {
153                ASSERT("Protocol %s can't accept a far protocol of type: %s",
154                                STR(tagToString(pProtocol->_type)),
155                                STR(tagToString(_type)));
156        }
157        if (_pNearProtocol == NULL) {
158                _pNearProtocol = pProtocol;
159                pProtocol->SetFarProtocol(this);
160#ifdef LOG_CONSTRUCTOR_DESTRUCTOR
161                FINEST("Protocol with id %u of type %s setted up; F: %p,N: %p, DF: %hhu, DN: %hhu",
162                                _id, STR(tagToString(_type)),
163                                _pFarProtocol, _pNearProtocol, _deleteFar, _deleteNear);
164#endif
165        } else {
166                if (_pNearProtocol != pProtocol) {
167                        ASSERT("Near protocol already present");
168                }
169        }
170}
171
172void BaseProtocol::ResetNearProtocol() {
173        if (_pNearProtocol != NULL)
174                _pNearProtocol->_pFarProtocol = NULL;
175        _pNearProtocol = NULL;
176}
177
178void BaseProtocol::DeleteNearProtocol(bool deleteNear) {
179        _deleteNear = deleteNear;
180}
181
182void BaseProtocol::DeleteFarProtocol(bool deleteFar) {
183        _deleteFar = deleteFar;
184}
185
186BaseProtocol *BaseProtocol::GetFarEndpoint() {
187        if (_pFarProtocol == NULL) {
188                return this;
189        } else {
190                return _pFarProtocol->GetFarEndpoint();
191        }
192}
193
194BaseProtocol *BaseProtocol::GetNearEndpoint() {
195        if (_pNearProtocol == NULL)
196                return this;
197        else
198                return _pNearProtocol->GetNearEndpoint();
199}
200
201void BaseProtocol::EnqueueForDelete() {
202        if (_enqueueForDelete) return;
203        _enqueueForDelete = true;
204        ProtocolManager::EnqueueForDelete(this);
205}
206
207void BaseProtocol::GracefullyEnqueueForDelete(bool fromFarSide) {
208        if (fromFarSide)
209                return GetFarEndpoint()->GracefullyEnqueueForDelete(false);
210
211        _gracefullyEnqueueForDelete = true;
212        if (GetOutputBuffer() != NULL) {
213                return;
214        }
215
216        if (_pNearProtocol != NULL) {
217                _pNearProtocol->GracefullyEnqueueForDelete(false);
218        } else {
219                EnqueueForDelete();
220        }
221}
222
223bool BaseProtocol::IsEnqueueForDelete() {
224        return _enqueueForDelete || _gracefullyEnqueueForDelete;
225
226}
227
228BaseClientApplication * BaseProtocol::GetApplication() {
229        return _pApplication;
230}
231
232void BaseProtocol::SetOutboundConnectParameters(Variant &customParameters) {
233        _customParameters = customParameters;
234}
235
236void BaseProtocol::GetStackStats(Variant &info, uint32_t namespaceId) {
237        IOHandler *pIOHandler = GetIOHandler();
238        if (pIOHandler != NULL) {
239                pIOHandler->GetStats(info["carrier"], namespaceId);
240        } else {
241                info["carrier"] = Variant();
242        }
243        BaseProtocol *pTemp = GetFarEndpoint();
244        while (pTemp != NULL) {
245                Variant item;
246                pTemp->GetStats(item, namespaceId);
247                info["stack"].PushToArray(item);
248                pTemp = pTemp->GetNearProtocol();
249        }
250}
251
252Variant &BaseProtocol::GetCustomParameters() {
253        return _customParameters;
254}
255
256BaseProtocol::operator string() {
257        string result = "";
258        if (GetIOHandler() != NULL) {
259                switch (GetIOHandler()->GetType()) {
260                        case IOHT_ACCEPTOR:
261                                result = format("A(%d) <-> ", GetIOHandler()->GetInboundFd());
262                                break;
263                        case IOHT_TCP_CARRIER:
264                                result = format("CTCP(%d) <-> ", GetIOHandler()->GetInboundFd());
265                                break;
266                        case IOHT_UDP_CARRIER:
267                                result = format("CUDP(%d) <-> ", GetIOHandler()->GetInboundFd());
268                                break;
269                        case IOHT_TCP_CONNECTOR:
270                                result = format("CO(%d) <-> ", GetIOHandler()->GetInboundFd());
271                                break;
272                        case IOHT_TIMER:
273                                result = format("T(%d) <-> ", GetIOHandler()->GetInboundFd());
274                                break;
275                        case IOHT_STDIO:
276                                result = format("STDIO <-> ");
277                                break;
278                        default:
279                                result = format("#unknown %hhu#(%d,%d) <-> ",
280                                                GetIOHandler()->GetType(),
281                                                GetIOHandler()->GetInboundFd(),
282                                                GetIOHandler()->GetOutboundFd());
283                                break;
284                }
285        }
286        BaseProtocol *pTemp = GetFarEndpoint();
287        while (pTemp != NULL) {
288                result += pTemp->ToString(_id);
289                pTemp = pTemp->_pNearProtocol;
290                if (pTemp != NULL)
291                        result += " <-> ";
292        }
293        return result;
294}
295
296bool BaseProtocol::Initialize(Variant &parameters) {
297        WARN("You should override bool BaseProtocol::Initialize(Variant &parameters) on protocol %s",
298                        STR(tagToString(_type)));
299        _customParameters = parameters;
300        return true;
301}
302
303IOHandler *BaseProtocol::GetIOHandler() {
304        if (_pFarProtocol != NULL)
305                return _pFarProtocol->GetIOHandler();
306        return NULL;
307}
308
309void BaseProtocol::SetIOHandler(IOHandler *pCarrier) {
310        if (_pFarProtocol != NULL)
311                _pFarProtocol->SetIOHandler(pCarrier);
312}
313
314IOBuffer * BaseProtocol::GetInputBuffer() {
315        if (_pFarProtocol != NULL)
316                return _pFarProtocol->GetInputBuffer();
317        return NULL;
318}
319
320IOBuffer * BaseProtocol::GetOutputBuffer() {
321        if (_pNearProtocol != NULL)
322                return _pNearProtocol->GetOutputBuffer();
323        return NULL;
324}
325
326uint64_t BaseProtocol::GetDecodedBytesCount() {
327        if (_pFarProtocol != NULL)
328                return _pFarProtocol->GetDecodedBytesCount();
329        return 0;
330}
331
332bool BaseProtocol::EnqueueForOutbound() {
333        if (_pFarProtocol != NULL)
334                return _pFarProtocol->EnqueueForOutbound();
335        return true;
336}
337
338bool BaseProtocol::EnqueueForTimeEvent(uint32_t seconds) {
339        if (_pFarProtocol != NULL)
340                return _pFarProtocol->EnqueueForTimeEvent(seconds);
341        return true;
342}
343
344bool BaseProtocol::TimePeriodElapsed() {
345        if (_pNearProtocol != NULL)
346                return _pNearProtocol->TimePeriodElapsed();
347        return true;
348}
349
350void BaseProtocol::ReadyForSend() {
351        if (_gracefullyEnqueueForDelete) {
352                EnqueueForDelete();
353                return;
354        }
355        if (_pNearProtocol != NULL)
356                _pNearProtocol->ReadyForSend();
357}
358
359void BaseProtocol::SignalInterProtocolEvent(Variant &event) {
360        if (_pNearProtocol != NULL)
361                _pNearProtocol->SignalInterProtocolEvent(event);
362}
363
364void BaseProtocol::SetApplication(BaseClientApplication *pApplication) {
365        //1. Get the old and the new application name and id
366        string oldAppName = "(none)";
367        uint32_t oldAppId = 0;
368        string newAppName = "(none)";
369        uint32_t newAppId = 0;
370        if (_pApplication != NULL) {
371                oldAppName = _pApplication->GetName();
372                oldAppId = _pApplication->GetId();
373        }
374        if (pApplication != NULL) {
375                newAppName = pApplication->GetName();
376                newAppId = pApplication->GetId();
377        }
378
379        //2. Are we landing on the same application?
380        if (oldAppId == newAppId) {
381                return;
382        }
383
384        //3. If the application is the same, return. Otherwise, unregister
385        if (_pApplication != NULL) {
386                _pApplication->UnRegisterProtocol(this);
387                _pApplication = NULL;
388        }
389
390        //4. Setup the new application
391        _pApplication = pApplication;
392
393        //5. Register to it
394        if (_pApplication != NULL) {
395                _pApplication->RegisterProtocol(this);
396        }
397
398        //6. Trigger log to production
399}
400
401bool BaseProtocol::SignalInputData(IOBuffer &buffer, sockaddr_in *pPeerAddress) {
402        WARN("This should be overridden. Protocol type is %s", STR(tagToString(_type)));
403        return SignalInputData(buffer);
404}
405
406bool BaseProtocol::SignalInputData(int32_t recvAmount, sockaddr_in *pPeerAddress) {
407        WARN("This should be overridden: %s", STR(tagToString(_type)));
408        return SignalInputData(recvAmount);
409}
410
411void BaseProtocol::GetStats(Variant &info, uint32_t namespaceId) {
412        info["id"] = (((uint64_t) namespaceId) << 32) | GetId();
413        info["type"] = tagToString(_type);
414        info["creationTimestamp"] = _creationTimestamp;
415        double queryTimestamp = 0;
416        GETCLOCKS(queryTimestamp);
417        queryTimestamp /= (double) CLOCKS_PER_SECOND;
418        queryTimestamp *= 1000.00;
419        info["queryTimestamp"] = queryTimestamp;
420        info["isEnqueueForDelete"] = (bool)IsEnqueueForDelete();
421        if (_pApplication != NULL)
422                info["applicationId"] = (((uint64_t) namespaceId) << 32) | _pApplication->GetId();
423        else
424                info["applicationId"] = (((uint64_t) namespaceId) << 32);
425}
426
427string BaseProtocol::ToString(uint32_t currentId) {
428        string result = "";
429        if (_id == currentId)
430                result = format("[%s(%u)]", STR(tagToString(_type)), _id);
431        else
432                result = format("%s(%u)", STR(tagToString(_type)), _id);
433        return result;
434}
435
436
Note: See TracBrowser for help on using the repository browser.