1#
2#   Copyright 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
16import random
17import re
18import time
19from acts import asserts
20from acts import base_test
21from acts.test_decorators import test_tracker_info
22from acts.test_utils.net import connectivity_test_utils as cutils
23from acts.test_utils.net import net_test_utils as nutils
24from acts.test_utils.net import socket_test_utils as sutils
25from acts.test_utils.net.net_test_utils import start_tcpdump
26from acts.test_utils.net.net_test_utils import stop_tcpdump
27from acts.test_utils.wifi import wifi_test_utils as wutils
28from scapy.all import rdpcap
29from scapy.all import Scapy_Exception
30from scapy.all import TCP
31from scapy.all import UDP
32
33
34ACK = "A"
35DROPPED_IPV4_KA_ACK = "DROPPED_IPV4_KEEPALIVE_ACK"
36MIN_TEST_KA_INTERVAL = 10
37# max keepalive interval is kept to 60 for test purposes
38MAX_TEST_KA_INTERVAL = 60
39# sleep time to test keepalives. this is set to a prime number to prevent
40# race conditions and as a result flaky tests.
41# Ex: if keepalive is started with 42s time interval, we expect 4 keepalives
42# after 181s.
43SLEEP_TIME = 181
44STRESS_COUNT = 5
45SUPPORTED_KERNEL_VERSION = 4.8
46TCP_SERVER_PORT = 853
47UDP_SERVER_PORT = 4500
48
49
50class SocketKeepaliveTest(base_test.BaseTestClass):
51    """Tests for Socket keepalive."""
52
53    def __init__(self, controllers):
54        """List and order of tests to run."""
55        base_test.BaseTestClass.__init__(self, controllers)
56        self.tests = (
57            "test_tcp_socket_keepalive_start_stop_wifi",
58            "test_natt_socket_keepalive_start_stop_wifi",
59            "test_tcp_socket_keepalive_error_client_socket_close_wifi",
60            "test_tcp_socket_keepalive_over_max_keepalive_limit_wifi",
61            "test_tcp_socket_keepalive_invalid_interval",
62            "test_natt_socket_keepalive_invalid_interval",
63            "test_tcp_socket_keepalive_start_stop_multiple_keepalives_wifi",
64            "test_tcp_socket_keepalive_start_stop_stress_wifi",
65            "test_tcp_socket_keepalive_on_data_received_wifi",
66            "test_natt_socket_keepalive_start_stop_lte",)
67
68    def setup_class(self):
69        """Setup devices for tests and unpack params."""
70
71        self.dut = self.android_devices[1]
72        # remote_server_2 is the host machine to test OnDataCallback and Error
73        # callbacks. The server program sends data to the DUT while keepalive
74        # is enabled. It also closes the server socket to verify Error callback
75        # 'test_tcp_socket_keepalive_on_data_received_wifi' requires this.
76        # remote_server is the host machine to test all other test cases.
77        # This host listens, accepts connections and verifies the keepalive
78        # intervals.
79        req_params = ("wifi_network", "remote_server", "remote_server_2")
80        self.unpack_userparams(req_params)
81        nutils.verify_lte_data_and_tethering_supported(self.dut)
82        self.max_ka_net = self.dut.droid.getSupportedKeepalivesForNetwork()
83        self.log.info("Max Keepalives for mobile network: %s" % self.max_ka_net)
84        wutils.start_wifi_connection_scan_and_ensure_network_found(
85            self.dut, self.wifi_network["SSID"])
86        wutils.wifi_connect(self.dut, self.wifi_network)
87        self.max_ka_wifi = self.dut.droid.getSupportedKeepalivesForNetwork()
88        self.log.info("Max Keepalives on wifi network: %s" % self.max_ka_wifi)
89        self.kernel_version = self._get_kernel_version(self.dut)
90        self.log.info("Kernel version: %s" % self.kernel_version)
91
92        self.host_ip = self.remote_server["ip_addr"]
93        self.tcpdump_pid = None
94        self.tcp_sockets = []
95        self.socket_keepalives = []
96        self.gce_tcpdump_pid = None
97        self.udp_encap = None
98
99    def setup_test(self):
100        asserts.skip_if(
101            self.test_name.startswith("test_tcp") and \
102                self.kernel_version < SUPPORTED_KERNEL_VERSION,
103            "TCP Keepalive is not supported on kernel %s. Need at least %s" %
104            (self.kernel_version, SUPPORTED_KERNEL_VERSION))
105
106        if self.test_name.endswith("_lte"):
107            wutils.wifi_toggle_state(self.dut, False)
108        time.sleep(3)
109        link_prop = self.dut.droid.connectivityGetActiveLinkProperties()
110        iface = link_prop["InterfaceName"]
111        self.log.info("Iface: %s" % iface)
112        self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses(iface)[0]
113        self.tcpdump_pid = start_tcpdump(self.dut, self.test_name)
114
115    def teardown_test(self):
116        if self.tcpdump_pid:
117            stop_tcpdump(self.dut, self.tcpdump_pid, self.test_name)
118            self.tcpdump_pid = None
119        if self.gce_tcpdump_pid:
120            host = self.remote_server
121            if "_on_data_" in self.test_name:
122                host = self.remote_server_2
123            nutils.stop_tcpdump_gce_server(
124                self.dut, self.gce_tcpdump_pid, None, host)
125            self.gce_tcpdump_pid = None
126        for ska in self.socket_keepalives:
127            cutils.stop_socket_keepalive(self.dut, ska)
128        self.socket_keepalives = []
129        for sock in self.tcp_sockets:
130            sutils.shutdown_socket(self.dut, sock)
131        self.tcp_sockets = []
132        if self.udp_encap:
133            self.dut.droid.ipSecCloseUdpEncapsulationSocket(self.udp_encap)
134        self.udp_encap = None
135        wutils.wifi_toggle_state(self.dut, True)
136
137    def teardown_class(self):
138        wutils.reset_wifi(self.dut)
139
140    def on_fail(self, test_name, begin_time):
141        self.dut.take_bug_report(test_name, begin_time)
142
143    ### Helper functions
144
145    def _get_kernel_version(self, ad):
146        """Get the kernel version on the device.
147
148        Args:
149            ad: android device object.
150
151        Returns:
152            Kernel version on the device.
153        """
154        cmd_out = ad.adb.shell("cat /proc/version")
155        pattern_match = re.findall(r"^Linux version \d.\d", cmd_out)
156        return float(pattern_match[0].split()[-1]) if pattern_match else None
157
158    def _verify_tcp_keepalives(self,
159                               pcap,
160                               interval,
161                               cport,
162                               beg,
163                               end,
164                               expected_ka_count,
165                               verify_ka_interval=True):
166        """Verify TCP keepalives received by host.
167
168        Args:
169            pcap: tcpdump file from host.
170            interval: keepalive time interval.
171            cport: client port after NAT on the host.
172            beg: beginning time for keepalives.
173            end: end time for keepalives.
174            expected_ka_count: expected no. of KA packets.
175            verify_ka_interval: if true, verify the keepalive time interval.
176
177        Returns:
178            True/False if keepalives are successful.
179        """
180        try:
181            packets = rdpcap(pcap)
182        except Scapy_Exception:
183            asserts.fail("Not a valid pcap file")
184
185        seq = None
186        time_stamps = []
187        for pkt in packets:
188            if pkt.time < beg:
189                continue
190            if pkt.time > end:
191                break
192            if TCP in pkt and pkt[TCP].dport == TCP_SERVER_PORT and \
193                    pkt[TCP].sport == cport and pkt[TCP].flags == ACK and \
194                    not seq or pkt[TCP].seq == seq:
195
196                seq = pkt[TCP].seq
197                time_stamps.append(pkt.time)
198
199        self.log.info("KA count: %s, expected %s" % (len(time_stamps),
200                                                     expected_ka_count))
201        if len(time_stamps) != expected_ka_count:
202            return False
203        if not verify_ka_interval:
204            return True
205        return self._verify_keepalive_interval(time_stamps, interval)
206
207    def _verify_natt_keepalives(self,
208                                pcap,
209                                interval,
210                                beg,
211                                end,
212                                expected_ka_count):
213        """Verify Natt keepalives received by host.
214
215        Args:
216            pcap: tcpdump file from host.
217            interval: expected time difference between keepalives.
218            beg: beginning time for keepalives.
219            end: end time for keepalives.
220            expected_ka_count: expected keepalive count.
221
222        Returns:
223            True/False if keepalives are successful.
224        """
225        try:
226            packets = rdpcap(pcap)
227        except Scapy_Exception:
228            asserts.fail("Not a valid pcap file")
229
230        ka_dict = {}
231        for pkt in packets:
232            if pkt.time < beg:
233                continue
234            if pkt.time > end:
235                break
236            if UDP in pkt and pkt[UDP].dport == UDP_SERVER_PORT:
237                if pkt[UDP].sport not in ka_dict:
238                    ka_dict[pkt[UDP].sport] = [float(pkt.time)]
239                else:
240                    ka_dict[pkt[UDP].sport].append(float(pkt.time))
241
242        for sport in ka_dict:
243            self.log.info("Source port: %s" % sport)
244            self.log.info("KA count: %s, expected: %s" % (len(ka_dict[sport]),
245                                                          expected_ka_count))
246            if len(ka_dict[sport]) == expected_ka_count and \
247                    self._verify_keepalive_interval(ka_dict[sport], interval):
248                return True
249        self.log.error("Keepalive time interval verification failed")
250        return False
251
252    def _verify_keepalive_interval(self, time_stamps, interval):
253        """Verify time difference between keepalive packets.
254
255        Args:
256            time_stamps: List of timestamps of each keepalive.
257            interval: Expected time difference.
258
259        Returns:
260            True if Keepalive interval matches with expected value.
261        """
262        i = 0
263        for t in time_stamps:
264            if i == 0:
265                prev = t
266                i += 1
267                continue
268            diff = int(round(t - prev))
269            self.log.info("KA interval: %s, expected: %s" % (diff, interval))
270            if diff != interval:
271                return False
272            prev = t
273            i += 1
274        return True
275
276    def _get_expected_ka_count(self, elapsed_time, ka_time_interval):
277        """Get expected keepalive count.
278
279        Args:
280            elapsed_time: time in seconds within which to count the keepalives.
281            ka_time_interval: time interval between keepalives.
282
283        Returns:
284            no. of keepalives.
285        """
286        return int(elapsed_time/ka_time_interval)
287
288    def _get_client_port_and_time_interval(self):
289        """Generate a random tcp port and keepalive time interval.
290
291        Returns:
292            client_port and keepalive time interval.
293        """
294        # (TODO: @gmoturu) Change this to autobind instead of generating a port.
295        client_port = random.randint(8000, 9000)
296        time_interval = random.randint(MIN_TEST_KA_INTERVAL,
297                                       MAX_TEST_KA_INTERVAL)
298        self.log.info("Socket Keepalive time interval: %s" % time_interval)
299        return client_port, time_interval
300
301    def _open_tcp_socket_and_connect(self, client_port, server_ip=None):
302        """Open a TCP socket and connect to server for keepalive testing.
303
304        Args:
305            client_port: port to open tcp socket on.
306            server_ip: IP addr of remote server.
307
308        Returns:
309            socket object and client port seen by server.
310        """
311        if not server_ip:
312            server_ip = self.host_ip
313        sock = self.dut.droid.openTcpSocket(server_ip,
314                                            TCP_SERVER_PORT,
315                                            self.dut_ip,
316                                            client_port)
317        asserts.assert_true(sock, "Failed to open TCP socket")
318        self.log.info("Socket key: %s" % sock)
319        self.tcp_sockets.append(sock)
320        cport_server = self.dut.droid.tcpSocketRecv(sock)
321        asserts.assert_true(cport_server, "Received null message from server")
322        self.log.info("Client port after NAT on host: %s" % cport_server)
323        return sock, cport_server
324
325    def _start_tcp_keepalive(self, sock, time_interval, expect_ka_start=True):
326        """Start TCP keepalive.
327
328        Args:
329            sock: TCP socket object.
330            time_interval: keepalive time interval.
331            expect_ka_start: if True, KA should Start, else Error outcome.
332
333        Returns:
334            key of socket keepalive object.
335        """
336        ska_key = cutils.start_tcp_socket_keepalive(self.dut,
337                                                    sock,
338                                                    time_interval)
339
340        if not expect_ka_start:
341            asserts.assert_false(ska_key,
342                                 "Expected starting socket keepalive to fail")
343            return None
344
345        asserts.assert_true(ska_key, "Failed to start socket keepalive")
346        self.socket_keepalives.append(ska_key)
347        return ska_key
348
349    def _get_dropped_keepalive_acks(self, ack=DROPPED_IPV4_KA_ACK):
350        """Get dropped keepalive acks from dumpsys output.
351
352        Args:
353            ack: Type of keepalive ack to check.
354
355        Returns:
356            Number of dropped acks.
357        """
358        dropped_acks = self.dut.adb.shell(
359            "dumpsys network_stack | grep '%s'" % ack)
360        dropped_acks = dropped_acks.rstrip()
361        self.log.info("Dropped keepalive acks: %s" % dropped_acks)
362        return 0 if not dropped_acks else int(dropped_acks.split(":")[-1])
363
364    def _test_socket_keepalive_start_stop(self):
365        """Test NATT and TCP socket keepalives for wifi and mobile networks."""
366        tcp_keepalive = True if "_tcp_" in self.test_name else False
367        ad = self.dut
368        port = TCP_SERVER_PORT if tcp_keepalive else UDP_SERVER_PORT
369        self.log.info("Client IP: %s" % self.dut_ip)
370        self.log.info("Server IP: %s" % self.host_ip)
371
372        # start tcpdump on the server
373        self.gce_tcpdump_pid, pcap_path = nutils.start_tcpdump_gce_server(
374            ad, self.test_name, port, self.remote_server)
375
376        # start keepalive
377        client_port, time_interval = self._get_client_port_and_time_interval()
378        ska_key = None
379        if tcp_keepalive:
380            self.log.info("Client port: %s" % client_port)
381            self.log.info("Server port: %s" % TCP_SERVER_PORT)
382            sock, cport_server = self._open_tcp_socket_and_connect(client_port)
383            ska_key = self._start_tcp_keepalive(sock, time_interval)
384        else:
385            self.log.info("UDP encap port on server: %s" % UDP_SERVER_PORT)
386            self.udp_encap = self.dut.droid.ipSecOpenUdpEncapsulationSocket()
387            ska_key = cutils.start_natt_socket_keepalive(self.dut,
388                                                         self.udp_encap,
389                                                         self.dut_ip,
390                                                         self.host_ip,
391                                                         time_interval)
392            self.socket_keepalives.append(ska_key)
393        asserts.assert_true(ska_key, "Failed to start socket keepalive")
394
395        # sleep for sometime to verify keepalives
396        beg_time = time.time()
397        self.log.info("Sleeping for %s seconds" % SLEEP_TIME)
398        time.sleep(SLEEP_TIME)
399        end_time = time.time()
400
401        # stop tcpdump
402        pcap_file = nutils.stop_tcpdump_gce_server(
403            ad, self.gce_tcpdump_pid, pcap_path, self.remote_server)
404        self.gce_tcpdump_pid = None
405
406        # verify keepalives
407        expected_ka_count = self._get_expected_ka_count(end_time-beg_time,
408                                                        time_interval)
409
410        if tcp_keepalive:
411            result = self._verify_tcp_keepalives(
412                pcap_file, time_interval, int(cport_server), beg_time, end_time,
413                expected_ka_count)
414        else:
415            result = self._verify_natt_keepalives(
416                pcap_file, time_interval, beg_time, end_time, expected_ka_count)
417        asserts.assert_true(result, "Keepalive verification failed")
418
419    ### Tests begin
420
421    @test_tracker_info(uuid="537e13ef-2366-40a3-86d4-596266d21eda")
422    def test_tcp_socket_keepalive_start_stop_wifi(self):
423        """Test TCP keepalive for onStart and onStop callbacks.
424
425        Steps:
426            1. Open a TCP socket on DUT and connect to server.
427            2. Start TCP keepalive and verify onStarted callback is received.
428            3. Verify that server received the keepalives.
429            4. Stop TCP keepalive and verify onStopped callback is received.
430        """
431        self._test_socket_keepalive_start_stop()
432
433    @test_tracker_info(uuid="8f23f3a0-7b65-4b5c-bc91-5decaddb7c9c")
434    def test_tcp_socket_keepalive_on_data_received_wifi(self):
435        """Test Error callback for tcp socket keepalive.
436
437        Steps:
438            1. Open a TCP socket on DUT and connect ot server on port 853.
439            2. Start TCP keepalive and verify on Start callback.
440            3. Send message from server and verify OnDataReceived Callback.
441            4. Send data and recv data from server.
442            5. Start keeaplive again and verify server receives them.
443        """
444        # start tcpdump on the server
445        host = self.remote_server_2
446        host_ip = host["ip_addr"]
447        tcpdump_pid, pcap_path = nutils.start_tcpdump_gce_server(
448            self.dut, self.test_name, TCP_SERVER_PORT, host)
449
450        # open socket, connect to server, start keepalive
451        time_interval = 11
452        sleep_time = 37
453        keepalive_count = 3
454        self.log.info("Client IP: %s" % self.dut_ip)
455        self.log.info("Server IP: %s" % host_ip)
456        client_port = random.randint(8000, 9000)
457        self.log.info("Client port: %s" % client_port)
458        sock, cport_server = self._open_tcp_socket_and_connect(client_port,
459                                                               host_ip)
460        ska_key = self._start_tcp_keepalive(sock, time_interval)
461
462        # wait for data to be received from server
463        begin_time = time.time()
464        self.log.info("Sleeping for %s seconds" % sleep_time)
465        time.sleep(sleep_time)
466        recv_msg = self.dut.droid.tcpSocketRecv(sock)
467        self.log.info("Received message: %s" % recv_msg)
468
469        # verify onDataReceived callback
470        status = cutils.socket_keepalive_data_received(self.dut, ska_key)
471        asserts.assert_true(status, "Failed to receive onDataReceived callback")
472        self.socket_keepalives = []
473
474        # wait for some time before starting keepalives
475        self.log.info("Sleeping for %s seconds" % sleep_time)
476        time.sleep(sleep_time)
477
478        # re-start keepalives and sleep for sometime to verify keepalives
479        ska_key = self._start_tcp_keepalive(sock, time_interval)
480        self.log.info("Sleeping for %s seconds" % sleep_time)
481        time.sleep(sleep_time)
482        end_time = time.time()
483        dropped_acks = self._get_dropped_keepalive_acks()
484
485        # expected ka count here is not based on beg_time and end_time as we
486        # wait some time before re-starting keepalives after OnDataReceived
487        # callback. the elapsed time will be sleep_time * 2. the extra keepalive
488        # accounts for the one sent by kernel. b/132924144 for reference.
489        expected_ka_count = 1+self._get_expected_ka_count(sleep_time*2,
490                                                          time_interval)
491
492        # stop tcpdump
493        pcap_file = nutils.stop_tcpdump_gce_server(
494            self.dut, tcpdump_pid, pcap_path, host)
495
496        # server closes socket - verify error callback
497        time.sleep(60)
498        status = cutils.socket_keepalive_error(self.dut, ska_key)
499        asserts.assert_true(status, "Failed to receive onError callback")
500        self.socket_keepalives = []
501        self.tcp_sockets = []
502
503        # verify keepalives
504        result = self._verify_tcp_keepalives(pcap_file,
505                                             time_interval,
506                                             int(cport_server),
507                                             begin_time,
508                                             end_time,
509                                             expected_ka_count,
510                                             False)
511        asserts.assert_true(result and keepalive_count == dropped_acks,
512                            "Keepalive verification failed")
513        asserts.assert_true(result, "Keepalive verification failed")
514
515    @test_tracker_info(uuid="c02bcc1c-f86b-4905-973a-b4200a2b86c1")
516    def test_tcp_socket_keepalive_start_stop_multiple_keepalives_wifi(self):
517        """Test TCP keepalive for onStart and onStop callbacks.
518
519        Steps:
520            1. Open 3 TCP socket on DUT and connect to server.
521            2. Start TCP keepalive and verify onStarted callback is received.
522            3. Verify that server received the keepalives.
523            4. Stop TCP keepalive and verify onStopped callback is received.
524        """
525        # start tcpdump on the server
526        tcpdump_pid, pcap_path = nutils.start_tcpdump_gce_server(
527            self.dut, self.test_name, TCP_SERVER_PORT, self.remote_server)
528
529        # open 3 sockets and start keepalives
530        interval_list = []
531        cport_list = []
532        cport_server_list = []
533        self.log.info("Client IP: %s" % self.dut_ip)
534        self.log.info("Server IP: %s" % self.host_ip)
535        for _ in range(self.max_ka_wifi):
536            cport, interval = self._get_client_port_and_time_interval()
537            cport_list.append(cport)
538            interval_list.append(interval)
539
540        for _ in range(self.max_ka_wifi):
541            sock, cport_server = self._open_tcp_socket_and_connect(
542                cport_list[_])
543            self._start_tcp_keepalive(sock, interval_list[_])
544            cport_server_list.append(cport_server)
545
546        # sleep for sometime to verify keepalives
547        begin_time = time.time()
548        self.log.info("Sleeping for %s seconds" % SLEEP_TIME)
549        time.sleep(SLEEP_TIME)
550        end_time = time.time()
551        dropped_acks = self._get_dropped_keepalive_acks()
552
553        # stop tcpdump
554        pcap_file = nutils.stop_tcpdump_gce_server(
555            self.dut, tcpdump_pid, pcap_path, self.remote_server)
556
557        # verify keepalives
558        total_dropped_acks = 0
559        for _ in range(self.max_ka_wifi):
560            total_dropped_acks += int(SLEEP_TIME/interval_list[_])
561            expected_ka_count = self._get_expected_ka_count(end_time-begin_time,
562                                                            interval_list[_])
563            result = self._verify_tcp_keepalives(pcap_file,
564                                                 interval_list[_],
565                                                 int(cport_server_list[_]),
566                                                 begin_time,
567                                                 end_time,
568                                                 expected_ka_count)
569            asserts.assert_true(result, "Keepalive verification failed")
570
571    @test_tracker_info(uuid="64374896-7a04-4a5b-b27c-e27b5f0e7159")
572    def test_tcp_socket_keepalive_start_stop_stress_wifi(self):
573        """Test TCP keepalive for onStart and onStop callbacks.
574
575        Steps:
576            1. Open 3 TCP socket on DUT and connect to server.
577            2. Start TCP keepalive and verify onStarted callback is received.
578            3. Verify that server received the keepalives.
579            4. Stop TCP keepalive and verify onStopped callback is received.
580            5. Repeat steps 1-4 few times.
581        """
582        # open 3 sockets
583        interval_list = []
584        cport_server_list = []
585        sock_list = []
586
587        self.log.info("Client IP: %s" % self.dut_ip)
588        self.log.info("Server IP: %s" % self.host_ip)
589        for _ in range(self.max_ka_wifi):
590            client_port = random.randint(8000, 9000)
591            self.log.info("Client port: %s" % client_port)
592            sock, cport_server = self._open_tcp_socket_and_connect(client_port)
593            sock_list.append(sock)
594            cport_server_list.append(cport_server)
595
596        for _ in range(STRESS_COUNT):
597
598            # start tcpdump on the server
599            tcpdump_pid, pcap_path = nutils.start_tcpdump_gce_server(
600                self.dut, self.test_name, TCP_SERVER_PORT, self.remote_server)
601
602            # start keepalives on sockets
603            for _ in range(self.max_ka_wifi):
604                time_interval = random.randint(MIN_TEST_KA_INTERVAL,
605                                               MAX_TEST_KA_INTERVAL)
606                self.log.info("TCP socket Keepalive time interval: %s" %
607                              time_interval)
608                interval_list.append(time_interval)
609                self._start_tcp_keepalive(sock_list[_], interval_list[_])
610
611            # sleep for sometime to verify keepalives
612            begin_time = time.time()
613            self.log.info("Sleeping for %s seconds" % SLEEP_TIME)
614            time.sleep(SLEEP_TIME)
615            end_time = time.time()
616            dropped_acks = self._get_dropped_keepalive_acks()
617
618            # stop keepalives
619            for ska in self.socket_keepalives:
620                self.log.info("Stopping keepalive %s" % ska)
621                cutils.stop_socket_keepalive(self.dut, ska)
622            self.socket_keepalives = []
623
624            # stop tcpdump
625            pcap_file = nutils.stop_tcpdump_gce_server(
626                self.dut, tcpdump_pid, pcap_path, self.remote_server)
627
628            # verify keepalives
629            total_dropped_acks = 0
630            for _ in range(self.max_ka_wifi):
631                total_dropped_acks += int(SLEEP_TIME/interval_list[_])
632                expected_ka_count = self._get_expected_ka_count(
633                    end_time-begin_time, interval_list[_])
634                result = self._verify_tcp_keepalives(pcap_file,
635                                                     interval_list[_],
636                                                     int(cport_server_list[_]),
637                                                     begin_time,
638                                                     end_time,
639                                                     expected_ka_count)
640                asserts.assert_true(result, "Keepalive verification failed")
641
642            interval_list = []
643
644    @test_tracker_info(uuid="de3970c1-23d1-4d52-b3c9-4a2f1e53e7f6")
645    def test_tcp_socket_keepalive_error_client_socket_close_wifi(self):
646        """Test Error callback for tcp socket keepalive.
647
648        Steps:
649            1. Open a TCP socket on DUT and connect to server on port 853.
650            2. Start TCP keepalive and verify on Start callback.
651            3. Wait for some time and shutdown the client socket.
652            4. Verify on Error callback is received.
653        """
654        # open socket, connect to server, start keepalive
655        client_port, time_interval = self._get_client_port_and_time_interval()
656        sock, _ = self._open_tcp_socket_and_connect(client_port)
657        ska_key = self._start_tcp_keepalive(sock, time_interval)
658
659        # wait for atleast 1 keepalive
660        self.log.info("Sleeping for %s seconds" % (time_interval+1))
661        time.sleep(time_interval+1)
662
663        # shutdown client socket
664        sutils.shutdown_socket(self.dut, sock)
665        self.tcp_sockets.remove(sock)
666        self.socket_keepalives = []
667
668        # verify Error callback received
669        result = cutils.socket_keepalive_error(self.dut, ska_key)
670        asserts.assert_true(result, "Failed to receive error callback")
671
672    @test_tracker_info(uuid="7c902e51-725a-41f1-aebc-8528197c450c")
673    def test_tcp_socket_keepalive_over_max_keepalive_limit_wifi(self):
674        """Test TCP socket keepalive over max keepalive limit.
675
676        Steps:
677            1. Start 4 TCP socket keepalives.
678            2. 3 Should be successful and 4th should fail with Error.
679        """
680        # open sockets and connect to server
681        max_ka_net = self.dut.droid.getSupportedKeepalivesForNetwork()
682        self.log.info("Max Keepalives supported: %s" % max_ka_net)
683        state = True
684        for _ in range(1, max_ka_net+1):
685            cport, interval = self._get_client_port_and_time_interval()
686            sock, _ = self._open_tcp_socket_and_connect(cport)
687            if _ == max_ka_net:
688                state = False
689            self._start_tcp_keepalive(sock, interval, state)
690
691    @test_tracker_info(uuid="308004c5-8e40-4e8b-9408-4a90e85a2261")
692    def test_tcp_socket_keepalive_invalid_interval(self):
693        """Test TCP socket keepalive with invalid interval.
694
695        Steps:
696            1. Start TCP socket keepalive with time interval <10 seconds.
697            2. Verify Error callback is received.
698        """
699        # keepalive time interval, client port
700        client_port = random.randint(8000, 9000)
701        time_interval = random.randint(1, 9)
702        self.log.info("Client port: %s" % client_port)
703        self.log.info("Server port: %s" % TCP_SERVER_PORT)
704
705        # open tcp socket
706        sock, _ = self._open_tcp_socket_and_connect(client_port)
707
708        # start TCP socket keepalive
709        self.log.info("TCP socket Keepalive time interval: %s" % time_interval)
710        self._start_tcp_keepalive(sock, time_interval, False)
711
712    @test_tracker_info(uuid="c9012da2-656f-44ef-bad6-26892335d4bd")
713    def test_natt_socket_keepalive_start_stop_wifi(self):
714        """Test Natt socket keepalive for onStart and onStop callbacks.
715
716        Steps:
717            1. Open a UDP encap socket on DUT.
718            2. Start Natt socket keepalive.
719            3. Verify that server received the keepalives.
720            4. Stop keepalive and verify onStopped callback is received.
721        """
722        self._test_socket_keepalive_start_stop()
723
724    @test_tracker_info(uuid="646bfd5d-936f-4069-8dea-fdd02582550d")
725    def test_natt_socket_keepalive_start_stop_lte(self):
726        """Test Natt socket keepalive for onStart and onStop callbacks.
727
728        Steps:
729            1. Open a UDP encap socket on DUT.
730            2. Start Natt socket keepalive.
731            3. Verify that server received the keepalives.
732            4. Stop keepalive and verify onStopped callback is received.
733        """
734        self._test_socket_keepalive_start_stop()
735
736    @test_tracker_info(uuid="8ab20733-4a9e-4e4d-a46f-4d32a9f221c5")
737    def test_natt_socket_keepalive_invalid_interval(self):
738        """Test invalid natt socket keepalive time interval.
739
740        Steps:
741          1. Start NATT socket keepalive with time interval <10 seconds.
742          2. Verify Error callback is recevied.
743        """
744        # keepalive time interval, client port
745        time_interval = random.randint(1, 9)
746        self.log.info("Natt socket keepalive time interval: %s" % time_interval)
747        self.log.info("UDP encap port on server: %s" % UDP_SERVER_PORT)
748
749        # open udp encap socket
750        self.udp_encap = self.dut.droid.ipSecOpenUdpEncapsulationSocket()
751
752        # start Natt socket keepalive
753        ska_key = cutils.start_natt_socket_keepalive(
754            self.dut, self.udp_encap, self.dut_ip, self.host_ip, time_interval)
755        asserts.assert_true(not ska_key, "Failed to receive error callback")
756
757    ### Tests End
758