1.9.30 sync.
[gae.git] / java / src / main / com / google / appengine / api / socket / AppEngineDatagramSocketImpl.java
blob7ce65c3ae1af6f96d45de999fa9cdb3de0e4c59d
1 // Copyright 2012 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.socket;
5 import com.google.appengine.api.socket.AppEngineSocketOptions.Option;
6 import com.google.appengine.api.socket.SocketServicePb.AddressPort;
7 import com.google.appengine.api.socket.SocketServicePb.BindReply;
8 import com.google.appengine.api.socket.SocketServicePb.BindRequest;
9 import com.google.appengine.api.socket.SocketServicePb.CloseReply;
10 import com.google.appengine.api.socket.SocketServicePb.CloseRequest;
11 import com.google.appengine.api.socket.SocketServicePb.CreateSocketReply;
12 import com.google.appengine.api.socket.SocketServicePb.CreateSocketRequest;
13 import com.google.appengine.api.socket.SocketServicePb.CreateSocketRequest.SocketFamily;
14 import com.google.appengine.api.socket.SocketServicePb.CreateSocketRequest.SocketProtocol;
15 import com.google.appengine.api.socket.SocketServicePb.GetSocketNameReply;
16 import com.google.appengine.api.socket.SocketServicePb.GetSocketNameRequest;
17 import com.google.appengine.api.socket.SocketServicePb.GetSocketOptionsReply;
18 import com.google.appengine.api.socket.SocketServicePb.GetSocketOptionsRequest;
19 import com.google.appengine.api.socket.SocketServicePb.ReceiveReply;
20 import com.google.appengine.api.socket.SocketServicePb.ReceiveRequest;
21 import com.google.appengine.api.socket.SocketServicePb.SendReply;
22 import com.google.appengine.api.socket.SocketServicePb.SendRequest;
23 import com.google.appengine.api.socket.SocketServicePb.SetSocketOptionsReply;
24 import com.google.appengine.api.socket.SocketServicePb.SetSocketOptionsRequest;
25 import com.google.appengine.api.socket.SocketServicePb.SocketOption.SocketOptionName;
27 import java.io.IOException;
28 import java.io.Serializable;
29 import java.net.DatagramPacket;
30 import java.net.DatagramSocketImpl;
31 import java.net.InetAddress;
32 import java.net.NetworkInterface;
33 import java.net.SocketAddress;
34 import java.net.SocketException;
35 import java.net.SocketOptions;
36 import java.util.Arrays;
38 /**
39 * Implements the {@link DatagramSocketImpl} interface for App Engine based datagram sockets.
42 class AppEngineDatagramSocketImpl
43 extends DatagramSocketImpl implements AppEngineSocketOptionsClient, Serializable {
45 private SocketApiHelper socketHelper = null;
47 String descriptor;
48 volatile int timeout = -1;
50 AppEngineDatagramSocketImpl() {
53 AppEngineDatagramSocketImpl(SocketApiHelper socketHelper) {
54 this.socketHelper = socketHelper;
57 SocketApiHelper getSocketApiHelper() {
58 return socketHelper == null ? AppEngineSocketImplFactory.SOCKET_API_HELPER : socketHelper;
61 void setOption(
62 AppEngineSocketOptions.Option option, Object value) throws SocketException {
63 checkNotClosed();
64 option.validateAndApply(this, value);
67 @Override
68 public void setTimeout(int timeout) {
69 this.timeout = timeout;
72 @Override
73 public void setSocketOptionAsBytes(Option option, byte[] value) throws SocketException {
74 SocketOptionName name = option.getOptName();
75 if (name == null) {
76 return;
79 SetSocketOptionsRequest request = new SetSocketOptionsRequest();
80 request.setSocketDescriptor(descriptor);
81 request.addOptions().setLevel(option.getLevel()).setOption(name).setValueAsBytes(value);
83 getSocketApiHelper().makeSyncCall(
84 "SetSocketOptions", request, new SetSocketOptionsReply(), null);
87 @Override
88 public void setOption(int optID, Object value) throws SocketException {
89 AppEngineSocketOptions.Option option = AppEngineSocketOptions.getOptionById(optID);
90 if (option == null) {
91 throw new SocketException("unrecognized socket option: " + optID);
93 setOption(option, value);
96 @Override
97 public Object getOption(int optID) throws SocketException {
98 if (SocketOptions.SO_TIMEOUT == optID) {
99 checkNotClosed();
100 return timeout < 0 ? Integer.MAX_VALUE : timeout;
102 AppEngineSocketOptions.Option option = AppEngineSocketOptions.getOptionById(optID);
103 if (option == null) {
104 throw new SocketException("unrecognized socket option: " + optID);
106 return getOption(option);
110 * Returns the value of the given option.
111 * @throws SocketException
113 private Object getOption(Option option) throws SocketException {
114 return option.getOption(this);
118 * @throws SocketException
119 * @see AppEngineSocketOptionsClient#getSocketOptionAsBytes(Option)
121 @Override
122 public byte[] getSocketOptionAsBytes(Option option) throws SocketException {
123 checkNotClosed();
124 switch (option) {
125 case SO_BINDADDR_OPT: {
126 GetSocketNameRequest request = new GetSocketNameRequest();
127 GetSocketNameReply response = new GetSocketNameReply();
128 request.setSocketDescriptor(descriptor);
129 getSocketApiHelper().makeSyncCall("GetSocketName", request, response, null);
130 return response.getProxyExternalIp().getPackedAddressAsBytes();
132 default: {
133 GetSocketOptionsRequest request = new GetSocketOptionsRequest();
134 GetSocketOptionsReply response = new GetSocketOptionsReply();
135 request.setSocketDescriptor(descriptor);
136 request.addOptions().setLevel(option.getLevel()).setOption(option.getOptName());
137 getSocketApiHelper().makeSyncCall("GetSocketOptions", request, response, null);
138 return response.optionss().get(0).getValueAsBytes();
144 * @throws SocketException if the socket is not open.
146 private void checkNotClosed() throws SocketException {
147 if (descriptor == null) {
148 throw new SocketException("socket closed");
152 @Override
153 protected void create() throws SocketException {
154 if (descriptor != null) {
155 throw new SocketException("create may not be called on an already created socket.");
158 CreateSocketRequest request = new CreateSocketRequest();
159 CreateSocketReply response = new CreateSocketReply();
161 request.setFamily(SocketFamily.IPv6);
162 request.setProtocol(SocketProtocol.UDP);
164 getSocketApiHelper().makeSyncCall("CreateSocket", request, response, null);
165 descriptor = response.getSocketDescriptor();
168 @Override
169 protected void bind(int lport, InetAddress laddr) throws SocketException {
170 checkNotClosed();
171 BindRequest request = new BindRequest().setSocketDescriptor(descriptor);
172 request.setProxyExternalIp(AppEngineSocketUtils.toAddressPort(laddr, lport));
173 getSocketApiHelper().makeSyncCall("Bind", request, new BindReply(), null);
176 @Override
177 protected void send(DatagramPacket p) throws IOException {
178 checkNotClosed();
179 byte[] bytes = p.getData();
180 int off = p.getOffset();
181 int len = p.getLength();
182 if (bytes.length != len || off != 0) {
183 bytes = Arrays.copyOfRange(bytes, off, off + len);
185 SendRequest request = new SendRequest().setSocketDescriptor(descriptor)
186 .setDataAsBytes(bytes);
187 InetAddress addr = p.getAddress();
188 if (addr != null) {
189 request.setSendTo(AppEngineSocketUtils.toAddressPort(addr, p.getPort()));
191 if (timeout != -1) {
192 request.setTimeoutSeconds(timeout * 0.001);
194 getSocketApiHelper().makeSyncCall("Send", request, new SendReply(), null);
197 @Override
198 protected int peek(InetAddress i) throws IOException {
199 throw new SocketException("#peek(InetAddress) is not implemented.");
202 @Override
203 protected int peekData(DatagramPacket p) throws IOException {
204 checkNotClosed();
205 receiveOrPeek(p, true);
206 return p.getPort();
209 @Override
210 protected void receive(DatagramPacket p) throws IOException {
211 checkNotClosed();
212 receiveOrPeek(p, false);
215 private void receiveOrPeek(DatagramPacket p, boolean isPeek) throws IOException {
216 checkNotClosed();
218 ReceiveReply response = new ReceiveReply();
219 ReceiveRequest request = new ReceiveRequest().setSocketDescriptor(descriptor)
220 .setDataSize(p.getLength());
221 if (timeout != -1) {
222 request.setTimeoutSeconds(timeout * 0.001);
225 if (isPeek) {
226 request.setFlags(ReceiveRequest.Flags.MSG_PEEK.getValue());
229 getSocketApiHelper().makeSyncCall("Receive", request, response, null);
231 byte[] readBytes = response.getDataAsBytes();
233 if (readBytes.length > 0) {
234 System.arraycopy(readBytes, 0, p.getData(), p.getOffset(), readBytes.length);
236 p.setLength(readBytes.length);
238 AddressPort addrPort = response.getReceivedFrom();
239 p.setPort(addrPort.getPort());
240 p.setAddress(InetAddress.getByAddress(addrPort.getPackedAddressAsBytes()));
243 @Deprecated
244 @Override
245 protected void setTTL(byte ttl) throws IOException {
246 setTimeToLive(ttl);
249 @Deprecated
250 @Override
251 protected byte getTTL() throws IOException {
252 return (byte) getTimeToLive();
255 @Override
256 protected void setTimeToLive(int ttl) throws IOException {
257 throw new SecurityException("App Engine does not allow multicast setTimeToLive");
260 @Override
261 protected int getTimeToLive() throws IOException {
262 throw new SecurityException("App Engine does not allow multicast getTimeToLive");
265 @Override
266 protected void join(InetAddress inetaddr) throws IOException {
267 throw new SecurityException("App Engine does not allow multicast join");
270 @Override
271 protected void leave(InetAddress inetaddr) throws IOException {
272 throw new SecurityException("App Engine does not allow multicast leave");
275 @Override
276 protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
277 throw new SecurityException("App Engine does not allow multicast joinGroup");
280 @Override
281 protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
282 throw new SecurityException("App Engine does not allow multicast leaveGroup");
285 @Override
286 protected void close() {
287 if (descriptor != null) {
288 try {
289 CloseRequest request = new CloseRequest().setSocketDescriptor(descriptor);
290 getSocketApiHelper().makeSyncCall("Close", request, new CloseReply(), null);
291 } catch (SocketException e) {
292 } finally {
293 descriptor = null;