1 /*
2  * Copyright (C) 2016 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 
17 package com.android.server.wifi.nan;
18 
19 import android.net.wifi.nan.IWifiNanSessionListener;
20 import android.net.wifi.nan.PublishData;
21 import android.net.wifi.nan.PublishSettings;
22 import android.net.wifi.nan.SubscribeData;
23 import android.net.wifi.nan.SubscribeSettings;
24 import android.net.wifi.nan.WifiNanSessionListener;
25 import android.os.RemoteException;
26 import android.util.Log;
27 import android.util.SparseArray;
28 
29 import libcore.util.HexEncoding;
30 
31 import java.io.FileDescriptor;
32 import java.io.PrintWriter;
33 
34 public class WifiNanSessionState {
35     private static final String TAG = "WifiNanSessionState";
36     private static final boolean DBG = false;
37     private static final boolean VDBG = false; // STOPSHIP if true
38 
39     private final SparseArray<String> mMacByRequestorInstanceId = new SparseArray<>();
40 
41     private int mSessionId;
42     private IWifiNanSessionListener mListener;
43     private int mEvents;
44 
45     private boolean mPubSubIdValid = false;
46     private int mPubSubId;
47 
48     private static final int SESSION_TYPE_NOT_INIT = 0;
49     private static final int SESSION_TYPE_PUBLISH = 1;
50     private static final int SESSION_TYPE_SUBSCRIBE = 2;
51     private int mSessionType = SESSION_TYPE_NOT_INIT;
52 
WifiNanSessionState(int sessionId, IWifiNanSessionListener listener, int events)53     public WifiNanSessionState(int sessionId, IWifiNanSessionListener listener, int events) {
54         mSessionId = sessionId;
55         mListener = listener;
56         mEvents = events;
57     }
58 
destroy()59     public void destroy() {
60         stop(WifiNanStateManager.getInstance().createNextTransactionId());
61         if (mPubSubIdValid) {
62             mMacByRequestorInstanceId.clear();
63             mListener = null;
64             mPubSubIdValid = false;
65         }
66     }
67 
getSessionId()68     public int getSessionId() {
69         return mSessionId;
70     }
71 
isPubSubIdSession(int pubSubId)72     public boolean isPubSubIdSession(int pubSubId) {
73         return mPubSubIdValid && mPubSubId == pubSubId;
74     }
75 
publish(short transactionId, PublishData data, PublishSettings settings)76     public void publish(short transactionId, PublishData data, PublishSettings settings) {
77         if (mSessionType == SESSION_TYPE_SUBSCRIBE) {
78             throw new IllegalStateException("A SUBSCRIBE session is being used for publish");
79         }
80         mSessionType = SESSION_TYPE_PUBLISH;
81 
82         WifiNanNative.getInstance().publish(transactionId, mPubSubIdValid ? mPubSubId : 0, data,
83                 settings);
84     }
85 
subscribe(short transactionId, SubscribeData data, SubscribeSettings settings)86     public void subscribe(short transactionId, SubscribeData data, SubscribeSettings settings) {
87         if (mSessionType == SESSION_TYPE_PUBLISH) {
88             throw new IllegalStateException("A PUBLISH session is being used for publish");
89         }
90         mSessionType = SESSION_TYPE_SUBSCRIBE;
91 
92         WifiNanNative.getInstance().subscribe(transactionId, mPubSubIdValid ? mPubSubId : 0, data,
93                 settings);
94     }
95 
sendMessage(short transactionId, int peerId, byte[] message, int messageLength, int messageId)96     public void sendMessage(short transactionId, int peerId, byte[] message, int messageLength,
97             int messageId) {
98         if (!mPubSubIdValid) {
99             Log.e(TAG, "sendMessage: attempting to send a message on a non-live session "
100                     + "(no successful publish or subscribe");
101             onMessageSendFail(messageId, WifiNanSessionListener.FAIL_REASON_NO_MATCH_SESSION);
102             return;
103         }
104 
105         String peerMacStr = mMacByRequestorInstanceId.get(peerId);
106         if (peerMacStr == null) {
107             Log.e(TAG, "sendMessage: attempting to send a message to an address which didn't "
108                     + "match/contact us");
109             onMessageSendFail(messageId, WifiNanSessionListener.FAIL_REASON_NO_MATCH_SESSION);
110             return;
111         }
112         byte[] peerMac = HexEncoding.decode(peerMacStr.toCharArray(), false);
113 
114         WifiNanNative.getInstance().sendMessage(transactionId, mPubSubId, peerId, peerMac, message,
115                 messageLength);
116     }
117 
stop(short transactionId)118     public void stop(short transactionId) {
119         if (!mPubSubIdValid || mSessionType == SESSION_TYPE_NOT_INIT) {
120             Log.e(TAG, "sendMessage: attempting to stop pub/sub on a non-live session (no "
121                     + "successful publish or subscribe");
122             return;
123         }
124 
125         if (mSessionType == SESSION_TYPE_PUBLISH) {
126             WifiNanNative.getInstance().stopPublish(transactionId, mPubSubId);
127         } else if (mSessionType == SESSION_TYPE_SUBSCRIBE) {
128             WifiNanNative.getInstance().stopSubscribe(transactionId, mPubSubId);
129         }
130     }
131 
onPublishSuccess(int publishId)132     public void onPublishSuccess(int publishId) {
133         mPubSubId = publishId;
134         mPubSubIdValid = true;
135     }
136 
onPublishFail(int status)137     public void onPublishFail(int status) {
138         mPubSubIdValid = false;
139         try {
140             if (mListener != null && (mEvents & WifiNanSessionListener.LISTEN_PUBLISH_FAIL) != 0) {
141                 mListener.onPublishFail(status);
142             }
143         } catch (RemoteException e) {
144             Log.w(TAG, "onPublishFail: RemoteException (FYI): " + e);
145         }
146     }
147 
onPublishTerminated(int status)148     public void onPublishTerminated(int status) {
149         mPubSubIdValid = false;
150         try {
151             if (mListener != null
152                     && (mEvents & WifiNanSessionListener.LISTEN_PUBLISH_TERMINATED) != 0) {
153                 mListener.onPublishTerminated(status);
154             }
155         } catch (RemoteException e) {
156             Log.w(TAG, "onPublishTerminated: RemoteException (FYI): " + e);
157         }
158     }
159 
onSubscribeSuccess(int subscribeId)160     public void onSubscribeSuccess(int subscribeId) {
161         mPubSubId = subscribeId;
162         mPubSubIdValid = true;
163     }
164 
onSubscribeFail(int status)165     public void onSubscribeFail(int status) {
166         mPubSubIdValid = false;
167         try {
168             if (mListener != null
169                     && (mEvents & WifiNanSessionListener.LISTEN_SUBSCRIBE_FAIL) != 0) {
170                 mListener.onSubscribeFail(status);
171             }
172         } catch (RemoteException e) {
173             Log.w(TAG, "onSubscribeFail: RemoteException (FYI): " + e);
174         }
175     }
176 
onSubscribeTerminated(int status)177     public void onSubscribeTerminated(int status) {
178         mPubSubIdValid = false;
179         try {
180             if (mListener != null
181                     && (mEvents & WifiNanSessionListener.LISTEN_SUBSCRIBE_TERMINATED) != 0) {
182                 mListener.onSubscribeTerminated(status);
183             }
184         } catch (RemoteException e) {
185             Log.w(TAG, "onSubscribeTerminated: RemoteException (FYI): " + e);
186         }
187     }
188 
onMessageSendSuccess(int messageId)189     public void onMessageSendSuccess(int messageId) {
190         try {
191             if (mListener != null
192                     && (mEvents & WifiNanSessionListener.LISTEN_MESSAGE_SEND_SUCCESS) != 0) {
193                 mListener.onMessageSendSuccess(messageId);
194             }
195         } catch (RemoteException e) {
196             Log.w(TAG, "onMessageSendSuccess: RemoteException (FYI): " + e);
197         }
198     }
199 
onMessageSendFail(int messageId, int status)200     public void onMessageSendFail(int messageId, int status) {
201         try {
202             if (mListener != null
203                     && (mEvents & WifiNanSessionListener.LISTEN_MESSAGE_SEND_FAIL) != 0) {
204                 mListener.onMessageSendFail(messageId, status);
205             }
206         } catch (RemoteException e) {
207             Log.w(TAG, "onMessageSendFail: RemoteException (FYI): " + e);
208         }
209     }
210 
onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength)211     public void onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo,
212             int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) {
213         String prevMac = mMacByRequestorInstanceId.get(requestorInstanceId);
214         mMacByRequestorInstanceId.put(requestorInstanceId, new String(HexEncoding.encode(peerMac)));
215 
216         if (DBG) Log.d(TAG, "onMatch: previous peer MAC replaced - " + prevMac);
217 
218         try {
219             if (mListener != null && (mEvents & WifiNanSessionListener.LISTEN_MATCH) != 0) {
220                 mListener.onMatch(requestorInstanceId, serviceSpecificInfo,
221                         serviceSpecificInfoLength, matchFilter, matchFilterLength);
222             }
223         } catch (RemoteException e) {
224             Log.w(TAG, "onMatch: RemoteException (FYI): " + e);
225         }
226     }
227 
onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message, int messageLength)228     public void onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message,
229             int messageLength) {
230         String prevMac = mMacByRequestorInstanceId.get(requestorInstanceId);
231         mMacByRequestorInstanceId.put(requestorInstanceId, new String(HexEncoding.encode(peerMac)));
232 
233         if (DBG) {
234             Log.d(TAG, "onMessageReceived: previous peer MAC replaced - " + prevMac);
235         }
236 
237         try {
238             if (mListener != null
239                     && (mEvents & WifiNanSessionListener.LISTEN_MESSAGE_RECEIVED) != 0) {
240                 mListener.onMessageReceived(requestorInstanceId, message, messageLength);
241             }
242         } catch (RemoteException e) {
243             Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e);
244         }
245     }
246 
dump(FileDescriptor fd, PrintWriter pw, String[] args)247     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
248         pw.println("NanSessionState:");
249         pw.println("  mSessionId: " + mSessionId);
250         pw.println("  mSessionType: " + mSessionType);
251         pw.println("  mEvents: " + mEvents);
252         pw.println("  mPubSubId: " + (mPubSubIdValid ? Integer.toString(mPubSubId) : "not valid"));
253         pw.println("  mMacByRequestorInstanceId: [" + mMacByRequestorInstanceId + "]");
254     }
255 }
256