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     private final Handler mHandler;
33     private final IkeMessage mRetransmitMsg;
34     private int mRetransmitCount = 0;
35     private int[] mRetransmissionTimeouts;
36 
Retransmitter(Handler handler, IkeMessage msg, int[] retransmissionTimeouts)37     public Retransmitter(Handler handler, IkeMessage msg, int[] retransmissionTimeouts) {
38         mHandler = handler;
39         mRetransmitMsg = msg;
40         mRetransmissionTimeouts = retransmissionTimeouts;
41     }
42 
43     /**
44      * Triggers a (re)transmission. Will enqueue a future retransmission signal on the given handler
45      */
retransmit()46     public void retransmit() {
47         if (mRetransmitMsg == null) {
48             return;
49         }
50 
51         // If the failed iteration is beyond the max attempts, clean up and shut down.
52         if (mRetransmitCount >= mRetransmissionTimeouts.length) {
53             handleRetransmissionFailure();
54             return;
55         }
56 
57         send(mRetransmitMsg);
58 
59         long timeout = mRetransmissionTimeouts[mRetransmitCount++];
60         mHandler.sendMessageDelayed(mHandler.obtainMessage(CMD_RETRANSMIT, this), timeout);
61     }
62 
63     /** Cancels any future retransmissions */
stopRetransmitting()64     public void stopRetransmitting() {
65         mHandler.removeMessages(CMD_RETRANSMIT, this);
66     }
67 
68     /** Retrieves the message this retransmitter is tracking */
getMessage()69     public IkeMessage getMessage() {
70         return mRetransmitMsg;
71     }
72 
73     /**
74      * Implementation-provided sender
75      *
76      * <p>For Retransmitter-internal use only.
77      *
78      * @param msg the message to be sent
79      */
send(IkeMessage msg)80     protected abstract void send(IkeMessage msg);
81 
82     /**
83      * Callback for implementations to be informed that we have reached the max retransmissions.
84      *
85      * <p>For Retransmitter-internal use only.
86      */
handleRetransmissionFailure()87     protected abstract void handleRetransmissionFailure();
88 }
89