Max retry over corresponding
@@ -15,6 +15,10 @@ | ||
15 | 15 | public abstract void start(Peer peer,String host, int port); |
16 | 16 | |
17 | 17 | /** |
18 | + * Starts the thread for receiving frames | |
19 | + */ | |
20 | + public abstract void start(Peer peer,String host, int dPort, int sPort); | |
21 | + /** | |
18 | 22 | * Stops the thread for receiving frames |
19 | 23 | */ |
20 | 24 | public abstract void stop(); |
@@ -1,6 +1,5 @@ | ||
1 | 1 | package iax.client.protocol.connection; |
2 | 2 | |
3 | -import java.io.IOException; | |
4 | 3 | import java.net.DatagramPacket; |
5 | 4 | import java.net.DatagramSocket; |
6 | 5 | import java.net.InetAddress; |
@@ -35,11 +34,24 @@ | ||
35 | 34 | * @param host ip of the asterisk host |
36 | 35 | */ |
37 | 36 | public void start(Peer peer,String host, int port) { |
37 | + start(peer, host, port, 0); | |
38 | + } | |
39 | + | |
40 | + /* (non-Javadoc) | |
41 | + * @see iax.protocol.connection.IConnection#start() | |
42 | + * @param peer peer that handle the received frames (and send the sending frames) | |
43 | + * @param host ip of the asterisk host | |
44 | + */ | |
45 | + public void start(Peer peer,String host, int dPort, int sPort) { | |
38 | 46 | this.peer = peer; |
39 | 47 | try { |
40 | 48 | hostIAddr = InetAddress.getByName(host); |
41 | - this.port = port; | |
42 | - socket = new DatagramSocket(); | |
49 | + this.port = dPort; | |
50 | + if (sPort == 0){ | |
51 | + socket = new DatagramSocket(); | |
52 | + }else{ | |
53 | + socket = new DatagramSocket(sPort); | |
54 | + } | |
43 | 55 | Thread t = new Thread(this); |
44 | 56 | t.start(); |
45 | 57 | } catch (Exception e) { |
@@ -6,6 +6,7 @@ | ||
6 | 6 | import iax.client.protocol.frame.Frame; |
7 | 7 | import iax.client.protocol.frame.InfoElement; |
8 | 8 | import iax.client.protocol.frame.ProtocolControlFrame; |
9 | +import iax.client.protocol.util.FrameUtil; | |
9 | 10 | |
10 | 11 | /** |
11 | 12 | * Call's state initial. It's a singleton. |
@@ -38,6 +39,9 @@ | ||
38 | 39 | switch (protocolControlFrame.getSubclass()) { |
39 | 40 | case ProtocolControlFrame.CALLTOKEN_SC: |
40 | 41 | // Log.d("Initial#handleRecvFrame","recv CALLTOKEN_SC"); |
42 | + int [] repliedSubclasses = FrameUtil.getReplySubclasses((protocolControlFrame.getSubclass())); | |
43 | + for (int i=0; i<repliedSubclasses.length; i++) | |
44 | + call.repliedFrame(repliedSubclasses[i]); | |
41 | 45 | ProtocolControlFrame newCallFrame = |
42 | 46 | new ProtocolControlFrame(call.getSrcCallNo(), false, 0, 0L, 0, |
43 | 47 | 0, false, ProtocolControlFrame.NEW_SC); |
@@ -22,12 +22,77 @@ | ||
22 | 22 | import java.util.TimerTask; |
23 | 23 | import java.util.concurrent.ConcurrentHashMap; |
24 | 24 | |
25 | + | |
25 | 26 | /** |
26 | 27 | * Class that encapsulates the functionality of a iax call and implements the interface AudioListener |
27 | 28 | * for playing and recording audio. |
28 | 29 | */ |
29 | 30 | public class Call implements AudioListener{ |
30 | - | |
31 | + class WaitAckRetryTimerTask extends TimerTask { | |
32 | + Call call; | |
33 | + FullFrame retryFullFrame; | |
34 | + WaitAckRetryTimerTask(Call call, FullFrame frame){ | |
35 | + this.call = call; | |
36 | + retryFullFrame = frame; | |
37 | + } | |
38 | + | |
39 | + @Override | |
40 | + public void run() { | |
41 | + try { | |
42 | + if (timersWaitingAck.containsKey(Long.valueOf(retryFullFrame.getTimestamp()))){ | |
43 | + retryFullFrame.incRetryCount(); | |
44 | + if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
45 | + peer.sendFrame(retryFullFrame); | |
46 | + } else{ | |
47 | + cancel(); | |
48 | + synchronized (timersWaitingAckLock) { | |
49 | + timersWaitingAck.remove(Long.valueOf(retryFullFrame.getTimestamp())); | |
50 | + } | |
51 | + throw new PeerException("Reached retries maximun in the call " + srcCallNo + | |
52 | + " for a full frame of type " + retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass() + | |
53 | + " timestamp:" + retryFullFrame.getTimestamp()); | |
54 | + } | |
55 | + }else{ | |
56 | + cancel(); | |
57 | + } | |
58 | + } catch (PeerException e) { | |
59 | + CallCommandSendFacade.hangup(call); | |
60 | + endCall(); | |
61 | + peer.setState(Unregistered.getInstance()); | |
62 | + e.printStackTrace(); | |
63 | + } | |
64 | + } | |
65 | + } | |
66 | + class WaitReplyRetryTimerTask extends TimerTask { | |
67 | + Call call; | |
68 | + FullFrame retryFullFrame; | |
69 | + WaitReplyRetryTimerTask(Call call, FullFrame frame){ | |
70 | + this.call = call; | |
71 | + retryFullFrame = frame; | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + public void run() { | |
76 | + try { | |
77 | + retryFullFrame.incRetryCount(); | |
78 | + if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
79 | + peer.sendFrame(retryFullFrame); | |
80 | + } else{ | |
81 | + cancel(); | |
82 | + synchronized (timersWaitingAckLock) { | |
83 | + timersWaitingReply.remove(Integer.valueOf(retryFullFrame.getSubclass())); | |
84 | + } | |
85 | + throw new PeerException("Reached retries maximun in the call " + srcCallNo + | |
86 | + " for a full frame of type " + retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
87 | + } | |
88 | + } catch (PeerException e) { | |
89 | + CallCommandSendFacade.hangup(call); | |
90 | + endCall(); | |
91 | + peer.setState(Unregistered.getInstance()); | |
92 | + e.printStackTrace(); | |
93 | + } | |
94 | + } | |
95 | + } | |
31 | 96 | /** |
32 | 97 | * Interval in milliseconds that the miniframe's timestamp is reset |
33 | 98 | */ |
@@ -39,14 +104,16 @@ | ||
39 | 104 | //Peer's ping refresh in seconds |
40 | 105 | //private final int PING_REFRESH = 5; |
41 | 106 | //Call's retry max |
42 | - private final int RETRY_MAXCOUNT = 10; | |
107 | + private final int RETRY_MAXCOUNT = 5; | |
43 | 108 | //Peer's retry refresh in seconds |
44 | - private final int RETRY_REFRESH = 1; | |
45 | - private final int MAX_CONTINUAL_FAILURE = 0; | |
109 | + private final int RETRY_REFRESH = 3; | |
110 | +// private final int MAX_CONTINUAL_FAILURE = 0; | |
46 | 111 | // HashMap with the frames that are waiting for an ack |
47 | - private ConcurrentHashMap<Long, FullFrame> framesWaitingAck; | |
112 | + private ConcurrentHashMap<Long, Timer> timersWaitingAck; | |
113 | + private Object timersWaitingAckLock = new Object(); | |
48 | 114 | // HashMap with the frames that are waiting for a specific reply |
49 | - private ConcurrentHashMap<Integer, FullFrame> framesWaitingReply; | |
115 | + private ConcurrentHashMap<Integer, Timer> timersWaitingReply; | |
116 | + private Object timersWaitingReplyLock = new Object(); | |
50 | 117 | // Audio player |
51 | 118 | private Player player; |
52 | 119 | // Audio Recorder |
@@ -60,7 +127,7 @@ | ||
60 | 127 | // Destination call number of this call (number got from the remote call) |
61 | 128 | private int destCallNo; |
62 | 129 | // Source timestamp for full frames from the first full frame sent by this call |
63 | - private long srcTimestamp; | |
130 | +// private long srcTimestamp; | |
64 | 131 | // Source timestamp for mini frames from the first mini frame sent by this call or the last mini frame's timestamp reset |
65 | 132 | private long srcTimestampMiniFrame; |
66 | 133 | // Oubound sequence number. |
@@ -73,10 +140,6 @@ | ||
73 | 140 | private boolean firstVoiceFrameSended; |
74 | 141 | // Peer that handles this call |
75 | 142 | private Peer peer; |
76 | - // Ping timer task to send ping frames | |
77 | -// private Timer pingTimer; | |
78 | - // Retry timer task to retry frames not commited whith a specific frame or an ack frame | |
79 | - private Timer retryTimer; | |
80 | 143 | //Flag to determinate if the call is hold or not |
81 | 144 | private boolean hold; |
82 | 145 | //Flag to determinate if the call is mute or not |
@@ -88,7 +151,7 @@ | ||
88 | 151 | |
89 | 152 | private boolean callTokenReceived = false; |
90 | 153 | |
91 | - private int continualFailureCount = 0; | |
154 | +// private int continualFailureCount = 0; | |
92 | 155 | /** |
93 | 156 | * Constructor. Initialize the player and the recorder |
94 | 157 | * @param peer the peer that handles this call |
@@ -101,8 +164,8 @@ | ||
101 | 164 | this.audioFactory = audioFactory; |
102 | 165 | this.hold = false; |
103 | 166 | this.mute = false; |
104 | - this.framesWaitingAck = new ConcurrentHashMap<Long, FullFrame>(); | |
105 | - this.framesWaitingReply = new ConcurrentHashMap<Integer, FullFrame>(); | |
167 | + this.timersWaitingAck = new ConcurrentHashMap<Long, Timer>(); | |
168 | + this.timersWaitingReply = new ConcurrentHashMap<Integer, Timer>(); | |
106 | 169 | try { |
107 | 170 | this.player = audioFactory.createPlayer(); |
108 | 171 | this.recorder = audioFactory.createRecorder(); |
@@ -245,26 +308,10 @@ | ||
245 | 308 | this.oseqno = 0; |
246 | 309 | this.destCallNo = 0; |
247 | 310 | this.firstVoiceFrameSended = true; |
248 | - this.framesWaitingAck.clear(); | |
311 | + this.timersWaitingAck.clear(); | |
312 | + this.timersWaitingReply.clear(); | |
249 | 313 | this.calledNumber = calledNumber; |
250 | 314 | this.state = Initial.getInstance(); |
251 | - this.srcTimestamp = System.currentTimeMillis(); | |
252 | -// ***** PING DESACTIVATED ***** | |
253 | -// this.pingTimer = new Timer(); | |
254 | -// TimerTask pingTimerTask = new TimerTask() { | |
255 | -// public void run() { | |
256 | -// ping(); | |
257 | -// } | |
258 | -// }; | |
259 | -// pingTimer.schedule(pingTimerTask, PING_REFRESH*1000, PING_REFRESH*1000); | |
260 | - this.retryTimer = new Timer(); | |
261 | - TimerTask retryTimerTask = new TimerTask() { | |
262 | - public void run() { | |
263 | - retryFramesWaiting(); | |
264 | - } | |
265 | - }; | |
266 | - retryTimer.schedule(retryTimerTask, RETRY_REFRESH*1000, RETRY_REFRESH*1000); | |
267 | - | |
268 | 315 | } |
269 | 316 | |
270 | 317 | /** |
@@ -296,10 +343,18 @@ | ||
296 | 343 | * Ends a call. For that stops the player and the recorder, and notifies the peer that this call is finished |
297 | 344 | */ |
298 | 345 | public void endCall() { |
299 | -// System.out.println("%%%%%%%%%%%%%%%%% Call#endCall called %%%%%%%%%%%%%%%%%%%%%%%%%"); | |
300 | -// ***** PING DESACTIVATED ***** | |
301 | -// pingTimer.cancel(); | |
302 | - retryTimer.cancel(); | |
346 | + Iterator<Timer> timers = timersWaitingAck.values().iterator(); | |
347 | + while(timers.hasNext()){ | |
348 | + Timer retryTimer = timers.next(); | |
349 | + retryTimer.cancel(); | |
350 | + } | |
351 | + timersWaitingAck.clear(); | |
352 | + timers = timersWaitingReply.values().iterator(); | |
353 | + while(timers.hasNext()){ | |
354 | + Timer retryTimer = timers.next(); | |
355 | + retryTimer.cancel(); | |
356 | + } | |
357 | + timersWaitingReply.clear(); | |
303 | 358 | player.stop(); |
304 | 359 | recorder.stop(); |
305 | 360 | peer.endCall(this); |
@@ -427,9 +482,16 @@ | ||
427 | 482 | * Ackes a full frame waiting for that removing it from the list of full frames waiting for ack |
428 | 483 | * @param timeStamp the timestamp of the full frame acked |
429 | 484 | */ |
430 | - public synchronized void ackedFrame(long timeStamp) { | |
431 | - framesWaitingAck.remove(new Long(timeStamp)); | |
432 | - continualFailureCount = 0; | |
485 | + public /* synchronized */ void ackedFrame(long timeStamp) { | |
486 | +// System.out.println("ackedFrame called timersWaitingAck.size:" + timersWaitingAck.size()); | |
487 | + synchronized (timersWaitingAckLock) { | |
488 | + Timer timer = timersWaitingAck.remove(Long.valueOf(timeStamp)); | |
489 | + if (timer != null){ | |
490 | + timer.cancel(); | |
491 | + }else{ | |
492 | + System.out.println("Call.ackedFrame timeStamp:" + timeStamp + " not found."); | |
493 | + } | |
494 | + } | |
433 | 495 | } |
434 | 496 | |
435 | 497 | /** |
@@ -436,9 +498,13 @@ | ||
436 | 498 | * Replied a full frame waiting for that removing it from the list of full frames waiting for reply |
437 | 499 | * @param id the id of the full frame reply |
438 | 500 | */ |
439 | - public synchronized void repliedFrame(int id) { | |
440 | - framesWaitingReply.remove(new Integer(id)); | |
441 | - continualFailureCount = 0; | |
501 | + public /* synchronized */ void repliedFrame(int id) { | |
502 | +// System.out.println("repliedFrame called timersWaitingReply.size:" + timersWaitingReply.size()); | |
503 | + synchronized (timersWaitingReplyLock) { | |
504 | + Timer timer = timersWaitingReply.get(Integer.valueOf(id)); | |
505 | + if (timer != null) timer.cancel(); | |
506 | + timersWaitingReply.remove(Integer.valueOf(id)); | |
507 | + } | |
442 | 508 | } |
443 | 509 | |
444 | 510 | /** |
@@ -454,9 +520,14 @@ | ||
454 | 520 | * delegates in the iax peer to send it |
455 | 521 | * @param fullFrame the full frame to send |
456 | 522 | */ |
457 | - public synchronized void sendFullFrameAndWaitForAck(FullFrame fullFrame) { | |
458 | - framesWaitingAck.put(new Long(fullFrame.getTimestamp()), fullFrame); | |
459 | - peer.sendFrame(fullFrame); | |
523 | + public /* synchronized */ void sendFullFrameAndWaitForAck(FullFrame fullFrame) { | |
524 | + synchronized (timersWaitingAckLock) { | |
525 | + Timer retryTimer = new Timer(); | |
526 | + TimerTask retryTimerTask = new WaitAckRetryTimerTask(this, fullFrame); | |
527 | + timersWaitingAck.put(Long.valueOf(fullFrame.getTimestamp()), retryTimer); | |
528 | + retryTimer.schedule(retryTimerTask, RETRY_REFRESH*1000, RETRY_REFRESH*1000); | |
529 | + peer.sendFrame(fullFrame); | |
530 | + } | |
460 | 531 | } |
461 | 532 | |
462 | 533 | /** |
@@ -464,9 +535,15 @@ | ||
464 | 535 | * delegates in the iax peer to send it |
465 | 536 | * @param fullFrame the full frame to send |
466 | 537 | */ |
467 | - public synchronized void sendFullFrameAndWaitForRep(FullFrame fullFrame) { | |
468 | - framesWaitingReply.put(new Integer(fullFrame.getSubclass()), fullFrame); | |
469 | - peer.sendFrame(fullFrame); | |
538 | + public /* synchronized */ void sendFullFrameAndWaitForRep(FullFrame fullFrame) { | |
539 | + synchronized (timersWaitingReplyLock) { | |
540 | + Timer retryTimer = new Timer(); | |
541 | + TimerTask retryTimerTask = new WaitReplyRetryTimerTask(this, fullFrame); | |
542 | + timersWaitingReply.put(Integer.valueOf(fullFrame.getSubclass()), retryTimer); | |
543 | + retryTimer.schedule(retryTimerTask, RETRY_REFRESH*1000, RETRY_REFRESH*1000); | |
544 | + peer.sendFrame(fullFrame); | |
545 | + } | |
546 | + | |
470 | 547 | } |
471 | 548 | |
472 | 549 | // static int x = 0; |
@@ -476,8 +553,8 @@ | ||
476 | 553 | * @param data the audio data of the frame |
477 | 554 | * @param absolute if the timestamp absolute or not |
478 | 555 | */ |
479 | - public synchronized void writeAudioIn(long timestamp, byte[] data, boolean absolute) { | |
480 | - if (!hold) { | |
556 | + public /* synchronized */ void writeAudioIn(long timestamp, byte[] data, boolean absolute) { | |
557 | + if (!hold) { | |
481 | 558 | if (!playing) { |
482 | 559 | player.play(); |
483 | 560 | playing = true; |
@@ -493,48 +570,6 @@ | ||
493 | 570 | recorder.record(this); |
494 | 571 | } |
495 | 572 | |
496 | - // Method to retry frames that haven't been commited whith a specific frame or an ack frame | |
497 | - private synchronized void retryFramesWaiting() { | |
498 | - try { | |
499 | - Iterator<FullFrame> iterator = framesWaitingAck.values().iterator(); | |
500 | - while(iterator.hasNext()){ | |
501 | - FullFrame retryFullFrame = (FullFrame)iterator.next(); | |
502 | - retryFullFrame.incRetryCount(); | |
503 | - if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
504 | - peer.sendFrame(retryFullFrame); | |
505 | - } else{ | |
506 | - iterator.remove(); | |
507 | - throw new PeerException("Reached retries maximun in the call " + srcCallNo + | |
508 | - " for a full frame of type " + retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
509 | - } | |
510 | - } | |
511 | - iterator = framesWaitingReply.values().iterator(); | |
512 | - while (iterator.hasNext()) { | |
513 | - FullFrame retryFullFrame = (FullFrame)iterator.next(); | |
514 | - retryFullFrame.incRetryCount(); | |
515 | - if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
516 | - peer.sendFrame(retryFullFrame); | |
517 | - } else { | |
518 | - iterator.remove(); | |
519 | - throw new PeerException("Reached retries maximun in the call " + srcCallNo + | |
520 | - " for a full frame of type " + retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
521 | - } | |
522 | - } | |
523 | - } catch (PeerException e) { | |
524 | -// if (continualFailureCount < MAX_CONTINUAL_FAILURE) { | |
525 | -// continualFailureCount++; | |
526 | -// } else { | |
527 | -// System.out.println("%%%%%%%%%%%%%%%%% retryFramesWaiting retry over %%%%%%%%%%%%%%%%%%%%%%%%%"); | |
528 | - framesWaitingAck.clear(); | |
529 | - framesWaitingReply.clear(); | |
530 | - CallCommandSendFacade.hangup(this); | |
531 | - endCall(); | |
532 | - peer.setState(Unregistered.getInstance()); | |
533 | -// } | |
534 | - e.printStackTrace(); | |
535 | - } | |
536 | - } | |
537 | - | |
538 | 573 | public void listen(byte[] buffer, int pos, int length) { |
539 | 574 | byte[] audioBuffer = new byte[length]; |
540 | 575 | System.arraycopy(buffer, pos, audioBuffer, 0, length); |
@@ -17,15 +17,79 @@ | ||
17 | 17 | import iax.client.protocol.peer.state.Waiting; |
18 | 18 | import iax.client.protocol.util.FrameUtil; |
19 | 19 | |
20 | -import java.util.HashMap; | |
21 | 20 | import java.util.Iterator; |
22 | 21 | import java.util.Timer; |
23 | 22 | import java.util.TimerTask; |
23 | +import java.util.concurrent.ConcurrentHashMap; | |
24 | 24 | |
25 | 25 | /** |
26 | 26 | * Peer that controls phone calls. |
27 | 27 | */ |
28 | 28 | public class Peer { |
29 | + class WaitAckRetryTimerTask extends TimerTask { | |
30 | + FullFrame retryFullFrame; | |
31 | + WaitAckRetryTimerTask(FullFrame frame){ | |
32 | + retryFullFrame = frame; | |
33 | + } | |
34 | + | |
35 | + @Override | |
36 | + public void run() { | |
37 | + if (timersWaitingAck != null){ | |
38 | + try { | |
39 | + if (timersWaitingAck.containsKey(Long.valueOf(retryFullFrame.getTimestamp()))){ | |
40 | + retryFullFrame.incRetryCount(); | |
41 | + if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
42 | + sendFrame(retryFullFrame); | |
43 | + } else{ | |
44 | + cancel(); | |
45 | + synchronized (timersWaitingAckLock) { | |
46 | + timersWaitingAck.remove(Long.valueOf(retryFullFrame.getTimestamp())); | |
47 | + } | |
48 | + throw new PeerException("Reached retries maximun in the peer for full frame of type " + | |
49 | + retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
50 | + } | |
51 | + }else{ | |
52 | + cancel(); | |
53 | + } | |
54 | + } catch (PeerException e) { | |
55 | + setState(Unregistered.getInstance()); | |
56 | + e.printStackTrace(); | |
57 | + } | |
58 | + } | |
59 | + } | |
60 | + } | |
61 | + class WaitReplyRetryTimerTask extends TimerTask { | |
62 | + FullFrame retryFullFrame; | |
63 | + WaitReplyRetryTimerTask(FullFrame frame){ | |
64 | + retryFullFrame = frame; | |
65 | + } | |
66 | + | |
67 | + @Override | |
68 | + public void run() { | |
69 | + if (timersWaitingReply != null){ | |
70 | + try { | |
71 | + retryFullFrame.incRetryCount(); | |
72 | + if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
73 | + sendFrame(retryFullFrame); | |
74 | + } else{ | |
75 | + cancel(); | |
76 | + synchronized (timersWaitingReplyLock) { | |
77 | + timersWaitingReply.remove(Integer.valueOf(retryFullFrame.getSubclass())); | |
78 | + } | |
79 | + if (retryFullFrame.getFrameType() == 6 | |
80 | + && retryFullFrame.getSubclass() == 13){ | |
81 | + reconnectFlag = true; | |
82 | + } | |
83 | + throw new PeerException("Reached retries maximun in the peer for full frame of type " + | |
84 | + retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
85 | + } | |
86 | + } catch (PeerException e) { | |
87 | + setState(Unregistered.getInstance()); | |
88 | + e.printStackTrace(); | |
89 | + } | |
90 | + } | |
91 | + } | |
92 | + } | |
29 | 93 | |
30 | 94 | /** |
31 | 95 | * Peer's source call number |
@@ -35,9 +99,10 @@ | ||
35 | 99 | * Peer's register refresh in seconds |
36 | 100 | */ |
37 | 101 | public final static int REGISTER_REFRESH = 60; |
102 | + public final static int REGISTER_REFRESH_SHORT = 10; | |
38 | 103 | |
39 | 104 | //Peer's retry refresh in seconds |
40 | - private final int RETRY_REFRESH = 1; | |
105 | + private final int RETRY_REFRESH = 3; | |
41 | 106 | //Peer's retry max |
42 | 107 | private final int RETRY_MAXCOUNT = 5; |
43 | 108 |
@@ -54,9 +119,13 @@ | ||
54 | 119 | // |
55 | 120 | private Call call; |
56 | 121 | //HashMap with the frames that are waiting for an ack |
57 | - private HashMap<Long, FullFrame> framesWaitingAck; | |
122 | +// private HashMap<Long, FullFrame> framesWaitingAck; | |
123 | + private ConcurrentHashMap<Long, Timer> timersWaitingAck; | |
124 | + private Object timersWaitingAckLock = new Object(); | |
58 | 125 | //HashMap with the frames that are waiting for a reply |
59 | - private HashMap<Integer, FullFrame> framesWaitingReply; | |
126 | +// private HashMap<Integer, FullFrame> framesWaitingReply; | |
127 | + private ConcurrentHashMap<Integer, Timer> timersWaitingReply; | |
128 | + private Object timersWaitingReplyLock = new Object(); | |
60 | 129 | //Local identifier for a given call. |
61 | 130 | private int newLocalSrcCallNo; |
62 | 131 | //Peer listener. |
@@ -68,7 +137,7 @@ | ||
68 | 137 | //Register timer task |
69 | 138 | private Timer registerTimer = null; |
70 | 139 | //Retry timer task to retry frames not committed whit a specific frame or an ack frame |
71 | - private Timer retryTimer; | |
140 | +// private Timer retryTimer; | |
72 | 141 | //Flag for determining if the peer is processing the exit |
73 | 142 | private boolean processingExit; |
74 | 143 | //Max calls |
@@ -94,7 +163,7 @@ | ||
94 | 163 | * @param maxCalls maximum number of concurrent calls(This parameter is not used now. ) |
95 | 164 | */ |
96 | 165 | public Peer(PeerListener peerListener, String userName, String password, String host, int port, boolean register, int maxCalls) { |
97 | - this(peerListener, userName, password, host, port, register,maxCalls, new NullAudioFactory(), null); | |
166 | + this(peerListener, userName, password, host, port, 0, register,maxCalls, new NullAudioFactory(), null); | |
98 | 167 | } |
99 | 168 | |
100 | 169 | /** |
@@ -107,7 +176,7 @@ | ||
107 | 176 | * @param maxCalls maximum number of concurrent calls(This parameter is not used now. ) |
108 | 177 | */ |
109 | 178 | public Peer(PeerListener peerListener, String userName, String password, String host, int port, boolean register, int maxCalls, AudioFactory audioFactory) { |
110 | - this(peerListener, userName, password, host, port, register,maxCalls, audioFactory, null); | |
179 | + this(peerListener, userName, password, host, port, 0, register,maxCalls, audioFactory, null); | |
111 | 180 | } |
112 | 181 | |
113 | 182 | /** |
@@ -122,6 +191,21 @@ | ||
122 | 191 | * @param connection Connection class |
123 | 192 | */ |
124 | 193 | public Peer(PeerListener peerListener, String userName, String password, String host, int port, boolean register, int maxCalls, AudioFactory audioFactory,Connection connection) { |
194 | + this(peerListener, userName, password, host, port, 0, register,maxCalls, audioFactory, null); | |
195 | + } | |
196 | + | |
197 | + /** | |
198 | + * Constructor. Initializes the peer with the given values. | |
199 | + * @param peerListener Peer listener. | |
200 | + * @param userName Registration user name. | |
201 | + * @param password Registration password. | |
202 | + * @param host Remote host. | |
203 | + * @param register true if the peer is going to register, or false if not | |
204 | + * @param maxCalls maximum number of concurrent calls(This parameter is not used now. ) | |
205 | + * @param audioFactory AudioFactory class | |
206 | + * @param connection Connection class | |
207 | + */ | |
208 | + public Peer(PeerListener peerListener, String userName, String password, String host, int dPort, int sPort, boolean register, int maxCalls, AudioFactory audioFactory,Connection connection) { | |
125 | 209 | this.userName = userName; |
126 | 210 | this.password = password; |
127 | 211 | this.host = host; |
@@ -139,18 +223,12 @@ | ||
139 | 223 | this.connection = connection; |
140 | 224 | } |
141 | 225 | this.call = null; |
142 | - this.framesWaitingAck = new HashMap<Long, FullFrame>(); | |
143 | - this.framesWaitingReply = new HashMap<Integer, FullFrame>(); | |
144 | - this.connection.start(this, host, port); | |
226 | + this.timersWaitingAck = new ConcurrentHashMap<Long, Timer>(); | |
227 | + this.timersWaitingReply = new ConcurrentHashMap<Integer, Timer>(); | |
228 | + this.connection.start(this, host, dPort, sPort); | |
145 | 229 | this.state = Unregistered.getInstance(); |
146 | 230 | this.processingExit = false; |
147 | - this.retryTimer = new Timer(); | |
148 | - TimerTask retryTimerTask = new TimerTask() { | |
149 | - public void run() { | |
150 | - retryFramesWaiting(); | |
151 | - } | |
152 | - }; | |
153 | - retryTimer.schedule(retryTimerTask, RETRY_REFRESH*1000, RETRY_REFRESH*1000); | |
231 | + register(); | |
154 | 232 | setRegisterSchedule(); |
155 | 233 | } |
156 | 234 |
@@ -165,7 +243,7 @@ | ||
165 | 243 | } |
166 | 244 | }; |
167 | 245 | // System.out.println("VVVVVVVVVVVVVVVVVVVV setRegisterSchedule regRefresh = " + regRefresh + " VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV"); |
168 | - registerTimer.schedule(registerTimerTask, 0, regRefresh * 1000); | |
246 | + registerTimer.schedule(registerTimerTask, regRefresh * 1000, regRefresh * 1000); | |
169 | 247 | } |
170 | 248 | |
171 | 249 | /** |
@@ -228,16 +306,12 @@ | ||
228 | 306 | this.state = state; |
229 | 307 | if (state instanceof Registered) { |
230 | 308 | peerListener.registered(); |
231 | - if (regRefresh != REGISTER_REFRESH) { | |
232 | - regRefresh = REGISTER_REFRESH; | |
233 | - setRegisterSchedule(); | |
234 | - } | |
309 | +// setRegisterSchedule(); | |
235 | 310 | } else if (state instanceof Waiting) { |
236 | 311 | peerListener.waiting(); |
237 | 312 | } else if (state instanceof Unregistered) { |
238 | 313 | peerListener.unregistered(); |
239 | - regRefresh = 5; | |
240 | - setRegisterSchedule(); | |
314 | +// setRegisterSchedule(); | |
241 | 315 | } |
242 | 316 | } |
243 | 317 |
@@ -254,9 +328,17 @@ | ||
254 | 328 | * Ackes a full frame waiting for that removing it from the list of full frames waiting for ack |
255 | 329 | * @param timeStamp the timestamp of the full frame acked |
256 | 330 | */ |
257 | - public synchronized void ackedFrame(long timeStamp) { | |
258 | - framesWaitingAck.remove(new Long(timeStamp)); | |
259 | -// continualFailureCount = 0; | |
331 | + public /* synchronized */ void ackedFrame(long timeStamp) { | |
332 | + if (timersWaitingAck != null){ | |
333 | + synchronized (timersWaitingAckLock) { | |
334 | + Timer timer = timersWaitingAck.remove(Long.valueOf(timeStamp)); | |
335 | + if (timer != null){ | |
336 | + timer.cancel(); | |
337 | + }else{ | |
338 | + System.out.println("Peer.ackedFrame timeStamp:" + timeStamp + " not found."); | |
339 | + } | |
340 | + } | |
341 | + } | |
260 | 342 | } |
261 | 343 | |
262 | 344 | /** |
@@ -263,9 +345,13 @@ | ||
263 | 345 | * Replied a full frame waiting for that removing it from the list of full frames waiting for reply |
264 | 346 | * @param id the id of the full frame reply |
265 | 347 | */ |
266 | - public synchronized void repliedFrame(int id) { | |
267 | - framesWaitingReply.remove(new Integer(id)); | |
268 | -// continualFailureCount = 0; | |
348 | + public /* synchronized */ void repliedFrame(int id) { | |
349 | + if (timersWaitingReply != null){ | |
350 | + synchronized (timersWaitingReplyLock) { | |
351 | + Timer timer = timersWaitingReply.remove(Integer.valueOf(id)); | |
352 | + if (timer != null) timer.cancel(); | |
353 | + } | |
354 | + } | |
269 | 355 | } |
270 | 356 | |
271 | 357 | /** |
@@ -288,7 +374,6 @@ | ||
288 | 374 | } |
289 | 375 | processingExit = true; |
290 | 376 | registerTimer.cancel(); |
291 | - retryTimer.cancel(); | |
292 | 377 | PeerCommandSendFacade.regrel(this); |
293 | 378 | int retry = 0; |
294 | 379 | while(! (state instanceof Unregistered) && retry < RETRY_MAXCOUNT) { |
@@ -299,7 +384,20 @@ | ||
299 | 384 | } |
300 | 385 | retry++; |
301 | 386 | } |
302 | - | |
387 | + Iterator<Timer> timers = timersWaitingAck.values().iterator(); | |
388 | + while(timers.hasNext()){ | |
389 | + Timer retryTimer = timers.next(); | |
390 | + retryTimer.cancel(); | |
391 | + } | |
392 | + timersWaitingAck.clear(); | |
393 | + timersWaitingAck = null; | |
394 | + timers = timersWaitingReply.values().iterator(); | |
395 | + while(timers.hasNext()){ | |
396 | + Timer retryTimer = timers.next(); | |
397 | + retryTimer.cancel(); | |
398 | + } | |
399 | + timersWaitingReply.clear(); | |
400 | + timersWaitingReply = null; | |
303 | 401 | //Wait for responses |
304 | 402 | if (this.connection != null){ |
305 | 403 | this.connection.stop(); |
@@ -399,9 +497,16 @@ | ||
399 | 497 | * delegates in the method sendFrame() to send it |
400 | 498 | * @param fullFrame the full frame to send |
401 | 499 | */ |
402 | - public synchronized void sendFullFrameAndWaitForAck(FullFrame fullFrame) { | |
403 | - framesWaitingAck.put(new Long(fullFrame.getTimestamp()), fullFrame); | |
404 | - sendFrame(fullFrame); | |
500 | + public /* synchronized */ void sendFullFrameAndWaitForAck(FullFrame fullFrame) { | |
501 | + if (timersWaitingAck != null){ | |
502 | + synchronized (timersWaitingAckLock) { | |
503 | + Timer retryTimer = new Timer(); | |
504 | + TimerTask retryTimerTask = new WaitAckRetryTimerTask(fullFrame); | |
505 | + timersWaitingAck.put(Long.valueOf(fullFrame.getTimestamp()), retryTimer); | |
506 | + retryTimer.schedule(retryTimerTask, RETRY_REFRESH*1000, RETRY_REFRESH*1000); | |
507 | + sendFrame(fullFrame); | |
508 | + } | |
509 | + } | |
405 | 510 | } |
406 | 511 | |
407 | 512 | /** |
@@ -409,9 +514,16 @@ | ||
409 | 514 | * delegates in the method sendFrame() to send it |
410 | 515 | * @param fullFrame the full frame to send |
411 | 516 | */ |
412 | - public synchronized void sendFullFrameAndWaitForRep(FullFrame fullFrame) { | |
413 | - framesWaitingReply.put(new Integer(fullFrame.getSubclass()), fullFrame); | |
414 | - sendFrame(fullFrame); | |
517 | + public /* synchronized */ void sendFullFrameAndWaitForRep(FullFrame fullFrame) { | |
518 | + if (timersWaitingReply != null){ | |
519 | + synchronized (timersWaitingReplyLock) { | |
520 | + Timer retryTimer = new Timer(); | |
521 | + TimerTask retryTimerTask = new WaitReplyRetryTimerTask(fullFrame); | |
522 | + timersWaitingReply.put(Integer.valueOf(fullFrame.getSubclass()), retryTimer); | |
523 | + retryTimer.schedule(retryTimerTask, RETRY_REFRESH*1000, RETRY_REFRESH*1000); | |
524 | + sendFrame(fullFrame); | |
525 | + } | |
526 | + } | |
415 | 527 | } |
416 | 528 | |
417 | 529 | /** |
@@ -476,19 +588,19 @@ | ||
476 | 588 | * @throws PeerException |
477 | 589 | */ |
478 | 590 | public synchronized void recvCall(ProtocolControlFrame recvCallFrame) throws PeerException { |
591 | + String callingName = ""; | |
592 | + String callingNumber = ""; | |
593 | + try { | |
594 | + callingName = recvCallFrame.getCallingName(); | |
595 | + } catch (Exception e) { | |
596 | + e.printStackTrace(); | |
597 | + } | |
598 | + try { | |
599 | + callingNumber = recvCallFrame.getCallingNumber(); | |
600 | + } catch (Exception e) { | |
601 | + e.printStackTrace(); | |
602 | + } | |
479 | 603 | if (call == null && peerListener.isEnabled()) { |
480 | - String callingName = ""; | |
481 | - String callingNumber = ""; | |
482 | - try { | |
483 | - callingName = recvCallFrame.getCallingName(); | |
484 | - } catch (Exception e) { | |
485 | - e.printStackTrace(); | |
486 | - } | |
487 | - try { | |
488 | - callingNumber = recvCallFrame.getCallingNumber(); | |
489 | - } catch (Exception e) { | |
490 | - e.printStackTrace(); | |
491 | - } | |
492 | 604 | Call newCall = null; |
493 | 605 | try { |
494 | 606 | newCall = new Call(this, newLocalSrcCallNo,audioFactory); |
@@ -502,50 +614,9 @@ | ||
502 | 614 | peerListener.recvCall(callingName, callingNumber); |
503 | 615 | } else { |
504 | 616 | PeerCommandSendFacade.ack(this, recvCallFrame); |
505 | - PeerCommandSendFacade.busy(this, recvCallFrame); | |
506 | - } | |
507 | - } | |
508 | - | |
509 | - // Method to retry frames that haven't been commited whith a specific frame or an ack frame | |
510 | - private synchronized void retryFramesWaiting() { | |
511 | - try { | |
512 | - Iterator<FullFrame> iterator = framesWaitingAck.values().iterator(); | |
513 | - while (iterator.hasNext()) { | |
514 | - FullFrame retryFullFrame = (FullFrame)iterator.next(); | |
515 | - retryFullFrame.incRetryCount(); | |
516 | - if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
517 | - sendFrame(retryFullFrame); | |
518 | - } else { | |
519 | - iterator.remove(); | |
520 | - if (retryFullFrame.getFrameType() == 6 | |
521 | - && retryFullFrame.getSubclass() == 13){ | |
522 | - reconnectFlag = true; | |
523 | - } | |
524 | - throw new PeerException("Reached retries maximun in the peer for full frame of type " + | |
525 | - retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
526 | - } | |
617 | + if (call != null && !call.getCalledNumber().equals(callingNumber)){ | |
618 | + PeerCommandSendFacade.busy(this, recvCallFrame); | |
527 | 619 | } |
528 | - iterator = framesWaitingReply.values().iterator(); | |
529 | - while (iterator.hasNext()) { | |
530 | - FullFrame retryFullFrame = (FullFrame)iterator.next(); | |
531 | - retryFullFrame.incRetryCount(); | |
532 | - if (retryFullFrame.getRetryCount() < RETRY_MAXCOUNT) { | |
533 | - sendFrame(retryFullFrame); | |
534 | - } else { | |
535 | - iterator.remove(); | |
536 | - if (retryFullFrame.getFrameType() == 6 | |
537 | - && retryFullFrame.getSubclass() == 13){ | |
538 | - reconnectFlag = true; | |
539 | - } | |
540 | - throw new PeerException("Reached retries maximun in the peer for full frame of type " + | |
541 | - retryFullFrame.getFrameType() + ", subclass " + retryFullFrame.getSubclass()); | |
542 | - } | |
543 | - } | |
544 | - } catch (PeerException e) { | |
545 | - framesWaitingAck.clear(); | |
546 | - framesWaitingReply.clear(); | |
547 | - setState(Unregistered.getInstance()); | |
548 | - e.printStackTrace(); | |
549 | 620 | } |
550 | 621 | } |
551 | 622 |
@@ -566,4 +637,14 @@ | ||
566 | 637 | public boolean isReconnect() { |
567 | 638 | return reconnectFlag; |
568 | 639 | } |
640 | + | |
641 | + public int getRegRefresh() { | |
642 | + return regRefresh; | |
643 | + } | |
644 | + | |
645 | + public void setRegRefresh(int regRefresh) { | |
646 | + this.regRefresh = regRefresh; | |
647 | + setRegisterSchedule(); | |
648 | + } | |
649 | + | |
569 | 650 | } |
\ No newline at end of file |
@@ -45,6 +45,9 @@ | ||
45 | 45 | int auth = 0; |
46 | 46 | String challenge = ""; |
47 | 47 | if (regauthFrame.getSubclass() == ProtocolControlFrame.CALLTOKEN_SC) { |
48 | + int [] repliedSubclasses = FrameUtil.getReplySubclasses((regauthFrame.getSubclass())); | |
49 | + for (int i=0; i<repliedSubclasses.length; i++) | |
50 | + peer.repliedFrame(repliedSubclasses[i]); | |
48 | 51 | ProtocolControlFrame regrelFrame = |
49 | 52 | new ProtocolControlFrame(Peer.PEER_SRCCALLNO, |
50 | 53 | false, |
@@ -45,6 +45,9 @@ | ||
45 | 45 | int auth = 0; |
46 | 46 | String challenge = ""; |
47 | 47 | if (regauthFrame.getSubclass() == ProtocolControlFrame.CALLTOKEN_SC) { |
48 | + int [] repliedSubclasses = FrameUtil.getReplySubclasses((regauthFrame.getSubclass())); | |
49 | + for (int i=0; i<repliedSubclasses.length; i++) | |
50 | + peer.repliedFrame(repliedSubclasses[i]); | |
48 | 51 | ProtocolControlFrame regreqFrame = |
49 | 52 | new ProtocolControlFrame(Peer.PEER_SRCCALLNO, |
50 | 53 | false, |