1 /* 2 * Copyright 2015 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty.channel.unix; 17 18 import io.netty.util.internal.EmptyArrays; 19 20 import java.io.FileNotFoundException; 21 import java.io.IOException; 22 import java.net.ConnectException; 23 import java.net.NoRouteToHostException; 24 import java.nio.channels.AlreadyConnectedException; 25 import java.nio.channels.ClosedChannelException; 26 import java.nio.channels.ConnectionPendingException; 27 import java.nio.channels.NotYetConnectedException; 28 29 import static io.netty.channel.unix.ErrorsStaticallyReferencedJniMethods.*; 30 31 /** 32 * <strong>Internal usage only!</strong> 33 * <p>Static members which call JNI methods must be defined in {@link ErrorsStaticallyReferencedJniMethods}. 34 */ 35 public final class Errors { 36 // As all our JNI methods return -errno on error we need to compare with the negative errno codes. 37 public static final int ERRNO_ENOENT_NEGATIVE = -errnoENOENT(); 38 public static final int ERRNO_ENOTCONN_NEGATIVE = -errnoENOTCONN(); 39 public static final int ERRNO_EBADF_NEGATIVE = -errnoEBADF(); 40 public static final int ERRNO_EPIPE_NEGATIVE = -errnoEPIPE(); 41 public static final int ERRNO_ECONNRESET_NEGATIVE = -errnoECONNRESET(); 42 public static final int ERRNO_EAGAIN_NEGATIVE = -errnoEAGAIN(); 43 public static final int ERRNO_EWOULDBLOCK_NEGATIVE = -errnoEWOULDBLOCK(); 44 public static final int ERRNO_EINPROGRESS_NEGATIVE = -errnoEINPROGRESS(); 45 public static final int ERROR_ECONNREFUSED_NEGATIVE = -errorECONNREFUSED(); 46 public static final int ERROR_EISCONN_NEGATIVE = -errorEISCONN(); 47 public static final int ERROR_EALREADY_NEGATIVE = -errorEALREADY(); 48 public static final int ERROR_ENETUNREACH_NEGATIVE = -errorENETUNREACH(); 49 50 /** 51 * Holds the mappings for errno codes to String messages. 52 * This eliminates the need to call back into JNI to get the right String message on an exception 53 * and thus is faster. 54 * 55 * The array length of 512 should be more then enough because errno.h only holds < 200 codes. 56 */ 57 private static final String[] ERRORS = new String[512]; 58 59 /** 60 * <strong>Internal usage only!</strong> 61 */ 62 public static final class NativeIoException extends IOException { 63 private static final long serialVersionUID = 8222160204268655526L; 64 private final int expectedErr; 65 private final boolean fillInStackTrace; 66 NativeIoException(String method, int expectedErr)67 public NativeIoException(String method, int expectedErr) { 68 this(method, expectedErr, true); 69 } 70 NativeIoException(String method, int expectedErr, boolean fillInStackTrace)71 public NativeIoException(String method, int expectedErr, boolean fillInStackTrace) { 72 super(method + "(..) failed: " + ERRORS[-expectedErr]); 73 this.expectedErr = expectedErr; 74 this.fillInStackTrace = fillInStackTrace; 75 } 76 expectedErr()77 public int expectedErr() { 78 return expectedErr; 79 } 80 81 @Override fillInStackTrace()82 public synchronized Throwable fillInStackTrace() { 83 if (fillInStackTrace) { 84 return super.fillInStackTrace(); 85 } 86 return this; 87 } 88 } 89 90 static final class NativeConnectException extends ConnectException { 91 private static final long serialVersionUID = -5532328671712318161L; 92 private final int expectedErr; NativeConnectException(String method, int expectedErr)93 NativeConnectException(String method, int expectedErr) { 94 super(method + "(..) failed: " + ERRORS[-expectedErr]); 95 this.expectedErr = expectedErr; 96 } 97 expectedErr()98 int expectedErr() { 99 return expectedErr; 100 } 101 } 102 103 static { 104 for (int i = 0; i < ERRORS.length; i++) { 105 // This is ok as strerror returns 'Unknown error i' when the message is not known. 106 ERRORS[i] = strError(i); 107 } 108 } 109 throwConnectException(String method, int err)110 static void throwConnectException(String method, int err) 111 throws IOException { 112 if (err == ERROR_EALREADY_NEGATIVE) { 113 throw new ConnectionPendingException(); 114 } 115 if (err == ERROR_ENETUNREACH_NEGATIVE) { 116 throw new NoRouteToHostException(); 117 } 118 if (err == ERROR_EISCONN_NEGATIVE) { 119 throw new AlreadyConnectedException(); 120 } 121 if (err == ERRNO_ENOENT_NEGATIVE) { 122 throw new FileNotFoundException(); 123 } 124 throw new ConnectException(method + "(..) failed: " + ERRORS[-err]); 125 } 126 newConnectionResetException(String method, int errnoNegative)127 public static NativeIoException newConnectionResetException(String method, int errnoNegative) { 128 NativeIoException exception = new NativeIoException(method, errnoNegative, false); 129 exception.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE); 130 return exception; 131 } 132 newIOException(String method, int err)133 public static NativeIoException newIOException(String method, int err) { 134 return new NativeIoException(method, err); 135 } 136 137 @Deprecated ioResult(String method, int err, NativeIoException resetCause, ClosedChannelException closedCause)138 public static int ioResult(String method, int err, NativeIoException resetCause, 139 ClosedChannelException closedCause) throws IOException { 140 // network stack saturated... try again later 141 if (err == ERRNO_EAGAIN_NEGATIVE || err == ERRNO_EWOULDBLOCK_NEGATIVE) { 142 return 0; 143 } 144 if (err == resetCause.expectedErr()) { 145 throw resetCause; 146 } 147 if (err == ERRNO_EBADF_NEGATIVE) { 148 throw closedCause; 149 } 150 if (err == ERRNO_ENOTCONN_NEGATIVE) { 151 throw new NotYetConnectedException(); 152 } 153 if (err == ERRNO_ENOENT_NEGATIVE) { 154 throw new FileNotFoundException(); 155 } 156 157 // TODO: We could even go further and use a pre-instantiated IOException for the other error codes, but for 158 // all other errors it may be better to just include a stack trace. 159 throw newIOException(method, err); 160 } 161 ioResult(String method, int err)162 public static int ioResult(String method, int err) throws IOException { 163 // network stack saturated... try again later 164 if (err == ERRNO_EAGAIN_NEGATIVE || err == ERRNO_EWOULDBLOCK_NEGATIVE) { 165 return 0; 166 } 167 if (err == ERRNO_EBADF_NEGATIVE) { 168 throw new ClosedChannelException(); 169 } 170 if (err == ERRNO_ENOTCONN_NEGATIVE) { 171 throw new NotYetConnectedException(); 172 } 173 if (err == ERRNO_ENOENT_NEGATIVE) { 174 throw new FileNotFoundException(); 175 } 176 177 throw new NativeIoException(method, err, false); 178 } 179 Errors()180 private Errors() { } 181 } 182