1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  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
17package java.nio;
18
19import java.io.Closeable;
20import java.io.FileDescriptor;
21import java.io.IOException;
22import java.nio.channels.Pipe;
23import java.nio.channels.SocketChannel;
24import java.nio.channels.spi.SelectorProvider;
25import libcore.io.ErrnoException;
26import libcore.io.IoUtils;
27import libcore.io.Libcore;
28import static libcore.io.OsConstants.*;
29
30/*
31 * Implements {@link java.nio.channels.Pipe}.
32 */
33final class PipeImpl extends Pipe {
34    private final PipeSinkChannel sink;
35    private final PipeSourceChannel source;
36
37    public PipeImpl(SelectorProvider selectorProvider) throws IOException {
38        try {
39            FileDescriptor fd1 = new FileDescriptor();
40            FileDescriptor fd2 = new FileDescriptor();
41            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
42
43            // It doesn't matter which file descriptor we use for which end;
44            // they're guaranteed to be indistinguishable.
45            this.sink = new PipeSinkChannel(selectorProvider, fd1);
46            this.source = new PipeSourceChannel(selectorProvider, fd2);
47        } catch (ErrnoException errnoException) {
48            throw errnoException.rethrowAsIOException();
49        }
50    }
51
52    @Override public SinkChannel sink() {
53        return sink;
54    }
55
56    @Override public SourceChannel source() {
57        return source;
58    }
59
60    private class PipeSourceChannel extends Pipe.SourceChannel implements FileDescriptorChannel {
61        private final FileDescriptor fd;
62        private final SocketChannel channel;
63
64        private PipeSourceChannel(SelectorProvider selectorProvider, FileDescriptor fd) throws IOException {
65            super(selectorProvider);
66            this.fd = fd;
67            this.channel = new SocketChannelImpl(selectorProvider, fd);
68        }
69
70        @Override protected void implCloseSelectableChannel() throws IOException {
71            channel.close();
72        }
73
74        @Override protected void implConfigureBlocking(boolean blocking) throws IOException {
75            IoUtils.setBlocking(getFD(), blocking);
76        }
77
78        public int read(ByteBuffer buffer) throws IOException {
79            return channel.read(buffer);
80        }
81
82        public long read(ByteBuffer[] buffers) throws IOException {
83            return channel.read(buffers);
84        }
85
86        public long read(ByteBuffer[] buffers, int offset, int length) throws IOException {
87            return channel.read(buffers, offset, length);
88        }
89
90        public FileDescriptor getFD() {
91            return fd;
92        }
93    }
94
95    private class PipeSinkChannel extends Pipe.SinkChannel implements FileDescriptorChannel {
96        private final FileDescriptor fd;
97        private final SocketChannel channel;
98
99        private PipeSinkChannel(SelectorProvider selectorProvider, FileDescriptor fd) throws IOException {
100            super(selectorProvider);
101            this.fd = fd;
102            this.channel = new SocketChannelImpl(selectorProvider, fd);
103        }
104
105        @Override protected void implCloseSelectableChannel() throws IOException {
106            channel.close();
107        }
108
109        @Override protected void implConfigureBlocking(boolean blocking) throws IOException {
110            IoUtils.setBlocking(getFD(), blocking);
111        }
112
113        public int write(ByteBuffer buffer) throws IOException {
114            return channel.write(buffer);
115        }
116
117        public long write(ByteBuffer[] buffers) throws IOException {
118            return channel.write(buffers);
119        }
120
121        public long write(ByteBuffer[] buffers, int offset, int length) throws IOException {
122            return channel.write(buffers, offset, length);
123        }
124
125        public FileDescriptor getFD() {
126            return fd;
127        }
128    }
129}
130