~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
 
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
4
 *
 
5
 * This code is free software; you can redistribute it and/or modify it
 
6
 * under the terms of the GNU General Public License version 2 only, as
 
7
 * published by the Free Software Foundation.  Oracle designates this
 
8
 * particular file as subject to the "Classpath" exception as provided
 
9
 * by Oracle in the LICENSE file that accompanied this code.
 
10
 *
 
11
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
14
 * version 2 for more details (a copy is included in the LICENSE file that
 
15
 * accompanied this code).
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License version
 
18
 * 2 along with this work; if not, write to the Free Software Foundation,
 
19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 *
 
21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
22
 * or visit www.oracle.com if you need additional information or have any
 
23
 * questions.
 
24
 */
 
25
 
 
26
package sun.nio.ch;
 
27
 
 
28
import java.nio.channels.*;
 
29
import java.net.InetSocketAddress;
 
30
import java.util.concurrent.Future;
 
31
import java.util.concurrent.atomic.AtomicBoolean;
 
32
import java.io.FileDescriptor;
 
33
import java.io.IOException;
 
34
import java.security.AccessControlContext;
 
35
import java.security.AccessController;
 
36
import java.security.PrivilegedAction;
 
37
 
 
38
/**
 
39
 * Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.
 
40
 */
 
41
 
 
42
class WindowsAsynchronousServerSocketChannelImpl
 
43
    extends AsynchronousServerSocketChannelImpl
 
44
{
 
45
    private final Iocp iocp;
 
46
 
 
47
    // flag to indicate that an accept operation is outstanding
 
48
    private AtomicBoolean accepting = new AtomicBoolean();
 
49
 
 
50
 
 
51
    WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {
 
52
        super(iocp);
 
53
 
 
54
        this.iocp = iocp;
 
55
    }
 
56
 
 
57
    @Override
 
58
    void implClose() throws IOException {
 
59
        // close socket (which may cause outstanding accept to be aborted).
 
60
        SocketDispatcher.closeImpl(fd);
 
61
    }
 
62
 
 
63
    @Override
 
64
    public AsynchronousChannelGroupImpl group() {
 
65
        return iocp;
 
66
    }
 
67
 
 
68
    /**
 
69
     * Task to initiate accept operation and to handle result.
 
70
     */
 
71
    private class AcceptTask implements Runnable, Iocp.ResultHandler {
 
72
        private final WindowsAsynchronousSocketChannelImpl channel;
 
73
        private final AccessControlContext acc;
 
74
        private final PendingFuture<AsynchronousSocketChannel,Object> result;
 
75
 
 
76
        AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
 
77
                   AccessControlContext acc,
 
78
                   PendingFuture<AsynchronousSocketChannel,Object> result)
 
79
        {
 
80
            this.channel = channel;
 
81
            this.acc = acc;
 
82
            this.result = result;
 
83
        }
 
84
 
 
85
        void enableAccept() {
 
86
            accepting.set(false);
 
87
        }
 
88
 
 
89
        void closeChildChannel() {
 
90
            try {
 
91
                channel.close();
 
92
            } catch (IOException ignore) { }
 
93
        }
 
94
 
 
95
        // caller must have acquired read lock for the listener and child channel.
 
96
        void finishAccept() throws IOException {
 
97
            /**
 
98
             * Set local/remote addresses. This is currently very inefficient
 
99
             * in that it requires 2 calls to getsockname and 2 calls to getpeername.
 
100
             * (should change this to use GetAcceptExSockaddrs)
 
101
             */
 
102
            updateAcceptContext(fd, channel.fd);
 
103
 
 
104
            InetSocketAddress local = Net.localAddress(channel.fd);
 
105
            final InetSocketAddress remote = Net.remoteAddress(channel.fd);
 
106
            channel.setConnected(local, remote);
 
107
 
 
108
            // permission check (in context of initiating thread)
 
109
            if (acc != null) {
 
110
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
 
111
                    public Void run() {
 
112
                        SecurityManager sm = System.getSecurityManager();
 
113
                        sm.checkAccept(remote.getAddress().getHostAddress(),
 
114
                                       remote.getPort());
 
115
                        return null;
 
116
                    }
 
117
                }, acc);
 
118
            }
 
119
        }
 
120
 
 
121
        /**
 
122
         * Initiates the accept operation.
 
123
         */
 
124
        @Override
 
125
        public void run() {
 
126
 
 
127
            try {
 
128
                // begin usage of listener socket
 
129
                begin();
 
130
                try {
 
131
                    // begin usage of child socket (as it is registered with
 
132
                    // completion port and so may be closed in the event that
 
133
                    // the group is forcefully closed).
 
134
                    channel.begin();
 
135
 
 
136
                    synchronized (result) {
 
137
 
 
138
                        int n = accept0(fd, channel.fd, this);
 
139
                        if (n == IOStatus.UNAVAILABLE) {
 
140
                            return;
 
141
                        }
 
142
 
 
143
                        // connection accepted immediately
 
144
                        finishAccept();
 
145
 
 
146
                        // allow another accept before the result is set
 
147
                        enableAccept();
 
148
                        result.setResult(channel);
 
149
                    }
 
150
                } finally {
 
151
                    // end usage on child socket
 
152
                    channel.end();
 
153
                }
 
154
            } catch (Throwable x) {
 
155
                // failed to initiate accept so release resources
 
156
                closeChildChannel();
 
157
                if (x instanceof ClosedChannelException)
 
158
                    x = new AsynchronousCloseException();
 
159
                if (!(x instanceof IOException) && !(x instanceof SecurityException))
 
160
                    x = new IOException(x);
 
161
                enableAccept();
 
162
                result.setFailure(x);
 
163
            } finally {
 
164
                // end of usage of listener socket
 
165
                end();
 
166
            }
 
167
 
 
168
            // accept completed immediately but may not have executed on
 
169
            // initiating thread in which case the operation may have been
 
170
            // cancelled.
 
171
            if (result.isCancelled()) {
 
172
                closeChildChannel();
 
173
            }
 
174
 
 
175
            // invoke completion handler
 
176
            Invoker.invokeIndirectly(result);
 
177
        }
 
