001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.net; 018 019 import org.apache.logging.log4j.Logger; 020 import org.apache.logging.log4j.core.appender.AppenderRuntimeException; 021 import org.apache.logging.log4j.status.StatusLogger; 022 023 import java.io.IOException; 024 import java.io.OutputStream; 025 import java.net.DatagramPacket; 026 import java.net.DatagramSocket; 027 import java.net.InetAddress; 028 import java.net.SocketException; 029 import java.net.UnknownHostException; 030 031 /** 032 * OutputStream for UDP connections. 033 */ 034 public class DatagramOutputStream extends OutputStream { 035 036 /** 037 * Allow subclasses access to the status logger without creating another instance. 038 */ 039 protected static final Logger LOGGER = StatusLogger.getLogger(); 040 041 private static final int SHIFT_1 = 8; 042 private static final int SHIFT_2 = 16; 043 private static final int SHIFT_3 = 24; 044 045 private DatagramSocket ds; 046 private final InetAddress address; 047 private final int port; 048 049 private byte[] data; 050 051 /** 052 * The Constructor. 053 * @param host The host to connect to. 054 * @param port The port on the host. 055 */ 056 public DatagramOutputStream(String host, int port) { 057 this.port = port; 058 try { 059 address = InetAddress.getByName(host); 060 } catch (UnknownHostException ex) { 061 String msg = "Could not find host " + host; 062 LOGGER.error(msg, ex); 063 throw new AppenderRuntimeException(msg, ex); 064 } 065 066 try { 067 ds = new DatagramSocket(); 068 } catch (SocketException ex) { 069 String msg = "Could not instantiate DatagramSocket to " + host; 070 LOGGER.error(msg, ex); 071 throw new AppenderRuntimeException(msg, ex); 072 } 073 } 074 075 @Override 076 public synchronized void write(byte[] bytes, int offset, int length) throws IOException { 077 copy(bytes, offset, length); 078 } 079 080 @Override 081 public synchronized void write(int i) throws IOException { 082 copy(new byte[] {(byte) (i >>> SHIFT_3), (byte) (i >>> SHIFT_2), (byte) (i >>> SHIFT_1), (byte) i}, 0, 4); 083 } 084 085 @Override 086 public synchronized void write(byte[] bytes) throws IOException { 087 copy(bytes, 0, bytes.length); 088 } 089 090 @Override 091 public synchronized void flush() throws IOException { 092 if (this.ds != null && this.address != null) { 093 DatagramPacket packet = new DatagramPacket(data, data.length, address, port); 094 ds.send(packet); 095 } 096 data = null; 097 } 098 099 @Override 100 public synchronized void close() throws IOException { 101 if (ds != null) { 102 if (data != null) { 103 flush(); 104 } 105 ds.close(); 106 ds = null; 107 } 108 } 109 110 private void copy(byte[] bytes, int offset, int length) { 111 int index = data == null ? 0 : data.length; 112 byte[] copy = new byte[length + index]; 113 if (data != null) { 114 System.arraycopy(data, 0, copy, 0, index); 115 } 116 System.arraycopy(bytes, offset, copy, index, length); 117 data = copy; 118 } 119 }