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 */ 017package org.apache.logging.log4j.core.net; 018 019import java.io.IOException; 020import java.io.OutputStream; 021import java.net.DatagramPacket; 022import java.net.DatagramSocket; 023import java.net.InetAddress; 024import java.net.SocketException; 025import java.net.UnknownHostException; 026 027import org.apache.logging.log4j.Logger; 028import org.apache.logging.log4j.core.appender.AppenderLoggingException; 029import org.apache.logging.log4j.status.StatusLogger; 030 031/** 032 * OutputStream for UDP connections. 033 */ 034public 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 private final byte[] header; 052 private final byte[] footer; 053 054 /** 055 * The Constructor. 056 * @param host The host to connect to. 057 * @param port The port on the host. 058 */ 059 public DatagramOutputStream(final String host, final int port, final byte[] header, final byte[] footer) { 060 this.port = port; 061 this.header = header; 062 this.footer = footer; 063 try { 064 address = InetAddress.getByName(host); 065 } catch (final UnknownHostException ex) { 066 final String msg = "Could not find host " + host; 067 LOGGER.error(msg, ex); 068 throw new AppenderLoggingException(msg, ex); 069 } 070 071 try { 072 ds = new DatagramSocket(); 073 } catch (final SocketException ex) { 074 final String msg = "Could not instantiate DatagramSocket to " + host; 075 LOGGER.error(msg, ex); 076 throw new AppenderLoggingException(msg, ex); 077 } 078 } 079 080 @Override 081 public synchronized void write(final byte[] bytes, final int offset, final int length) throws IOException { 082 copy(bytes, offset, length); 083 } 084 085 @Override 086 public synchronized void write(final int i) throws IOException { 087 copy(new byte[] {(byte) (i >>> SHIFT_3), (byte) (i >>> SHIFT_2), (byte) (i >>> SHIFT_1), (byte) i}, 0, 4); 088 } 089 090 @Override 091 public synchronized void write(final byte[] bytes) throws IOException { 092 copy(bytes, 0, bytes.length); 093 } 094 095 @Override 096 public synchronized void flush() throws IOException { 097 try { 098 if (this.data != null && this.ds != null && this.address != null) { 099 if (footer != null) { 100 copy(footer, 0, footer.length); 101 } 102 final DatagramPacket packet = new DatagramPacket(data, data.length, address, port); 103 ds.send(packet); 104 } 105 } finally { 106 data = null; 107 if (header != null) { 108 copy(header, 0, header.length); 109 } 110 } 111 } 112 113 @Override 114 public synchronized void close() throws IOException { 115 if (ds != null) { 116 if (data != null) { 117 flush(); 118 } 119 ds.close(); 120 ds = null; 121 } 122 } 123 124 private void copy(final byte[] bytes, final int offset, final int length) { 125 final int index = data == null ? 0 : data.length; 126 final byte[] copy = new byte[length + index]; 127 if (data != null) { 128 System.arraycopy(data, 0, copy, 0, data.length); 129 } 130 System.arraycopy(bytes, offset, copy, index, length); 131 data = copy; 132 } 133}