1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.internal.net.ipsec.ike.utils;
17 
18 import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_RETRANSMIT;
19 
20 import android.os.Handler;
21 
22 import com.android.internal.net.ipsec.ike.message.IkeMessage;
23 
24 /**
25  * Retransmitter represents a class that will send a message and trigger delayed retransmissions
26  *
27  * <p>The Retransmitter class will queue retransmission signals on the provided handler. The owner
28  * of this retransmitter instance is expected to wait for the signal, and call retransmit() on the
29  * instance of this class.
30  */
31 public abstract class Retransmitter {
32 
33     /**
34      * Retransmission allowed state. Initial state when created.
35      *
36      * <p>This state allows packet transmission.
37      */
38     static final int STATE_RETRANSMISSION_ALLOWED = 1;
39     /**
40      * Retransmission suspended state.
41      *
42      * <p>This state does not allow packet transmission.
43      */
44     static final int STATE_RETRANSMISSION_SUSPENDED = 2;
45     /**
46      * Retransmission finished state.
47      *
48      * <p>This state does not allow packet transmission.
49      */
50     static final int STATE_RETRANSMISSION_FINISHED = 3;
51 
52     private final Handler mHandler;
53     private final IkeMessage mRetransmitMsg;
54     private int mRetransmitCount = 0;
55     private int[] mRetransmissionTimeouts;
56 
57     /** State of retransmitting. */
58     private int mRetransmitterState;
59 
Retransmitter(Handler handler, IkeMessage msg, int[] retransmissionTimeouts)60     public Retransmitter(Handler handler, IkeMessage msg, int[] retransmissionTimeouts) {
61         mHandler = handler;
62         mRetransmitMsg = msg;
63         mRetransmissionTimeouts = retransmissionTimeouts;
64         mRetransmitterState = STATE_RETRANSMISSION_ALLOWED;
65     }
66 
67     /**
68      * Triggers a (re)transmission. Will enqueue a future retransmission signal on the given handler
69      *
70      * <p>This method will only transmit packets when the Retransmitter is in the
71      * STATE_RETRANSMISSION_ALLOWED state
72      */
retransmit()73     public void retransmit() {
74         if (mRetransmitMsg == null) {
75             return;
76         }
77         // Packets can be transferred only when retransmission is in allowed state. Any other state
78         // does not allow packet transfer.
79         if (mRetransmitterState != STATE_RETRANSMISSION_ALLOWED) {
80             return;
81         }
82 
83         // If the failed iteration is beyond the max attempts, clean up and shut down.
84         if (mRetransmitCount >= mRetransmissionTimeouts.length) {
85             handleRetransmissionFailure();
86             return;
87         }
88 
89         send();
90 
91         long timeout = mRetransmissionTimeouts[mRetransmitCount++];
92         mHandler.sendMessageDelayed(mHandler.obtainMessage(CMD_RETRANSMIT, this), timeout);
93     }
94 
95     /**
96      * Finish retransmitting and cancels any future retransmissions.
97      *
98      * <p>This function is called when all packet transmissions have been completed and any future
99      * next retransmission is no longer needed.
100      */
stopRetransmitting()101     public void stopRetransmitting() {
102         mHandler.removeMessages(CMD_RETRANSMIT, this);
103 
104         // Set as stopped
105         mRetransmitterState = STATE_RETRANSMISSION_FINISHED;
106     }
107 
108     /**
109      * Suspends retransmitting.
110      *
111      * <p>Cancels any future retransmissions and sets the state to the Suspended. Retransmission can
112      * only be resumed using the {@link #restartRetransmitting()}.
113      */
suspendRetransmitting()114     public void suspendRetransmitting() {
115         // When retransmission is finished, it does not transition to the suspend state.
116         if (mRetransmitterState != STATE_RETRANSMISSION_ALLOWED) {
117             return;
118         }
119 
120         // Remove future retransmissions.
121         mHandler.removeMessages(CMD_RETRANSMIT, this);
122 
123         // Set as suspended
124         mRetransmitterState = STATE_RETRANSMISSION_SUSPENDED;
125     }
126 
127     /**
128      * Restarts retransmitting.
129      *
130      * <p>Resumes a retransmission suspended by {@link #suspendRetransmitting} and retransmission
131      * starts again from the beginning by resetting retransmit count.
132      *
133      * <p>The state finished by {@link #stopRetransmitting()} will not be restarted again.
134      */
restartRetransmitting()135     public void restartRetransmitting() {
136         // When retransmission is finished, it does not transition to the allowed state.
137         if (mRetransmitterState != STATE_RETRANSMISSION_SUSPENDED) {
138             return;
139         }
140 
141         // Set as resumed.
142         mRetransmitterState = STATE_RETRANSMISSION_ALLOWED;
143 
144         // Reset retransmission count to 0.
145         mRetransmitCount = 0;
146 
147         // Resume retransmitting.
148         retransmit();
149     }
150 
151     /** Retrieves the message this retransmitter is tracking */
getMessage()152     public IkeMessage getMessage() {
153         return mRetransmitMsg;
154     }
155 
156     /**
157      * Implementation-provided sender
158      *
159      * <p>For Retransmitter-internal use only.
160      */
send()161     protected abstract void send();
162 
163     /**
164      * Callback for implementations to be informed that we have reached the max retransmissions.
165      *
166      * <p>For Retransmitter-internal use only.
167      */
handleRetransmissionFailure()168     protected abstract void handleRetransmissionFailure();
169 }
170