1 /**
2 * @copyright
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 * ====================================================================
21 * @endcopyright
22 *
23 * @file org_apache_subversion_javahl_util_TunnelChannel.cpp
24 * @brief Implementation of the native methods in the Java classes
25 * TunnelChannel, RequestChannel and ResponseChannel
26 */
27
28 #include <string>
29
30 #include <apr_file_io.h>
31
32 #include "../include/org_apache_subversion_javahl_util_TunnelChannel.h"
33 #include "../include/org_apache_subversion_javahl_util_RequestChannel.h"
34 #include "../include/org_apache_subversion_javahl_util_ResponseChannel.h"
35
36 #include "jniwrapper/jni_exception.hpp"
37 #include "jniwrapper/jni_channel.hpp"
38 #include "jniwrapper/jni_stack.hpp"
39
40 #include "svn_private_config.h"
41
42 namespace {
get_file_descriptor(Java::Env env,jlong jfd)43 apr_file_t* get_file_descriptor(Java::Env env, jlong jfd)
44 {
45 apr_file_t* fd = reinterpret_cast<apr_file_t*>(jfd);
46 if (!fd)
47 Java::NullPointerException(env).raise("nativeChannel");
48 return fd;
49 }
50
throw_IOException(Java::Env env,const char * message,apr_status_t status)51 void throw_IOException(Java::Env env, const char* message,
52 apr_status_t status)
53 {
54 char buf[1024];
55 std::string msg(message);
56 apr_strerror(status, buf, sizeof(buf) - 1);
57 msg += buf;
58 Java::IOException(env).raise(msg.c_str());
59 }
60
61 class TunnelReader : public Java::ChannelReader
62 {
63 public:
TunnelReader(Java::Env env,jlong jnative_channel)64 explicit TunnelReader(Java::Env env, jlong jnative_channel)
65 : m_fd(get_file_descriptor(env, jnative_channel))
66 {}
67
operator ()(Java::Env env,void * buffer,jint length)68 virtual jint operator()(Java::Env env, void* buffer, jint length)
69 {
70 if (!length)
71 return 0;
72
73 apr_size_t bytes_read = length;
74 const apr_status_t status = apr_file_read(m_fd, buffer, &bytes_read);
75 if (status && !APR_STATUS_IS_EOF(status))
76 {
77 throw_IOException(
78 env, _("Error reading from native file handle: "),
79 status);
80 return -1;
81 }
82 if (APR_STATUS_IS_EOF(status))
83 return -1;
84 return jint(bytes_read);
85 }
86
87 private:
88 apr_file_t* const m_fd;
89 };
90
91 class TunnelWriter : public Java::ChannelWriter
92 {
93 public:
TunnelWriter(Java::Env env,jlong jnative_channel)94 explicit TunnelWriter(Java::Env env, jlong jnative_channel)
95 : m_fd(get_file_descriptor(env, jnative_channel))
96 {}
97
operator ()(Java::Env env,const void * buffer,jint length)98 virtual jint operator()(Java::Env env, const void* buffer, jint length)
99 {
100 if (!length)
101 return 0;
102
103 apr_size_t bytes_written;
104 const apr_status_t status =
105 apr_file_write_full(m_fd, buffer, length, &bytes_written);
106 if (status)
107 {
108 throw_IOException(
109 env, _("Error writing to native file handle: "),
110 status);
111 return -1;
112 }
113 return jint(bytes_written);
114 }
115
116 private:
117 apr_file_t* const m_fd;
118 };
119
120 } // anonymous namespace
121
122
123 JNIEXPORT void JNICALL
Java_org_apache_subversion_javahl_util_TunnelChannel_nativeClose(JNIEnv * jenv,jclass jclazz,jlong jnative_channel)124 Java_org_apache_subversion_javahl_util_TunnelChannel_nativeClose(
125 JNIEnv* jenv, jclass jclazz, jlong jnative_channel)
126 {
127 SVN_JAVAHL_JNI_TRY_STATIC(TunnelChannel, close)
128 {
129 const Java::Env env(jenv);
130
131 apr_file_t* const fd = get_file_descriptor(env, jnative_channel);
132 if (!fd)
133 return;
134
135 const apr_status_t status = apr_file_close(fd);
136 if (status)
137 throw_IOException(
138 env, _("Error closing native file handle: "),
139 status);
140 }
141 SVN_JAVAHL_JNI_CATCH;
142 }
143
144 JNIEXPORT jint JNICALL
Java_org_apache_subversion_javahl_util_RequestChannel_nativeRead(JNIEnv * jenv,jclass jclazz,jlong jnative_channel,jobject jdst_buffer)145 Java_org_apache_subversion_javahl_util_RequestChannel_nativeRead(
146 JNIEnv* jenv, jclass jclazz, jlong jnative_channel, jobject jdst_buffer)
147 {
148 SVN_JAVAHL_JNI_TRY_STATIC(RequestChannel, read)
149 {
150 const Java::Env env(jenv);
151
152 TunnelReader reader(env, jnative_channel);
153 Java::ReadableByteChannel channel(env, reader);
154 return channel.read(jdst_buffer);
155 }
156 SVN_JAVAHL_JNI_CATCH;
157 return -1;
158 }
159
160 JNIEXPORT jint JNICALL
Java_org_apache_subversion_javahl_util_ResponseChannel_nativeWrite(JNIEnv * jenv,jclass jclazz,jlong jnative_channel,jobject jsrc_buffer)161 Java_org_apache_subversion_javahl_util_ResponseChannel_nativeWrite(
162 JNIEnv* jenv, jclass jclazz, jlong jnative_channel, jobject jsrc_buffer)
163 {
164 SVN_JAVAHL_JNI_TRY_STATIC(ResponseChannel, write)
165 {
166 const Java::Env env(jenv);
167
168 TunnelWriter writer(env, jnative_channel);
169 Java::WritableByteChannel channel(env, writer);
170 return channel.write(jsrc_buffer);
171 }
172 SVN_JAVAHL_JNI_CATCH;
173 return -1;
174 }
175