1 /**
2 * sigcall.cpp
3 * This file is part of the YATE Project http://YATE.null.ro
4 *
5 * Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
6 *
7 * Yet Another Telephony Engine - a fully featured software PBX and IVR
8 * Copyright (C) 2004-2014 Null Team
9 *
10 * This software is distributed under multiple licenses;
11 * see the COPYING file in the main directory for licensing
12 * information for this specific distribution.
13 *
14 * This use of this software may be subject to additional restrictions.
15 * See the LEGAL file in the main directory for details.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 #include "yatesig.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26
27
28 using namespace TelEngine;
29
30 const TokenDict SignallingCircuit::s_lockNames[] = {
31 {"localhw", LockLocalHWFail},
32 {"localmaint", LockLocalMaint},
33 {"lockinghw", LockingHWFail},
34 {"lockingmaint", LockingMaint},
35 {"localhwchanged", LockLocalHWFailChg},
36 {"localmaintchanged", LockLocalMaintChg},
37 {"resetting", Resetting},
38 {"remotehw", LockRemoteHWFail},
39 {"remotemaint", LockRemoteMaint},
40 {"remotehwchanged", LockRemoteHWFailChg},
41 {"remotemaintchanged", LockRemoteMaintChg},
42 {0,0},
43 };
44
45 const TokenDict SignallingCallControl::s_mediaRequired[] = {
46 { "no", SignallingCallControl::MediaNever },
47 { "false", SignallingCallControl::MediaNever },
48 { "off", SignallingCallControl::MediaNever },
49 { "disable", SignallingCallControl::MediaNever },
50 { "answered", SignallingCallControl::MediaAnswered },
51 { "connected", SignallingCallControl::MediaAnswered },
52 { "ringing", SignallingCallControl::MediaRinging },
53 { "progress", SignallingCallControl::MediaRinging },
54 { "yes", SignallingCallControl::MediaAlways },
55 { "true", SignallingCallControl::MediaAlways },
56 { "on", SignallingCallControl::MediaAlways },
57 { "enable", SignallingCallControl::MediaAlways },
58 { 0, 0 }
59 };
60
61 /**
62 * SignallingCallControl
63 */
SignallingCallControl(const NamedList & params,const char * msgPrefix)64 SignallingCallControl::SignallingCallControl(const NamedList& params,
65 const char* msgPrefix)
66 : Mutex(true,"SignallingCallControl"),
67 m_mediaRequired(MediaNever),
68 m_verifyEvent(false),
69 m_verifyTimer(0),
70 m_circuits(0),
71 m_strategy(SignallingCircuitGroup::Increment),
72 m_exiting(false)
73 {
74 // Controller location
75 m_location = params.getValue(YSTRING("location"));
76 // Strategy
77 const char* strategy = params.getValue(YSTRING("strategy"),"increment");
78 m_strategy = SignallingCircuitGroup::str2strategy(strategy);
79 String restrict;
80 if (m_strategy != SignallingCircuitGroup::Random)
81 restrict = params.getValue(YSTRING("strategy-restrict"));
82 if (!restrict.null()) {
83 if (restrict == "odd")
84 m_strategy |= SignallingCircuitGroup::OnlyOdd;
85 else if (restrict == "even")
86 m_strategy |= SignallingCircuitGroup::OnlyEven;
87 else if (restrict == "odd-fallback")
88 m_strategy |= SignallingCircuitGroup::OnlyOdd | SignallingCircuitGroup::Fallback;
89 else if (restrict == "even-fallback")
90 m_strategy |= SignallingCircuitGroup::OnlyEven | SignallingCircuitGroup::Fallback;
91 }
92
93 // Message prefix
94 m_msgPrefix = params.getValue(YSTRING("message-prefix"),msgPrefix);
95
96 // Verify event timer
97 m_verifyTimer.interval(params,"verifyeventinterval",10,120,true,true);
98 m_verifyTimer.start();
99
100 // Media Required
101 m_mediaRequired = (MediaRequired)params.getIntValue(YSTRING("needmedia"),
102 s_mediaRequired,m_mediaRequired);
103 }
104
~SignallingCallControl()105 SignallingCallControl::~SignallingCallControl()
106 {
107 attach((SignallingCircuitGroup*)0);
108 }
109
110 // Attach a signalling circuit group. Set its strategy
attach(SignallingCircuitGroup * circuits)111 SignallingCircuitGroup* SignallingCallControl::attach(SignallingCircuitGroup* circuits)
112 {
113 Lock mylock(this);
114 // Don't attach if it's the same object
115 if (m_circuits == circuits)
116 return 0;
117 cleanup(circuits ? "circuit group attach" : "circuit group detach");
118 if (m_circuits && circuits)
119 Debug(DebugNote,
120 "SignallingCallControl. Replacing circuit group (%p) with (%p) [%p]",
121 m_circuits,circuits,this);
122 SignallingCircuitGroup* tmp = m_circuits;
123 m_circuits = circuits;
124 if (m_circuits) {
125 Lock lock(m_circuits);
126 m_circuits->setStrategy(m_strategy);
127 }
128 return tmp;
129 }
130
131 // Reserve a circuit from a given list in attached group
reserveCircuit(SignallingCircuit * & cic,const char * range,int checkLock,const String * list,bool mandatory,bool reverseRestrict)132 bool SignallingCallControl::reserveCircuit(SignallingCircuit*& cic, const char* range,
133 int checkLock, const String* list, bool mandatory, bool reverseRestrict)
134 {
135 DDebug(DebugAll,"SignallingCallControl::reserveCircuit(%p,'%s',%d,'%s',%s,%s) [%p]",
136 cic,range,checkLock,TelEngine::c_safe(list),
137 String::boolText(mandatory),String::boolText(reverseRestrict),this);
138 Lock mylock(this);
139 releaseCircuit(cic);
140 if (!m_circuits)
141 return false;
142 if (list) {
143 int s = -1;
144 if (!mandatory && reverseRestrict) {
145 s = m_circuits->strategy();
146 // Use the opposite strategy restriction
147 if (s & SignallingCircuitGroup::OnlyEven)
148 s = (s & ~SignallingCircuitGroup::OnlyEven) | SignallingCircuitGroup::OnlyOdd;
149 else if (s & SignallingCircuitGroup::OnlyOdd)
150 s = (s & ~SignallingCircuitGroup::OnlyOdd) | SignallingCircuitGroup::OnlyEven;
151 }
152 cic = m_circuits->reserve(*list,mandatory,checkLock,s,m_circuits->findRange(range));
153 }
154 else if (range) {
155 const char* nRange = range;
156 switch (nRange[0]) {
157 case '!':
158 mandatory = true;
159 nRange++;
160 break;
161 case '?':
162 mandatory = false;
163 nRange++;
164 break;
165 }
166 int num = String(nRange).toInteger();
167 if (num > 0) {
168 // Specific circuit required
169 SignallingCircuit* circuit = m_circuits->find(num);
170 if (circuit && !circuit->locked(checkLock) && circuit->reserve()) {
171 if (circuit->ref())
172 cic = circuit;
173 else
174 m_circuits->release(circuit);
175 }
176 if (cic || mandatory)
177 return (cic != 0);
178 DDebug(DebugInfo,"SignallingCallControl. Fallback, circuit %u not available [%p]",num,this);
179 }
180 cic = m_circuits->reserve(checkLock,-1,m_circuits->findRange(range));
181 }
182 else
183 cic = m_circuits->reserve(checkLock,-1);
184 return (cic != 0);
185 }
186
187 // Release a given circuit
releaseCircuit(SignallingCircuit * & cic,bool sync)188 bool SignallingCallControl::releaseCircuit(SignallingCircuit*& cic, bool sync)
189 {
190 if (!cic)
191 return false;
192 bool ok = cic->status(SignallingCircuit::Idle,sync);
193 DDebug(DebugAll,"SignallingCallControl. Released circuit %u [%p]",cic->code(),this);
194 cic->deref();
195 cic = 0;
196 return ok;
197 }
198
releaseCircuit(unsigned int code,bool sync)199 bool SignallingCallControl::releaseCircuit(unsigned int code, bool sync)
200 {
201 Lock mylock(this);
202 SignallingCircuit* cic = m_circuits ? m_circuits->find(code) : 0;
203 if (!cic)
204 return false;
205 return cic->status(SignallingCircuit::Idle,sync);
206 }
207
208 // Get events from calls
209 // Raise Disable event when no more calls and exiting
getEvent(const Time & when)210 SignallingEvent* SignallingCallControl::getEvent(const Time& when)
211 {
212 lock();
213 // Verify ?
214 if (m_verifyEvent && m_verifyTimer.timeout(when.msec())) {
215 SignallingMessage* msg = new SignallingMessage;
216 SignallingEvent* event = new SignallingEvent(SignallingEvent::Verify,msg,this);
217 buildVerifyEvent(msg->params());
218 TelEngine::destruct(msg);
219 setVerify(true,false,&when);
220 unlock();
221 return event;
222 }
223 ListIterator iter(m_calls);
224 for (;;) {
225 SignallingCall* call = static_cast<SignallingCall*>(iter.get());
226 // End of iteration?
227 if (!call)
228 break;
229 RefPointer<SignallingCall> callRef = call;
230 // Dead pointer?
231 if (!callRef)
232 continue;
233 unlock();
234 SignallingEvent* event = callRef->getEvent(when);
235 // Check if this call controller wants the event
236 if (event && !processEvent(event))
237 return event;
238 lock();
239 }
240 unlock();
241 // Get events from circuits not reserved
242 // TODO: Find a better way to parse circuit list to get events
243 Lock lckCtrl(this);
244 if (m_circuits) {
245 Lock lckCic(m_circuits);
246 for (ObjList* o = m_circuits->circuits().skipNull(); o; o = o->skipNext()) {
247 SignallingCircuit* cic = static_cast<SignallingCircuit*>(o->get());
248 if (cic->status() == SignallingCircuit::Reserved)
249 continue;
250 SignallingCircuitEvent* ev = cic->getEvent(when);
251 if (!ev)
252 continue;
253 SignallingEvent* event = processCircuitEvent(ev);
254 if (event)
255 return event;
256 }
257 }
258 // Terminate if exiting and no more calls
259 //TODO: Make sure we raise this event one time only
260 if (exiting() && !m_calls.skipNull())
261 return new SignallingEvent(SignallingEvent::Disable,0,this);
262 return 0;
263 }
264
265 // Clear call list
clearCalls()266 void SignallingCallControl::clearCalls()
267 {
268 lock();
269 m_calls.clear();
270 unlock();
271 }
272
273 // Remove a call from list
removeCall(SignallingCall * call,bool del)274 void SignallingCallControl::removeCall(SignallingCall* call, bool del)
275 {
276 if (!call)
277 return;
278 lock();
279 if (m_calls.remove(call,del))
280 DDebug(DebugAll,
281 "SignallingCallControl. Call (%p) removed%s from queue [%p]",
282 call,(del ? " and deleted" : ""),this);
283 unlock();
284 }
285
286 // Set the verify event flag. Restart/fire verify timer
setVerify(bool restartTimer,bool fireNow,const Time * time)287 void SignallingCallControl::setVerify(bool restartTimer, bool fireNow, const Time* time)
288 {
289 m_verifyEvent = true;
290 if (!restartTimer)
291 return;
292 m_verifyTimer.stop();
293 if (!fireNow)
294 m_verifyTimer.start(time ? time->msec() : Time::msecNow());
295 else
296 m_verifyTimer.fire();
297 }
298
299
300 /**
301 * SignallingCall
302 */
SignallingCall(SignallingCallControl * controller,bool outgoing,bool signalOnly)303 SignallingCall::SignallingCall(SignallingCallControl* controller, bool outgoing, bool signalOnly)
304 : Mutex(true,"SignallingCall"),
305 m_lastEvent(0),
306 m_overlap(false),
307 m_controller(controller),
308 m_outgoing(outgoing),
309 m_signalOnly(signalOnly),
310 m_inMsgMutex(true,"SignallingCall::inMsg"),
311 m_private(0)
312 {
313 }
314
~SignallingCall()315 SignallingCall::~SignallingCall()
316 {
317 lock();
318 m_inMsg.clear();
319 if (m_controller)
320 m_controller->removeCall(this,false);
321 unlock();
322 }
323
324 // Event termination notification
eventTerminated(SignallingEvent * event)325 void SignallingCall::eventTerminated(SignallingEvent* event)
326 {
327 Lock mylock(this);
328 if (!m_lastEvent || !event || m_lastEvent != event)
329 return;
330 XDebug(DebugAll,"SignallingCall. Event (%p,'%s') terminated [%p]",event,event->name(),this);
331 m_lastEvent = 0;
332 }
333
enqueue(SignallingMessage * msg)334 void SignallingCall::enqueue(SignallingMessage* msg)
335 {
336 if (!msg)
337 return;
338 Lock lock(m_inMsgMutex);
339 m_inMsg.append(msg);
340 XDebug(DebugAll,"SignallingCall. Enqueued message (%p,'%s') [%p]",
341 msg,msg->name(),this);
342 }
343
344 // Dequeue a received message
dequeue(bool remove)345 SignallingMessage* SignallingCall::dequeue(bool remove)
346 {
347 Lock lock(m_inMsgMutex);
348 ObjList* obj = m_inMsg.skipNull();
349 if (!obj)
350 return 0;
351 SignallingMessage* msg = static_cast<SignallingMessage*>(obj->get());
352 if (remove) {
353 m_inMsg.remove(msg,false);
354 XDebug(DebugAll,"SignallingCall. Dequeued message (%p,'%s') [%p]",
355 msg,msg->name(),this);
356 }
357 return msg;
358 }
359
360
361 /**
362 * SignallingEvent
363 */
364 const TokenDict SignallingEvent::s_types[] = {
365 {"Unknown", Unknown},
366 {"Generic", Generic},
367 {"NewCall", NewCall},
368 {"Accept", Accept},
369 {"Connect", Connect},
370 {"Complete", Complete},
371 {"Progress", Progress},
372 {"Ringing", Ringing},
373 {"Answer", Answer},
374 {"Transfer", Transfer},
375 {"Suspend", Suspend},
376 {"Resume", Resume},
377 {"Release", Release},
378 {"Info", Info},
379 {"Charge", Charge},
380 {"Message", Message},
381 {"Facility", Facility},
382 {"Circuit", Circuit},
383 {"Enable", Enable},
384 {"Disable", Disable},
385 {"Reset", Reset},
386 {"Verify", Verify},
387 {0,0}
388 };
389
SignallingEvent(Type type,SignallingMessage * message,SignallingCall * call)390 SignallingEvent::SignallingEvent(Type type, SignallingMessage* message, SignallingCall* call)
391 : m_type(type), m_message(0), m_call(0), m_controller(0), m_cicEvent(0)
392 {
393 if (call && call->ref()) {
394 m_call = call;
395 m_controller = call->controller();
396 }
397 if (message && message->ref())
398 m_message = message;
399 }
400
SignallingEvent(Type type,SignallingMessage * message,SignallingCallControl * controller)401 SignallingEvent::SignallingEvent(Type type, SignallingMessage* message, SignallingCallControl* controller)
402 : m_type(type), m_message(0), m_call(0), m_controller(controller), m_cicEvent(0)
403 {
404 if (message && message->ref())
405 m_message = message;
406 }
407
408 // Constructor for a signalling circuit related event
SignallingEvent(SignallingCircuitEvent * & event,SignallingCall * call)409 SignallingEvent::SignallingEvent(SignallingCircuitEvent*& event, SignallingCall* call)
410 : m_type(Circuit), m_message(0), m_call(0), m_controller(0), m_cicEvent(event)
411 {
412 event = 0;
413 if (call && call->ref()) {
414 m_call = call;
415 m_controller = call->controller();
416 }
417 }
418
~SignallingEvent()419 SignallingEvent::~SignallingEvent()
420 {
421 m_controller = 0;
422 if (m_message)
423 m_message->deref();
424 if (m_call) {
425 m_call->eventTerminated(this);
426 m_call->deref();
427 }
428 TelEngine::destruct(m_cicEvent);
429 }
430
sendEvent()431 bool SignallingEvent::sendEvent()
432 {
433 if (m_call)
434 return m_call->sendEvent(this);
435 delete this;
436 return false;
437 }
438
439
440 /**
441 * SignallingCircuitEvent
442 */
SignallingCircuitEvent(SignallingCircuit * cic,Type type,const char * name)443 SignallingCircuitEvent::SignallingCircuitEvent(SignallingCircuit* cic, Type type, const char* name)
444 : NamedList(name),
445 m_circuit(0),
446 m_type(type)
447 {
448 XDebug(DebugAll,"SignallingCircuitEvent::SignallingCircuitEvent() [%p]",this);
449 if (cic && cic->ref())
450 m_circuit = cic;
451 }
452
~SignallingCircuitEvent()453 SignallingCircuitEvent::~SignallingCircuitEvent()
454 {
455 if (m_circuit) {
456 m_circuit->eventTerminated(this);
457 m_circuit->deref();
458 }
459 XDebug(DebugAll,"SignallingCircuitEvent::~SignallingCircuitEvent() [%p]",this);
460 }
461
462 // Send this event through the circuit. Release (delete) the event on success
sendEvent()463 bool SignallingCircuitEvent::sendEvent()
464 {
465 bool ok = m_circuit && m_circuit->sendEvent(type(),this);
466 delete this;
467 return ok;
468 }
469
470
471 /**
472 * SignallingCircuit
473 */
474 static const TokenDict s_cicTypeDict[] = {
475 {"TDM", SignallingCircuit::TDM},
476 {"RTP", SignallingCircuit::RTP},
477 {"IAX", SignallingCircuit::IAX},
478 {"Unknown", SignallingCircuit::Unknown},
479 {"Local", SignallingCircuit::Local},
480 {0,0}
481 };
482
483 static const TokenDict s_cicStatusDict[] = {
484 {"Missing", SignallingCircuit::Missing},
485 {"Disabled", SignallingCircuit::Disabled},
486 {"Idle", SignallingCircuit::Idle},
487 {"Reserved", SignallingCircuit::Reserved},
488 {"Starting", SignallingCircuit::Starting},
489 {"Stopping", SignallingCircuit::Stopping},
490 {"Special", SignallingCircuit::Special},
491 {"Connected", SignallingCircuit::Connected},
492 {0,0}
493 };
494
SignallingCircuit(Type type,unsigned int code,SignallingCircuitGroup * group,SignallingCircuitSpan * span)495 SignallingCircuit::SignallingCircuit(Type type, unsigned int code,
496 SignallingCircuitGroup* group, SignallingCircuitSpan* span)
497 : m_mutex(true,"SignallingCircuit::operations"),
498 m_group(group), m_span(span),
499 m_code(code), m_type(type),
500 m_status(Disabled),
501 m_lock(0), m_lastEvent(0), m_noEvents(true)
502 {
503 XDebug(m_group,DebugAll,"SignallingCircuit::SignallingCircuit [%p]",this);
504 }
505
SignallingCircuit(Type type,unsigned int code,Status status,SignallingCircuitGroup * group,SignallingCircuitSpan * span)506 SignallingCircuit::SignallingCircuit(Type type, unsigned int code, Status status,
507 SignallingCircuitGroup* group, SignallingCircuitSpan* span)
508 : m_mutex(true,"SignallingCircuit::operations"),
509 m_group(group), m_span(span),
510 m_code(code), m_type(type),
511 m_status(status),
512 m_lock(0), m_lastEvent(0), m_noEvents(true)
513 {
514 XDebug(m_group,DebugAll,"SignallingCircuit::SignallingCircuit [%p]",this);
515 }
516
~SignallingCircuit()517 SignallingCircuit::~SignallingCircuit()
518 {
519 clearEvents();
520 XDebug(m_group,DebugAll,"SignallingCircuit::~SignallingCircuit [%p]",this);
521 }
522
523 // Set circuit data from a list of parameters
setParams(const NamedList & params)524 bool SignallingCircuit::setParams(const NamedList& params)
525 {
526 bool ok = true;
527 unsigned int n = params.length();
528 for (unsigned int i = 0; i < n; i++) {
529 NamedString* param = params.getParam(i);
530 if (param && !setParam(param->name(),*param))
531 ok = false;
532 }
533 return ok;
534 }
535
536 // Get first event from queue
getEvent(const Time & when)537 SignallingCircuitEvent* SignallingCircuit::getEvent(const Time& when)
538 {
539 if (m_noEvents)
540 return 0;
541 Lock lock(m_mutex);
542 if (m_lastEvent)
543 return 0;
544 ObjList* obj = m_events.skipNull();
545 if (!obj) {
546 m_noEvents = true;
547 return 0;
548 }
549 m_lastEvent = static_cast<SignallingCircuitEvent*>(m_events.remove(obj->get(),false));
550 return m_lastEvent;
551 }
552
sendEvent(SignallingCircuitEvent::Type type,NamedList * params)553 bool SignallingCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
554 {
555 XDebug(m_group,DebugStub,"SignallingCircuit::sendEvent(%u,%p) [%p]",type,params,this);
556 return false;
557 }
558
559 // Set/reset circuit flag(s)
cicFlag(SignallingCircuit * cic,bool set,int flag,int chgFlag,bool setChg)560 inline bool cicFlag(SignallingCircuit* cic, bool set, int flag, int chgFlag, bool setChg)
561 {
562 if (chgFlag) {
563 if (setChg)
564 cic->setLock(chgFlag);
565 else
566 cic->resetLock(chgFlag);
567 }
568 if (set == (0 != cic->locked(flag)))
569 return false;
570 if (set)
571 cic->setLock(flag);
572 else
573 cic->resetLock(flag);
574 return true;
575 }
576
577 // Set/reset HW failure lock flag
hwLock(bool set,bool remote,bool changed,bool setChanged)578 bool SignallingCircuit::hwLock(bool set, bool remote, bool changed, bool setChanged)
579 {
580 Lock lock(m_mutex);
581 int flag = remote ? LockRemoteHWFail : LockLocalHWFail;
582 int chgFlag = changed ? (remote ? LockRemoteHWFailChg : LockLocalHWFailChg) : 0;
583 return cicFlag(this,set,flag,chgFlag,setChanged);
584 }
585
586 // Set/reset maintenance lock flag
maintLock(bool set,bool remote,bool changed,bool setChanged)587 bool SignallingCircuit::maintLock(bool set, bool remote, bool changed, bool setChanged)
588 {
589 Lock lock(m_mutex);
590 int flag = remote ? LockRemoteMaint : LockLocalMaint;
591 int chgFlag = changed ? (remote ? LockRemoteMaintChg : LockLocalMaintChg) : 0;
592 return cicFlag(this,set,flag,chgFlag,setChanged);
593 }
594
595 // Add event to queue
addEvent(SignallingCircuitEvent * event)596 void SignallingCircuit::addEvent(SignallingCircuitEvent* event)
597 {
598 if (!event)
599 return;
600 Lock lock(m_mutex);
601 m_noEvents = false;
602 m_events.append(event);
603 }
604
605 // Clear event queue
clearEvents()606 void SignallingCircuit::clearEvents()
607 {
608 Lock lock(m_mutex);
609 m_events.clear();
610 }
611
612 // Event termination notification
eventTerminated(SignallingCircuitEvent * event)613 void SignallingCircuit::eventTerminated(SignallingCircuitEvent* event)
614 {
615 Lock lock(m_mutex);
616 if (event && m_lastEvent == event) {
617 XDebug(m_group,DebugAll,"Event (%p) '%s' terminated for cic=%u [%p]",
618 event,event->c_str(),code(),this);
619 m_lastEvent = 0;
620 }
621 }
622
623 // Get the text associated with a circuit type
lookupType(int type)624 const char* SignallingCircuit::lookupType(int type)
625 {
626 return lookup(type,s_cicTypeDict);
627 }
628
629 // Get the text associated with a circuit status
lookupStatus(int status)630 const char* SignallingCircuit::lookupStatus(int status)
631 {
632 return lookup(status,s_cicStatusDict);
633 }
634
635 /**
636 * SignallingCircuitRange
637 */
SignallingCircuitRange(const String & rangeStr,const char * name,int strategy)638 SignallingCircuitRange::SignallingCircuitRange(const String& rangeStr,
639 const char* name, int strategy)
640 : String(name),
641 m_count(0), m_last(0),
642 m_strategy(strategy),
643 m_used(0)
644 {
645 add(rangeStr);
646 }
647
648 // Allocate and return an array containing range circuits
copyRange(unsigned int & count) const649 unsigned int* SignallingCircuitRange::copyRange(unsigned int& count) const
650 {
651 if (!m_count)
652 return 0;
653 count = m_count;
654 unsigned int* tmp = new unsigned int[count];
655 ::memcpy(tmp,range(),m_range.length());
656 return tmp;
657 }
658
659 // Add codes to this range from a string
add(const String & rangeStr)660 bool SignallingCircuitRange::add(const String& rangeStr)
661 {
662 unsigned int n = 0;
663 unsigned int* p = SignallingUtils::parseUIntArray(rangeStr,0,(unsigned int)-1,n,true);
664 if (!p)
665 return false;
666 add(p,n);
667 delete[] p;
668 return true;
669 }
670
671 // Add an array of circuit codes to this range
add(unsigned int * codes,unsigned int len)672 void SignallingCircuitRange::add(unsigned int* codes, unsigned int len)
673 {
674 if (!(codes && len))
675 return;
676 m_range.append(codes,len*sizeof(unsigned int));
677 m_count += len;
678 updateLast();
679 }
680
681 // Add a compact range of circuit codes to this range
add(unsigned int first,unsigned int last)682 void SignallingCircuitRange::add(unsigned int first, unsigned int last)
683 {
684 if (first > last)
685 return;
686 unsigned int count = last - first + 1;
687 DataBlock data(0,count*sizeof(unsigned int));
688 unsigned int* codes = (unsigned int*)data.data();
689 for (unsigned int i = 0; i < count; i++)
690 codes[i] = first+i;
691 m_range.append(data);
692 m_count += count;
693 updateLast();
694 }
695
696 // Remove a circuit code from this range
remove(unsigned int code)697 void SignallingCircuitRange::remove(unsigned int code)
698 {
699 unsigned int* d = (unsigned int*)range();
700 for (unsigned int i = 0; i < count(); i++)
701 if (d[i] == code)
702 d[i] = 0;
703 updateLast();
704 }
705
706
707 // Check if a circuit code is within this range
find(unsigned int code)708 bool SignallingCircuitRange::find(unsigned int code)
709 {
710 if (!range())
711 return false;
712 for (unsigned int i = 0; i < count(); i++)
713 if (range()[i] == code)
714 return true;
715 return false;
716 }
717
718 // Update last circuit code
updateLast()719 void SignallingCircuitRange::updateLast()
720 {
721 m_last = 0;
722 for (unsigned int i = 0; i < count(); i++)
723 if (m_last <= range()[i])
724 m_last = range()[i] + 1;
725 }
726
727
728 /**
729 * SignallingCircuitGroup
730 */
731 const TokenDict SignallingCircuitGroup::s_strategy[] = {
732 {"increment", Increment},
733 {"decrement", Decrement},
734 {"lowest", Lowest},
735 {"highest", Highest},
736 {"random", Random},
737 {0,0}
738 };
739
SignallingCircuitGroup(unsigned int base,int strategy,const char * name)740 SignallingCircuitGroup::SignallingCircuitGroup(unsigned int base, int strategy, const char* name)
741 : SignallingComponent(name),
742 Mutex(true,"SignallingCircuitGroup"),
743 m_range(String::empty(),name,strategy),
744 m_base(base)
745 {
746 setName(name);
747 XDebug(this,DebugAll,"SignallingCircuitGroup::SignallingCircuitGroup() [%p]",this);
748 }
749
750 // Set circuits status to Missing. Clear circuit list
751 // Clear span list
~SignallingCircuitGroup()752 SignallingCircuitGroup::~SignallingCircuitGroup()
753 {
754 clearAll();
755 XDebug(this,DebugAll,"SignallingCircuitGroup::~SignallingCircuitGroup() [%p]",this);
756 }
757
758 // Find a circuit by code
find(unsigned int cic,bool local)759 SignallingCircuit* SignallingCircuitGroup::find(unsigned int cic, bool local)
760 {
761 if (!local) {
762 if (cic < m_base)
763 return 0;
764 cic -= m_base;
765 }
766 Lock mylock(this);
767 if (cic >= m_range.m_last)
768 return 0;
769 ObjList* l = m_circuits.skipNull();
770 for (; l; l = l->skipNext()) {
771 SignallingCircuit* c = static_cast<SignallingCircuit*>(l->get());
772 if (c->code() == cic)
773 return c;
774 }
775 return 0;
776 }
777
778 // Find a range of circuits owned by this group
findRange(const char * name)779 SignallingCircuitRange* SignallingCircuitGroup::findRange(const char* name)
780 {
781 Lock mylock(this);
782 ObjList* obj = m_ranges.find(name);
783 return obj ? static_cast<SignallingCircuitRange*>(obj->get()) : 0;
784 }
785
getCicList(String & dest)786 void SignallingCircuitGroup::getCicList(String& dest)
787 {
788 dest = "";
789 Lock mylock(this);
790 for (ObjList* l = m_circuits.skipNull(); l; l = l->skipNext()) {
791 SignallingCircuit* c = static_cast<SignallingCircuit*>(l->get());
792 dest.append(String(c->code()),",");
793 }
794 }
795
796 // Insert a circuit if not already in the list
insert(SignallingCircuit * circuit)797 bool SignallingCircuitGroup::insert(SignallingCircuit* circuit)
798 {
799 if (!circuit)
800 return false;
801 Lock mylock(this);
802 if (m_circuits.find(circuit) || find(circuit->code(),true))
803 return false;
804 circuit->m_group = this;
805 m_circuits.append(circuit);
806 m_range.add(circuit->code());
807 return true;
808 }
809
810 // Remove a circuit from list. Update maximum circuit code
remove(SignallingCircuit * circuit)811 void SignallingCircuitGroup::remove(SignallingCircuit* circuit)
812 {
813 if (!circuit)
814 return;
815 Lock mylock(this);
816 if (!m_circuits.remove(circuit,false))
817 return;
818 circuit->m_group = 0;
819 m_range.remove(circuit->code());
820 // TODO: remove from all ranges
821 }
822
823 // Append a span to the list if not already there
insertSpan(SignallingCircuitSpan * span)824 bool SignallingCircuitGroup::insertSpan(SignallingCircuitSpan* span)
825 {
826 if (!span)
827 return false;
828 Lock mylock(this);
829 if (!m_spans.find(span))
830 m_spans.append(span);
831 return true;
832 }
833
buildSpan(const String & name,unsigned int start,NamedList * param)834 SignallingCircuitSpan* SignallingCircuitGroup::buildSpan(const String& name, unsigned int start, NamedList* param)
835 {
836 // Local class used to pass the circuit group pointer to the span
837 class VoiceParams : public NamedList
838 {
839 public:
840 inline VoiceParams(const char* name, SignallingCircuitGroup* group)
841 : NamedList(name), m_group(group)
842 { }
843 virtual void* getObject(const String& name) const
844 { return (name == YSTRING("SignallingCircuitGroup")) ? m_group : NamedList::getObject(name); }
845 SignallingCircuitGroup* m_group;
846 };
847
848 VoiceParams params(debugName(),this);
849 params << "/" << name;
850 params.addParam("voice",name);
851 if (param)
852 params.copyParams(*param);
853 if (start)
854 params.addParam("start",String(start));
855 return YSIGCREATE(SignallingCircuitSpan,¶ms);
856 }
857
858 // Build and insert a range from circuits belonging to a given span
insertRange(SignallingCircuitSpan * span,const char * name,int strategy)859 void SignallingCircuitGroup::insertRange(SignallingCircuitSpan* span, const char* name,
860 int strategy)
861 {
862 if (!span)
863 return;
864 if (!name)
865 name = span->id();
866 Lock mylock(this);
867 String tmp;
868 for (ObjList* o = m_circuits.skipNull(); o; o = o->skipNext()) {
869 SignallingCircuit* c = static_cast<SignallingCircuit*>(o->get());
870 if (span == c->span())
871 tmp.append(String(c->code()),",");
872 }
873 mylock.drop();
874 insertRange(tmp,name,strategy);
875 }
876
877 // Build and insert a range contained in a string
insertRange(const String & range,const char * name,int strategy)878 void SignallingCircuitGroup::insertRange(const String& range, const char* name,
879 int strategy)
880 {
881 Lock mylock(this);
882 if (findRange(name))
883 return;
884 if (strategy < 0)
885 strategy = m_range.m_strategy;
886 m_ranges.append(new SignallingCircuitRange(range,name,strategy));
887 Debug(this,DebugNote,"Added range %s: %s [%p]",name,range.c_str(),this);
888 }
889
890 // Remove a span from list
removeSpan(SignallingCircuitSpan * span,bool delCics,bool delSpan)891 void SignallingCircuitGroup::removeSpan(SignallingCircuitSpan* span, bool delCics, bool delSpan)
892 {
893 if (!span)
894 return;
895 Lock mylock(this);
896 if (delCics)
897 removeSpanCircuits(span);
898 m_spans.remove(span,delSpan);
899 }
900
901 // Remove circuits belonging to a span
removeSpanCircuits(SignallingCircuitSpan * span)902 void SignallingCircuitGroup::removeSpanCircuits(SignallingCircuitSpan* span)
903 {
904 if (!span)
905 return;
906 Lock mylock(this);
907 ListIterator iter(m_circuits);
908 for (GenObject* obj = 0; (obj = iter.get());) {
909 SignallingCircuit* c = static_cast<SignallingCircuit*>(obj);
910 if (span == c->span()) {
911 remove(c);
912 TelEngine::destruct(c);
913 }
914 }
915 }
916
917 // Get the status of a circuit given by its code
status(unsigned int cic)918 SignallingCircuit::Status SignallingCircuitGroup::status(unsigned int cic)
919 {
920 Lock mylock(this);
921 SignallingCircuit* circuit = find(cic);
922 return circuit ? circuit->status() : SignallingCircuit::Missing;
923 }
924
925 // Change the status of a circuit given by its code
status(unsigned int cic,SignallingCircuit::Status newStat,bool sync)926 bool SignallingCircuitGroup::status(unsigned int cic, SignallingCircuit::Status newStat,
927 bool sync)
928 {
929 Lock mylock(this);
930 SignallingCircuit* circuit = find(cic);
931 return circuit && circuit->status(newStat,sync);
932 }
933
adjustParity(unsigned int & n,int strategy,bool up)934 inline void adjustParity(unsigned int& n, int strategy, bool up)
935 {
936 if (((strategy & SignallingCircuitGroup::OnlyEven) && (n & 1)) ||
937 ((strategy & SignallingCircuitGroup::OnlyOdd) && !(n & 1))) {
938 if (up)
939 n++;
940 else if (n)
941 n--;
942 else
943 n = (strategy & SignallingCircuitGroup::OnlyEven) ? 0 : 1;
944 }
945 }
946
947 // Choose the next circuit code to check, depending on strategy
advance(unsigned int n,int strategy,SignallingCircuitRange & range)948 unsigned int SignallingCircuitGroup::advance(unsigned int n, int strategy,
949 SignallingCircuitRange& range)
950 {
951 // Increment by 2 when even or odd only circuits are requested
952 unsigned int delta = (strategy & (OnlyOdd|OnlyEven)) ? 2 : 1;
953 switch (strategy & 0xfff) {
954 case Increment:
955 case Lowest:
956 n += delta;
957 if (n >= range.m_last) {
958 n = 0;
959 adjustParity(n,strategy,true);
960 }
961 break;
962 case Decrement:
963 case Highest:
964 if (n >= delta)
965 n -= delta;
966 else {
967 n = range.m_last;
968 adjustParity(n,strategy,false);
969 }
970 break;
971 default:
972 n = (n + 1) % range.m_last;
973 break;
974 }
975 return n;
976 }
977
978 // Reserve a circuit
reserve(int checkLock,int strategy,SignallingCircuitRange * range)979 SignallingCircuit* SignallingCircuitGroup::reserve(int checkLock, int strategy,
980 SignallingCircuitRange* range)
981 {
982 DDebug(this,DebugInfo,"SignallingCircuitGroup::reserve(%d,%d,%p) [%p]",
983 checkLock,strategy,range,this);
984 Lock mylock(this);
985 if (!range)
986 range = &m_range;
987 if (range->m_last < 1)
988 return 0;
989 if (strategy < 0)
990 strategy = range->m_strategy;
991 bool up = true;
992 unsigned int n = range->m_used;
993 // first adjust the last used channel number
994 switch (strategy & 0xfff) {
995 case Increment:
996 n = (n + 1) % range->m_last;
997 break;
998 case Decrement:
999 if (n < 2)
1000 n = range->m_last;
1001 else
1002 n--;
1003 up = false;
1004 break;
1005 case Lowest:
1006 n = 0;
1007 break;
1008 case Highest:
1009 n = range->m_last;
1010 up = false;
1011 break;
1012 default:
1013 while ((range->m_last > 1) && (n == range->m_used))
1014 n = Random::random() % range->m_last;
1015 }
1016 // then go to the proper even/odd start circuit
1017 adjustParity(n,strategy,up);
1018 // remember where the scan started
1019 unsigned int start = n;
1020 // try at most how many channels we have, halve that if we only scan even or odd
1021 unsigned int i = range->m_last;
1022 if (strategy & (OnlyOdd|OnlyEven))
1023 i = (i + 1) / 2;
1024 while (i--) {
1025 // Check if the circuit is within range
1026 if (range->find(n)) {
1027 SignallingCircuit* circuit = find(n,true);
1028 if (circuit && !circuit->locked(checkLock) && circuit->reserve()) {
1029 if (circuit->ref()) {
1030 range->m_used = n;
1031 return circuit;
1032 }
1033 release(circuit);
1034 return 0;
1035 }
1036 }
1037 n = advance(n,strategy,*range);
1038 // if wrapped around bail out, don't scan again
1039 if (n == start)
1040 break;
1041 }
1042 mylock.drop();
1043 if (strategy & Fallback) {
1044 if (strategy & OnlyEven) {
1045 Debug(this,DebugNote,"No even circuits available, falling back to odd [%p]",this);
1046 return reserve(checkLock,OnlyOdd | (strategy & 0xfff),range);
1047 }
1048 if (strategy & OnlyOdd) {
1049 Debug(this,DebugNote,"No odd circuits available, falling back to even [%p]",this);
1050 return reserve(checkLock,OnlyEven | (strategy & 0xfff),range);
1051 }
1052 }
1053 return 0;
1054 }
1055
1056 // Reserve a circuit from the given list
1057 // Reserve another one if not found and not mandatory
reserve(const String & list,bool mandatory,int checkLock,int strategy,SignallingCircuitRange * range)1058 SignallingCircuit* SignallingCircuitGroup::reserve(const String& list, bool mandatory,
1059 int checkLock, int strategy, SignallingCircuitRange* range)
1060 {
1061 DDebug(this,DebugInfo,"SignallingCircuitGroup::reserve('%s',%s,%d,%d,%p) [%p]",
1062 list.c_str(),String::boolText(mandatory),checkLock,strategy,range,this);
1063 Lock mylock(this);
1064 if (!range)
1065 range = &m_range;
1066 // Check if any of the given circuits are free
1067 while (true) {
1068 if (list.null())
1069 break;
1070 ObjList* circuits = list.split(',',false);
1071 if (!circuits)
1072 break;
1073 SignallingCircuit* circuit = 0;
1074 for (ObjList* obj = circuits->skipNull(); obj; obj = obj->skipNext()) {
1075 int code = (static_cast<String*>(obj->get()))->toInteger(-1);
1076 if (code > 0 && range->find(code))
1077 circuit = find(code,false);
1078 if (circuit && !circuit->locked(checkLock) && circuit->reserve()) {
1079 if (circuit->ref()) {
1080 range->m_used = m_base + circuit->code();
1081 break;
1082 }
1083 release(circuit);
1084 }
1085 circuit = 0;
1086 }
1087 TelEngine::destruct(circuits);
1088 if (circuit)
1089 return circuit;
1090 break;
1091 }
1092 // Don't try to reserve another one if the given list is mandatory
1093 if (mandatory)
1094 return 0;
1095 return reserve(checkLock,strategy,range);
1096 }
1097
1098 // Clear data
clearAll()1099 void SignallingCircuitGroup::clearAll()
1100 {
1101 Lock mylock(this);
1102 // Remove spans and their circuits
1103 ListIterator iter(m_spans);
1104 for (GenObject* obj = 0; (obj = iter.get());)
1105 removeSpan(static_cast<SignallingCircuitSpan*>(obj),true,true);
1106 // Remove the rest of circuits. Reset circuits' group
1107 // Some of them may continue to exists after clearing the list
1108 for (ObjList* l = m_circuits.skipNull(); l; l = l->skipNext()) {
1109 SignallingCircuit* c = static_cast<SignallingCircuit*>(l->get());
1110 c->status(SignallingCircuit::Missing,true);
1111 c->m_group = 0;
1112 }
1113 m_circuits.clear();
1114 m_ranges.clear();
1115 }
1116
1117
1118 /**
1119 * SignallingCircuitSpan
1120 */
SignallingCircuitSpan(const char * id,SignallingCircuitGroup * group)1121 SignallingCircuitSpan::SignallingCircuitSpan(const char* id, SignallingCircuitGroup* group)
1122 : SignallingComponent(id),
1123 m_group(group), m_increment(0), m_id(id)
1124 {
1125 if (m_group)
1126 m_group->insertSpan(this);
1127 XDebug(DebugAll,"SignallingCircuitSpan::SignallingCircuitSpan() '%s' [%p]",id,this);
1128 }
1129
~SignallingCircuitSpan()1130 SignallingCircuitSpan::~SignallingCircuitSpan()
1131 {
1132 if (m_group)
1133 m_group->removeSpan(this,true,false);
1134 XDebug(DebugAll,"SignallingCircuitSpan::~SignallingCircuitSpan() '%s' [%p]",m_id.safe(),this);
1135 }
1136
1137
1138 /**
1139 * AnalogLine
1140 */
typeNames()1141 const TokenDict* AnalogLine::typeNames()
1142 {
1143 static const TokenDict names[] = {
1144 {"FXO", FXO},
1145 {"FXS", FXS},
1146 {"recorder", Recorder},
1147 {"monitor", Monitor},
1148 {0,0}
1149 };
1150 return names;
1151 }
1152
stateNames()1153 const TokenDict* AnalogLine::stateNames()
1154 {
1155 static const TokenDict names[] = {
1156 {"OutOfService", OutOfService},
1157 {"Idle", Idle},
1158 {"Dialing", Dialing},
1159 {"DialComplete", DialComplete},
1160 {"Ringing", Ringing},
1161 {"Answered", Answered},
1162 {"CallEnded", CallEnded},
1163 {"OutOfOrder", OutOfOrder},
1164 {0,0}
1165 };
1166 return names;
1167 }
1168
csNames()1169 const TokenDict* AnalogLine::csNames() {
1170 static const TokenDict names[] = {
1171 {"after", After},
1172 {"before", Before},
1173 {"none", NoCallSetup},
1174 {0,0}
1175 };
1176 return names;
1177 }
1178
getValidInt(const NamedList & params,const char * param,int defVal)1179 inline u_int64_t getValidInt(const NamedList& params, const char* param, int defVal)
1180 {
1181 int tmp = params.getIntValue(param,defVal);
1182 return tmp >= 0 ? tmp : defVal;
1183 }
1184
1185 // Reserve the line's circuit
AnalogLine(AnalogLineGroup * grp,unsigned int cic,const NamedList & params)1186 AnalogLine::AnalogLine(AnalogLineGroup* grp, unsigned int cic, const NamedList& params)
1187 : Mutex(true,"AnalogLine"),
1188 m_type(Unknown),
1189 m_state(Idle),
1190 m_inband(false),
1191 m_echocancel(0),
1192 m_acceptPulseDigit(true),
1193 m_answerOnPolarity(false),
1194 m_hangupOnPolarity(false),
1195 m_polarityControl(false),
1196 m_callSetup(NoCallSetup),
1197 m_callSetupTimeout(0),
1198 m_noRingTimeout(0),
1199 m_alarmTimeout(0),
1200 m_group(grp),
1201 m_circuit(0),
1202 m_private(0),
1203 m_peer(0),
1204 m_getPeerEvent(false)
1205 {
1206 // Check and set some data
1207 const char* error = 0;
1208 while (true) {
1209 #define CHECK_DATA(test,sError) if (test) { error = sError; break; }
1210 CHECK_DATA(!m_group,"circuit group is missing")
1211 CHECK_DATA(m_group->findLine(cic),"circuit already allocated")
1212 SignallingCircuit* circuit = m_group->find(cic);
1213 if (circuit && circuit->ref())
1214 m_circuit = circuit;
1215 CHECK_DATA(!m_circuit,"circuit is missing")
1216 break;
1217 #undef CHECK_DATA
1218 }
1219 if (error) {
1220 Debug(m_group,DebugNote,"Can't create analog line (cic=%u): %s",
1221 cic,error);
1222 return;
1223 }
1224
1225 m_type = m_group->type();
1226 if (m_type == Recorder)
1227 m_type = FXO;
1228 m_address << m_group->toString() << "/" << m_circuit->code();
1229 m_inband = params.getBoolValue(YSTRING("dtmfinband"),false);
1230 String tmp = params.getValue(YSTRING("echocancel"));
1231 if (tmp.isBoolean())
1232 m_echocancel = tmp.toBoolean() ? 1 : -1;
1233 m_answerOnPolarity = params.getBoolValue(YSTRING("answer-on-polarity"),false);
1234 m_hangupOnPolarity = params.getBoolValue(YSTRING("hangup-on-polarity"),false);
1235 m_polarityControl = params.getBoolValue(YSTRING("polaritycontrol"),false);
1236
1237 m_callSetup = (CallSetupInfo)lookup(params.getValue(YSTRING("callsetup")),csNames(),After);
1238
1239 m_callSetupTimeout = getValidInt(params,"callsetup-timeout",2000);
1240 m_noRingTimeout = getValidInt(params,"ring-timeout",10000);
1241 m_alarmTimeout = getValidInt(params,"alarm-timeout",30000);
1242 m_delayDial = getValidInt(params,"delaydial",2000);
1243
1244 DDebug(m_group,DebugAll,"AnalogLine() addr=%s type=%s [%p]",
1245 address(),lookup(m_type,typeNames()),this);
1246
1247 if (!params.getBoolValue(YSTRING("out-of-service"),false)) {
1248 resetCircuit();
1249 if (params.getBoolValue(YSTRING("connect"),true))
1250 connect(false);
1251 }
1252 else
1253 enable(false,false);
1254 }
1255
~AnalogLine()1256 AnalogLine::~AnalogLine()
1257 {
1258 DDebug(m_group,DebugAll,"~AnalogLine() addr=%s [%p]",address(),this);
1259 }
1260
1261 // Remove old peer's peer. Set this line's peer
setPeer(AnalogLine * line,bool sync)1262 void AnalogLine::setPeer(AnalogLine* line, bool sync)
1263 {
1264 Lock mylock(this);
1265 if (line == this) {
1266 Debug(m_group,DebugNote,"%s: Attempt to set peer to itself [%p]",
1267 address(),this);
1268 return;
1269 }
1270 if (line == m_peer) {
1271 if (sync && m_peer) {
1272 XDebug(m_group,DebugAll,"%s: Syncing with peer (%p) '%s' [%p]",
1273 address(),m_peer,m_peer->address(),this);
1274 m_peer->setPeer(this,false);
1275 }
1276 return;
1277 }
1278 AnalogLine* tmp = m_peer;
1279 m_peer = 0;
1280 if (tmp) {
1281 DDebug(m_group,DebugAll,"%s: Removed peer (%p) '%s' [%p]",
1282 address(),tmp,tmp->address(),this);
1283 if (sync)
1284 tmp->setPeer(0,false);
1285 }
1286 m_peer = line;
1287 if (m_peer) {
1288 DDebug(m_group,DebugAll,"%s: Peer set to (%p) '%s' [%p]",
1289 address(),m_peer,m_peer->address(),this);
1290 if (sync)
1291 m_peer->setPeer(this,false);
1292 }
1293 }
1294
1295 // Reset the line circuit's echo canceller to line default echo canceller state
resetEcho(bool train)1296 void AnalogLine::resetEcho(bool train)
1297 {
1298 if (!(m_circuit || m_echocancel))
1299 return;
1300 bool enable = (m_echocancel > 0);
1301 m_circuit->setParam("echocancel",String::boolText(enable));
1302 if (enable && train)
1303 m_circuit->setParam("echotrain",String(""));
1304 }
1305
1306 // Connect the line's circuit. Reset line echo canceller
connect(bool sync)1307 bool AnalogLine::connect(bool sync)
1308 {
1309 Lock mylock(this);
1310 bool ok = m_circuit && m_circuit->connect();
1311 resetEcho(true);
1312 if (sync && ok && m_peer)
1313 m_peer->connect(false);
1314 return ok;
1315 }
1316
1317 // Disconnect the line's circuit. Reset line echo canceller
disconnect(bool sync)1318 bool AnalogLine::disconnect(bool sync)
1319 {
1320 Lock mylock(this);
1321 bool ok = m_circuit && m_circuit->disconnect();
1322 resetEcho(false);
1323 if (sync && ok && m_peer)
1324 m_peer->disconnect(false);
1325 return ok;
1326 }
1327
1328 // Send an event through this line
sendEvent(SignallingCircuitEvent::Type type,NamedList * params)1329 bool AnalogLine::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
1330 {
1331 Lock mylock(this);
1332 if (state() == OutOfService)
1333 return false;
1334 if (m_inband &&
1335 (type == SignallingCircuitEvent::Dtmf || type == SignallingCircuitEvent::PulseDigit))
1336 return false;
1337 return m_circuit && m_circuit->sendEvent(type,params);
1338 }
1339
1340 // Get events from the line's circuit if not out of service
getEvent(const Time & when)1341 AnalogLineEvent* AnalogLine::getEvent(const Time& when)
1342 {
1343 Lock mylock(this);
1344 if (state() == OutOfService) {
1345 checkTimeouts(when);
1346 return 0;
1347 }
1348
1349 SignallingCircuitEvent* event = m_circuit ? m_circuit->getEvent(when) : 0;
1350 if (!event) {
1351 checkTimeouts(when);
1352 return 0;
1353 }
1354
1355 if ((event->type() == SignallingCircuitEvent::PulseDigit ||
1356 event->type() == SignallingCircuitEvent::PulseStart) &&
1357 !m_acceptPulseDigit) {
1358 DDebug(m_group,DebugInfo,"%s: ignoring pulse event '%s' [%p]",
1359 address(),event->c_str(),this);
1360 delete event;
1361 return 0;
1362 }
1363
1364 return new AnalogLineEvent(this,event);
1365 }
1366
1367 // Alternate get events from this line or peer
getMonitorEvent(const Time & when)1368 AnalogLineEvent* AnalogLine::getMonitorEvent(const Time& when)
1369 {
1370 Lock mylock(this);
1371 m_getPeerEvent = !m_getPeerEvent;
1372 AnalogLineEvent* event = 0;
1373 if (m_getPeerEvent) {
1374 event = getEvent(when);
1375 if (!event && m_peer)
1376 event = m_peer->getEvent(when);
1377 }
1378 else {
1379 if (m_peer)
1380 event = m_peer->getEvent(when);
1381 if (!event)
1382 event = getEvent(when);
1383 }
1384 return event;
1385 }
1386
1387 // Change the line state if neither current or new state are OutOfService
changeState(State newState,bool sync)1388 bool AnalogLine::changeState(State newState, bool sync)
1389 {
1390 Lock mylock(this);
1391 bool ok = false;
1392 while (true) {
1393 if (m_state == newState || m_state == OutOfService || newState == OutOfService)
1394 break;
1395 if (newState != Idle && newState < m_state)
1396 break;
1397 DDebug(m_group,DebugInfo,"%s: changed state from %s to %s [%p]",
1398 address(),lookup(m_state,stateNames()),
1399 lookup(newState,stateNames()),this);
1400 m_state = newState;
1401 ok = true;
1402 break;
1403 }
1404 if (sync && ok && m_peer)
1405 m_peer->changeState(newState,false);
1406 return true;
1407 }
1408
1409 // Enable/disable line. Change circuit's state to Disabled/Reserved when
1410 // entering/exiting the OutOfService state
enable(bool ok,bool sync,bool connectNow)1411 bool AnalogLine::enable(bool ok, bool sync, bool connectNow)
1412 {
1413 Lock mylock(this);
1414 while (true) {
1415 if (ok) {
1416 if (m_state != OutOfService)
1417 break;
1418 Debug(m_group,DebugInfo,"%s: back in service [%p]",address(),this);
1419 m_state = Idle;
1420 if (m_circuit) {
1421 m_circuit->status(SignallingCircuit::Reserved);
1422 if (connectNow)
1423 connect(false);
1424 }
1425 break;
1426 }
1427 // Disable
1428 if (m_state == OutOfService)
1429 break;
1430 Debug(m_group,DebugNote,"%s: out of service [%p]",address(),this);
1431 m_state = OutOfService;
1432 disconnect(false);
1433 if (m_circuit)
1434 m_circuit->status(SignallingCircuit::Disabled);
1435 break;
1436 }
1437 if (sync && m_peer)
1438 m_peer->enable(ok,false,connectNow);
1439 return true;
1440 }
1441
1442 // Deref the circuit
destroyed()1443 void AnalogLine::destroyed()
1444 {
1445 lock();
1446 disconnect(false);
1447 if (m_circuit)
1448 m_circuit->status(SignallingCircuit::Idle);
1449 setPeer(0,true);
1450 if (m_group)
1451 m_group->removeLine(this);
1452 TelEngine::destruct(m_circuit);
1453 unlock();
1454 RefObject::destroyed();
1455 }
1456
1457
1458 /**
1459 * AnalogLineGroup
1460 */
1461
1462 // Construct an analog line group owning single lines
AnalogLineGroup(AnalogLine::Type type,const char * name,bool slave)1463 AnalogLineGroup::AnalogLineGroup(AnalogLine::Type type, const char* name, bool slave)
1464 : SignallingCircuitGroup(0,SignallingCircuitGroup::Increment,name),
1465 m_type(type),
1466 m_fxo(0),
1467 m_slave(false)
1468 {
1469 setName(name);
1470 if (m_type == AnalogLine::FXO)
1471 m_slave = slave;
1472 XDebug(this,DebugAll,"AnalogLineGroup() [%p]",this);
1473 }
1474
1475 // Constructs an FXS analog line monitor
AnalogLineGroup(const char * name,AnalogLineGroup * fxo)1476 AnalogLineGroup::AnalogLineGroup(const char* name, AnalogLineGroup* fxo)
1477 : SignallingCircuitGroup(0,SignallingCircuitGroup::Increment,name),
1478 m_type(AnalogLine::FXS),
1479 m_fxo(fxo)
1480 {
1481 setName(name);
1482 if (m_fxo)
1483 m_fxo->debugChain(this);
1484 else
1485 Debug(this,DebugWarn,"Request to create monitor without fxo group [%p]",this);
1486 XDebug(this,DebugAll,"AnalogLineGroup() monitor fxo=%p [%p]",m_fxo,this);
1487 }
1488
~AnalogLineGroup()1489 AnalogLineGroup::~AnalogLineGroup()
1490 {
1491 XDebug(this,DebugAll,"~AnalogLineGroup() [%p]",this);
1492 }
1493
1494 // Append it to the list
appendLine(AnalogLine * line,bool destructOnFail)1495 bool AnalogLineGroup::appendLine(AnalogLine* line, bool destructOnFail)
1496 {
1497 AnalogLine::Type type = m_type;
1498 if (type == AnalogLine::Recorder)
1499 type = AnalogLine::FXO;
1500 if (!(line && line->type() == type && line->group() == this)) {
1501 if (destructOnFail)
1502 TelEngine::destruct(line);
1503 return false;
1504 }
1505 Lock mylock(this);
1506 m_lines.append(line);
1507 DDebug(this,DebugAll,"Added line (%p) %s [%p]",line,line->address(),this);
1508 return true;
1509 }
1510
1511 // Remove a line from the list and destruct it
removeLine(unsigned int cic)1512 void AnalogLineGroup::removeLine(unsigned int cic)
1513 {
1514 Lock mylock(this);
1515 AnalogLine* line = findLine(cic);
1516 if (!line)
1517 return;
1518 removeLine(line);
1519 TelEngine::destruct(line);
1520 }
1521
1522 // Remove a line from the list without destroying it
removeLine(AnalogLine * line)1523 void AnalogLineGroup::removeLine(AnalogLine* line)
1524 {
1525 if (!line)
1526 return;
1527 Lock mylock(this);
1528 if (m_lines.remove(line,false))
1529 DDebug(this,DebugAll,"Removed line %p %s [%p]",line,line->address(),this);
1530 }
1531
1532 // Find a line by its circuit
findLine(unsigned int cic)1533 AnalogLine* AnalogLineGroup::findLine(unsigned int cic)
1534 {
1535 Lock mylock(this);
1536 for (ObjList* o = m_lines.skipNull(); o; o = o->skipNext()) {
1537 AnalogLine* line = static_cast<AnalogLine*>(o->get());
1538 if (line->circuit() && line->circuit()->code() == cic)
1539 return line;
1540 }
1541 return 0;
1542 }
1543
1544 // Find a line by its address
findLine(const String & address)1545 AnalogLine* AnalogLineGroup::findLine(const String& address)
1546 {
1547 Lock mylock(this);
1548 ObjList* tmp = m_lines.find(address);
1549 return tmp ? static_cast<AnalogLine*>(tmp->get()) : 0;
1550 }
1551
1552 // Iterate through the line list to get an event
getEvent(const Time & when)1553 AnalogLineEvent* AnalogLineGroup::getEvent(const Time& when)
1554 {
1555 lock();
1556 ListIterator iter(m_lines);
1557 for (;;) {
1558 AnalogLine* line = static_cast<AnalogLine*>(iter.get());
1559 // End of iteration?
1560 if (!line)
1561 break;
1562 RefPointer<AnalogLine> lineRef = line;
1563 // Dead pointer?
1564 if (!lineRef)
1565 continue;
1566 unlock();
1567 AnalogLineEvent* event = !fxo() ? lineRef->getEvent(when) : lineRef->getMonitorEvent(when);
1568 if (event)
1569 return event;
1570 lock();
1571 }
1572 unlock();
1573 return 0;
1574 }
1575
1576 // Remove all spans and circuits. Release object
destroyed()1577 void AnalogLineGroup::destroyed()
1578 {
1579 lock();
1580 for (ObjList* o = m_lines.skipNull(); o; o = o->skipNext()) {
1581 AnalogLine* line = static_cast<AnalogLine*>(o->get());
1582 Lock lock(line);
1583 line->m_group = 0;
1584 }
1585 m_lines.clear();
1586 TelEngine::destruct(m_fxo);
1587 unlock();
1588 SignallingCircuitGroup::destroyed();
1589 }
1590
1591 /* vi: set ts=8 sw=4 sts=4 noet: */
1592