178
 
 
179
        /**
 
180
         * Executed when the I/O has completed
 
181
         */
 
182
        @Override
 
183
        public void completed(int bytesTransferred, boolean canInvokeDirect) {
 
184
            try {
 
185
                // connection accept after group has shutdown
 
186
                if (iocp.isShutdown()) {
 
187
                    throw new IOException(new ShutdownChannelGroupException());
 
188
                }
 
189
 
 
190
                // finish the accept
 
191
                try {
 
192
                    begin();
 
193
                    try {
 
194
                        channel.begin();
 
195
                        finishAccept();
 
196
                    } finally {
 
197
                        channel.end();
 
198
                    }
 
199
                } finally {
 
200
                    end();
 
201
                }
 
202
 
 
203
                // allow another accept before the result is set
 
204
                enableAccept();
 
205
                result.setResult(channel);
 
206
            } catch (Throwable x) {
 
207
                enableAccept();
 
208
                closeChildChannel();
 
209
                if (x instanceof ClosedChannelException)
 
210
                    x = new AsynchronousCloseException();
 
211
                if (!(x instanceof IOException) && !(x instanceof SecurityException))
 
212
                    x = new IOException(x);
 
213
                result.setFailure(x);
 
214
            }
 
215
 
 
216
            // if an async cancel has already cancelled the operation then
 
217
            // close the new channel so as to free resources
 
218
            if (result.isCancelled()) {
 
219
                closeChildChannel();
 
220
            }
 
221
 
 
222
            // invoke handler (but not directly)
 
223
            Invoker.invokeIndirectly(result);
 
224
        }
 
225
 
 
226
        @Override
 
227
        public void failed(int error, IOException x) {
 
228
            enableAccept();
 
229
            closeChildChannel();
 
230
 
 
231
            // release waiters
 
232
            if (isOpen()) {
 
233
                result.setFailure(x);
 
234
            } else {
 
235
                result.setFailure(new AsynchronousCloseException());
 
236
            }
 
237
            Invoker.invokeIndirectly(result);
 
238
        }
 
239
    }
 
240
 
 
241
    @Override
 
242
    Future<AsynchronousSocketChannel> implAccept(Object attachment,
 
243
        final CompletionHandler<AsynchronousSocketChannel,Object> handler)
 
244
    {
 
245
        if (!isOpen()) {
 
246
            Throwable exc = new ClosedChannelException();
 
247
            if (handler == null)
 
248
                return CompletedFuture.withFailure(exc);
 
249
            Invoker.invokeIndirectly(this, handler, attachment, null, exc);
 
250
            return null;
 
251
        }
 
252
        if (isAcceptKilled())
 
253
            throw new RuntimeException("Accept not allowed due to cancellation");
 
254
 
 
255
        // ensure channel is bound to local address
 
256
        if (localAddress == null)
 
257
            throw new NotYetBoundException();
 
258
 
 
259
        // create the socket that will be accepted. The creation of the socket
 
260
        // is enclosed by a begin/end for the listener socket to ensure that
 
261
        // we check that the listener is open and also to prevent the I/O
 
262
        // port from being closed as the new socket is registered.
 
263
        WindowsAsynchronousSocketChannelImpl ch = null;
 
264
        IOException ioe = null;
 
265
        try {
 
266
            begin();
 
267
            ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);
 
268
        } catch (IOException x) {
 
269
            ioe = x;
 
270
        } finally {
 
271
            end();
 
272
        }
 
273
        if (ioe != null) {
 
274
            if (handler == null)
 
275
                return CompletedFuture.withFailure(ioe);
 
276
            Invoker.invokeIndirectly(this, handler, attachment, null, ioe);
 
277
            return null;
 
278
        }
 
279
 
 
280
        // need calling context when there is security manager as
 
281
        // permission check may be done in a different thread without
 
282
        // any application call frames on the stack
 
283
        AccessControlContext acc = (System.getSecurityManager() == null) ?
 
284
            null : AccessController.getContext();
 
285
 
 
286
        PendingFuture<AsynchronousSocketChannel,Object> result =
 
287
            new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);
 
288
        AcceptTask task = new AcceptTask(ch, acc, result);
 
289
        result.setContext(task);
 
290
 
 
291
        // check and set flag to prevent concurrent accepting
 
292
        if (!accepting.compareAndSet(false, true))
 
293
            throw new AcceptPendingException();
 
294
 
 
295
        // initiate I/O
 
296
        if (Iocp.supportsThreadAgnosticIo()) {
 
297
            task.run();
 
298
        } else {
 
299
            Invoker.invokeOnThreadInThreadPool(this, task);
 
300
        }
 
301
        return result;
 
302
    }
 
303
 
 
304
    // -- Native methods --
 
305
 
 
306
    private static native void initIDs();
 
307
 
 
308
    private static native int accept0(FileDescriptor listenSocket, FileDescriptor acceptSocket,
 
309
        Iocp.ResultHandler handler) throws IOException;
 
310
 
 
311
    private static native void updateAcceptContext(FileDescriptor listenSocket,
 
312
        FileDescriptor acceptSocket) throws IOException;
 
313
 
 
314
    private static native void closesocket0(long socket) throws IOException;
 
315
 
 
316
    static {
 
317
        Util.load();
 
318
        initIDs();
 
319
    }
 
320
}