1 /* 2 * Copyright (c) 2000, 2013, 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 /* 27 * 28 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 29 * Copyright 1997 The Open Group Research Institute. All rights reserved. 30 */ 31 32 package sun.security.krb5.internal; 33 34 import sun.misc.IOUtils; 35 36 import java.io.*; 37 import java.net.*; 38 39 public abstract class NetClient implements AutoCloseable { 40 public static NetClient getInstance(String protocol, String hostname, int port, 41 int timeout) throws IOException { 42 if (protocol.equals("TCP")) { 43 return new TCPClient(hostname, port, timeout); 44 } else { 45 return new UDPClient(hostname, port, timeout); 46 } 47 } 48 49 abstract public void send(byte[] data) throws IOException; 50 abstract public byte[] receive() throws IOException; 51 abstract public void close() throws IOException; 52 } 53 54 class TCPClient extends NetClient { 55 56 private Socket tcpSocket; 57 private BufferedOutputStream out; 58 private BufferedInputStream in; 59 60 TCPClient(String hostname, int port, int timeout) 61 throws IOException { 62 tcpSocket = new Socket(); 63 tcpSocket.connect(new InetSocketAddress(hostname, port), timeout); 64 out = new BufferedOutputStream(tcpSocket.getOutputStream()); 65 in = new BufferedInputStream(tcpSocket.getInputStream()); 66 tcpSocket.setSoTimeout(timeout); 67 } 68 69 @Override 70 public void send(byte[] data) throws IOException { 71 byte[] lenField = new byte[4]; 72 intToNetworkByteOrder(data.length, lenField, 0, 4); 73 out.write(lenField); 74 75 out.write(data); 76 out.flush(); 77 } 78 79 @Override 80 public byte[] receive() throws IOException { 81 byte[] lenField = new byte[4]; 82 int count = readFully(lenField, 4); 83 84 if (count != 4) { 85 if (Krb5.DEBUG) { 86 System.out.println( 87 ">>>DEBUG: TCPClient could not read length field"); 88 } 89 return null; 90 } 91 92 int len = networkByteOrderToInt(lenField, 0, 4); 93 if (Krb5.DEBUG) { 94 System.out.println( 95 ">>>DEBUG: TCPClient reading " + len + " bytes"); 96 } 97 if (len <= 0) { 98 if (Krb5.DEBUG) { 99 System.out.println( 100 ">>>DEBUG: TCPClient zero or negative length field: "+len); 101 } 102 return null; 103 } 104 105 try { 106 return IOUtils.readFully(in, len, true); 107 } catch (IOException ioe) { 108 if (Krb5.DEBUG) { 109 System.out.println( 110 ">>>DEBUG: TCPClient could not read complete packet (" + 111 len + "/" + count + ")"); 112 } 113 return null; 114 } 115 } 116 117 @Override 118 public void close() throws IOException { 119 tcpSocket.close(); 120 } 121 122 /** 123 * Read requested number of bytes before returning. 124 * @return The number of bytes actually read; -1 if none read 125 */ 126 private int readFully(byte[] inBuf, int total) throws IOException { 127 int count, pos = 0; 128 129 while (total > 0) { 130 count = in.read(inBuf, pos, total); 131 132 if (count == -1) { 133 return (pos == 0? -1 : pos); 134 } 135 pos += count; 136 total -= count; 137 } 138 return pos; 139 } 140 141 /** 142 * Returns the integer represented by 4 bytes in network byte order. 143 */ 144 private static int networkByteOrderToInt(byte[] buf, int start, 145 int count) { 146 if (count > 4) { 147 throw new IllegalArgumentException( 148 "Cannot handle more than 4 bytes"); 149 } 150 151 int answer = 0; 152 153 for (int i = 0; i < count; i++) { 154 answer <<= 8; 155 answer |= ((int)buf[start+i] & 0xff); 156 } 157 return answer; 158 } 159 160 /** 161 * Encodes an integer into 4 bytes in network byte order in the buffer 162 * supplied. 163 */ 164 private static void intToNetworkByteOrder(int num, byte[] buf, 165 int start, int count) { 166 if (count > 4) { 167 throw new IllegalArgumentException( 168 "Cannot handle more than 4 bytes"); 169 } 170 171 for (int i = count-1; i >= 0; i--) { 172 buf[start+i] = (byte)(num & 0xff); 173 num >>>= 8; 174 } 175 } 176 } 177 178 class UDPClient extends NetClient { 179 InetAddress iaddr; 180 int iport; 181 int bufSize = 65507; 182 DatagramSocket dgSocket; 183 DatagramPacket dgPacketIn; 184 185 UDPClient(String hostname, int port, int timeout) 186 throws UnknownHostException, SocketException { 187 iaddr = InetAddress.getByName(hostname); 188 iport = port; 189 dgSocket = new DatagramSocket(); 190 dgSocket.setSoTimeout(timeout); 191 dgSocket.connect(iaddr, iport); 192 } 193 194 @Override 195 public void send(byte[] data) throws IOException { 196 DatagramPacket dgPacketOut = new DatagramPacket(data, data.length, 197 iaddr, iport); 198 dgSocket.send(dgPacketOut); 199 } 200 201 @Override 202 public byte[] receive() throws IOException { 203 byte[] ibuf = new byte[bufSize]; 204 dgPacketIn = new DatagramPacket(ibuf, ibuf.length); 205 try { 206 dgSocket.receive(dgPacketIn); 207 } 208 catch (SocketException e) { 209 if (e instanceof PortUnreachableException) { 210 throw e; 211 } 212 dgSocket.receive(dgPacketIn); 213 } 214 byte[] data = new byte[dgPacketIn.getLength()]; 215 System.arraycopy(dgPacketIn.getData(), 0, data, 0, 216 dgPacketIn.getLength()); 217 return data; 218 } 219 220 @Override 221 public void close() { 222 dgSocket.close(); 223 } 224 } --- EOF ---