1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef TCN_H
18 #define TCN_H
19 
20 #include "apr.h"
21 #include "apr_general.h"
22 #include "apr_lib.h"
23 #include "apr_pools.h"
24 #include "apr_portable.h"
25 #include "apr_network_io.h"
26 #include "apr_poll.h"
27 #include "apr_ring.h"
28 #include "apr_strings.h"
29 
30 #if !APR_HAS_THREADS
31 #error "Missing threading support from APR."
32 #endif
33 
34 #if defined(DEBUG) || defined(_DEBUG)
35 /* On -DDEBUG use the statistics */
36 #ifndef TCN_DO_STATISTICS
37 #define TCN_DO_STATISTICS
38 #endif
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #if defined(_WIN32) && !defined(__CYGWIN__)
43 #include <process.h>
44 #else
45 #include <unistd.h>
46 #endif
47 
48 #include "tcn_api.h"
49 
50 
51 #if defined(_DEBUG) || defined(DEBUG)
52 #include <assert.h>
53 #define TCN_ASSERT(x)  assert((x))
54 #else
55 #define TCN_ASSERT(x) (void)0
56 #endif
57 
58 #ifndef APR_MAX_IOVEC_SIZE
59 #define APR_MAX_IOVEC_SIZE 1024
60 #endif
61 
62 #define TCN_TIMEUP      APR_OS_START_USERERR + 1
63 #define TCN_EAGAIN      APR_OS_START_USERERR + 2
64 #define TCN_EINTR       APR_OS_START_USERERR + 3
65 #define TCN_EINPROGRESS APR_OS_START_USERERR + 4
66 #define TCN_ETIMEDOUT   APR_OS_START_USERERR + 5
67 
68 #define TCN_LOG_EMERG  1
69 #define TCN_LOG_ERROR  2
70 #define TCN_LOG_NOTICE 3
71 #define TCN_LOG_WARN   4
72 #define TCN_LOG_INFO   5
73 #define TCN_LOG_DEBUG  6
74 
75 #define TCN_ERROR_WRAP(E)                   \
76     if (APR_STATUS_IS_TIMEUP(E))            \
77         (E) = TCN_TIMEUP;                   \
78     else if (APR_STATUS_IS_EAGAIN(E))       \
79         (E) = TCN_EAGAIN;                   \
80     else if (APR_STATUS_IS_EINTR(E))        \
81         (E) = TCN_EINTR;                    \
82     else if (APR_STATUS_IS_EINPROGRESS(E))  \
83         (E) = TCN_EINPROGRESS;              \
84     else if (APR_STATUS_IS_ETIMEDOUT(E))    \
85         (E) = TCN_ETIMEDOUT;                \
86     else                                    \
87         (E) = (E)
88 
89 #define TCN_CLASS_PATH  "org/apache/tomcat/jni/"
90 #define TCN_FINFO_CLASS TCN_CLASS_PATH "FileInfo"
91 #define TCN_AINFO_CLASS TCN_CLASS_PATH "Sockaddr"
92 #define TCN_ERROR_CLASS TCN_CLASS_PATH "Error"
93 #define TCN_PARENT_IDE  "TCN_PARENT_ID"
94 
95 #define UNREFERENCED(P)      (P) = (P)
96 #define UNREFERENCED_STDARGS e = e; o = o
97 #ifdef WIN32
98 #define LLT(X) (X)
99 #else
100 #define LLT(X) ((long)(X))
101 #endif
102 #define P2J(P)          ((jlong)LLT(P))
103 #define J2P(P, T)       ((T)LLT((jlong)P))
104 /* On stack buffer size */
105 #define TCN_BUFFER_SZ   8192
106 #define TCN_STDARGS     JNIEnv *e, jobject o
107 #define TCN_IMPARGS     JNIEnv *e, jobject o, void *sock
108 #define TCN_IMPCALL(X)  e, o, X->opaque
109 
110 #define TCN_IMPLEMENT_CALL(RT, CL, FN)  \
111     JNIEXPORT RT JNICALL Java_org_apache_tomcat_jni_##CL##_##FN
112 
113 #define TCN_IMPLEMENT_METHOD(RT, FN)    \
114     static RT method_##FN
115 
116 #define TCN_GETNET_METHOD(FN)  method_##FN
117 
118 #define TCN_SOCKET_UNKNOWN  0
119 #define TCN_SOCKET_APR      1
120 #define TCN_SOCKET_SSL      2
121 #define TCN_SOCKET_UNIX     3
122 #define TCN_SOCKET_NTPIPE   4
123 
124 #define TCN_SOCKET_GET_POOL 0
125 #define TCN_SOCKET_GET_IMPL 1
126 #define TCN_SOCKET_GET_APRS 2
127 #define TCN_SOCKET_GET_TYPE 3
128 
129 typedef struct {
130     int type;
131     apr_status_t (*cleanup)(void *);
132     apr_status_t (APR_THREAD_FUNC *close) (apr_socket_t *);
133     apr_status_t (APR_THREAD_FUNC *shutdown) (apr_socket_t *, apr_shutdown_how_e);
134     apr_status_t (APR_THREAD_FUNC *opt_get)(apr_socket_t *, apr_int32_t, apr_int32_t *);
135     apr_status_t (APR_THREAD_FUNC *opt_set)(apr_socket_t *, apr_int32_t, apr_int32_t);
136     apr_status_t (APR_THREAD_FUNC *timeout_get)(apr_socket_t *, apr_interval_time_t *);
137     apr_status_t (APR_THREAD_FUNC *timeout_set)(apr_socket_t *, apr_interval_time_t);
138     apr_status_t (APR_THREAD_FUNC *send) (apr_socket_t *, const char *, apr_size_t *);
139     apr_status_t (APR_THREAD_FUNC *sendv)(apr_socket_t *, const struct iovec *, apr_int32_t, apr_size_t *);
140     apr_status_t (APR_THREAD_FUNC *recv) (apr_socket_t *, char *, apr_size_t *);
141 } tcn_nlayer_t;
142 
143 typedef struct tcn_socket_t tcn_socket_t;
144 typedef struct tcn_pfde_t   tcn_pfde_t;
145 
146 struct tcn_pfde_t {
147     APR_RING_ENTRY(tcn_pfde_t) link;
148     apr_pollfd_t fd;
149 };
150 
151 struct tcn_socket_t {
152     apr_pool_t   *pool;
153     apr_pool_t   *child;
154     apr_socket_t *sock;
155     void         *opaque;
156     char         *jsbbuff;
157     char         *jrbbuff;
158     tcn_nlayer_t *net;
159     tcn_pfde_t   *pe;
160     apr_time_t          last_active;
161     apr_interval_time_t timeout;
162 };
163 
164 /* Private helper functions */
165 void            tcn_Throw(JNIEnv *, const char *, ...);
166 void            tcn_ThrowException(JNIEnv *, const char *);
167 void            tcn_ThrowMemoryException(JNIEnv *, const char *, int, const char *);
168 void            tcn_ThrowAPRException(JNIEnv *, apr_status_t);
169 jstring         tcn_new_string(JNIEnv *, const char *);
170 jstring         tcn_new_stringn(JNIEnv *, const char *, size_t);
171 jbyteArray      tcn_new_arrayb(JNIEnv *, const unsigned char *, size_t);
172 jobjectArray    tcn_new_arrays(JNIEnv *env, size_t len);
173 char           *tcn_get_string(JNIEnv *, jstring);
174 char           *tcn_strdup(JNIEnv *, jstring);
175 char           *tcn_pstrdup(JNIEnv *, jstring, apr_pool_t *);
176 apr_status_t    tcn_load_finfo_class(JNIEnv *, jclass);
177 apr_status_t    tcn_load_ainfo_class(JNIEnv *, jclass);
178 unsigned long   tcn_get_thread_id(void);
179 
180 #define J2S(V)  c##V
181 #define J2L(V)  p##V
182 
183 #define J2T(T) (apr_time_t)((T))
184 
185 #define TCN_BEGIN_MACRO     if (1) {
186 #define TCN_END_MACRO       } else (void)(0)
187 
188 #define TCN_ALLOC_CSTRING(V)     \
189     const char *c##V = V ? (const char *)((*e)->GetStringUTFChars(e, V, 0)) : NULL
190 
191 #define TCN_FREE_CSTRING(V)      \
192     if (c##V) (*e)->ReleaseStringUTFChars(e, V, c##V)
193 
194 #define TCN_ALLOC_JSTRING(V)     \
195     char *c##V = tcn_get_string(e, (V))
196 
197 #define AJP_TO_JSTRING(V)   (*e)->NewStringUTF((e), (V))
198 
199 #define TCN_FREE_JSTRING(V)      \
200     TCN_BEGIN_MACRO              \
201         if (c##V)                \
202             free(c##V);          \
203     TCN_END_MACRO
204 
205 #define TCN_CHECK_ALLOCATED(x)                              \
206         if (x == NULL) {                                    \
207             tcn_ThrowMemoryException(e, __FILE__, __LINE__, \
208             "APR memory allocation failed");                \
209             goto cleanup;                                   \
210         } else (void)(0)
211 
212 #define TCN_THROW_IF_ERR(x, r)                  \
213     TCN_BEGIN_MACRO                             \
214         apr_status_t R = (x);                   \
215         if (R != APR_SUCCESS) {                 \
216             tcn_ThrowAPRException(e, R);        \
217             (r) = 0;                            \
218             goto cleanup;                       \
219         }                                       \
220     TCN_END_MACRO
221 
222 #define TCN_THROW_OS_ERROR(E)   \
223     tcn_ThrowAPRException((E), apr_get_os_error())
224 
225 #define TCN_LOAD_CLASS(E, C, N, R)                  \
226     TCN_BEGIN_MACRO                                 \
227         jclass _##C = (*(E))->FindClass((E), N);    \
228         if (_##C == NULL) {                         \
229             (*(E))->ExceptionClear((E));            \
230             return R;                               \
231         }                                           \
232         C = (*(E))->NewGlobalRef((E), _##C);        \
233         (*(E))->DeleteLocalRef((E), _##C);          \
234     TCN_END_MACRO
235 
236 #define TCN_UNLOAD_CLASS(E, C)                      \
237         (*(E))->DeleteGlobalRef((E), (C))
238 
239 #define TCN_IS_NULL(E, O)                           \
240         ((*(E))->IsSameObject((E), (O), NULL) == JNI_TRUE)
241 
242 #define TCN_GET_METHOD(E, C, M, N, S, R)            \
243     TCN_BEGIN_MACRO                                 \
244         M = (*(E))->GetMethodID((E), C, N, S);      \
245         if (M == NULL) {                            \
246             return R;                               \
247         }                                           \
248     TCN_END_MACRO
249 
250 #define TCN_MAX_METHODS 8
251 
252 typedef struct {
253     jobject     obj;
254     jmethodID   mid[TCN_MAX_METHODS];
255     void        *opaque;
256 } tcn_callback_t;
257 
258 #define TCN_MIN(a, b) ((a) < (b) ? (a) : (b))
259 #define TCN_MAX(a, b) ((a) > (b) ? (a) : (b))
260 
261 #ifdef WIN32
262 #define TCN_ALLOC_WSTRING(V)     \
263     jsize wl##V = (*e)->GetStringLength(e, V);   \
264     const jchar *ws##V = V ? (const jchar *)((*e)->GetStringChars(e, V, 0)) : NULL; \
265     jchar *w##V = NULL
266 
267 #define TCN_INIT_WSTRING(V)                                     \
268         w##V = (jchar *)malloc((wl##V + 1) * sizeof(jchar));    \
269         wcsncpy(w##V, ws##V, wl##V);                        \
270         w##V[wl##V] = 0
271 
272 #define TCN_FREE_WSTRING(V)      \
273     if (ws##V) (*e)->ReleaseStringChars(e, V, ws##V); \
274     if (ws##V) free (w##V)
275 
276 #define J2W(V)  w##V
277 
278 #endif
279 
280 #if  !APR_HAVE_IPV6
281 #define APR_INET6 APR_INET
282 #endif
283 
284 #define GET_S_FAMILY(T, F)           \
285     if (F == 0) T = APR_UNSPEC;      \
286     else if (F == 1) T = APR_INET;   \
287     else if (F == 2) T = APR_INET6;  \
288     else T = F
289 
290 #define GET_S_TYPE(T, F)             \
291     if (F == 0) T = SOCK_STREAM;     \
292     else if (F == 1) T = SOCK_DGRAM; \
293     else T = F
294 
295 #define TCN_NO_SOCKET_TIMEOUT -2
296 
297 #endif /* TCN_H */
298