/** * Copyright 2013, Landz and its contributors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package z.znr.socket; import sun.net.util.IPAddressUtil; import static z.util.Unsafes.UNSAFE; import static z.znr.Syscall.*; import static z.znr.Syscall.sys_bind; import static z.znr.socket.SocketOptions.*; /** * bits/socket.h, bits/socket_type.h */ public final class Sockets { public final static class DomainFamily { /* IP protocol family. */ public static final int INET = 2; /* IP version 6. */ public static final int INET6 = 10; } public static final class SocketType { /* Sequenced, reliable, connection-based byte streams. */ public static final int SOCK_STREAM = 1; /* Connectionless, unreliable datagrams of fixed maximum length. */ public static final int SOCK_DGRAM = 2; /* Atomically set close-on-exec flag for the new descriptor(s). */ public static final int SOCK_CLOEXEC = 02000000; /* Atomically mark descriptor(s) as non-blocking. */ public static final int SOCK_NONBLOCK = 00004000; } //sys/socket.h public static final class ShutDownType { /** No more receptions. */ public static final int SHUT_RD = 0; /** No more transmissions. */ public static final int SHUT_WR = 1; /** No more receptions or transmissions.*/ public static final int SHUT_RDWR = 2; } public static final int socketTcp() { return sys_socket(DomainFamily.INET, SocketType.SOCK_STREAM, IPPROTO_IP); } public static final int bind(int sockfd, String ipAddress, int port) { try ( SocketAddressInet addr = new SocketAddressInet(ipAddress, port) ) { return bind(sockfd, addr); } } public static final int bind(int sockfd, SocketAddress addr) { return sys_bind(sockfd, addr.address(), addr.size()); } public static final int connect(int sockfd, String ipAddress, int port) { try ( SocketAddressInet addr = new SocketAddressInet(ipAddress, port) ) { return connect(sockfd, addr); } } public static final int connect(int sockfd, SocketAddress addr) { return sys_connect(sockfd, addr.address(), addr.size()); } public static final int listen(int sockfd, int backlog) { return sys_listen(sockfd, backlog); } //bits/socket.h //TODO: set to a larger? private static final int SOMAXCONN = 128; public static final int listen(int sockfd) { return sys_listen(sockfd, SOMAXCONN); } public static final int acceptNonBlock(int sockfd) { return sys_accept4(sockfd, 0L, 0, SocketType.SOCK_NONBLOCK); } public static final int acceptBlock(int sockfd) { return sys_accept4(sockfd, 0L, 0, 0); } public static final int accept(int sockfd, SocketAddress addr, int flags) { return sys_accept4(sockfd, addr.address(), addr.size(), flags); } public static final int shutdownWrite(int sockfd) { return sys_shutdown(sockfd, ShutDownType.SHUT_WR); } public static final int shutdownAll(int sockfd) { return sys_shutdown(sockfd, ShutDownType.SHUT_RDWR); } public static final int close(int sockfd) { return sys_close(sockfd); } public static final long read(int fd, long address, long count) { return sys_read(fd,address,count); } public static final long write(int fd, long address, long count) { return sys_write(fd,address,count); } //TODO: this may be changed to be more efficient in the future public static final byte[] encodeSockAddrBytes( int domain, String address, int port) { if (domain==DomainFamily.INET) { byte[] rt = new byte[16]; rt[0] = DomainFamily.INET; rt[2] = (byte) ((port>>>8) & 0xff); rt[3] = (byte) (port & 0xff); byte[] ip = IPAddressUtil.textToNumericFormatV4(address); rt[4] = ip[0]; rt[5] = ip[1]; rt[6] = ip[2]; rt[7] = ip[3]; return rt; } else if (domain==DomainFamily.INET6) { byte[] rt = new byte[28]; rt[0] = DomainFamily.INET6; rt[2] = (byte) ((port>>>8) & 0xff); rt[3] = (byte) (port & 0xff); //TODO: sin6_flowinfo rt[4] = 0; rt[5] = 0; rt[6] = 0; rt[7] = 0; byte[] ipv6 = IPAddressUtil.textToNumericFormatV6(address); System.arraycopy(rt,8,ipv6,0,ipv6.length); //TODO: sin6_scope_id rt[24] = 0; rt[25] = 0; rt[26] = 0; rt[27] = 0; return rt; } else { throw new IllegalArgumentException( "can understand the socket domain family"); } } public static final void encodeSockAddrBytes( long address, int domain, String addr, int port) { if (domain==DomainFamily.INET) { UNSAFE.putByte(address,(byte)DomainFamily.INET); UNSAFE.putByte(address+1,(byte)0); UNSAFE.putByte(address+2, (byte) ((port>>>8) & 0xff)); UNSAFE.putByte(address+3, (byte) (port & 0xff)); byte[] ip = IPAddressUtil.textToNumericFormatV4(addr); if (ip==null) { throw new IllegalArgumentException( "The socket address can not be recognized."); } UNSAFE.putByte(address+4, ip[0]); UNSAFE.putByte(address+5, ip[1]); UNSAFE.putByte(address+6, ip[2]); UNSAFE.putByte(address+7, ip[3]); //TODO is padded value significant? } else if (domain==DomainFamily.INET6) { UNSAFE.putByte(address,(byte)DomainFamily.INET6); UNSAFE.putByte(address+1,(byte)0); UNSAFE.putByte(address+2, (byte) ((port>>>8) & 0xff)); UNSAFE.putByte(address+3, (byte) (port & 0xff)); //TODO: sin6_flowinfo UNSAFE.putByte(address+4, (byte)0); UNSAFE.putByte(address+5, (byte)0); UNSAFE.putByte(address+6, (byte)0); UNSAFE.putByte(address+7, (byte)0); byte[] ipv6 = IPAddressUtil.textToNumericFormatV6(addr); if (ipv6==null) { throw new IllegalArgumentException( "The socket address can not be recognized."); } for (int i = 0; i < 16; i++) { UNSAFE.putByte(address+i+8, ipv6[i]); } //TODO: sin6_scope_id UNSAFE.putByte(address+24, (byte)0); UNSAFE.putByte(address+25, (byte)0); UNSAFE.putByte(address+26, (byte)0); UNSAFE.putByte(address+27, (byte)0); } else { throw new IllegalArgumentException( "can understand the socket domain family"); } } }