View Javadoc
1   /*
2    * Copyright 2016 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  /*
17   *  Licensed to the Apache Software Foundation (ASF) under one or more
18   *  contributor license agreements.  See the NOTICE file distributed with
19   *  this work for additional information regarding copyright ownership.
20   *  The ASF licenses this file to You under the Apache License, Version 2.0
21   *  (the "License"); you may not use this file except in compliance with
22   *  the License.  You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   *  Unless required by applicable law or agreed to in writing, software
27   *  distributed under the License is distributed on an "AS IS" BASIS,
28   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   *  See the License for the specific language governing permissions and
30   *  limitations under the License.
31   */
32  
33  package io.netty.internal.tcnative;
34  
35  import java.io.File;
36  
37  public final class Library {
38  
39      /* Default library names */
40      private static final String [] NAMES = {
41          "netty_tcnative",
42          "libnetty_tcnative"
43      };
44  
45      private static final String PROVIDED = "provided";
46  
47      /*
48       * A handle to the unique Library singleton instance.
49       */
50      private static Library _instance = null;
51  
52      private Library() throws Exception {
53          boolean loaded = false;
54          String path = System.getProperty("java.library.path");
55          String [] paths = path.split(File.pathSeparator);
56          StringBuilder err = new StringBuilder();
57          for (int i = 0; i < NAMES.length; i++) {
58              try {
59                  loadLibrary(NAMES[i]);
60                  loaded = true;
61              } catch (ThreadDeath t) {
62                  throw t;
63              } catch (VirtualMachineError t) {
64                  throw t;
65              } catch (Throwable t) {
66                  String name = System.mapLibraryName(NAMES[i]);
67                  for (int j = 0; j < paths.length; j++) {
68                      File fd = new File(paths[j] , name);
69                      if (fd.exists()) {
70                          // File exists but failed to load
71                          throw new RuntimeException(t);
72                      }
73                  }
74                  if (i > 0) {
75                      err.append(", ");
76                  }
77                  err.append(t.getMessage());
78              }
79              if (loaded) {
80                  break;
81              }
82          }
83          if (!loaded) {
84              throw new UnsatisfiedLinkError(err.toString());
85          }
86      }
87  
88      private Library(String libraryName) {
89          if (!PROVIDED.equals(libraryName)) {
90              loadLibrary(libraryName);
91          }
92      }
93  
94      private static void loadLibrary(String libraryName) {
95          System.loadLibrary(calculatePackagePrefix().replace('.', '_') + libraryName);
96      }
97  
98      /**
99       * The shading prefix added to this class's full name.
100      *
101      * @throws UnsatisfiedLinkError if the shader used something other than a prefix
102      */
103     private static String calculatePackagePrefix() {
104         String maybeShaded = Library.class.getName();
105         // Use ! instead of . to avoid shading utilities from modifying the string
106         String expected = "io!netty!internal!tcnative!Library".replace('!', '.');
107         if (!maybeShaded.endsWith(expected)) {
108             throw new UnsatisfiedLinkError(String.format(
109                     "Could not find prefix added to %s to get %s. When shading, only adding a "
110                             + "package prefix is supported", expected, maybeShaded));
111         }
112         return maybeShaded.substring(0, maybeShaded.length() - expected.length());
113     }
114 
115     /* create global TCN's APR pool
116      * This has to be the first call to TCN library.
117      */
118     private static native boolean initialize0();
119 
120     private static native boolean aprHasThreads();
121 
122     private static native int aprMajorVersion();
123 
124     /* APR_VERSION_STRING */
125     private static native String aprVersionString();
126 
127     /**
128      * Calls {@link #initialize(String, String)} with {@code "provided"} and {@code null}.
129      *
130      * @return {@code true} if initialization was successful
131      * @throws Exception if an error happens during initialization
132      */
133     public static boolean initialize() throws Exception {
134         return initialize(PROVIDED, null);
135     }
136 
137     /**
138      * Setup native library. This is the first method that must be called!
139      *
140      * @param libraryName the name of the library to load
141      * @param engine Support for external a Crypto Device ("engine"), usually
142      * @return {@code true} if initialization was successful
143      * @throws Exception if an error happens during initialization
144      */
145     public static boolean initialize(String libraryName, String engine) throws Exception {
146         if (_instance == null) {
147             _instance = libraryName == null ? new Library() : new Library(libraryName);
148 
149             if (aprMajorVersion() < 1) {
150                 throw new UnsatisfiedLinkError("Unsupported APR Version (" +
151                                                aprVersionString() + ")");
152             }
153 
154             if (!aprHasThreads()) {
155                 throw new UnsatisfiedLinkError("Missing APR_HAS_THREADS");
156             }
157         }
158         return initialize0() && SSL.initialize(engine) == 0;
159     }
160 }