diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 14:03:56 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 14:03:56 -0800 |
commit | 2fb02ef3025449e24e756a7f645ea6eab7a1fd4f (patch) | |
tree | 15baa1ab62b329c09dc7a8e912b0f14c7e67d40b | |
parent | d11a65b017fde8c4c997f41ee59e87e90d68b3f5 (diff) | |
download | libcore-2fb02ef3025449e24e756a7f645ea6eab7a1fd4f.zip libcore-2fb02ef3025449e24e756a7f645ea6eab7a1fd4f.tar.gz libcore-2fb02ef3025449e24e756a7f645ea6eab7a1fd4f.tar.bz2 |
auto import from //depot/cupcake/@132589
29 files changed, 504 insertions, 1808 deletions
diff --git a/icu/src/main/native/DecimalFormatInterface.cpp b/icu/src/main/native/DecimalFormatInterface.cpp index 6221826..fb5cf9f 100644 --- a/icu/src/main/native/DecimalFormatInterface.cpp +++ b/icu/src/main/native/DecimalFormatInterface.cpp @@ -50,13 +50,13 @@ static UBool icuError(JNIEnv *env, UErrorCode errorcode) default : exception = env->FindClass("java/lang/RuntimeException"); } - + return (env->ThrowNew(exception, emsg) != 0); } return 0; } -static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale, +static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale, jstring pattern) { // the errorcode returned by unum_open @@ -70,9 +70,9 @@ static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale, const char *localeChars = env->GetStringUTFChars(locale, NULL); // open a default type number format - UNumberFormat *fmt = unum_open(UNUM_PATTERN_DECIMAL, pattChars, pattLen, + UNumberFormat *fmt = unum_open(UNUM_PATTERN_DECIMAL, pattChars, pattLen, localeChars, NULL, &status); - + // release the allocated strings env->ReleaseStringChars(pattern, pattChars); env->ReleaseStringUTFChars(locale, localeChars); @@ -88,20 +88,20 @@ static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale, static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) { - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; // close this number format unum_close(fmt); } -static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol, +static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol, jstring text) { - + // the errorcode returned by unum_setSymbol UErrorCode status = U_ZERO_ERROR; - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; // prepare the symbol string for the call to unum_setSymbol @@ -109,9 +109,9 @@ static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol, int textLen = env->GetStringLength(text); // set the symbol - unum_setSymbol(fmt, (UNumberFormatSymbol) symbol, textChars, textLen, + unum_setSymbol(fmt, (UNumberFormatSymbol) symbol, textChars, textLen, &status); - + // release previously allocated space env->ReleaseStringChars(text, textChars); @@ -126,14 +126,14 @@ static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) { // the errorcode returned by unum_getSymbol UErrorCode status = U_ZERO_ERROR; - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; UChar* result = NULL; resultlength=0; // find out how long the result will be - reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result, + reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result, resultlength, &status); result = NULL; @@ -141,7 +141,7 @@ static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) { status=U_ZERO_ERROR; resultlength=reslenneeded+1; result=(UChar*)malloc(sizeof(UChar) * resultlength); - reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result, + reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result, resultlength, &status); } if (icuError(env, status) != FALSE) { @@ -154,17 +154,17 @@ static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) { return res; } - -static void setAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, + +static void setAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, jint value) { - + UNumberFormat *fmt = (UNumberFormat *)(int)addr; unum_setAttribute(fmt, (UNumberFormatAttribute) symbol, value); } - + static jint getAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) { - + UNumberFormat *fmt = (UNumberFormat *)(int)addr; int res = unum_getAttribute(fmt, (UNumberFormatAttribute) symbol); @@ -172,27 +172,27 @@ static jint getAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) { return res; } -static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, +static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, jstring text) { // the errorcode returned by unum_setTextAttribute UErrorCode status = U_ZERO_ERROR; - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; const UChar *textChars = env->GetStringChars(text, NULL); int textLen = env->GetStringLength(text); - unum_setTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, textChars, + unum_setTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, textChars, textLen, &status); - + env->ReleaseStringChars(text, textChars); icuError(env, status); } -static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, +static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) { uint32_t resultlength, reslenneeded; @@ -200,14 +200,14 @@ static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, // the errorcode returned by unum_getTextAttribute UErrorCode status = U_ZERO_ERROR; - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; UChar* result = NULL; resultlength=0; // find out how long the result will be - reslenneeded=unum_getTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, + reslenneeded=unum_getTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, result, resultlength, &status); result = NULL; @@ -215,8 +215,8 @@ static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, status=U_ZERO_ERROR; resultlength=reslenneeded+1; result=(UChar*)malloc(sizeof(UChar) * resultlength); - reslenneeded=unum_getTextAttribute(fmt, - (UNumberFormatTextAttribute) symbol, result, resultlength, + reslenneeded=unum_getTextAttribute(fmt, + (UNumberFormatTextAttribute) symbol, result, resultlength, &status); } if (icuError(env, status) != FALSE) { @@ -230,13 +230,13 @@ static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, return res; } -static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr, +static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr, jboolean localized, jstring pattern) { // the errorcode returned by unum_applyPattern UErrorCode status = U_ZERO_ERROR; - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; const UChar *pattChars = env->GetStringChars(pattern, NULL); @@ -249,7 +249,7 @@ static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr, icuError(env, status); } -static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr, +static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr, jboolean localized) { uint32_t resultlength, reslenneeded; @@ -257,7 +257,7 @@ static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr, // the errorcode returned by unum_toPattern UErrorCode status = U_ZERO_ERROR; - // get the pointer to the number format + // get the pointer to the number format UNumberFormat *fmt = (UNumberFormat *)(int)addr; UChar* result = NULL; @@ -271,7 +271,7 @@ static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr, status=U_ZERO_ERROR; resultlength=reslenneeded+1; result=(UChar*)malloc(sizeof(UChar) * resultlength); - reslenneeded=unum_toPattern(fmt, localized, result, resultlength, + reslenneeded=unum_toPattern(fmt, localized, result, resultlength, &status); } if (icuError(env, status) != FALSE) { @@ -284,19 +284,19 @@ static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr, return res; } - -static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value, + +static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value, jobject field, jstring fieldType, jobject attributes) { const char * fieldPositionClassName = "java/text/FieldPosition"; const char * stringBufferClassName = "java/lang/StringBuffer"; jclass fieldPositionClass = env->FindClass(fieldPositionClassName); jclass stringBufferClass = env->FindClass(stringBufferClassName); - jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, + jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, "setBeginIndex", "(I)V"); - jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, + jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, "setEndIndex", "(I)V"); - jmethodID appendMethodID = env->GetMethodID(stringBufferClass, + jmethodID appendMethodID = env->GetMethodID(stringBufferClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); const char * fieldName = NULL; @@ -331,7 +331,7 @@ static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value, if(status==U_BUFFER_OVERFLOW_ERROR) { status=U_ZERO_ERROR; - result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); + result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); res->extract(result, reslenneeded + 1, status); } @@ -393,18 +393,18 @@ static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value, return resulting; } -static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value, +static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value, jobject field, jstring fieldType, jobject attributes) { const char * fieldPositionClassName = "java/text/FieldPosition"; const char * stringBufferClassName = "java/lang/StringBuffer"; jclass fieldPositionClass = env->FindClass(fieldPositionClassName); jclass stringBufferClass = env->FindClass(stringBufferClassName); - jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, + jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, "setBeginIndex", "(I)V"); - jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, + jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, "setEndIndex", "(I)V"); - jmethodID appendMethodID = env->GetMethodID(stringBufferClass, + jmethodID appendMethodID = env->GetMethodID(stringBufferClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); const char * fieldName = NULL; @@ -439,7 +439,7 @@ static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value, if(status==U_BUFFER_OVERFLOW_ERROR) { status=U_ZERO_ERROR; - result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); + result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); res->extract(result, reslenneeded + 1, status); @@ -502,7 +502,7 @@ static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value, return resulting; } -static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring value, +static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring value, jobject field, jstring fieldType, jobject attributes, jint scale) { // const char * valueUTF = env->GetStringUTFChars(value, NULL); @@ -521,36 +521,21 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val uint32_t reslenneeded; + bool isInteger = (scale == 0); + // prepare digit list - const char *valueChars = env->GetStringUTFChars(value, NULL); + const char *digits = env->GetStringUTFChars(value, NULL); - bool isInteger = (scale == 0); - bool isPositive = (*valueChars != '-'); - - // skip the '-' if the number is negative - const char *digits = (isPositive ? valueChars : valueChars + 1); - int length = strlen(digits); - - // The length of our digit list buffer must be the actual string length + 3, - // because ICU will append some additional characters at the head and at the - // tail of the string, in order to keep strtod() happy: - // - // - The sign "+" or "-" is appended at the head - // - The exponent "e" and the "\0" terminator is appended at the tail - // - // In retrospect, the changes to ICU's DigitList that were necessary for - // big numbers look a bit hacky. It would make sense to rework all this - // once ICU 4.x has been integrated into Android. Ideally, big number - // support would make it into ICU itself, so we don't need our private - // fix anymore. - DigitList digitList(length + 3); - digitList.fCount = length; + // length must be string lengt + 2 because there's an additional + // character in front of the string ("+" or "-") and a \0 at the end + DigitList digitList(strlen(digits) + 2); + digitList.fCount = strlen(digits); strcpy(digitList.fDigits, digits); - env->ReleaseStringUTFChars(value, valueChars); + env->ReleaseStringUTFChars(value, digits); digitList.fDecimalAt = digitList.fCount - scale; - digitList.fIsPositive = isPositive; + digitList.fIsPositive = (*digits != '-'); digitList.fRoundingMode = DecimalFormat::kRoundHalfUp; UChar *result = NULL; @@ -563,9 +548,10 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val UErrorCode status = U_ZERO_ERROR; DecimalFormat::AttributeBuffer *attrBuffer = NULL; - attrBuffer = (DecimalFormat::AttributeBuffer *) calloc(sizeof(DecimalFormat::AttributeBuffer), 1); + attrBuffer = (DecimalFormat::AttributeBuffer *) malloc(sizeof(DecimalFormat::AttributeBuffer)); attrBuffer->bufferSize = 128; - attrBuffer->buffer = (char *) calloc(129 * sizeof(char), 1); + attrBuffer->buffer = (char *) malloc(129 * sizeof(char)); + attrBuffer->buffer[0] = '\0'; DecimalFormat *fmt = (DecimalFormat *)(int)addr; @@ -578,7 +564,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val if(status==U_BUFFER_OVERFLOW_ERROR) { status=U_ZERO_ERROR; - result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); + result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); res.extract(result, reslenneeded + 1, status); @@ -598,7 +584,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val } free(attrBuffer->buffer); free(attrBuffer); - return NULL; + return NULL; } int attrLength = (strlen(attrBuffer->buffer) + 1 ); @@ -610,7 +596,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val // prepare the classes and method ids const char * stringBufferClassName = "java/lang/StringBuffer"; jclass stringBufferClass = env->FindClass(stringBufferClassName); - jmethodID appendMethodID = env->GetMethodID(stringBufferClass, + jmethodID appendMethodID = env->GetMethodID(stringBufferClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1); // cut off the leading ';' @@ -669,7 +655,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val return resulting; } -static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, +static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, jobject position) { const char * textUTF = env->GetStringUTFChars(text, NULL); @@ -694,11 +680,11 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, jclass bigDecimalClass = env->FindClass(bigDecimalClassName); jclass bigIntegerClass = env->FindClass(bigIntegerClassName); - jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, + jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, "getIndex", "()I"); - jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, + jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, "setIndex", "(I)V"); - jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, + jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, "setErrorIndex", "(I)V"); jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V"); @@ -710,8 +696,8 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, bool resultAssigned; int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL); - // make sure the ParsePosition is valid. Actually icu4c would parse a number - // correctly even if the parsePosition is set to -1, but since the RI fails + // make sure the ParsePosition is valid. Actually icu4c would parse a number + // correctly even if the parsePosition is set to -1, but since the RI fails // for that case we have to fail too if(parsePos < 0 || parsePos > strlength) { return NULL; @@ -721,9 +707,9 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, const UnicodeString src((UChar*)str, strlength, strlength); ParsePosition pp; - + pp.setIndex(parsePos); - + DigitList digits; ((const DecimalFormat*)fmt)->parse(src, resultAssigned, res, pp, FALSE, digits); @@ -733,8 +719,8 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, if(pp.getErrorIndex() == -1) { parsePos = pp.getIndex(); } else { - env->CallVoidMethod(position, setErrorIndexMethodID, - (jint) pp.getErrorIndex()); + env->CallVoidMethod(position, setErrorIndexMethodID, + (jint) pp.getErrorIndex()); return NULL; } @@ -759,17 +745,17 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, case Formattable::kDouble: resultDouble = res.getDouble(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); - return env->NewObject(doubleClass, dblInitMethodID, + return env->NewObject(doubleClass, dblInitMethodID, (jdouble) resultDouble); case Formattable::kLong: resultLong = res.getLong(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); - return env->NewObject(longClass, longInitMethodID, + return env->NewObject(longClass, longInitMethodID, (jlong) resultLong); case Formattable::kInt64: resultInt64 = res.getInt64(); env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos); - return env->NewObject(longClass, longInitMethodID, + return env->NewObject(longClass, longInitMethodID, (jlong) resultInt64); default: return NULL; @@ -819,7 +805,7 @@ static jint cloneImpl(JNIEnv *env, jclass clazz, jint addr) { static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - {"openDecimalFormatImpl", "(Ljava/lang/String;Ljava/lang/String;)I", + {"openDecimalFormatImpl", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) openDecimalFormatImpl}, {"closeDecimalFormatImpl", "(I)V", (void*) closeDecimalFormatImpl}, {"setSymbol", "(IILjava/lang/String;)V", (void*) setSymbol}, @@ -830,22 +816,22 @@ static JNINativeMethod gMethods[] = { {"getTextAttribute", "(II)Ljava/lang/String;", (void*) getTextAttribute}, {"applyPatternImpl", "(IZLjava/lang/String;)V", (void*) applyPatternImpl}, {"toPatternImpl", "(IZ)Ljava/lang/String;", (void*) toPatternImpl}, - {"format", - "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", + {"format", + "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", (void*) formatLong}, - {"format", - "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", + {"format", + "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", (void*) formatDouble}, - {"format", - "(ILjava/lang/String;Ljava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;I)Ljava/lang/String;", + {"format", + "(ILjava/lang/String;Ljava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;I)Ljava/lang/String;", (void*) formatDigitList}, - {"parse", - "(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;", + {"parse", + "(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;", (void*) parse}, {"cloneImpl", "(I)I", (void*) cloneImpl} }; int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env) { - return jniRegisterNativeMethods(env, - "com/ibm/icu4jni/text/NativeDecimalFormat", gMethods, + return jniRegisterNativeMethods(env, + "com/ibm/icu4jni/text/NativeDecimalFormat", gMethods, NELEM(gMethods)); } diff --git a/luni/src/main/java/java/io/BufferedInputStream.java b/luni/src/main/java/java/io/BufferedInputStream.java index 0b9afc3..1720366 100644 --- a/luni/src/main/java/java/io/BufferedInputStream.java +++ b/luni/src/main/java/java/io/BufferedInputStream.java @@ -108,7 +108,7 @@ public class BufferedInputStream extends FilterInputStream { Logger.global.info( "Default buffer size used in BufferedInputStream " + "constructor. It would be " + - "better to be explicit if an 8k buffer is required."); + "better to be explicit if a 8k buffer is required."); // END android-added } diff --git a/luni/src/main/java/java/io/BufferedOutputStream.java b/luni/src/main/java/java/io/BufferedOutputStream.java index 835d13f..55419d1 100644 --- a/luni/src/main/java/java/io/BufferedOutputStream.java +++ b/luni/src/main/java/java/io/BufferedOutputStream.java @@ -80,7 +80,7 @@ public class BufferedOutputStream extends FilterOutputStream { Logger.global.info( "Default buffer size used in BufferedOutputStream " + "constructor. It would be " + - "better to be explicit if an 8k buffer is required."); + "better to be explicit if a 8k buffer is required."); // END android-added } diff --git a/luni/src/main/java/java/io/BufferedReader.java b/luni/src/main/java/java/io/BufferedReader.java index e82e538..c490b89 100644 --- a/luni/src/main/java/java/io/BufferedReader.java +++ b/luni/src/main/java/java/io/BufferedReader.java @@ -80,7 +80,7 @@ public class BufferedReader extends Reader { Logger.global.info( "Default buffer size used in BufferedReader " + "constructor. It would be " + - "better to be explicit if an 8k-char buffer is required."); + "better to be explicit if a 8k-char buffer is required."); // END android-added } diff --git a/luni/src/main/java/java/io/BufferedWriter.java b/luni/src/main/java/java/io/BufferedWriter.java index 761b9c5..66bfcc9 100644 --- a/luni/src/main/java/java/io/BufferedWriter.java +++ b/luni/src/main/java/java/io/BufferedWriter.java @@ -80,7 +80,7 @@ public class BufferedWriter extends Writer { Logger.global.info( "Default buffer size used in BufferedWriter " + "constructor. It would be " + - "better to be explicit if an 8k-char buffer is required."); + "better to be explicit if a 8k-char buffer is required."); // END android-added } diff --git a/luni/src/main/java/java/util/ArrayList.java b/luni/src/main/java/java/util/ArrayList.java index 3bae372..5ea316a 100644 --- a/luni/src/main/java/java/util/ArrayList.java +++ b/luni/src/main/java/java/util/ArrayList.java @@ -112,7 +112,7 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>, Cloneable, * @param object * the object to add. * @throws IndexOutOfBoundsException - * when {@code location < 0 || > size()} + * when {@code location < 0 || >= size()} * @since Android 1.0 */ @Override diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java index 30510c2..6c995bb 100644 --- a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java +++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java @@ -17,14 +17,15 @@ package org.apache.harmony.luni.tests.java.lang; +import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; import junit.framework.TestCase; import java.io.UnsupportedEncodingException; -import java.math.BigDecimal; +import java.lang.reflect.Constructor; @TestTargetClass(String.class) public class StringTest extends TestCase { @@ -700,40 +701,4 @@ public class StringTest extends TestCase { } catch (IndexOutOfBoundsException e) { } } - - @TestTargetNew( - level = TestLevel.ADDITIONAL, - notes = "Regression test for some existing bugs and crashes", - method = "format", - args = { String.class, Object.class } - ) - public void testProblemCases() { - BigDecimal[] input = new BigDecimal[] { - new BigDecimal("20.00000"), - new BigDecimal("20.000000"), - new BigDecimal(".2"), - new BigDecimal("2"), - new BigDecimal("-2"), - new BigDecimal("200000000000000000000000"), - new BigDecimal("20000000000000000000000000000000000000000000000000") - }; - - String[] output = new String[] { - "20.00", - "20.00", - "0.20", - "2.00", - "-2.00", - "200000000000000000000000.00", - "20000000000000000000000000000000000000000000000000.00" - }; - - for (int i = 0; i < input.length; i++) { - String result = String.format("%.2f", input[i]); - assertEquals("Format test for \"" + input[i] + "\" failed, " + - "expected=" + output[i] + ", " + - "actual=" + result, output[i], result); - } - } - } diff --git a/run-core-tests b/run-core-tests index 25e53ee..3656e2d 100755 --- a/run-core-tests +++ b/run-core-tests @@ -26,5 +26,6 @@ mkdir $tmp chmod 777 $tmp exec dalvikvm -Duser.language=en -Duser.region=US -Djava.io.tmpdir=$tmp \ - -Xbootclasspath:$BOOTCLASSPATH:/system/framework/core-tests.jar \ + -Xbootclasspath:$BOOTCLASSPATH \ + -classpath /system/framework/core-tests.jar \ com.google.coretests.Main "$@" diff --git a/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java index 8f0d08b..035e924 100644 --- a/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java +++ b/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java @@ -66,17 +66,6 @@ public class X509NameTokenizer { if (escaped || quoted) { - // BEGIN android-added - // copied from a newer version of BouncyCastle - if (c == '#' && buf.charAt(buf.length() - 1) == '=') - { - buf.append('\\'); - } - else if (c == '+' && seperator != '+') - { - buf.append('\\'); - } - // END android-added buf.append(c); escaped = false; } @@ -99,4 +88,4 @@ public class X509NameTokenizer index = end; return buf.toString().trim(); } -}
\ No newline at end of file +} diff --git a/x-net/src/main/java/javax/net/ssl/SSLSocketFactory.java b/x-net/src/main/java/javax/net/ssl/SSLSocketFactory.java index 2b7c03e..cb821c2 100644 --- a/x-net/src/main/java/javax/net/ssl/SSLSocketFactory.java +++ b/x-net/src/main/java/javax/net/ssl/SSLSocketFactory.java @@ -24,7 +24,6 @@ import java.security.Security; // BEGIN android-added import java.lang.reflect.Method; import java.net.UnknownHostException; -import java.util.logging.Logger; // END android-added import javax.net.SocketFactory; @@ -58,56 +57,60 @@ public abstract class SSLSocketFactory extends SocketFactory { * @since Android 1.0 */ public static SocketFactory getDefault() { - synchronized (SSLSocketFactory.class) { - if (defaultSocketFactory != null) { - // BEGIN android-added - log("SSLSocketFactory", "Using factory " + defaultSocketFactory); - // END android-added - return defaultSocketFactory; - } - if (defaultName == null) { - AccessController.doPrivileged(new java.security.PrivilegedAction(){ - public Object run() { - defaultName = Security.getProperty("ssl.SocketFactory.provider"); - if (defaultName != null) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (cl == null) { - cl = ClassLoader.getSystemClassLoader(); - } - try { - defaultSocketFactory = (SocketFactory) Class.forName( - defaultName, true, cl).newInstance(); - } catch (Exception e) { - return e; - } - } - return null; - } - }); - } - - if (defaultSocketFactory == null) { - // Try to find in providers - SSLContext context = DefaultSSLContext.getContext(); - if (context != null) { - defaultSocketFactory = context.getSocketFactory(); - } - } - if (defaultSocketFactory == null) { - // Use internal implementation - defaultSocketFactory = new DefaultSSLSocketFactory("No SSLSocketFactory installed"); - } + if (defaultSocketFactory != null) { // BEGIN android-added log("SSLSocketFactory", "Using factory " + defaultSocketFactory); // END android-added return defaultSocketFactory; } + if (defaultName == null) { + AccessController.doPrivileged(new java.security.PrivilegedAction(){ + public Object run() { + defaultName = Security.getProperty("ssl.SocketFactory.provider"); + if (defaultName != null) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + try { + defaultSocketFactory = (SocketFactory) Class.forName( + defaultName, true, cl).newInstance(); + } catch (Exception e) { + return e; + } + } + return null; + } + }); + } + + if (defaultSocketFactory == null) { + // Try to find in providers + SSLContext context = DefaultSSLContext.getContext(); + if (context != null) { + defaultSocketFactory = context.getSocketFactory(); + } + } + if (defaultSocketFactory == null) { + // Use internal implementation + defaultSocketFactory = new DefaultSSLSocketFactory("No SSLSocketFactory installed"); + } + // BEGIN android-added + log("SSLSocketFactory", "Using factory " + defaultSocketFactory); + // END android-added + return defaultSocketFactory; } // BEGIN android-added @SuppressWarnings("unchecked") private static void log(String tag, String msg) { - Logger.getLogger(tag).info(msg); + try { + Class clazz = Class.forName("android.util.Log"); + Method method = clazz.getMethod("d", new Class[] { String.class, String.class }); + method.invoke(null, new Object[] { tag, msg }); + } catch (Exception ex) { + // Silently ignore. + } } // END android-added diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java deleted file mode 100644 index a95d38f..0000000 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import java.util.*; -import java.util.logging.Level; -import java.io.*; - -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionContext; -import javax.security.cert.X509Certificate; -import javax.security.cert.CertificateEncodingException; -import javax.security.cert.CertificateException; - -/** - * Supports SSL session caches. - */ -abstract class AbstractSessionContext implements SSLSessionContext { - - volatile int maximumSize; - volatile int timeout; - - final SSLParameters parameters; - - /** Identifies OpenSSL sessions. */ - static final int OPEN_SSL = 1; - - /** - * Constructs a new session context. - * - * @param parameters - * @param maximumSize of cache - * @param timeout for cache entries - */ - AbstractSessionContext(SSLParameters parameters, int maximumSize, - int timeout) { - this.parameters = parameters; - this.maximumSize = maximumSize; - this.timeout = timeout; - } - - /** - * Returns the collection of sessions ordered by least-recently-used first. - */ - abstract Iterator<SSLSession> sessionIterator(); - - public final Enumeration getIds() { - final Iterator<SSLSession> iterator = sessionIterator(); - return new Enumeration<byte[]>() { - public boolean hasMoreElements() { - return iterator.hasNext(); - } - public byte[] nextElement() { - return iterator.next().getId(); - } - }; - } - - public final int getSessionCacheSize() { - return maximumSize; - } - - public final int getSessionTimeout() { - return timeout; - } - - /** - * Makes sure cache size is < maximumSize. - */ - abstract void trimToSize(); - - public final void setSessionCacheSize(int size) - throws IllegalArgumentException { - if (size < 0) { - throw new IllegalArgumentException("size < 0"); - } - - int oldMaximum = maximumSize; - maximumSize = size; - - // Trim cache to size if necessary. - if (size < oldMaximum) { - trimToSize(); - } - } - - /** - * Converts the given session to bytes. - * - * @return session data as bytes or null if the session can't be converted - */ - byte[] toBytes(SSLSession session) { - // TODO: Support SSLSessionImpl, too. - if (!(session instanceof OpenSSLSessionImpl)) { - return null; - } - - OpenSSLSessionImpl sslSession = (OpenSSLSessionImpl) session; - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DataOutputStream daos = new DataOutputStream(baos); - - daos.writeInt(OPEN_SSL); // session type ID - - // Session data. - byte[] data = sslSession.getEncoded(); - daos.writeInt(data.length); - daos.write(data); - - // Certificates. - X509Certificate[] certs = session.getPeerCertificateChain(); - daos.writeInt(certs.length); - - // TODO: Call nativegetpeercertificates() - for (X509Certificate cert : certs) { - data = cert.getEncoded(); - daos.writeInt(data.length); - daos.write(data); - } - - return baos.toByteArray(); - } catch (IOException e) { - log(e); - return null; - } catch (CertificateEncodingException e) { - log(e); - return null; - } - } - - /** - * Creates a session from the given bytes. - * - * @return a session or null if the session can't be converted - */ - SSLSession toSession(byte[] data, String host, int port) { - ByteArrayInputStream bais = new ByteArrayInputStream(data); - DataInputStream dais = new DataInputStream(bais); - try { - int type = dais.readInt(); - if (type != OPEN_SSL) { - log(new AssertionError("Unexpected type ID: " + type)); - return null; - } - - int length = dais.readInt(); - byte[] sessionData = new byte[length]; - dais.readFully(sessionData); - - int count = dais.readInt(); - X509Certificate[] certs = new X509Certificate[count]; - for (int i = 0; i < count; i++) { - length = dais.readInt(); - byte[] certData = new byte[length]; - dais.readFully(certData); - certs[i] = X509Certificate.getInstance(certData); - } - - return new OpenSSLSessionImpl(sessionData, parameters, host, port, - certs, this); - } catch (IOException e) { - log(e); - return null; - } catch (CertificateException e) { - log(e); - return null; - } - } - - static void log(Throwable t) { - java.util.logging.Logger.global.log(Level.WARNING, - "Error converting session.", t); - } - - /** - * Byte array wrapper. Implements equals() and hashCode(). - */ - static class ByteArray { - - private final byte[] bytes; - - ByteArray(byte[] bytes) { - this.bytes = bytes; - } - - @Override - public int hashCode() { - return Arrays.hashCode(bytes); - } - - @Override - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") - public boolean equals(Object o) { - ByteArray other = (ByteArray) o; - return Arrays.equals(bytes, other.bytes); - } - } -}
\ No newline at end of file diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java index 55a06f5..8419096 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java @@ -613,18 +613,22 @@ public class ClientHandshakeImpl extends HandshakeProtocol { host = engineOwner.getPeerHost(); port = engineOwner.getPeerPort(); } + // END android-changed if (host == null || port == -1) { return null; // starts new session } - ClientSessionContext context = parameters.getClientSessionContext(); - SSLSessionImpl session - = (SSLSessionImpl) context.getSession(host, port); - if (session != null) { - session = (SSLSessionImpl) session.clone(); + byte[] id; + SSLSession ses; + SSLSessionContext context = parameters.getClientSessionContext(); + for (Enumeration en = context.getIds(); en.hasMoreElements();) { + id = (byte[])en.nextElement(); + ses = context.getSession(id); + if (host.equals(ses.getPeerHost()) && port == ses.getPeerPort()) { + return (SSLSessionImpl)((SSLSessionImpl)ses).clone(); // resume + } } - return session; - // END android-changed + return null; // starts new session } } diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java deleted file mode 100644 index 2c8738f..0000000 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.HashMap; -import java.util.ArrayList; -import java.util.Arrays; - -import javax.net.ssl.SSLSession; - -/** - * Caches client sessions. Indexes by host and port. Users are typically - * looking to reuse any session for a given host and port. Users of the - * standard API are forced to iterate over the sessions semi-linearly as - * opposed to in constant time. - */ -public class ClientSessionContext extends AbstractSessionContext { - - /* - * We don't care about timeouts in the client implementation. Trying - * to reuse an expired session and having to start a new one requires no - * more effort than starting a new one, so you might as well try to reuse - * one on the off chance it's still valid. - */ - - /** Sessions indexed by host and port in access order. */ - final Map<HostAndPort, SSLSession> sessions - = new LinkedHashMap<HostAndPort, SSLSession>() { - @Override - protected boolean removeEldestEntry( - Map.Entry<HostAndPort, SSLSession> eldest) { - // Called while lock is held on sessions. - boolean remove = maximumSize > 0 && size() > maximumSize; - if (remove) { - removeById(eldest.getValue()); - } - return remove; - } - }; - - /** - * Sessions indexed by ID. Initialized on demand. Protected from concurrent - * access by holding a lock on sessions. - */ - Map<ByteArray, SSLSession> sessionsById; - - final SSLClientSessionCache persistentCache; - - public ClientSessionContext(SSLParameters parameters, - SSLClientSessionCache persistentCache) { - super(parameters, 10, 0); - this.persistentCache = persistentCache; - } - - public final void setSessionTimeout(int seconds) - throws IllegalArgumentException { - if (seconds < 0) { - throw new IllegalArgumentException("seconds < 0"); - } - timeout = seconds; - } - - Iterator<SSLSession> sessionIterator() { - synchronized (sessions) { - SSLSession[] array = sessions.values().toArray( - new SSLSession[sessions.size()]); - return Arrays.asList(array).iterator(); - } - } - - void trimToSize() { - synchronized (sessions) { - int size = sessions.size(); - if (size > maximumSize) { - int removals = size - maximumSize; - Iterator<SSLSession> i = sessions.values().iterator(); - do { - removeById(i.next()); - i.remove(); - } while (--removals > 0); - } - } - } - - void removeById(SSLSession session) { - if (sessionsById != null) { - sessionsById.remove(new ByteArray(session.getId())); - } - } - - /** - * {@inheritDoc} - * - * @see #getSession(String, int) for an implementation-specific but more - * efficient approach - */ - public SSLSession getSession(byte[] sessionId) { - /* - * This method is typically used in conjunction with getIds() to - * iterate over the sessions linearly, so it doesn't make sense for - * it to impact access order. - * - * It also doesn't load sessions from the persistent cache as doing - * so would likely force every session to load. - */ - - ByteArray id = new ByteArray(sessionId); - synchronized (sessions) { - indexById(); - return sessionsById.get(id); - } - } - - /** - * Ensures that the ID-based index is initialized. - */ - private void indexById() { - if (sessionsById == null) { - sessionsById = new HashMap<ByteArray, SSLSession>(); - for (SSLSession session : sessions.values()) { - sessionsById.put(new ByteArray(session.getId()), session); - } - } - } - - /** - * Adds the given session to the ID-based index if the index has already - * been initialized. - */ - private void indexById(SSLSession session) { - if (sessionsById != null) { - sessionsById.put(new ByteArray(session.getId()), session); - } - } - - /** - * Finds a cached session for the given host name and port. - * - * @param host of server - * @param port of server - * @return cached session or null if none found - */ - public SSLSession getSession(String host, int port) { - synchronized (sessions) { - SSLSession session = sessions.get(new HostAndPort(host, port)); - if (session != null) { - return session; - } - } - - // Look in persistent cache. - if (persistentCache != null) { - byte[] data = persistentCache.getSessionData(host, port); - if (data != null) { - SSLSession session = toSession(data, host, port); - if (session != null) { - synchronized (sessions) { - sessions.put(new HostAndPort(host, port), session); - indexById(session); - } - return session; - } - } - } - - return null; - } - - void putSession(SSLSession session) { - HostAndPort key = new HostAndPort(session.getPeerHost(), - session.getPeerPort()); - synchronized (sessions) { - sessions.put(key, session); - indexById(session); - } - - // TODO: This in a background thread. - if (persistentCache != null) { - byte[] data = toBytes(session); - if (data != null) { - persistentCache.putSessionData(session, data); - } - } - } - - static class HostAndPort { - final String host; - final int port; - - HostAndPort(String host, int port) { - this.host = host; - this.port = port; - } - - @Override - public int hashCode() { - return host.hashCode() * 31 + port; - } - - @Override - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") - public boolean equals(Object o) { - HostAndPort other = (HostAndPort) o; - return host.equals(other.host) && port == other.port; - } - } -} diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java deleted file mode 100644 index ab097e4..0000000 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import javax.net.ssl.SSLSession; -import java.util.Map; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Set; -import java.util.TreeSet; -import java.util.Iterator; -import java.util.Arrays; -import java.util.logging.Level; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * File-based cache implementation. Only one process should access the - * underlying directory at a time. - */ -public class FileClientSessionCache { - - static final int MAX_SIZE = 20; - - static final java.util.logging.Logger logger - = java.util.logging.Logger.getLogger( - FileClientSessionCache.class.getName()); - - private FileClientSessionCache() {} - - /** - * This cache creates one file per SSL session using "host.port" for - * the file name. Files are created or replaced when session data is put - * in the cache (see {@link #putSessionData}). Files are read on - * cache hits, but not on cache misses. - * - * <p>When the number of session files exceeds MAX_SIZE, we delete the - * least-recently-used file. We don't current persist the last access time, - * so the ordering actually ends up being least-recently-modified in some - * cases and even just "not accessed in this process" if the filesystem - * doesn't track last modified times. - */ - static class Impl implements SSLClientSessionCache { - - /** Directory to store session files in. */ - final File directory; - - /** - * Map of name -> File. Keeps track of the order files were accessed in. - */ - Map<String, File> accessOrder = newAccessOrder(); - - /** The number of files on disk. */ - int size; - - /** - * The initial set of files. We use this to defer adding information - * about all files to accessOrder until necessary. - */ - String[] initialFiles; - - /** - * Constructs a new cache backed by the given directory. - */ - Impl(File directory) throws IOException { - boolean exists = directory.exists(); - if (exists && !directory.isDirectory()) { - throw new IOException(directory - + " exists but is not a directory."); - } - - if (exists) { - // Read and sort initial list of files. We defer adding - // information about these files to accessOrder until necessary - // (see indexFiles()). Sorting the list enables us to detect - // cache misses in getSessionData(). - // Note: Sorting an array here was faster than creating a - // HashSet on Dalvik. - initialFiles = directory.list(); - Arrays.sort(initialFiles); - size = initialFiles.length; - } else { - // Create directory. - if (!directory.mkdirs()) { - throw new IOException("Creation of " + directory - + " directory failed."); - } - size = 0; - } - - this.directory = directory; - } - - /** - * Creates a new access-ordered linked hash map. - */ - private static Map<String, File> newAccessOrder() { - return new LinkedHashMap<String, File>( - MAX_SIZE, 0.75f, true /* access order */); - } - - /** - * Gets the file name for the given host and port. - */ - private static String fileName(String host, int port) { - if (host == null) { - throw new NullPointerException("host"); - } - return host + "." + port; - } - - public synchronized byte[] getSessionData(String host, int port) { - /* - * Note: This method is only called when the in-memory cache - * in SSLSessionContext misses, so it would be unnecesarily - * rendundant for this cache to store data in memory. - */ - - String name = fileName(host, port); - File file = accessOrder.get(name); - - if (file == null) { - // File wasn't in access order. Check initialFiles... - if (initialFiles == null) { - // All files are in accessOrder, so it doesn't exist. - return null; - } - - // Look in initialFiles. - if (Arrays.binarySearch(initialFiles, name) < 0) { - // Not found. - return null; - } - - // The file is on disk but not in accessOrder yet. - file = new File(directory, name); - accessOrder.put(name, file); - } - - FileInputStream in; - try { - in = new FileInputStream(file); - } catch (FileNotFoundException e) { - logReadError(host, e); - return null; - } - try { - int size = (int) file.length(); - byte[] data = new byte[size]; - new DataInputStream(in).readFully(data); - logger.log(Level.FINE, "Read session for " + host + "."); - return data; - } catch (IOException e) { - logReadError(host, e); - return null; - } finally { - try { - in.close(); - } catch (IOException e) { /* ignore */ } - } - } - - static void logReadError(String host, Throwable t) { - logger.log(Level.INFO, "Error reading session data for " + host - + ".", t); - } - - public synchronized void putSessionData(SSLSession session, - byte[] sessionData) { - String host = session.getPeerHost(); - if (sessionData == null) { - throw new NullPointerException("sessionData"); - } - - String name = fileName(host, session.getPeerPort()); - File file = new File(directory, name); - - // Used to keep track of whether or not we're expanding the cache. - boolean existedBefore = file.exists(); - - FileOutputStream out; - try { - out = new FileOutputStream(file); - } catch (FileNotFoundException e) { - // We can't write to the file. - logWriteError(host, e); - return; - } - - // If we expanded the cache (by creating a new file)... - if (!existedBefore) { - size++; - - // Delete an old file if necessary. - makeRoom(); - } - - boolean writeSuccessful = false; - try { - out.write(sessionData); - writeSuccessful = true; - } catch (IOException e) { - logWriteError(host, e); - } finally { - boolean closeSuccessful = false; - try { - out.close(); - closeSuccessful = true; - } catch (IOException e) { - logWriteError(host, e); - } finally { - if (!writeSuccessful || !closeSuccessful) { - // Storage failed. Clean up. - delete(file); - } else { - // Success! - accessOrder.put(name, file); - logger.log(Level.FINE, "Stored session for " + host - + "."); - } - } - } - } - - /** - * Deletes old files if necessary. - */ - private void makeRoom() { - if (size <= MAX_SIZE) { - return; - } - - indexFiles(); - - // Delete LRUed files. - int removals = size - MAX_SIZE; - Iterator<File> i = accessOrder.values().iterator(); - do { - delete(i.next()); - i.remove(); - } while (--removals > 0); - } - - /** - * Lazily updates accessOrder to know about all files as opposed to - * just the files accessed since this process started. - */ - private void indexFiles() { - String[] initialFiles = this.initialFiles; - if (initialFiles != null) { - this.initialFiles = null; - - // Files on disk only, sorted by last modified time. - // TODO: Use last access time. - Set<CacheFile> diskOnly = new TreeSet<CacheFile>(); - for (String name : initialFiles) { - // If the file hasn't been accessed in this process... - if (!accessOrder.containsKey(name)) { - diskOnly.add(new CacheFile(directory, name)); - } - } - - if (!diskOnly.isEmpty()) { - // Add files not accessed in this process to the beginning - // of accessOrder. - Map<String, File> newOrder = newAccessOrder(); - for (CacheFile cacheFile : diskOnly) { - newOrder.put(cacheFile.name, cacheFile); - } - newOrder.putAll(accessOrder); - - this.accessOrder = newOrder; - } - } - } - - @SuppressWarnings("ThrowableInstanceNeverThrown") - private void delete(File file) { - if (!file.delete()) { - logger.log(Level.INFO, "Failed to delete " + file + ".", - new IOException()); - } - size--; - } - - static void logWriteError(String host, Throwable t) { - logger.log(Level.INFO, "Error writing session data for " - + host + ".", t); - } - } - - /** - * Maps directories to the cache instances that are backed by those - * directories. We synchronize access using the cache instance, so it's - * important that everyone shares the same instance. - */ - static final Map<File, FileClientSessionCache.Impl> caches - = new HashMap<File, FileClientSessionCache.Impl>(); - - /** - * Returns a cache backed by the given directory. Creates the directory - * (including parent directories) if necessary. This cache should have - * exclusive access to the given directory. - * - * @param directory to store files in - * @return a cache backed by the given directory - * @throws IOException if the file exists and is not a directory or if - * creating the directories fails - */ - public static synchronized SSLClientSessionCache usingDirectory( - File directory) throws IOException { - FileClientSessionCache.Impl cache = caches.get(directory); - if (cache == null) { - cache = new FileClientSessionCache.Impl(directory); - caches.put(directory, cache); - } - return cache; - } - - /** For testing. */ - static synchronized void reset() { - caches.clear(); - } - - /** A file containing a piece of cached data. */ - static class CacheFile extends File { - - final String name; - - CacheFile(File dir, String name) { - super(dir, name); - this.name = name; - } - - long lastModified = -1; - - @Override - public long lastModified() { - long lastModified = this.lastModified; - if (lastModified == -1) { - lastModified = this.lastModified = super.lastModified(); - } - return lastModified; - } - - @Override - public int compareTo(File another) { - // Sort by last modified time. - long result = lastModified() - another.lastModified(); - if (result == 0) { - return super.compareTo(another); - } - return result < 0 ? -1 : 1; - } - } -}
\ No newline at end of file diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java index e985908..4fc6e99 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java @@ -302,8 +302,7 @@ public class OpenSSLServerSocketImpl extends javax.net.ssl.SSLServerSocket { @Override public Socket accept() throws IOException { - OpenSSLSocketImpl socket - = new OpenSSLSocketImpl(sslParameters, ssl_op_no); + OpenSSLSocketImpl socket = new OpenSSLSocketImpl(sslParameters, ssl_op_no); implAccept(socket); socket.accept(ssl_ctx, client_mode); diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java index ca7d6f8..475d388 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java @@ -23,7 +23,6 @@ import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Iterator; -import java.util.UnknownFormatConversionException; import java.util.Vector; import javax.net.ssl.SSLPeerUnverifiedException; @@ -56,41 +55,21 @@ public class OpenSSLSessionImpl implements SSLSession { private SSLParameters sslParameters; private String peerHost; private int peerPort; - private final SSLSessionContext sessionContext; /** * Class constructor creates an SSL session context given the appropriate * SSL parameters. - * - * @param session the Identifier for SSL session * @param sslParameters the SSL parameters like ciphers' suites etc. + * @param ssl the Identifier for SSL session */ - protected OpenSSLSessionImpl(int session, SSLParameters sslParameters, - String peerHost, int peerPort, SSLSessionContext sessionContext) { + protected OpenSSLSessionImpl(int session, SSLParameters sslParameters, String peerHost, int peerPort) { this.session = session; this.sslParameters = sslParameters; this.peerHost = peerHost; this.peerPort = peerPort; - this.sessionContext = sessionContext; } /** - * Constructs a session from a byte[]. - */ - OpenSSLSessionImpl(byte[] derData, SSLParameters sslParameters, - String peerHost, int peerPort, - javax.security.cert.X509Certificate[] peerCertificateChain, - SSLSessionContext sessionContext) - throws IOException { - this.sslParameters = sslParameters; - this.peerHost = peerHost; - this.peerPort = peerPort; - this.peerCertificateChain = peerCertificateChain; - this.sessionContext = sessionContext; - initializeNative(derData); - } - - /** * Returns the identifier of the actual OpenSSL session. */ private native byte[] nativegetid(); @@ -111,40 +90,6 @@ public class OpenSSLSessionImpl implements SSLSession { private native long nativegetcreationtime(); /** - * Serialize the native state of the session ( ID, cypher, keys - but - * not certs ), using openSSL i2d_SSL_SESSION() - * - * @return the DER encoding of the session. - */ - private native byte[] nativeserialize(); - - /** - * Create a SSL_SESSION object using d2i_SSL_SESSION. - */ - private native int nativedeserialize(byte[] data, int size); - - /** - * Get the session object in DER format. This allows saving the session - * data or sharing it with other processes. - */ - byte[] getEncoded() { - return nativeserialize(); - } - - /** - * Init the underlying native object from DER data. This - * allows loading the saved session. - * @throws IOException - */ - private void initializeNative(byte[] derData) throws IOException { - this.session = nativedeserialize(derData, derData.length); - if (this.session == 0) { - throw new IOException("Invalid session data"); - } - } - - - /** * Gets the creation time of the SSL session. * @return the session's creation time in milli seconds since 12.00 PM, * January 1st, 1970 @@ -392,7 +337,7 @@ public class OpenSSLSessionImpl implements SSLSession { if (sm != null) { sm.checkPermission(new SSLPermission("getSSLSessionContext")); } - return sessionContext; + return sslParameters.getClientSessionContext(); } /** @@ -402,7 +347,7 @@ public class OpenSSLSessionImpl implements SSLSession { * @return true if this session may be resumed. */ public boolean isValid() { - SSLSessionContext context = sessionContext; + SSLSessionContextImpl context = sslParameters.getClientSessionContext(); if (isValid && context != null && context.getSessionTimeout() != 0 @@ -427,7 +372,7 @@ public class OpenSSLSessionImpl implements SSLSession { * of security, by the full machinery of the <code>AccessController</code> * class. * - * @param name the name of the binding to find. + * @param <code>String name</code> the name of the binding to find. * @return the value bound to that name, or null if the binding does not * exist. * @throws <code>IllegalArgumentException</code> if the argument is null. @@ -471,9 +416,9 @@ public class OpenSSLSessionImpl implements SSLSession { * -data bounds are monitored, as a matter of security, by the full * machinery of the <code>AccessController</code> class. * - * @param name the name of the link (no null are + * @param <code>String name</code> the name of the link (no null are * accepted!) - * @param value data object that shall be bound to + * @param <code>Object value</code> data object that shall be bound to * name. * @throws <code>IllegalArgumentException</code> if one or both * argument(s) is null. @@ -499,7 +444,7 @@ public class OpenSSLSessionImpl implements SSLSession { * monitored, as a matter of security, by the full machinery of the * <code>AccessController</code> class. * - * @param name the name of the link (no null are + * @param <code>String name</code> the name of the link (no null are * accepted!) * @throws <code>IllegalArgumentException</code> if the argument is null. */ diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java index 8779736..1d38ca9 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.lang.reflect.Method; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; @@ -30,6 +31,7 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; +import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; @@ -56,7 +58,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { private int ssl; private InputStream is; private OutputStream os; - private final Object handshakeLock = new Object(); + private Object handshakeLock = new Object(); private Object readLock = new Object(); private Object writeLock = new Object(); private SSLParameters sslParameters; @@ -64,7 +66,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { private Socket socket; private boolean autoClose; private boolean handshakeStarted = false; - private ArrayList<HandshakeCompletedListener> listeners; + private ArrayList listeners; private long ssl_op_no = 0x00000000L; private int timeout = 0; private InetSocketAddress address; @@ -135,11 +137,11 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Class constructor with 2 parameters * - * @param sslParameters Parameters for the SSL + * @param <code>SSLParameters sslParameters</code> Parameters for the SSL * context - * @param ssl_op_no Parameter to set the enabled + * @param <code>long ssl_op_no</code> Parameter to set the enabled * protocols - * @throws IOException if network fails + * @throws <code>IOException</code> if network fails */ protected OpenSSLSocketImpl(SSLParameters sslParameters, long ssl_op_no) throws IOException { super(); @@ -151,9 +153,9 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Class constructor with 1 parameter * - * @param sslParameters Parameters for the SSL + * @param <code>SSLParameters sslParameters</code> Parameters for the SSL * context - * @throws IOException if network fails + * @throws <code>IOException</code> if network fails */ protected OpenSSLSocketImpl(SSLParameters sslParameters) throws IOException { super(); @@ -165,8 +167,11 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Class constructor with 3 parameters * - * @throws IOException if network fails - * @throws java.net.UnknownHostException host not defined + * @param <code> String host</code> + * @param <code>int port</code> + * @param <code>SSLParameters sslParameters</code> + * @throws <code>IOException</code> if network fails + * @throws <code>UnknownHostException</code> host not defined */ protected OpenSSLSocketImpl(String host, int port, SSLParameters sslParameters) @@ -181,8 +186,11 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Class constructor with 3 parameters: 1st is InetAddress * - * @throws IOException if network fails - * @throws java.net.UnknownHostException host not defined + * @param <code>InetAddress address</code> + * @param <code>int port</code> + * @param <code>SSLParameters sslParameters</code> + * @throws <code>IOException</code> if network fails + * @throws <code>UnknownHostException</code> host not defined */ protected OpenSSLSocketImpl(InetAddress address, int port, SSLParameters sslParameters) @@ -197,8 +205,13 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Class constructor with 5 parameters: 1st is host * - * @throws IOException if network fails - * @throws java.net.UnknownHostException host not defined + * @param <code>String host</code> + * @param <code>int port</code> + * @param <code>InetAddress localHost</code> + * @param <code>int localPort</code> + * @param <code>SSLParameters sslParameters</code> + * @throws <code>IOException</code> if network fails + * @throws <code>UnknownHostException</code> host not defined */ protected OpenSSLSocketImpl(String host, int port, InetAddress clientAddress, int clientPort, SSLParameters sslParameters) @@ -212,8 +225,13 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Class constructor with 5 parameters: 1st is InetAddress * - * @throws IOException if network fails - * @throws java.net.UnknownHostException host not defined + * @param <code>InetAddress address</code> + * @param <code>int port</code> + * @param <code>InetAddress localAddress</code> + * @param <code>int localPort</code> + * @param <code>SSLParameters sslParameters</code> + * @throws <code>IOException</code> if network fails + * @throws <code>UnknownHostException</code> host not defined */ protected OpenSSLSocketImpl(InetAddress address, int port, InetAddress clientAddress, int clientPort, SSLParameters sslParameters) @@ -228,7 +246,12 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * Constructor with 5 parameters: 1st is socket. Enhances an existing socket * with SSL functionality. * - * @throws IOException if network fails + * @param <code>Socket socket</code> + * @param <code>String host</code> + * @param <code>int port</code> + * @param <code>boolean autoClose</code> + * @param <code>SSLParameters sslParameters</code> + * @throws <code>IOException</code> if network fails */ protected OpenSSLSocketImpl(Socket socket, String host, int port, boolean autoClose, SSLParameters sslParameters) throws IOException { @@ -255,26 +278,26 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * * @return OpenSSLSessionImpl */ - private OpenSSLSessionImpl getCachedClientSession() { - if (super.getInetAddress() == null || - super.getInetAddress().getHostAddress() == null || - super.getInetAddress().getHostName() == null) { - return null; + private OpenSSLSessionImpl getOpenSSLSessionImpl() { + try { + byte[] id; + SSLSession ses; + for (Enumeration<byte[]> en = sslParameters.getClientSessionContext().getIds(); en.hasMoreElements();) { + id = en.nextElement(); + ses = sslParameters.getClientSessionContext().getSession(id); + if (ses instanceof OpenSSLSessionImpl && ses.isValid() && + super.getInetAddress() != null && + super.getInetAddress().getHostAddress() != null && + super.getInetAddress().getHostName().equals(ses.getPeerHost()) && + super.getPort() == ses.getPeerPort()) { + return (OpenSSLSessionImpl) ses; + } + } + } catch (Exception ex) { + // It's not clear to me under what circumstances the above code + // might fail. I also can't reproduce it. } - ClientSessionContext sessionContext - = sslParameters.getClientSessionContext(); - return (OpenSSLSessionImpl) sessionContext.getSession( - super.getInetAddress().getHostName(), - super.getPort()); - } - - /** - * Ensures that logger is lazily loaded. The outer class seems to load - * before logging is ready. - */ - static class LoggerHolder { - static final Logger logger = Logger.getLogger( - OpenSSLSocketImpl.class.getName()); + return null; } /** @@ -294,60 +317,38 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { return; } } - - OpenSSLSessionImpl session = getCachedClientSession(); + + { + // Debug + int size = 0; + for (Enumeration<byte[]> en = sslParameters.getClientSessionContext().getIds(); + en.hasMoreElements(); en.nextElement()) { size++; }; + } + OpenSSLSessionImpl session = getOpenSSLSessionImpl(); // Check if it's allowed to create a new session (default is true) - if (session == null && !sslParameters.getEnableSessionCreation()) { + if (!sslParameters.getEnableSessionCreation() && session == null) { throw new SSLHandshakeException("SSL Session may not be created"); } else { - Socket socket = this.socket != null ? this.socket : this; - int sessionId = session != null ? session.session : 0; - if (nativeconnect(ssl_ctx, socket, sslParameters.getUseClientMode(), - sessionId)) { - // nativeconnect shouldn't return true if the session is not - // done + if (nativeconnect(ssl_ctx, this.socket != null ? + this.socket : this, sslParameters.getUseClientMode(), session != null ? session.session : 0)) { session.lastAccessedTime = System.currentTimeMillis(); sslSession = session; - - LoggerHolder.logger.fine("Reused cached session for " - + getInetAddress().getHostName() + "."); } else { - if (session != null) { - LoggerHolder.logger.fine("Reuse of cached session for " - + getInetAddress().getHostName() + " failed."); - } else { - LoggerHolder.logger.fine("Created new session for " - + getInetAddress().getHostName() + "."); - } - - ClientSessionContext sessionContext - = sslParameters.getClientSessionContext(); - if (address == null) { - sslSession = new OpenSSLSessionImpl( - nativegetsslsession(ssl), sslParameters, - super.getInetAddress().getHostName(), - super.getPort(), sessionContext); - } else { - sslSession = new OpenSSLSessionImpl( - nativegetsslsession(ssl), sslParameters, - address.getHostName(), address.getPort(), - sessionContext); - } - + if (address == null) sslSession = new OpenSSLSessionImpl(nativegetsslsession(ssl), + sslParameters, super.getInetAddress().getHostName(), super.getPort()); + else sslSession = new OpenSSLSessionImpl(nativegetsslsession(ssl), + sslParameters, address.getHostName(), address.getPort()); try { - X509Certificate[] peerCertificates = (X509Certificate[]) - sslSession.getPeerCertificates(); + X509Certificate[] peerCertificates = (X509Certificate[]) sslSession.getPeerCertificates(); - if (peerCertificates == null - || peerCertificates.length == 0) { + if (peerCertificates == null || peerCertificates.length == 0) { throw new SSLException("Server sends no certificate"); } - sslParameters.getTrustManager().checkServerTrusted( - peerCertificates, - nativecipherauthenticationmethod()); - sessionContext.putSession(sslSession); + sslParameters.getTrustManager().checkServerTrusted(peerCertificates, + nativecipherauthenticationmethod()); + sslParameters.getClientSessionContext().putSession(sslSession); } catch (CertificateException e) { throw new SSLException("Not trusted server certificate", e); } @@ -359,8 +360,9 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { HandshakeCompletedEvent event = new HandshakeCompletedEvent(this, sslSession); int size = listeners.size(); - for (int i = 0; i < size; i++) { - listeners.get(i).handshakeCompleted(event); + for (int i=0; i<size; i++) { + ((HandshakeCompletedListener)listeners.get(i)) + .handshakeCompleted(event); } } } @@ -379,27 +381,22 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { nativeaccept(this, m_ctx, client_mode); - ServerSessionContext sessionContext - = sslParameters.getServerSessionContext(); sslSession = new OpenSSLSessionImpl(nativegetsslsession(ssl), - sslParameters, super.getInetAddress().getHostName(), - super.getPort(), sessionContext); + sslParameters, super.getInetAddress().getHostName(), super.getPort()); sslSession.lastAccessedTime = System.currentTimeMillis(); - sessionContext.putSession(sslSession); } /** * Callback methode for the OpenSSL native certificate verification process. * - * @param bytes Byte array containing the cert's + * @param <code>byte[][] bytes</code> Byte array containing the cert's * information. * @return 0 if the certificate verification fails or 1 if OK */ @SuppressWarnings("unused") private int verify_callback(byte[][] bytes) { try { - X509Certificate[] peerCertificateChain - = new X509Certificate[bytes.length]; + X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length]; for(int i = 0; i < bytes.length; i++) { peerCertificateChain[i] = new X509CertImpl(javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded()); @@ -585,6 +582,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * Registers a listener to be notified that a SSL handshake * was successfully completed on this connection. + * @param <code>HandShakeCompletedListener listener</code> * @throws <code>IllegalArgumentException</code> if listener is null. */ public void addHandshakeCompletedListener( @@ -600,6 +598,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * The method removes a registered listener. + * @param <code>HandShakeCompletedListener listener</code> * @throws IllegalArgumentException if listener is null or not registered */ public void removeHandshakeCompletedListener( @@ -632,7 +631,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * SSL sessions. If the flag is set to false, and there are no actual * sessions to resume, then there will be no successful handshaking. * - * @param flag true if session may be created; false + * @param <code>boolean flag</code> true if session may be created; false * if a session already exists and must be resumed. */ public void setEnableSessionCreation(boolean flag) { @@ -684,9 +683,9 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * This method enables the cipher suites listed by * getSupportedCipherSuites(). * - * @param suites names of all the cipher suites to + * @param <code> String[] suites</code> names of all the cipher suites to * put on use - * @throws IllegalArgumentException when one or more of the + * @throws <code>IllegalArgumentException</code> when one or more of the * ciphers in array suites are not supported, or when the array * is null. */ @@ -782,9 +781,9 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { /** * This method set the actual SSL socket to client mode. * - * @param mode true if the socket starts in client + * @param <code>boolean mode</code> true if the socket starts in client * mode - * @throws IllegalArgumentException if mode changes during + * @throws <code>IllegalArgumentException</code> if mode changes during * handshake. */ public synchronized void setUseClientMode(boolean mode) { @@ -819,7 +818,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * Sets the SSL socket to use client's authentication. Relevant only for * server sockets! * - * @param need true if client authentication is + * @param <code>boolean need</code> true if client authentication is * desired, false if not. */ public void setNeedClientAuth(boolean need) { @@ -832,7 +831,7 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * method will continue the negotiation if the client decide not to send * authentication credentials. * - * @param want true if client authentication is + * @param <code>boolean want</code> true if client authentication is * desired, false if not. */ public void setWantClientAuth(boolean want) { @@ -879,9 +878,6 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { * socket's closure. */ public void close() throws IOException { - // TODO: Close SSL sockets using a background thread so they close - // gracefully. - synchronized (handshakeLock) { if (!handshakeStarted) { handshakeStarted = true; @@ -991,11 +987,10 @@ public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { } /** - * Helper class for a thread that knows how to call - * {@link OpenSSLSocketImpl#close} on behalf of instances being finalized, - * since that call can take arbitrarily long (e.g., due to a slow network), - * and an overly long-running finalizer will cause the process to be - * totally aborted. + * Helper class for a thread that knows how to call {@link #close} on behalf + * of instances being finalized, since that call can take arbitrarily long + * (e.g., due to a slow network), and an overly long-running finalizer will + * cause the process to be totally aborted. */ private class Finalizer extends Thread { public void run() { diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLClientSessionCache.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLClientSessionCache.java deleted file mode 100644 index 8a73fa5..0000000 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLClientSessionCache.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import javax.net.ssl.SSLSession; - -/** - * A persistent {@link javax.net.ssl.SSLSession} cache used by - * {@link javax.net.ssl.SSLSessionContext} to share client-side SSL sessions - * across processes. For example, this cache enables applications to - * persist and reuse sessions across restarts. - * - * <p>The {@code SSLSessionContext} implementation converts - * {@code SSLSession}s into raw bytes and vice versa. The exact makeup of the - * session data is dependent upon the caller's implementation and is opaque to - * the {@code SSLClientSessionCache} implementation. - */ -public interface SSLClientSessionCache { - - /** - * Gets data from a pre-existing session for a given server host and port. - * - * @param host from {@link javax.net.ssl.SSLSession#getPeerHost()} - * @param port from {@link javax.net.ssl.SSLSession#getPeerPort()} - * @return the session data or null if none is cached - * @throws NullPointerException if host is null - */ - public byte[] getSessionData(String host, int port); - - /** - * Stores session data for the given session. - * - * @param session to cache data for - * @param sessionData to cache - * @throws NullPointerException if session, result of - * {@code session.getPeerHost()} or data is null - */ - public void putSessionData(SSLSession session, byte[] sessionData); -}
\ No newline at end of file diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java index 2e4de04..3f4ab96 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java @@ -22,6 +22,9 @@ package org.apache.harmony.xnet.provider.jsse; +// BEGIN android-removed +// import org.apache.harmony.xnet.provider.jsse.SSLSocketFactoryImpl; +// END android-removed import org.apache.harmony.xnet.provider.jsse.SSLEngineImpl; import org.apache.harmony.xnet.provider.jsse.SSLParameters; // BEGIN android-removed @@ -39,21 +42,19 @@ import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; -// BEGIN android-note -// Modified heavily during SSLSessionContext refactoring. Added support for -// persistent session caches. -// END android-note - /** * Implementation of SSLContext service provider interface. */ public class SSLContextImpl extends SSLContextSpi { - /** Client session cache. */ - private ClientSessionContext clientSessionContext; - - /** Server session cache. */ - private ServerSessionContext serverSessionContext; + // client session context contains the set of reusable + // client-side SSL sessions + private SSLSessionContextImpl clientSessionContext = + new SSLSessionContextImpl(); + // server session context contains the set of reusable + // server-side SSL sessions + private SSLSessionContextImpl serverSessionContext = + new SSLSessionContextImpl(); protected SSLParameters sslParameters; @@ -63,44 +64,26 @@ public class SSLContextImpl extends SSLContextSpi { public void engineInit(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) throws KeyManagementException { - engineInit(kms, tms, sr, null, null); - } - - /** - * Initializes this {@code SSLContext} instance. All of the arguments are - * optional, and the security providers will be searched for the required - * implementations of the needed algorithms. - * - * @param kms the key sources or {@code null} - * @param tms the trust decision sources or {@code null} - * @param sr the randomness source or {@code null} - * @param clientCache persistent client session cache or {@code null} - * @param serverCache persistent server session cache or {@code null} - * @throws KeyManagementException if initializing this instance fails - * - * @since Android 1.1 - */ - public void engineInit(KeyManager[] kms, TrustManager[] tms, - SecureRandom sr, SSLClientSessionCache clientCache, - SSLServerSessionCache serverCache) throws KeyManagementException { - sslParameters = new SSLParameters(kms, tms, sr, - clientCache, serverCache); - clientSessionContext = sslParameters.getClientSessionContext(); - serverSessionContext = sslParameters.getServerSessionContext(); + sslParameters = new SSLParameters(kms, tms, sr, clientSessionContext, + serverSessionContext); } public SSLSocketFactory engineGetSocketFactory() { if (sslParameters == null) { throw new IllegalStateException("SSLContext is not initiallized."); } + // BEGIN android-changed return new OpenSSLSocketFactoryImpl(sslParameters); + // END android-changed } public SSLServerSocketFactory engineGetServerSocketFactory() { if (sslParameters == null) { throw new IllegalStateException("SSLContext is not initiallized."); } + // BEGIN android-changed return new OpenSSLServerSocketFactoryImpl(sslParameters); + // END android-changed } public SSLEngine engineCreateSSLEngine(String host, int port) { @@ -118,11 +101,12 @@ public class SSLContextImpl extends SSLContextSpi { return new SSLEngineImpl((SSLParameters) sslParameters.clone()); } - public ServerSessionContext engineGetServerSessionContext() { + public SSLSessionContext engineGetServerSessionContext() { return serverSessionContext; } - public ClientSessionContext engineGetClientSessionContext() { + public SSLSessionContext engineGetClientSessionContext() { return clientSessionContext; } -}
\ No newline at end of file +} + diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParameters.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParameters.java index 60a5535..9a14f46 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParameters.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParameters.java @@ -22,6 +22,8 @@ package org.apache.harmony.xnet.provider.jsse; +import org.apache.harmony.xnet.provider.jsse.SSLSessionContextImpl; + import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -43,9 +45,7 @@ import javax.net.ssl.X509TrustManager; * and controls whether new SSL sessions may be established by this * socket or not. */ -// BEGIN android-changed -public class SSLParameters implements Cloneable { -// END android-changed +public class SSLParameters { // default source of authentication keys private static X509KeyManager defaultKeyManager; @@ -58,12 +58,10 @@ public class SSLParameters implements Cloneable { // client session context contains the set of reusable // client-side SSL sessions -// BEGIN android-changed - private final ClientSessionContext clientSessionContext; + private SSLSessionContextImpl clientSessionContext; // server session context contains the set of reusable // server-side SSL sessions - private final ServerSessionContext serverSessionContext; -// END android-changed + private SSLSessionContextImpl serverSessionContext; // source of authentication keys private X509KeyManager keyManager; // source of authentication trust decisions @@ -90,7 +88,16 @@ public class SSLParameters implements Cloneable { // if the peer with this parameters allowed to cteate new SSL session private boolean enable_session_creation = true; -// BEGIN android-changed + /** + * Creates an instance of SSLParameters. + */ + private SSLParameters() { + // BEGIN android-removed + // this.enabledCipherSuites = CipherSuite.defaultCipherSuites; + // END android-removed + } + + // BEGIN android-added protected CipherSuite[] getEnabledCipherSuitesMember() { if (enabledCipherSuites == null) this.enabledCipherSuites = CipherSuite.defaultCipherSuites; return enabledCipherSuites; @@ -113,26 +120,23 @@ public class SSLParameters implements Cloneable { if (ssl_ctx == 0) ssl_ctx = nativeinitsslctx(); return ssl_ctx; } -// END android-changed + // END android-added /** * Initializes the parameters. Naturally this constructor is used * in SSLContextImpl.engineInit method which dirrectly passes its * parameters. In other words this constructor holds all * the functionality provided by SSLContext.init method. - * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[], - * SecureRandom)} for more information + * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[],SecureRandom)} + * for more information */ protected SSLParameters(KeyManager[] kms, TrustManager[] tms, -// BEGIN android-changed - SecureRandom sr, SSLClientSessionCache clientCache, - SSLServerSessionCache serverCache) + SecureRandom sr, SSLSessionContextImpl clientSessionContext, + SSLSessionContextImpl serverSessionContext) throws KeyManagementException { - this.serverSessionContext - = new ServerSessionContext(this, serverCache); - this.clientSessionContext - = new ClientSessionContext(this, clientCache); -// END android-changed + this(); + this.serverSessionContext = serverSessionContext; + this.clientSessionContext = clientSessionContext; try { // initialize key manager boolean initialize_default = false; @@ -224,9 +228,8 @@ public class SSLParameters implements Cloneable { protected static SSLParameters getDefault() throws KeyManagementException { if (defaultParameters == null) { -// BEGIN android-changed - defaultParameters = new SSLParameters(null, null, null, null, null); -// END android-changed + defaultParameters = new SSLParameters(null, null, null, + new SSLSessionContextImpl(), new SSLSessionContextImpl()); } return (SSLParameters) defaultParameters.clone(); } @@ -234,18 +237,14 @@ public class SSLParameters implements Cloneable { /** * @return server session context */ -// BEGIN android-changed - protected ServerSessionContext getServerSessionContext() { -// END android-changed + protected SSLSessionContextImpl getServerSessionContext() { return serverSessionContext; } /** * @return client session context */ -// BEGIN android-changed - protected ClientSessionContext getClientSessionContext() { -// END android-changed + protected SSLSessionContextImpl getClientSessionContext() { return clientSessionContext; } @@ -336,7 +335,7 @@ public class SSLParameters implements Cloneable { /** * Sets the set of available protocols for use in SSL connection. - * @param protocols String[] + * @param suites: String[] */ protected void setEnabledProtocols(String[] protocols) { if (protocols == null) { @@ -423,13 +422,23 @@ public class SSLParameters implements Cloneable { * @return the clone. */ protected Object clone() { -// BEGIN android-changed - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(e); - } -// END android-changed + SSLParameters parameters = new SSLParameters(); + + parameters.clientSessionContext = clientSessionContext; + parameters.serverSessionContext = serverSessionContext; + parameters.keyManager = keyManager; + parameters.trustManager = trustManager; + parameters.secureRandom = secureRandom; + + parameters.enabledCipherSuites = enabledCipherSuites; + parameters.enabledProtocols = enabledProtocols; + + parameters.client_mode = client_mode; + parameters.need_client_auth = need_client_auth; + parameters.want_client_auth = want_client_auth; + parameters.enable_session_creation = enable_session_creation; + + return parameters; } } diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLServerSessionCache.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLServerSessionCache.java deleted file mode 100644 index 32a0e72..0000000 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLServerSessionCache.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import javax.net.ssl.SSLSession; - -/** - * A persistent {@link javax.net.ssl.SSLSession} cache used by - * {@link javax.net.ssl.SSLSessionContext} to share server-side SSL sessions - * across processes. For example, this cache enables one server to resume - * a session started by a different server based on a session ID provided - * by the client. - * - * <p>The {@code SSLSessionContext} implementation converts - * {@code SSLSession}s into raw bytes and vice versa. The exact makeup of the - * session data is dependent upon the caller's implementation and is opaque to - * the {@code SSLServerSessionCache} implementation. - */ -public interface SSLServerSessionCache { - - /** - * Gets the session data for given session ID. - * - * @param id from {@link javax.net.ssl.SSLSession#getId()} - * @return the session data or null if none is cached - * @throws NullPointerException if id is null - */ - public byte[] getSessionData(byte[] id); - - /** - * Stores session data for the given session. - * - * @param session to cache data for - * @param sessionData to cache - * @throws NullPointerException if session or data is null - */ - public void putSessionData(SSLSession session, byte[] sessionData); -}
\ No newline at end of file diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java new file mode 100644 index 0000000..6882aa1 --- /dev/null +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionContextImpl.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Boris Kuznetsov + * @version $Revision$ + */ +package org.apache.harmony.xnet.provider.jsse; + +import java.nio.ByteBuffer; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +/** + * SSLSessionContext implementation + * + * @see javax.net.ssl.SSLSessionContext + */ +public class SSLSessionContextImpl implements SSLSessionContext { + + private int cacheSize = 20; + private long timeout = 0; + private final LinkedHashMap<ByteBuffer, SSLSession> sessions = + new LinkedHashMap<ByteBuffer, SSLSession>(cacheSize, 0.75f, true) { + @Override + public boolean removeEldestEntry( + Map.Entry<ByteBuffer, SSLSession> eldest) { + return cacheSize > 0 && this.size() > cacheSize; + } + }; + private volatile LinkedHashMap<ByteBuffer, SSLSession> clone = + new LinkedHashMap<ByteBuffer, SSLSession>(); + + /** + * @see javax.net.ssl.SSLSessionContext#getIds() + */ + public Enumeration<byte[]> getIds() { + return new Enumeration<byte[]>() { + Iterator<ByteBuffer> iterator = clone.keySet().iterator(); + public boolean hasMoreElements() { + return iterator.hasNext(); + } + public byte[] nextElement() { + return iterator.next().array(); + } + }; + } + + /** + * @see javax.net.ssl.SSLSessionContext#getSession(byte[] sessionId) + */ + public SSLSession getSession(byte[] sessionId) { + synchronized (sessions) { + return sessions.get(ByteBuffer.wrap(sessionId)); + } + } + + /** + * @see javax.net.ssl.SSLSessionContext#getSessionCacheSize() + */ + public int getSessionCacheSize() { + synchronized (sessions) { + return cacheSize; + } + } + + /** + * @see javax.net.ssl.SSLSessionContext#getSessionTimeout() + */ + public int getSessionTimeout() { + synchronized (sessions) { + return (int) (timeout/1000); + } + } + + /** + * @see javax.net.ssl.SSLSessionContext#setSessionCacheSize(int size) + */ + public void setSessionCacheSize(int size) throws IllegalArgumentException { + if (size < 0) { + throw new IllegalArgumentException("size < 0"); + } + synchronized (sessions) { + cacheSize = size; + if (cacheSize > 0 && cacheSize < sessions.size()) { + int removals = sessions.size() - cacheSize; + Iterator<ByteBuffer> iterator = sessions.keySet().iterator(); + while (removals-- > 0) { + iterator.next(); + iterator.remove(); + } + clone = (LinkedHashMap<ByteBuffer, SSLSession>) + sessions.clone(); + } + } + } + + /** + * @see javax.net.ssl.SSLSessionContext#setSessionTimeout(int seconds) + */ + public void setSessionTimeout(int seconds) throws IllegalArgumentException { + if (seconds < 0) { + throw new IllegalArgumentException("seconds < 0"); + } + synchronized (sessions) { + timeout = seconds*1000; + // Check timeouts and remove expired sessions + SSLSession ses; + Iterator<Map.Entry<ByteBuffer, SSLSession>> iterator = + sessions.entrySet().iterator(); + while (iterator.hasNext()) { + SSLSession session = iterator.next().getValue(); + if (!session.isValid()) { + // safe to remove with this special method since it doesn't + // make the iterator throw a ConcurrentModificationException + iterator.remove(); + } + } + clone = (LinkedHashMap<ByteBuffer, SSLSession>) sessions.clone(); + } + } + + /** + * Adds session to the session cache + * @param ses + */ + void putSession(SSLSession ses) { + synchronized (sessions) { + sessions.put(ByteBuffer.wrap(ses.getId()), ses); + clone = (LinkedHashMap<ByteBuffer, SSLSession>) sessions.clone(); + } + } +} diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionImpl.java index 4510c96..df46094 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionImpl.java @@ -40,6 +40,7 @@ import javax.net.ssl.SSLSessionBindingListener; import javax.net.ssl.SSLSessionContext; import org.apache.harmony.luni.util.TwoKeyHashMap; +import org.apache.harmony.xnet.provider.jsse.SSLSessionContextImpl; /** * @@ -82,9 +83,8 @@ public class SSLSessionImpl implements SSLSession { /** * Context of the session */ -// BEGIN android-changed - SSLSessionContext context; -// END android-changed + SSLSessionContextImpl context; + /** * certificates were sent to the peer diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java index f6eef23..93dc9c4 100644 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java +++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java @@ -81,6 +81,7 @@ public class ServerHandshakeImpl extends HandshakeProtocol { /** * Start session negotiation + * @param session */ public void start() { if (session == null) { // initial handshake @@ -298,7 +299,7 @@ public class ServerHandshakeImpl extends HandshakeProtocol { clientFinished = new Finished(io_stream, length); verifyFinished(clientFinished.getData()); // BEGIN android-added - session.context = parameters.getServerSessionContext(); + session.context = parameters.getClientSessionContext(); // END android-added parameters.getServerSessionContext().putSession(session); if (!isResuming) { diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java deleted file mode 100644 index a3c2c6d..0000000 --- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Iterator; -import java.util.ArrayList; -import java.util.Arrays; - -import javax.net.ssl.SSLSession; - -/** - * Caches server sessions. Indexes by session ID. Users typically look up - * sessions using the ID provided by an SSL client. - */ -public class ServerSessionContext extends AbstractSessionContext { - - /* - * TODO: Expire timed-out sessions more pro-actively. - */ - - private final Map<ByteArray, SSLSession> sessions - = new LinkedHashMap<ByteArray, SSLSession>() { - @Override - protected boolean removeEldestEntry( - Map.Entry<ByteArray, SSLSession> eldest) { - return maximumSize > 0 && size() > maximumSize; - } - }; - - private final SSLServerSessionCache persistentCache; - - public ServerSessionContext(SSLParameters parameters, - SSLServerSessionCache persistentCache) { - super(parameters, 100, 0); - this.persistentCache = persistentCache; - } - - Iterator<SSLSession> sessionIterator() { - synchronized (sessions) { - SSLSession[] array = sessions.values().toArray( - new SSLSession[sessions.size()]); - return Arrays.asList(array).iterator(); - } - } - - void trimToSize() { - synchronized (sessions) { - int size = sessions.size(); - if (size > maximumSize) { - int removals = size - maximumSize; - Iterator<SSLSession> i = sessions.values().iterator(); - do { - i.next(); - i.remove(); - } while (--removals > 0); - } - } - } - - public void setSessionTimeout(int seconds) - throws IllegalArgumentException { - if (seconds < 0) { - throw new IllegalArgumentException("seconds < 0"); - } - timeout = seconds; - } - - public SSLSession getSession(byte[] sessionId) { - ByteArray key = new ByteArray(sessionId); - synchronized (sessions) { - SSLSession session = sessions.get(key); - if (session != null) { - return session; - } - } - - // Check persistent cache. - if (persistentCache != null) { - byte[] data = persistentCache.getSessionData(sessionId); - if (data != null) { - SSLSession session = toSession(data, null, -1); - if (session != null) { - synchronized (sessions) { - sessions.put(key, session); - } - return session; - } - } - } - - return null; - } - - void putSession(SSLSession session) { - ByteArray key = new ByteArray(session.getId()); - synchronized (sessions) { - sessions.put(key, session); - } - - // TODO: In background thread. - if (persistentCache != null) { - byte[] data = toBytes(session); - if (data != null) { - persistentCache.putSessionData(session, data); - } - } - } -} diff --git a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp index feae690..0c0e455 100644 --- a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp +++ b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp @@ -61,7 +61,7 @@ static void throwIOExceptionStr(JNIEnv* env, const char* message) } /** - * Gets the peer certificate in the chain and fills a byte array with the + * Gets the peer certificate in the chain and fills a byte array with the * information therein. */ static jobjectArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeercertificates(JNIEnv* env, @@ -91,62 +91,7 @@ static jobjectArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_get } /** - * Serialize the session. - * See apache mod_ssl - */ -static jbyteArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_serialize(JNIEnv* env, jobject object) -{ - SSL_SESSION * ssl_session; - jbyteArray bytes = NULL; - jbyte *tmp; - int size; - unsigned char *ucp; - - ssl_session = getSslSessionPointer(env, object); - if (ssl_session == NULL) { - return NULL; - } - - // Compute the size of the DER data - size = i2d_SSL_SESSION(ssl_session, NULL); - if (size == 0) { - return NULL; - } - - bytes = env->NewByteArray(size); - if (bytes != NULL) { - tmp = env->GetByteArrayElements(bytes, NULL); - ucp = (unsigned char *) tmp; - i2d_SSL_SESSION(ssl_session, &ucp); - env->ReleaseByteArrayElements(bytes, tmp, 0); - } - - return bytes; - -} - -/** - * Deserialize the session. - */ -static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_deserialize(JNIEnv* env, jobject object, jbyteArray bytes, jint size) -{ - const unsigned char *ucp; - jbyte *tmp; - SSL_SESSION *ssl_session; - - if (bytes != NULL) { - tmp = env->GetByteArrayElements(bytes, NULL); - ucp = (const unsigned char *) tmp; - ssl_session = d2i_SSL_SESSION(NULL, &ucp, (long) size); - env->ReleaseByteArrayElements(bytes, tmp, 0); - - return (jint) ssl_session; - } - return 0; -} - -/** - * Gets and returns in a byte array the ID of the actual SSL session. + * Gets and returns in a byte array the ID of the actual SSL session. */ static jbyteArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getid(JNIEnv* env, jobject object) { @@ -167,8 +112,8 @@ static jbyteArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getid } /** - * Gets and returns in a long integer the creation's time of the - * actual SSL session. + * Gets and returns in a long integer the creation's time of the + * actual SSL session. */ static jlong org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getcreationtime(JNIEnv* env, jobject object) { @@ -181,7 +126,7 @@ static jlong org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getcreatio } /** - * Gets and returns in a string the peer's host's name. + * Gets and returns in a string the peer's host's name. */ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerhost(JNIEnv* env, jobject object) { @@ -213,7 +158,7 @@ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerh } /** - * Gets and returns in a string the peer's port name (https, ftp, etc.). + * Gets and returns in a string the peer's port name (https, ftp, etc.). */ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerport(JNIEnv* env, jobject object) { @@ -234,7 +179,7 @@ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerp bio = SSL_get_rbio(ssl); port = BIO_get_conn_port(bio); - /* Notice: port name can be NULL */ + /* Notice: port name can be NULL */ result = env->NewStringUTF(port); SSL_free(ssl); @@ -244,7 +189,7 @@ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeerp } /** - * Gets and returns in a string the version of the SSL protocol. If it + * Gets and returns in a string the version of the SSL protocol. If it * returns the string "unknown" it means that no connection is established. */ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getprotocol(JNIEnv* env, jobject object) @@ -273,7 +218,7 @@ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getproto } /** - * Gets and returns in a string the set of ciphers the actual SSL session uses. + * Gets and returns in a string the set of ciphers the actual SSL session uses. */ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getciphersuite(JNIEnv* env, jobject object) { @@ -319,9 +264,7 @@ static JNINativeMethod sMethods[] = {"nativegetprotocol", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getprotocol}, {"nativegetciphersuite", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getciphersuite}, {"nativegetpeercertificates", "()[[B", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getpeercertificates}, - {"nativefree", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_free}, - {"nativeserialize", "()[B", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_serialize}, - {"nativedeserialize", "([BI)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_deserialize} + {"nativefree", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_free} }; /** diff --git a/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContextTest.java b/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContextTest.java deleted file mode 100644 index af4490b..0000000 --- a/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContextTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import junit.framework.TestCase; - -import javax.net.ssl.SSLSession; -import java.util.Enumeration; -import java.util.Set; -import java.util.HashSet; - -public class ClientSessionContextTest extends TestCase { - - public void testGetSessionById() { - ClientSessionContext context = new ClientSessionContext(null, null); - - SSLSession a = new FakeSession("a"); - SSLSession b = new FakeSession("b"); - - context.putSession(a); - context.putSession(b); - - assertSame(a, context.getSession("a".getBytes())); - assertSame(b, context.getSession("b".getBytes())); - - assertSame(a, context.getSession("a", 443)); - assertSame(b, context.getSession("b", 443)); - - assertEquals(2, context.sessions.size()); - - Set<SSLSession> sessions = new HashSet<SSLSession>(); - Enumeration ids = context.getIds(); - while (ids.hasMoreElements()) { - sessions.add(context.getSession((byte[]) ids.nextElement())); - } - - Set<SSLSession> expected = new HashSet<SSLSession>(); - expected.add(a); - expected.add(b); - - assertEquals(expected, sessions); - } - - public void testTrimToSize() { - ClientSessionContext context = new ClientSessionContext(null, null); - - FakeSession a = new FakeSession("a"); - FakeSession b = new FakeSession("b"); - FakeSession c = new FakeSession("c"); - FakeSession d = new FakeSession("d"); - - context.putSession(a); - context.putSession(b); - context.putSession(c); - context.putSession(d); - - context.setSessionCacheSize(2); - - Set<SSLSession> sessions = new HashSet<SSLSession>(); - Enumeration ids = context.getIds(); - while (ids.hasMoreElements()) { - sessions.add(context.getSession((byte[]) ids.nextElement())); - } - - Set<SSLSession> expected = new HashSet<SSLSession>(); - expected.add(c); - expected.add(d); - - assertEquals(expected, sessions); - } - -} diff --git a/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/FakeSession.java b/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/FakeSession.java deleted file mode 100644 index 4a793dd..0000000 --- a/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/FakeSession.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionContext; -import java.security.cert.Certificate; -import java.security.Principal; - -class FakeSession implements SSLSession { - final String host; - - FakeSession(String host) { - this.host = host; - } - - public int getApplicationBufferSize() { - throw new UnsupportedOperationException(); - } - - public String getCipherSuite() { - throw new UnsupportedOperationException(); - } - - public long getCreationTime() { - throw new UnsupportedOperationException(); - } - - public byte[] getId() { - return host.getBytes(); - } - - public long getLastAccessedTime() { - throw new UnsupportedOperationException(); - } - - public Certificate[] getLocalCertificates() { - throw new UnsupportedOperationException(); - } - - public Principal getLocalPrincipal() { - throw new UnsupportedOperationException(); - } - - public int getPacketBufferSize() { - throw new UnsupportedOperationException(); - } - - public javax.security.cert.X509Certificate[] getPeerCertificateChain() { - throw new UnsupportedOperationException(); - } - - public Certificate[] getPeerCertificates() { - throw new UnsupportedOperationException(); - } - - public String getPeerHost() { - return host; - } - - public int getPeerPort() { - return 443; - } - - public Principal getPeerPrincipal() { - throw new UnsupportedOperationException(); - } - - public String getProtocol() { - throw new UnsupportedOperationException(); - } - - public SSLSessionContext getSessionContext() { - throw new UnsupportedOperationException(); - } - - public Object getValue(String name) { - throw new UnsupportedOperationException(); - } - - public String[] getValueNames() { - throw new UnsupportedOperationException(); - } - - public void invalidate() { - throw new UnsupportedOperationException(); - } - - public boolean isValid() { - throw new UnsupportedOperationException(); - } - - public void putValue(String name, Object value) { - throw new UnsupportedOperationException(); - } - - public void removeValue(String name) { - throw new UnsupportedOperationException(); - } -} diff --git a/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCacheTest.java b/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCacheTest.java deleted file mode 100644 index ee50863..0000000 --- a/x-net/src/test/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCacheTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.xnet.provider.jsse; - -import junit.framework.TestCase; - -import java.io.File; -import java.io.IOException; - -public class FileClientSessionCacheTest extends TestCase { - - public void testMaxSize() throws IOException, InterruptedException { - String tmpDir = System.getProperty("java.io.tmpdir"); - if (tmpDir == null) { - fail("Please set 'java.io.tmpdir' system property."); - } - File cacheDir = new File(tmpDir - + "/" + FileClientSessionCacheTest.class.getName() + "/cache"); - final SSLClientSessionCache cache - = FileClientSessionCache.usingDirectory(cacheDir); - Thread[] threads = new Thread[10]; - final int iterations = FileClientSessionCache.MAX_SIZE * 10; - for (int i = 0; i < threads.length; i++) { - final int id = i; - threads[i] = new Thread() { - @Override - public void run() { - for (int i = 0; i < iterations; i++) { - cache.putSessionData(new FakeSession(id + "." + i), - new byte[10]); - } - } - }; - } - for (int i = 0; i < threads.length; i++) { - threads[i].start(); - } - for (int i = 0; i < threads.length; i++) { - threads[i].join(); - } - assertEquals(FileClientSessionCache.MAX_SIZE, cacheDir.list().length); - } -} |