Home | History | Annotate | Download | only in include
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * 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 CONSCRYPT_BIOINPUTSTREAM_H_
     18 #define CONSCRYPT_BIOINPUTSTREAM_H_
     19 
     20 #include <jni.h>
     21 #include <openssl/ssl.h>
     22 
     23 #include "BioStream.h"
     24 
     25 namespace conscrypt {
     26 
     27 class BioInputStream : public BioStream {
     28 public:
     29     BioInputStream(jobject stream, bool isFinite) : BioStream(stream), isFinite_(isFinite) {}
     30 
     31     int read(char *buf, int len) {
     32         return read_internal(buf, len, JniConstants::inputStream_readMethod);
     33     }
     34 
     35     int gets(char *buf, int len) {
     36         if (len > PEM_LINE_LENGTH) {
     37             len = PEM_LINE_LENGTH;
     38         }
     39 
     40         int read = read_internal(buf, len - 1, JniConstants::openSslInputStream_readLineMethod);
     41         buf[read] = '\0';
     42         JNI_TRACE("BIO::gets \"%s\"", buf);
     43         return read;
     44     }
     45 
     46     bool isFinite() const {
     47         return isFinite_;
     48     }
     49 
     50 private:
     51     const bool isFinite_;
     52 
     53     int read_internal(char *buf, int len, jmethodID method) {
     54         JNIEnv *env = JniConstants::getJNIEnv();
     55         if (env == nullptr) {
     56             JNI_TRACE("BioInputStream::read could not get JNIEnv");
     57             return -1;
     58         }
     59 
     60         if (env->ExceptionCheck()) {
     61             JNI_TRACE("BioInputStream::read called with pending exception");
     62             return -1;
     63         }
     64 
     65         ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len));
     66         if (javaBytes.get() == nullptr) {
     67             JNI_TRACE("BioInputStream::read failed call to NewByteArray");
     68             return -1;
     69         }
     70 
     71         jint read = env->CallIntMethod(getStream(), method, javaBytes.get());
     72         if (env->ExceptionCheck()) {
     73             JNI_TRACE("BioInputStream::read failed call to InputStream#read");
     74             return -1;
     75         }
     76 
     77         /* Java uses -1 to indicate EOF condition. */
     78         if (read == -1) {
     79             setEof(true);
     80             read = 0;
     81         } else if (read > 0) {
     82             env->GetByteArrayRegion(javaBytes.get(), 0, read, reinterpret_cast<jbyte *>(buf));
     83         }
     84 
     85         return read;
     86     }
     87 
     88 public:
     89     /** Length of PEM-encoded line (64) plus CR plus NUL */
     90     static const int PEM_LINE_LENGTH = 66;
     91 };
     92 
     93 }  // namespace conscrypt
     94 
     95 #endif  // CONSCRYPT_BIOINPUTSTREAM_H_
     96