• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.googlecode.android_scripting.facade.net;
18 
19 import android.net.NetworkUtils;
20 import android.os.ParcelFileDescriptor;
21 import android.system.ErrnoException;
22 import android.system.Os;
23 
24 import com.googlecode.android_scripting.Log;
25 import com.googlecode.android_scripting.facade.FacadeManager;
26 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
27 import com.googlecode.android_scripting.rpc.Rpc;
28 
29 import java.io.DataInputStream;
30 import java.io.DataOutputStream;
31 import java.io.FileDescriptor;
32 import java.io.IOException;
33 import java.io.InterruptedIOException;
34 import java.io.ObjectInputStream;
35 import java.io.ObjectOutputStream;
36 import java.net.DatagramPacket;
37 import java.net.DatagramSocket;
38 import java.net.InetAddress;
39 import java.net.ServerSocket;
40 import java.net.Socket;
41 import java.net.SocketException;
42 import java.nio.charset.StandardCharsets;
43 import java.util.HashMap;
44 
45 /**
46  * This class has APIs for various socket types
47  * android.system.Os socket used for UDP and TCP sockets
48  * java.net.DatagramSocket for UDP sockets
49  * java.net.Socket and java.net.ServerSocket for TCP sockets
50  */
51 public class SocketFacade extends RpcReceiver {
52 
53     public static HashMap<String, DatagramSocket> sDatagramSocketHashMap =
54             new HashMap<String, DatagramSocket>();
55     private static HashMap<String, Socket> sSocketHashMap =
56             new HashMap<String, Socket>();
57     private static HashMap<String, ServerSocket> sServerSocketHashMap =
58             new HashMap<String, ServerSocket>();
59     private static HashMap<String, FileDescriptor> sFileDescriptorHashMap =
60             new HashMap<String, FileDescriptor>();
61     public static int MAX_BUF_SZ = 2048;
62     public static int SOCK_TIMEOUT = 1500;
63 
SocketFacade(FacadeManager manager)64     public SocketFacade(FacadeManager manager) {
65         super(manager);
66     }
67 
68     /**
69      * Method to return hash value of a DatagramSocket object
70      * Assumes that a unique hashCode is generated for each object
71      * and odds of equal hashCode for different sockets is negligible
72      */
getDatagramSocketId(DatagramSocket socket)73     private String getDatagramSocketId(DatagramSocket socket) {
74         return "DATAGRAMSOCKET:" + socket.hashCode();
75     }
76 
77     /**
78      * Method to return hash value of a Socket object
79      * Assumes that a unique hashCode is generated for each object
80      * and odds of equal hashCode for different sockets is negligible
81      */
getSocketId(Socket socket)82     private String getSocketId(Socket socket) {
83         return "SOCKET:" + socket.hashCode();
84     }
85 
86     /**
87      * Method to return hash value of a ServerSocket object
88      * Assumes that a unique hashCode is generated for each object
89      * and odds of equal hashCode for different sockets is negligible
90      */
getServerSocketId(ServerSocket socket)91     private String getServerSocketId(ServerSocket socket) {
92         return "SERVERSOCKET:" + socket.hashCode();
93     }
94 
95     /**
96      * Method to return hash value of a FileDescriptor object
97      * Assumes that a unique hashCode is generated for each object
98      * and odds of equal hashCode for different sockets is negligible
99      */
getFileDescriptorId(FileDescriptor fd)100     private String getFileDescriptorId(FileDescriptor fd) {
101         return "FILEDESCRIPTOR:" + fd.hashCode();
102     }
103 
104     /**
105      * Method to retrieve FileDescriptor from hash key
106      * @param id : Hash key of {@link FileDescriptor}
107      * @return FileDescriptor
108      */
getFileDescriptor(String id)109     public static FileDescriptor getFileDescriptor(String id) {
110         return sFileDescriptorHashMap.get(id);
111     }
112 
113     /**
114      * Method to retrieve DatagramSocket from hash key
115      * @param datagramSocketId : Hash key of {@link DatagramSocket}
116      * @return DatagramSocket
117      */
getDatagramSocket(String datagramSocketId)118     public static DatagramSocket getDatagramSocket(String datagramSocketId) {
119         return sDatagramSocketHashMap.get(datagramSocketId);
120     }
121 
122     /**
123      * Method to retrieve Socket from hash key
124      * @param socketId : Hash key of {@link Socket}
125      * @return Socket
126      */
getSocket(String socketId)127     public static Socket getSocket(String socketId) {
128         return sSocketHashMap.get(socketId);
129     }
130 
131     /**
132      * Method to retrieve ServerSocket from hash key
133      * @param serverSocketId : Hash key of {@link ServerSocket}
134      * @return ServerSocket
135      */
getServerSocket(String serverSocketId)136     public static ServerSocket getServerSocket(String serverSocketId) {
137         return sServerSocketHashMap.get(serverSocketId);
138     }
139 
140     /*
141      * The following APIs for open, close, send and recv over Stream sockets
142      * This uses java.net.Socket and java.net.ServerSocket and applies only for TCP traffic
143      */
144 
145     /**
146      * Open TCP client socket and connect to server using java.net.Socket
147      * @param remote : IP addr of the server
148      * @param remotePort : Port of the server's socket
149      * @param local : IP addr of the client
150      * @param localPort : Port the client's socket
151      * @return Hash key of {@link Socket}
152      */
153     @Rpc(description = "Open TCP socket & connect to server")
openTcpSocket( String remote, Integer remotePort, String local, Integer localPort)154     public String openTcpSocket(
155             String remote,
156             Integer remotePort,
157             String local,
158             Integer localPort) {
159         try {
160             InetAddress remoteAddr = NetworkUtils.numericToInetAddress(remote);
161             InetAddress localAddr = NetworkUtils.numericToInetAddress(local);
162             Socket socket = new Socket(remoteAddr, remotePort.intValue(), localAddr,
163                     localPort.intValue());
164             socket.setSoLinger(true, 0);
165             String id = getSocketId(socket);
166             sSocketHashMap.put(id, socket);
167             return id;
168         } catch (IOException e) {
169             Log.e("Socket: Failed to open TCP client socket ", e);
170         }
171         return null;
172     }
173 
174     /**
175      * Return port number of Socket
176      * @param socketId : Hash key of {@link Socket}
177      * @return Port number in int
178      */
179     @Rpc(description = "Get port number of a Socket")
getPortOfSocket(String socketId)180     public int getPortOfSocket(String socketId) {
181         Socket socket = sSocketHashMap.get(socketId);
182         return socket.getLocalPort();
183     }
184 
185     /**
186      * Close socket of java.net.Socket class
187      * @param socketId : Hash key of {@link Socket}
188      * @return True if closing socket is successful
189      */
190     @Rpc(description = "Close TCP client socket")
closeTcpSocket(String socketId)191     public Boolean closeTcpSocket(String socketId) {
192         Socket socket = sSocketHashMap.get(socketId);
193         try {
194             socket.close();
195             sSocketHashMap.remove(socketId);
196             return true;
197         } catch (IOException e) {
198             Log.e("Socket: Failed to close TCP client socket ", e);
199         }
200         return false;
201     }
202 
203     /**
204      * Open TCP server socket using java.net.ServerSocket
205      * @param addr : IP addr of the server
206      * @param port : Port of the server's socket
207      * @return Hash key of {@link ServerSocket}
208      */
209     @Rpc(description = "Open TCP server socket and accept connection")
openTcpServerSocket(String addr, Integer port)210     public String openTcpServerSocket(String addr, Integer port) {
211         try {
212             InetAddress localAddr = NetworkUtils.numericToInetAddress(addr);
213             ServerSocket serverSocket = new ServerSocket(port.intValue(), 10, localAddr);
214             String id = getServerSocketId(serverSocket);
215             sServerSocketHashMap.put(id, serverSocket);
216             return id;
217         } catch (IOException e) {
218             Log.e("Socket: Failed to open TCP server socket ", e);
219         }
220         return null;
221     }
222 
223     /**
224      * Return port number of ServerSocket
225      * @param serverSocketId : Hash key of {@link ServerSocket}
226      * @return Port number in int
227      */
228     @Rpc(description = "Get port number of a ServerSocket")
getPortOfServerSocket(String serverSocketId)229     public int getPortOfServerSocket(String serverSocketId) {
230         ServerSocket socket = sServerSocketHashMap.get(serverSocketId);
231         return socket.getLocalPort();
232     }
233 
234     /**
235      * Close TCP server socket
236      * @param serverSocketId : Hash key of {@link ServerSocket}
237      * @return True if server socket is closed
238      */
239     @Rpc(description = "Close TCP server socket")
closeTcpServerSocket(String serverSocketId)240     public Boolean closeTcpServerSocket(String serverSocketId) {
241         ServerSocket socket = sServerSocketHashMap.get(serverSocketId);
242         try {
243             socket.close();
244             sServerSocketHashMap.remove(serverSocketId);
245             return true;
246         } catch (IOException e) {
247             Log.e("Socket: Failed to close TCP server socket ", e);
248         }
249         return false;
250     }
251 
252     /**
253      * Get FileDescriptor of a Socket object
254      * @param socketId : Hash key of {@link Socket}
255      * @return Filedescriptor object in string
256      */
257     @Rpc(description = "Get FileDescriptor object of socket")
getFileDescriptorOfSocket(String socketId)258     public String getFileDescriptorOfSocket(String socketId) {
259         Socket socket = sSocketHashMap.get(socketId);
260         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
261         FileDescriptor fd = pfd.getFileDescriptor();
262         String fdId = getFileDescriptorId(fd);
263         sFileDescriptorHashMap.put(fdId, fd);
264         return fdId;
265     }
266 
267     /**
268      * Shutdown a FileDescriptor
269      * @param id : Hash key of {@link FileDescriptor}
270      * @return true if shutdown of Filedescriptor is successful, false if not
271      */
272     @Rpc(description = "Shutdown FileDescriptor")
shutdownFileDescriptor(String id)273     public Boolean shutdownFileDescriptor(String id) {
274         try {
275             FileDescriptor fd = sFileDescriptorHashMap.get(id);
276             Os.shutdown(fd, 2);
277             return true;
278         } catch (ErrnoException e) {
279             Log.e("Socket: Failed to shutdown FileDescriptor ", e);
280         }
281         return false;
282     }
283 
284     /**
285      * Get the local port on which the ServerSocket is listening. Useful when the server socket
286      * is initialized with 0 port (i.e. selects an available port)
287      *
288      * @param serverSocketId : Hash key of ServerSocket (returned by
289      * {@link #openTcpServerSocket(String, Integer)}.
290      * @return An integer - the port number (0 in case of an error).
291      */
292     @Rpc(description = "Get the TCP Server socket port number")
getTcpServerSocketPort(String serverSocketId)293     public Integer getTcpServerSocketPort(String serverSocketId) {
294         ServerSocket socket = sServerSocketHashMap.get(serverSocketId);
295         return socket.getLocalPort();
296     }
297 
298     /**
299      * Accept TCP connection
300      * @param serverSocketId : Hash key of ServerSocket
301      * @return Hash key of {@link Socket}
302      */
303     @Rpc(description = "Accept connection")
acceptTcpSocket(String serverSocketId)304     public String acceptTcpSocket(String serverSocketId) {
305         try {
306             ServerSocket serverSocket = sServerSocketHashMap.get(serverSocketId);
307             Socket socket = serverSocket.accept();
308             String sockId = getSocketId(socket);
309             sSocketHashMap.put(sockId, socket);
310             return sockId;
311         } catch (IOException e) {
312             Log.e("Socket: Failed to accept connection ", e);
313         }
314         return null;
315     }
316 
317     /**
318      * Send data to server - only ASCII/UTF characters
319      * @param socketId : Hash key of {@link Socket}
320      * @param message : Data to send to in String
321      * @return True if sending data is successful, false if not
322      */
323     @Rpc(description = "Send data from client")
sendDataOverTcpSocket(String socketId, String message)324     public Boolean sendDataOverTcpSocket(String socketId, String message) {
325         Socket socket = sSocketHashMap.get(socketId);
326         try {
327             ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
328             oos.writeObject(message);
329             return true;
330         } catch (IOException | SecurityException | IllegalArgumentException e) {
331             Log.e("Socket: Failed to send data from socket ", e);
332         }
333         return false;
334     }
335 
336     /**
337      * Receive data on ServerSocket - only ASCII/UTF characters
338      * @param serverSocketId : Hash key of {@link ServerSocket}
339      * @return Received data in String, null if unabled to read from socket
340      */
341     @Rpc(description = "Recv data from client")
recvDataOverTcpSocket(String serverSocketId)342     public String recvDataOverTcpSocket(String serverSocketId) {
343         Socket socket = sSocketHashMap.get(serverSocketId);
344         try {
345             ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
346             String message = (String) ois.readObject();
347             Log.d("Socket: Received " + message);
348             return message;
349         } catch (IOException | SecurityException | IllegalArgumentException
350                 | ClassNotFoundException e) {
351             Log.e("Socket: Failed to read from socket ", e);
352         }
353         return null;
354     }
355 
356     /**
357      * Send data over TCP socket using DataOutputStream
358      * @param socketId : Hash key of {@link Socket}
359      * @param message : Data to send in string
360      * @return true if sending data is successful, false if not
361      */
362     @Rpc(description = "Send data from client using DataOutputStream")
tcpSocketWrite(String socketId, String message)363     public Boolean tcpSocketWrite(String socketId, String message) {
364         Socket socket = sSocketHashMap.get(socketId);
365         try {
366             DataOutputStream out = new DataOutputStream(socket.getOutputStream());
367             Log.d("Socket: Sending -> " + message);
368             out.write(message.getBytes(), 0, message.length());
369             out.flush();
370             return true;
371         } catch (IOException | SecurityException | IllegalArgumentException e) {
372             Log.e("Socket: Failed to read from socket ", e);
373         }
374         return false;
375     }
376 
377     /**
378      * Receive data over TCP socket using DataInputStream
379      * @param socketId : Hash key of {@link Socket}
380      * @return String message if received data, null if not
381      */
382     @Rpc(description = "Recv data from server using DataInputStream")
tcpSocketRecv(String socketId)383     public String tcpSocketRecv(String socketId) {
384         Socket socket = sSocketHashMap.get(socketId);
385         try {
386             byte[] messageByte = new byte[1024];
387             DataInputStream in = new DataInputStream(socket.getInputStream());
388             int bytesRead = in.read(messageByte);
389             String message = new String(messageByte, 0, bytesRead);
390             Log.d("Socket: Received -> " + message);
391             return message;
392         } catch (IOException | SecurityException | IllegalArgumentException e) {
393             Log.e("Socket: Failed to read from socket ", e);
394         }
395         return null;
396     }
397 
398     /*
399      * The following APIs are used to open, close, send and recv data over DatagramSocket
400      * This uses java.net.DatagramSocket class and only applies for UDP
401      */
402 
403     /**
404      * Open datagram socket using java.net.DatagramSocket
405      * @param addr : IP addr to use
406      * @param port : port to open socket on
407      * @return Hash key of {@link DatagramSocket}
408      */
409     @Rpc(description = "Open datagram socket")
openDatagramSocket(String addr, Integer port)410     public String openDatagramSocket(String addr, Integer port) {
411         InetAddress localAddr = NetworkUtils.numericToInetAddress(addr);
412         try {
413             DatagramSocket socket = new DatagramSocket(port.intValue(), localAddr);
414             socket.setSoTimeout(SOCK_TIMEOUT);
415             String id = getDatagramSocketId(socket);
416             sDatagramSocketHashMap.put(id, socket);
417             return id;
418         } catch (SocketException e) {
419             Log.e("Socket: Failed to open datagram socket");
420         }
421         return null;
422     }
423 
424     /**
425      * Return port number of DatagramSocket
426      * @param datagramSocketId : Hash key of {@link DatagramSocket}
427      * @return Port number in int
428      */
429     @Rpc(description = "Get port number of a DatagramSocket")
getPortOfDatagramSocket(String datagramSocketId)430     public int getPortOfDatagramSocket(String datagramSocketId) {
431         DatagramSocket socket = sDatagramSocketHashMap.get(datagramSocketId);
432         return socket.getLocalPort();
433     }
434 
435     /**
436      * Close datagram socket
437      * @param datagramSocketId : Hash key of {@link DatagramSocket}
438      * @return True if close is successful
439      */
440     @Rpc(description = "Close datagram socket")
closeDatagramSocket(String datagramSocketId)441     public Boolean closeDatagramSocket(String datagramSocketId) {
442         DatagramSocket socket = sDatagramSocketHashMap.get(datagramSocketId);
443         socket.close();
444         sDatagramSocketHashMap.remove(datagramSocketId);
445         return true;
446     }
447 
448     /**
449      * Send data from datagram socket to server.
450      * @param datagramSocketId : Hash key of {@link DatagramSocket}
451      * @param message : data to send in String
452      * @param addr : IP addr to send the data to
453      * @param port : port of the socket to send the data to
454      * @return True if sending data is successful
455      */
456     @Rpc(description = "Send data over socket", returns = "True if sending data successful")
sendDataOverDatagramSocket(String datagramSocketId, String message, String addr, Integer port)457     public Boolean sendDataOverDatagramSocket(String datagramSocketId, String message, String addr,
458             Integer port) {
459         byte[] buf = message.getBytes();
460         try {
461             InetAddress remoteAddr = NetworkUtils.numericToInetAddress(addr);
462             DatagramSocket socket = sDatagramSocketHashMap.get(datagramSocketId);
463             DatagramPacket pkt = new DatagramPacket(buf, buf.length, remoteAddr, port.intValue());
464             socket.send(pkt);
465             return true;
466         } catch (IOException e) {
467             Log.e("Socket: Failed to send data over datagram socket");
468         }
469         return false;
470     }
471 
472     /**
473      * Receive data on the datagram socket
474      * @param datagramSocketId : Hash key of {@link DatagramSocket}
475      * @return Received data in String format
476      */
477     @Rpc(description = "Receive data over socket", returns = "Received data in String")
recvDataOverDatagramSocket(String datagramSocketId)478     public String recvDataOverDatagramSocket(String datagramSocketId) {
479         byte[] buf = new byte[MAX_BUF_SZ];
480         try {
481             DatagramSocket socket = sDatagramSocketHashMap.get(datagramSocketId);
482             DatagramPacket dgramPacket = new DatagramPacket(buf, MAX_BUF_SZ);
483             socket.receive(dgramPacket);
484             return new String(dgramPacket.getData(), 0, dgramPacket.getLength());
485         } catch (IOException e) {
486             Log.e("Socket: Failed to recv data over datagram socket");
487         }
488         return null;
489     }
490 
491     /*
492      * The following APIs are used to open, close, send and receive data over Os.socket
493      * This uses android.system.Os class and can be used for UDP and TCP traffic
494      */
495 
496     /**
497      * Open socket using android.system.Os class.
498      * @param domain : protocol family. Ex: IPv4 or IPv6
499      * @param type : socket type. Ex: DGRAM or STREAM
500      * @param addr : IP addr to use
501      * @param port : port to open socket on
502      * @return Hash key of {@link FileDescriptor}
503      */
504     @Rpc(description = "Open socket")
openSocket(Integer domain, Integer type, String addr, Integer port)505     public String openSocket(Integer domain, Integer type, String addr, Integer port) {
506         try {
507             FileDescriptor fd = Os.socket(domain, type, 0);
508             InetAddress localAddr = NetworkUtils.numericToInetAddress(addr);
509             Os.bind(fd, localAddr, port.intValue());
510             String id = getFileDescriptorId(fd);
511             sFileDescriptorHashMap.put(id, fd);
512             return id;
513         } catch (SocketException | ErrnoException e) {
514             Log.e("Socket: Failed to open socket ", e);
515         }
516         return null;
517     }
518 
519     /**
520      * Close socket of android.system.Os class
521      * @param id : Hash key of {@link FileDescriptor}
522      * @return True if connect successful
523      */
524     @Rpc(description = "Close socket")
closeSocket(String id)525     public Boolean closeSocket(String id) {
526         FileDescriptor fd = sFileDescriptorHashMap.get(id);
527         try {
528             Os.close(fd);
529             return true;
530         } catch (ErrnoException e) {
531             Log.e("Socket: Failed to close socket ", e);
532         }
533         return false;
534     }
535 
536     /**
537      * Send data from the socket
538      * @param remoteAddr : IP addr to send the data to
539      * @param remotePort : Port of the socket to send the data to
540      * @param message : data to send in String
541      * @param id : Hash key of {@link FileDescriptor}
542      * @return True if connect successful
543      */
544     @Rpc(description = "Send data to server")
sendDataOverSocket( String remoteAddr, Integer remotePort, String message, String id)545     public Boolean sendDataOverSocket(
546             String remoteAddr, Integer remotePort, String message, String id) {
547         FileDescriptor fd = sFileDescriptorHashMap.get(id);
548         InetAddress remote = NetworkUtils.numericToInetAddress(remoteAddr);
549         try {
550             byte [] data = new String(message).getBytes(StandardCharsets.UTF_8);
551             int bytes = Os.sendto(fd, data, 0, data.length, 0, remote, remotePort.intValue());
552             Log.d("Socket: Sent " + String.valueOf(bytes) + " bytes");
553             return true;
554         } catch (ErrnoException | SocketException e) {
555             Log.e("Socket: Sending data over socket failed ", e);
556         }
557         return false;
558     }
559 
560     /**
561      * Receive data on the socket.
562      * @param id : Hash key of {@link FileDescriptor}
563      * @return Received data in String format
564      */
565     @Rpc(description = "Recv data on server")
recvDataOverSocket(String id)566     public String recvDataOverSocket(String id) {
567         byte[] data = new byte[MAX_BUF_SZ];
568         FileDescriptor fd = sFileDescriptorHashMap.get(id);
569         try {
570             Os.read(fd, data, 0, data.length);
571             return new String(data, StandardCharsets.UTF_8);
572         } catch (ErrnoException | InterruptedIOException e) {
573             Log.e("Socket: Receiving data over socket failed ", e);
574         }
575         return null;
576     }
577 
578     /**
579      * Listen for connections from client.
580      * @param id : Hash key of {@link FileDescriptor}
581      * @return True if listen successful
582      */
583     @Rpc(description = "Listen for connection on server")
listenSocket(String id)584     public Boolean listenSocket(String id) {
585         FileDescriptor fd = sFileDescriptorHashMap.get(id);
586         try {
587             // Start listening with buffer of size 10
588             Os.listen(fd, 10);
589             return true;
590         } catch (ErrnoException e) {
591             Log.e("Socket: Failed to listen on socket ", e);
592         }
593         return false;
594     }
595 
596     /**
597      * TCP connect to server from client.
598      * @param id : Hash key of {@link FileDescriptor}
599      * @param addr : IP addr in string of server
600      * @param port : server's port to connect to
601      * @return True if connect successful
602      */
603     @Rpc(description = "Connect to server")
connectSocket(String id, String addr, Integer port)604     public Boolean connectSocket(String id, String addr, Integer port) {
605         FileDescriptor fd = sFileDescriptorHashMap.get(id);
606         try {
607             InetAddress remoteAddr = NetworkUtils.numericToInetAddress(addr);
608             Os.connect(fd, remoteAddr, port.intValue());
609             return true;
610         } catch (SocketException | ErrnoException e) {
611             Log.e("Socket: Failed to connect socket ", e);
612         }
613         return false;
614     }
615 
616     /**
617      * Accept TCP connection from the client to server.
618      * @param id : Hash key of server {@link FileDescriptor}
619      * @return Hash key of FileDescriptor returned by successful accept()
620      */
621     @Rpc(description = "Accept connection on server")
acceptSocket(String id)622     public String acceptSocket(String id) {
623         FileDescriptor fd = sFileDescriptorHashMap.get(id);
624         try {
625             FileDescriptor socket = Os.accept(fd, null);
626             String socketId = getFileDescriptorId(socket);
627             sFileDescriptorHashMap.put(socketId, socket);
628             return socketId;
629         } catch (SocketException | ErrnoException e) {
630             Log.e("Socket: Failed to accept on socket ", e);
631         }
632         return null;
633     }
634 
635     @Override
shutdown()636     public void shutdown() {}
637 }
638