• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 android.net.netlink;
18 
19 import android.system.ErrnoException;
20 import android.system.NetlinkSocketAddress;
21 import android.system.Os;
22 import android.system.OsConstants;
23 import android.system.StructTimeval;
24 import android.util.Log;
25 import libcore.io.IoUtils;
26 import libcore.io.Libcore;
27 
28 import java.io.Closeable;
29 import java.io.FileDescriptor;
30 import java.io.InterruptedIOException;
31 import java.net.SocketAddress;
32 import java.net.SocketException;
33 import java.nio.ByteBuffer;
34 import java.nio.ByteOrder;
35 
36 
37 /**
38  * NetlinkSocket
39  *
40  * A small wrapper class to assist with AF_NETLINK socket operations.
41  *
42  * @hide
43  */
44 public class NetlinkSocket implements Closeable {
45     private static final String TAG = "NetlinkSocket";
46     private static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
47     private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
48 
49     final private FileDescriptor mDescriptor;
50     private NetlinkSocketAddress mAddr;
51     private long mLastRecvTimeoutMs;
52     private long mLastSendTimeoutMs;
53 
NetlinkSocket(int nlProto)54     public NetlinkSocket(int nlProto) throws ErrnoException {
55         mDescriptor = Os.socket(
56                 OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto);
57 
58         Libcore.os.setsockoptInt(
59                 mDescriptor, OsConstants.SOL_SOCKET,
60                 OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE);
61     }
62 
getLocalAddress()63     public NetlinkSocketAddress getLocalAddress() throws ErrnoException {
64         return (NetlinkSocketAddress) Os.getsockname(mDescriptor);
65     }
66 
bind(NetlinkSocketAddress localAddr)67     public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException {
68         Os.bind(mDescriptor, (SocketAddress)localAddr);
69     }
70 
connectTo(NetlinkSocketAddress peerAddr)71     public void connectTo(NetlinkSocketAddress peerAddr)
72             throws ErrnoException, SocketException {
73         Os.connect(mDescriptor, (SocketAddress) peerAddr);
74     }
75 
connectToKernel()76     public void connectToKernel() throws ErrnoException, SocketException {
77         connectTo(new NetlinkSocketAddress(0, 0));
78     }
79 
80     /**
81      * Wait indefinitely (or until underlying socket error) for a
82      * netlink message of at most DEFAULT_RECV_BUFSIZE size.
83      */
recvMessage()84     public ByteBuffer recvMessage()
85             throws ErrnoException, InterruptedIOException {
86         return recvMessage(DEFAULT_RECV_BUFSIZE, 0);
87     }
88 
89     /**
90      * Wait up to |timeoutMs| (or until underlying socket error) for a
91      * netlink message of at most DEFAULT_RECV_BUFSIZE size.
92      */
recvMessage(long timeoutMs)93     public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException {
94         return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs);
95     }
96 
checkTimeout(long timeoutMs)97     private void checkTimeout(long timeoutMs) {
98         if (timeoutMs < 0) {
99             throw new IllegalArgumentException("Negative timeouts not permitted");
100         }
101     }
102 
103     /**
104      * Wait up to |timeoutMs| (or until underlying socket error) for a
105      * netlink message of at most |bufsize| size.
106      *
107      * Multi-threaded calls with different timeouts will cause unexpected results.
108      */
recvMessage(int bufsize, long timeoutMs)109     public ByteBuffer recvMessage(int bufsize, long timeoutMs)
110             throws ErrnoException, IllegalArgumentException, InterruptedIOException {
111         checkTimeout(timeoutMs);
112 
113         synchronized (mDescriptor) {
114             if (mLastRecvTimeoutMs != timeoutMs) {
115                 Os.setsockoptTimeval(mDescriptor,
116                         OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
117                         StructTimeval.fromMillis(timeoutMs));
118                 mLastRecvTimeoutMs = timeoutMs;
119             }
120         }
121 
122         ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
123         int length = Os.read(mDescriptor, byteBuffer);
124         if (length == bufsize) {
125             Log.w(TAG, "maximum read");
126         }
127         byteBuffer.position(0);
128         byteBuffer.limit(length);
129         byteBuffer.order(ByteOrder.nativeOrder());
130         return byteBuffer;
131     }
132 
133     /**
134      * Send a message to a peer to which this socket has previously connected.
135      *
136      * This blocks until completion or an error occurs.
137      */
sendMessage(byte[] bytes, int offset, int count)138     public boolean sendMessage(byte[] bytes, int offset, int count)
139             throws ErrnoException, InterruptedIOException {
140         return sendMessage(bytes, offset, count, 0);
141     }
142 
143     /**
144      * Send a message to a peer to which this socket has previously connected,
145      * waiting at most |timeoutMs| milliseconds for the send to complete.
146      *
147      * Multi-threaded calls with different timeouts will cause unexpected results.
148      */
sendMessage(byte[] bytes, int offset, int count, long timeoutMs)149     public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs)
150             throws ErrnoException, IllegalArgumentException, InterruptedIOException {
151         checkTimeout(timeoutMs);
152 
153         synchronized (mDescriptor) {
154             if (mLastSendTimeoutMs != timeoutMs) {
155                 Os.setsockoptTimeval(mDescriptor,
156                         OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
157                         StructTimeval.fromMillis(timeoutMs));
158                 mLastSendTimeoutMs = timeoutMs;
159             }
160         }
161 
162         return (count == Os.write(mDescriptor, bytes, offset, count));
163     }
164 
165     @Override
close()166     public void close() {
167         IoUtils.closeQuietly(mDescriptor);
168     }
169 }
170