summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/gnu
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu')
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/Vio.java5
-rw-r--r--libjava/classpath/gnu/CORBA/CollocatedOrbs.java164
-rw-r--r--libjava/classpath/gnu/CORBA/Connected_objects.java10
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java6
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/Ext.java6
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NameParser.java3
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java6
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java42
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/TransientContext.java4
-rw-r--r--libjava/classpath/gnu/CORBA/OrbFunctional.java122
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/LocalRequest.java7
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java2
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuPOA.java4
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java15
-rw-r--r--libjava/classpath/gnu/CORBA/SafeForDirectCalls.java50
-rw-r--r--libjava/classpath/gnu/CORBA/SimpleDelegate.java40
-rw-r--r--libjava/classpath/gnu/classpath/.cvsignore1
-rw-r--r--libjava/classpath/gnu/classpath/ListenerData.java136
-rw-r--r--libjava/classpath/gnu/classpath/SystemProperties.java1
-rw-r--r--libjava/classpath/gnu/classpath/debug/Component.java7
-rw-r--r--libjava/classpath/gnu/classpath/debug/SystemLogger.java41
-rw-r--r--libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java85
-rw-r--r--libjava/classpath/gnu/java/awt/LowPriorityEvent.java48
-rw-r--r--libjava/classpath/gnu/java/awt/color/PyccConverter.java9
-rw-r--r--libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java12
-rw-r--r--libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java6
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java45
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Constants.java61
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java75
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Latin.java177
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java53
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java51
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Scaler.java52
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Script.java62
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java49
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Segment.java47
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Width.java46
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java2
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java17
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/Scaler.java12
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java5
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java6
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java2
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java181
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/QuadSegment.java69
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ShapeCache.java85
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java8
-rw-r--r--libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java14
-rw-r--r--libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java247
-rw-r--r--libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java58
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java283
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java405
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java509
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java130
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java216
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java283
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java149
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java143
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java229
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java8
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java2
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java73
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java22
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java43
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java190
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java112
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java45
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java78
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java209
-rw-r--r--libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java118
-rw-r--r--libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java371
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java11
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java7
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java22
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java6
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java156
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java209
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java11
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java48
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java352
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java2
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java4
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java317
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java32
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java8
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java7
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XFontPeer2.java6
-rw-r--r--libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java292
-rw-r--r--libjava/classpath/gnu/java/io/class-dependencies.conf75
-rw-r--r--libjava/classpath/gnu/java/lang/InstrumentationImpl.java16
-rw-r--r--libjava/classpath/gnu/java/lang/management/BeanImpl.java437
-rw-r--r--libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java45
-rw-r--r--libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java6
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java2
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java17
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java4
-rw-r--r--libjava/classpath/gnu/java/locale/.cvsignore1
-rw-r--r--libjava/classpath/gnu/java/net/DefaultProxySelector.java80
-rw-r--r--libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java252
-rw-r--r--libjava/classpath/gnu/java/net/PlainSocketImpl.java376
-rw-r--r--libjava/classpath/gnu/java/net/local/LocalSocketImpl.java7
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java50
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java40
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/Handler.java46
-rw-r--r--libjava/classpath/gnu/java/nio/DatagramChannelImpl.java165
-rw-r--r--libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java13
-rw-r--r--libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java122
-rw-r--r--libjava/classpath/gnu/java/nio/EpollSelectorImpl.java399
-rw-r--r--libjava/classpath/gnu/java/nio/FileChannelImpl.java (renamed from libjava/classpath/gnu/java/nio/channels/FileChannelImpl.java)173
-rw-r--r--libjava/classpath/gnu/java/nio/FileLockImpl.java2
-rw-r--r--libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java189
-rw-r--r--libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java527
-rw-r--r--libjava/classpath/gnu/java/nio/NIOSocket.java29
-rw-r--r--libjava/classpath/gnu/java/nio/NIOSocketImpl.java110
-rw-r--r--libjava/classpath/gnu/java/nio/PipeImpl.java34
-rw-r--r--libjava/classpath/gnu/java/nio/SelectionKeyImpl.java1
-rw-r--r--libjava/classpath/gnu/java/nio/SelectorImpl.java20
-rw-r--r--libjava/classpath/gnu/java/nio/SelectorProviderImpl.java37
-rw-r--r--libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java39
-rw-r--r--libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java13
-rw-r--r--libjava/classpath/gnu/java/nio/SocketChannelImpl.java262
-rw-r--r--libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java13
-rw-r--r--libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java11
-rw-r--r--libjava/classpath/gnu/java/nio/VMChannelOwner.java57
-rw-r--r--libjava/classpath/gnu/java/rmi/server/ActivatableRef.java8
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java67
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java61
-rw-r--r--libjava/classpath/gnu/java/security/.cvsignore1
-rw-r--r--libjava/classpath/gnu/java/security/Engine.java174
-rw-r--r--libjava/classpath/gnu/java/security/Requires.java59
-rw-r--r--libjava/classpath/gnu/java/security/action/GetPropertyAction.java4
-rw-r--r--libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java4
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java4
-rw-r--r--libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java118
-rw-r--r--libjava/classpath/gnu/java/util/DoubleEnumeration.java12
-rw-r--r--libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java27
-rw-r--r--libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java53
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexed.java17
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java13
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java14
-rw-r--r--libjava/classpath/gnu/java/util/regex/RE.java34
-rw-r--r--libjava/classpath/gnu/java/util/regex/REMatch.java4
-rw-r--r--libjava/classpath/gnu/java/util/regex/RESyntax.java11
-rw-r--r--libjava/classpath/gnu/java/util/regex/REToken.java15
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenChar.java12
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenEnd.java15
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenEndSub.java4
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java8
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenOneOf.java1
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenRepeated.java199
-rw-r--r--libjava/classpath/gnu/javax/crypto/RSACipherImpl.java67
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java39
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java95
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/PKCS7.java4
-rw-r--r--libjava/classpath/gnu/javax/management/Server.java2200
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java956
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java439
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java187
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java177
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java840
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java116
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java116
-rw-r--r--libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java467
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java53
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java597
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java (renamed from libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401Swing.java)78
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java80
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java594
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java130
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java637
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java288
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java83
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java16
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java142
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java101
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/Session.java364
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java59
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java1205
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Alert.java422
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java37
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Builder.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java205
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java)95
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java226
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java113
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java272
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java13
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java56
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java388
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java)22
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java1193
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java283
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java227
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java122
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java129
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java1150
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java315
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java137
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java163
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java75
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java125
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java126
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java51
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java281
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java47
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java72
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Context.java334
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Debug.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java93
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java6
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java107
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java77
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java151
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Extension.java260
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java290
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java159
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Finished.java146
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java490
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java472
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java)55
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java336
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java307
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java356
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java35
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java98
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java57
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java110
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java47
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java59
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java297
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java118
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java73
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Random.java112
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Record.java198
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java232
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java189
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java131
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java315
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java842
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java235
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java233
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java283
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java136
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java108
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java199
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java3515
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java133
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java137
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java833
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java181
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java115
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java116
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java116
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java178
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java151
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java248
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java1377
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java271
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java131
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java311
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java)89
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java50
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java311
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java127
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java163
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Session.java381
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java250
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java198
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Signature.java140
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java146
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java104
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java)69
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java298
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java)72
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Util.java109
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java272
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java95
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java147
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java619
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java30
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java97
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java (renamed from libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java)78
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java64
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java78
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java170
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java60
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java500
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java81
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java62
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java718
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java273
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java80
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java84
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/Length.java283
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/Selector.java244
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java3
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java4
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java5
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java70
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java11
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java38
-rw-r--r--libjava/classpath/gnu/test/.cvsignore1
-rw-r--r--libjava/classpath/gnu/xml/dom/DomAttr.java2
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNode.java3
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java8
-rw-r--r--libjava/classpath/gnu/xml/stream/SAXParser.java15
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java6
-rw-r--r--libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java97
-rw-r--r--libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java111
-rw-r--r--libjava/classpath/gnu/xml/transform/StreamSerializer.java3
-rw-r--r--libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java52
-rw-r--r--libjava/classpath/gnu/xml/transform/XSLURIResolver.java21
-rw-r--r--libjava/classpath/gnu/xml/xpath/Expr.java35
322 files changed, 37967 insertions, 13829 deletions
diff --git a/libjava/classpath/gnu/CORBA/CDR/Vio.java b/libjava/classpath/gnu/CORBA/CDR/Vio.java
index fd878cb3555..28f1c5672f6 100644
--- a/libjava/classpath/gnu/CORBA/CDR/Vio.java
+++ b/libjava/classpath/gnu/CORBA/CDR/Vio.java
@@ -155,7 +155,6 @@ public abstract class Vio
* read(InputStream, Class) or read(InputStream, Serializable).
*
* @param input a stream to read from.
- * @param repository_id a repository id of the object being read, may be null.
*
* @return the loaded value.
*
@@ -173,7 +172,7 @@ public abstract class Vio
* is known. Hence it may be faster to use the alternative methods,
* read(InputStream, Class) or read(InputStream, Serializable).
*
- * @param an_input a stream to read from.
+ * @param input a stream to read from.
* @param repository_id a repository id of the object being read, may be null.
*
* @return the loaded value.
@@ -904,7 +903,7 @@ public abstract class Vio
*
* @param output an output stream to write into.
* @param value a value to write.
- * @param id a value repository id (can be either single string or string
+ * @param ids a value repository id (can be either single string or string
* array).
* @param helper a helper, writing object - specifical part. Can be null if
* the value should be written using other methods.
diff --git a/libjava/classpath/gnu/CORBA/CollocatedOrbs.java b/libjava/classpath/gnu/CORBA/CollocatedOrbs.java
new file mode 100644
index 00000000000..fc1e513efec
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CollocatedOrbs.java
@@ -0,0 +1,164 @@
+/* CollocatedOrbs.java -- Handles collocations
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.CORBA;
+
+import gnu.CORBA.Poa.gnuServantObject;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+
+import org.omg.CORBA.LocalObject;
+import org.omg.CORBA.portable.Delegate;
+import org.omg.CORBA.portable.ObjectImpl;
+
+/**
+ * This class provides support for the direct method invocations without
+ * involving the network in the case when both ORBs run on the same java
+ * virtual machine. Special attention is only needed when call is made
+ * between two independent ORBs, instantiated via ORB.init. The call to the
+ * object, obtained via IOR reference from the ORB where it was locally
+ * connected is always local anyway.
+ *
+ * For security reasons it may be sensible to keep this class and all support
+ * package private.
+ *
+ * @author Audrius Meskauskas
+ */
+class CollocatedOrbs
+{
+ /**
+ * This field is used in automated Classpath specific testing to disable
+ * the direct calls.
+ */
+ static boolean DIRECT_CALLS_ALLOWED = true;
+
+ /**
+ * Containts the references of the all running GNU Classpath ORBs in the
+ * local virtual machine. GNU Classpath ORBs register themselves here when
+ * created and unregister when either ORB.destroy is called or in the
+ * finalizer.
+ */
+ private static ArrayList orbs = new ArrayList();
+
+ /**
+ * The address of the local host.
+ */
+ static String localHost;
+
+ static
+ {
+ try
+ {
+ localHost = InetAddress.getLocalHost().getHostAddress();
+ }
+ catch (UnknownHostException ex)
+ {
+ throw new InternalError("Local host is not accessible:" + ex);
+ }
+ }
+
+ /**
+ * Register the new ORB
+ *
+ * @param orb the orb to register
+ */
+ static void registerOrb(OrbFunctional orb)
+ {
+ if (DIRECT_CALLS_ALLOWED)
+ synchronized (orbs)
+ {
+ assert ! orbs.contains(orb);
+ orbs.add(orb);
+ }
+ }
+
+ /**
+ * Unregister the ORB. The ORB will no longer be reacheable locally but may
+ * be reacheable via network as if it would be remote.
+ *
+ * @param orb the orb to unregister
+ */
+ static void unregisterOrb(OrbFunctional orb)
+ {
+ if (DIRECT_CALLS_ALLOWED)
+ synchronized (orbs)
+ {
+ assert orbs.contains(orb);
+ orbs.remove(orb);
+ }
+ }
+
+ /**
+ * Search the possibly local object. If the IOR is not local or none of the
+ * found ORBs of this virtual machine knows about it, null is returned.
+ *
+ * @param ior the IOR to search
+ * @return the found local CORBA object or null in not found.
+ */
+ static org.omg.CORBA.Object searchLocalObject(IOR ior)
+ {
+ if (! DIRECT_CALLS_ALLOWED && ! ior.Internet.host.equals(localHost))
+ return null;
+
+ synchronized (orbs)
+ {
+ OrbFunctional orb;
+ org.omg.CORBA.Object object;
+ for (int i = 0; i < orbs.size(); i++)
+ {
+ orb = (OrbFunctional) orbs.get(i);
+ object = orb.find_connected_object(ior.key, ior.Internet.port);
+ if (object != null)
+ {
+ if (object instanceof SafeForDirectCalls)
+ {
+ return object;
+ }
+ else if (object instanceof gnuServantObject)
+ {
+ return object;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/CORBA/Connected_objects.java b/libjava/classpath/gnu/CORBA/Connected_objects.java
index ce5761007c0..53ef2dd17d9 100644
--- a/libjava/classpath/gnu/CORBA/Connected_objects.java
+++ b/libjava/classpath/gnu/CORBA/Connected_objects.java
@@ -242,4 +242,14 @@ public class Connected_objects
free_object_number++;
return instance_number;
}
+
+ /**
+ * Get the number of the connected objects.
+ *
+ * @return the size of the internal map.
+ */
+ public int size()
+ {
+ return objects.size();
+ }
} \ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java b/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java
index 79d787083ca..108ca270d21 100644
--- a/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java
+++ b/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java
@@ -1,5 +1,5 @@
/* Binding_iterator.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.CORBA.NamingService;
+import gnu.CORBA.SafeForDirectCalls;
+
import org.omg.CosNaming.Binding;
import org.omg.CosNaming.BindingHolder;
import org.omg.CosNaming.BindingListHolder;
@@ -51,7 +53,7 @@ import org.omg.CosNaming._BindingIteratorImplBase;
* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
*/
public class Binding_iterator_impl
- extends _BindingIteratorImplBase
+ extends _BindingIteratorImplBase implements SafeForDirectCalls
{
/**
* The value, returned by the {@link #next_one} when there
diff --git a/libjava/classpath/gnu/CORBA/NamingService/Ext.java b/libjava/classpath/gnu/CORBA/NamingService/Ext.java
index ee27e68cd79..d339cb194e6 100644
--- a/libjava/classpath/gnu/CORBA/NamingService/Ext.java
+++ b/libjava/classpath/gnu/CORBA/NamingService/Ext.java
@@ -1,5 +1,5 @@
/* TransientContextExt.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.CORBA.NamingService;
+import gnu.CORBA.SafeForDirectCalls;
+
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.Object;
import org.omg.CORBA.portable.Delegate;
@@ -61,7 +63,7 @@ import org.omg.CosNaming._NamingContextExtImplBase;
* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
*/
public class Ext
- extends _NamingContextExtImplBase
+ extends _NamingContextExtImplBase implements SafeForDirectCalls
{
/**
* The older version of the naming context, where all relevant calls
diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameParser.java b/libjava/classpath/gnu/CORBA/NamingService/NameParser.java
index c750b2eb4c0..aa922b96a54 100644
--- a/libjava/classpath/gnu/CORBA/NamingService/NameParser.java
+++ b/libjava/classpath/gnu/CORBA/NamingService/NameParser.java
@@ -193,9 +193,6 @@ public class NameParser
boolean corbaname;
- // The alternative addresses, if given.
- ArrayList alt_addr = new ArrayList();
-
// The version numbers with default values.
int major = 1;
int minor = 0;
diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java b/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java
index 0e0782a5756..d717b9d4011 100644
--- a/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java
+++ b/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java
@@ -1,5 +1,5 @@
/* NameTransformer.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -75,10 +75,6 @@ public class NameTransformer
ArrayList components = new ArrayList();
StringTokenizer st = new StringTokenizer(a_name, "./\\", true);
- String id;
- String kind;
- String next;
-
// Create the buffer array, reserving the last element for null.
String[] n = new String[ st.countTokens() + 1 ];
diff --git a/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java b/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java
index 3669879f22a..a8cd0b313b3 100644
--- a/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java
+++ b/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java
@@ -85,35 +85,26 @@ public class NamingServiceTransient
}
/**
- * Start the naming service on the current host at the given port. The
- * parameter -org.omg.CORBA.ORBInitialPort NNN or -ORBInitialPort NNN, if
- * present, specifies the port, on that the service must be started. If this
- * key is not specified, the service starts at the port 900.
+ * Start the naming service on the current host at the given port.
*
- * The parameter -ior FILE_NAME, if present, forces to store the ior string of
- * this naming service to the specified file.
- *
- * @param args the parameter string.
+ * @param portArgument the port on which the service will be
+ * started, or -1 to use the default port, 900
+ * @param fileArgument if non-null, store the IOR string of this
+ * naming service in a file by this name
*/
- public static void main(String[] args)
+ public static void start(int portArgument, String fileArgument)
{
int port = PORT;
- String iorf = null;
+
+ if (portArgument > -1)
+ port = portArgument;
+
+ String iorf = fileArgument;
try
{
// Create and initialize the ORB
final OrbFunctional orb = new OrbFunctional();
- if (args.length > 1)
- for (int i = 0; i < args.length - 1; i++)
- {
- if (args[i].endsWith("ORBInitialPort"))
- port = Integer.parseInt(args[i + 1]);
-
- if (args[i].equals("-ior"))
- iorf = args[i + 1];
- }
-
OrbFunctional.setPort(port);
// Create the servant and register it with the ORB
@@ -133,15 +124,6 @@ public class NamingServiceTransient
p.close();
}
- System.out.println("GNU Classpath transient naming service "
- + "started at " + iorr.Internet.host + ":" + iorr.Internet.port
- + " key 'NameService'.\n\n"
- + "Copyright (C) 2006 Free Software Foundation\n"
- + "This tool comes with ABSOLUTELY NO WARRANTY. "
- + "This is free software, and you are\nwelcome to "
- + "redistribute it under conditions, defined in "
- + "GNU Classpath license.\n\n" + ior);
-
new Thread()
{
public void run()
@@ -154,7 +136,7 @@ public class NamingServiceTransient
catch (Exception e)
{
System.err.println("ERROR: " + e);
- e.printStackTrace(System.out);
+ e.printStackTrace(System.err);
}
// Restore the default value for allocating ports for the subsequent
diff --git a/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java b/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java
index c2d8275e001..cec87931e28 100644
--- a/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java
+++ b/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java
@@ -54,6 +54,8 @@ import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.CosNaming.NamingContextPackage.NotFoundReason;
import org.omg.CosNaming._NamingContextImplBase;
+import gnu.CORBA.SafeForDirectCalls;
+
import java.util.Iterator;
import java.util.Map;
@@ -69,7 +71,7 @@ import java.util.Map;
*/
public class TransientContext
extends _NamingContextImplBase
- implements NamingContext, NamingContextOperations
+ implements NamingContext, NamingContextOperations, SafeForDirectCalls
{
/**
* Use serial version UID for interoperability.
diff --git a/libjava/classpath/gnu/CORBA/OrbFunctional.java b/libjava/classpath/gnu/CORBA/OrbFunctional.java
index 7b9c34ada12..bfb5e3d86c1 100644
--- a/libjava/classpath/gnu/CORBA/OrbFunctional.java
+++ b/libjava/classpath/gnu/CORBA/OrbFunctional.java
@@ -938,48 +938,55 @@ public class OrbFunctional extends OrbRestricted
/**
* Start the ORBs main working cycle (receive invocation - invoke on the local
- * object - send response - wait for another invocation).
- *
- * The method only returns after calling {@link #shutdown(boolean)}.
+ * object - send response - wait for another invocation). The method only
+ * returns after calling {@link #shutdown(boolean)}.
*/
public void run()
{
- running = true;
-
- // Instantiate the port server for each socket.
- Iterator iter = connected_objects.entrySet().iterator();
- Map.Entry m;
- Connected_objects.cObject obj;
-
- while (iter.hasNext())
+ CollocatedOrbs.registerOrb(this);
+ try
{
- m = (Map.Entry) iter.next();
- obj = (Connected_objects.cObject) m.getValue();
+ running = true;
- portServer subserver;
+ // Instantiate the port server for each socket.
+ Iterator iter = connected_objects.entrySet().iterator();
+ Map.Entry m;
+ Connected_objects.cObject obj;
- if (obj.identity == null)
- {
- subserver = new portServer(obj.port);
- portServers.add(subserver);
- }
- else
- subserver = (portServer) identities.get(obj.identity);
-
- if (!subserver.isAlive())
+ while (iter.hasNext())
{
- // Reuse the current thread for the last portServer.
- if (!iter.hasNext())
+ m = (Map.Entry) iter.next();
+ obj = (Connected_objects.cObject) m.getValue();
+
+ portServer subserver;
+
+ if (obj.identity == null)
{
- // Discard the iterator, eliminating lock checks.
- iter = null;
- subserver.run();
- return;
+ subserver = new portServer(obj.port);
+ portServers.add(subserver);
}
else
- subserver.start();
+ subserver = (portServer) identities.get(obj.identity);
+
+ if (! subserver.isAlive())
+ {
+ // Reuse the current thread for the last portServer.
+ if (! iter.hasNext())
+ {
+ // Discard the iterator, eliminating lock checks.
+ iter = null;
+ subserver.run();
+ return;
+ }
+ else
+ subserver.start();
+ }
}
}
+ finally
+ {
+ CollocatedOrbs.unregisterOrb(this);
+ }
}
/**
@@ -1051,22 +1058,26 @@ public class OrbFunctional extends OrbRestricted
org.omg.CORBA.Object object = find_local_object(ior);
if (object == null)
{
- ObjectImpl impl = StubLocator.search(this, ior);
- try
- {
- if (impl._get_delegate() == null)
- impl._set_delegate(new IorDelegate(this, ior));
- }
- catch (BAD_OPERATION ex)
+ // Check maybe the local object on another ORB, but same VM.
+ object = CollocatedOrbs.searchLocalObject(ior);
+ if (object == null)
{
- // Some colaborants may throw this exception
- // in response to the attempt to get the unset delegate.
- impl._set_delegate(new IorDelegate(this, ior));
- }
+ // Surely remote object.
+ ObjectImpl impl = StubLocator.search(this, ior);
+ try
+ {
+ if (impl._get_delegate() == null)
+ impl._set_delegate(new IorDelegate(this, ior));
+ }
+ catch (BAD_OPERATION ex)
+ {
+ // Some colaborants may throw this exception
+ // in response to the attempt to get the unset delegate.
+ impl._set_delegate(new IorDelegate(this, ior));
+ }
- object = impl;
- // TODO remove commented out code below.
- // connected_objects.add(ior.key, impl, ior.Internet.port, null);
+ object = impl;
+ }
}
return object;
}
@@ -1239,15 +1250,10 @@ public class OrbFunctional extends OrbRestricted
}
if (ior.Id == null)
ior.Id = ref.object.getClass().getName();
- try
- {
- ior.Internet.host = InetAddress.getLocalHost().getHostAddress();
- ior.Internet.port = ref.port;
- }
- catch (UnknownHostException ex)
- {
- throw new BAD_OPERATION("Cannot resolve the local host address");
- }
+
+ ior.Internet.host = CollocatedOrbs.localHost;
+ ior.Internet.port = ref.port;
+
return ior;
}
@@ -1775,4 +1781,14 @@ public class OrbFunctional extends OrbRestricted
running = false;
super.finalize();
}
+
+ /**
+ * Get the number of objects that are connected to this ORB.
+ *
+ * @return the number of objects, connected to this ORB.
+ */
+ public int countConnectedObjects()
+ {
+ return connected_objects.size();
+ }
} \ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java b/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java
index a2c0bb106c3..4a9ef8d9044 100644
--- a/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java
+++ b/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java
@@ -193,11 +193,14 @@ public class LocalRequest extends gnuRequest implements ResponseHandler,
/**
* Make an invocation and return a stream from where the results can be read.
*
- * @param the invoke handler (can be null, then it is obtained self
+ * @param handler the invoke handler (can be null, then it is obtained self
* dependently).
*/
public org.omg.CORBA.portable.InputStream v_invoke(InvokeHandler handler)
{
+ // Check maybe POA is in the discarding mode (will throw TRANSIENT if it is).
+ poa.checkDiscarding();
+
// Local request must be intercepted both by server and request
// interceptors.
boolean s_intercept = false;
@@ -246,7 +249,7 @@ public class LocalRequest extends gnuRequest implements ResponseHandler,
s_interceptor.receive_request_service_contexts(s_info);
}
-
+
if (handler == null)
{
handler = object.getHandler(operation(), cookie, false);
diff --git a/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java b/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java
index bb00aab70eb..4fc51ff154b 100644
--- a/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java
+++ b/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java
@@ -290,4 +290,4 @@ public class ORB_1_4
}
}
-} \ No newline at end of file
+}
diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java b/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java
index 460a0a6029a..8ceec23d781 100644
--- a/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java
+++ b/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java
@@ -1582,7 +1582,7 @@ public class gnuPOA
*
* @throws TRANSIENT if the POA is in discarding mode.
*/
- private void checkDiscarding()
+ void checkDiscarding()
throws TRANSIENT
{
if (m_manager.get_state() == State.DISCARDING)
@@ -1813,4 +1813,4 @@ public class gnuPOA
{
return ref_template_ids;
}
-} \ No newline at end of file
+}
diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java b/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java
index 020897a45b4..77b0ff46792 100644
--- a/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java
+++ b/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java
@@ -129,6 +129,12 @@ public class gnuServantObject extends ObjectImpl
* ids are requested from the servant.
*/
public final String[] repository_ids;
+
+ /**
+ * True indicates that the NO_RETAIN policy applies for the servant.
+ * The servant must be discarded after the each call.
+ */
+ boolean noRetain;
/**
* Create an object with no connected servant. The servant must be set later.
@@ -147,6 +153,8 @@ public class gnuServantObject extends ObjectImpl
manager = a_poa.the_POAManager();
poa = a_poa;
orb = an_orb;
+
+ noRetain = poa.applies(ServantRetentionPolicyValue.NON_RETAIN);
}
/**
@@ -182,6 +190,8 @@ public class gnuServantObject extends ObjectImpl
}
repository_ids = null;
orb = an_orb;
+
+ noRetain = poa != null && poa.applies(ServantRetentionPolicyValue.NON_RETAIN);
}
/**
@@ -222,7 +232,7 @@ public class gnuServantObject extends ObjectImpl
boolean forwarding_allowed
) throws gnuForwardRequest
{
- if (servant != null)
+ if (servant != null && !noRetain)
{
return servantToHandler(servant);
}
@@ -641,13 +651,14 @@ public class gnuServantObject extends ObjectImpl
poa.servant_locator.postinvoke(Id, poa, method,
cookie.value, servant
);
- servant = null;
}
}
}
finally
{
orb.currents.remove(Thread.currentThread());
+ if (noRetain)
+ servant = null;
}
}
catch (ForwardRequest fex)
diff --git a/libjava/classpath/gnu/CORBA/SafeForDirectCalls.java b/libjava/classpath/gnu/CORBA/SafeForDirectCalls.java
new file mode 100644
index 00000000000..f3efb6677f0
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/SafeForDirectCalls.java
@@ -0,0 +1,50 @@
+/* SafeForDirectCalls.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.CORBA;
+
+/**
+ * This interface marks that the object does not modify the passed read only
+ * parameters and hence, if it is local, it is safe to call the methods
+ * directly, without cloning such parameters. Otherwise such parameters should
+ * be cloned.
+ */
+public interface SafeForDirectCalls
+{
+
+}
diff --git a/libjava/classpath/gnu/CORBA/SimpleDelegate.java b/libjava/classpath/gnu/CORBA/SimpleDelegate.java
index c6e20e17374..cb0a7d6034d 100644
--- a/libjava/classpath/gnu/CORBA/SimpleDelegate.java
+++ b/libjava/classpath/gnu/CORBA/SimpleDelegate.java
@@ -98,22 +98,31 @@ public class SimpleDelegate
}
/**
- * Not implemented.
- *
- * @throws NO_IMPLEMENT, always.
+ * Create the request for the local call
*/
public Request create_request(org.omg.CORBA.Object target, Context context,
String operation, NVList parameters,
NamedValue returns
)
{
- throw new NO_IMPLEMENT();
+ if (orb instanceof OrbFunctional)
+ {
+ ((OrbFunctional) orb).ensureRunning();
+ }
+ gnuRequest g = new gnuRequest();
+ g.setORB(orb);
+ g.setOperation(operation);
+ g.setIor(ior);
+ g.m_target = target;
+ g.ctx(context);
+ g.set_args(parameters);
+ if (returns != null)
+ g.set_result(returns);
+ return g;
}
/**
- * Not implemented.
- *
- * @throws NO_IMPLEMENT, always.
+ * Create the request for the local call.
*/
public Request create_request(org.omg.CORBA.Object target, Context context,
String operation, NVList parameters,
@@ -121,7 +130,22 @@ public class SimpleDelegate
ContextList ctx_list
)
{
- throw new NO_IMPLEMENT();
+ if (orb instanceof OrbFunctional)
+ {
+ ((OrbFunctional) orb).ensureRunning();
+ }
+ gnuRequest g = new gnuRequest();
+ g.setORB(orb);
+ g.setOperation(operation);
+ g.setIor(ior);
+ g.m_target = target;
+ g.ctx(context);
+ g.set_args(parameters);
+ g.set_exceptions(exceptions);
+ g.set_context_list(ctx_list);
+ if (returns != null)
+ g.set_result(returns);
+ return g;
}
/**
diff --git a/libjava/classpath/gnu/classpath/.cvsignore b/libjava/classpath/gnu/classpath/.cvsignore
new file mode 100644
index 00000000000..11f6639ebbd
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/.cvsignore
@@ -0,0 +1 @@
+Configuration.java
diff --git a/libjava/classpath/gnu/classpath/ListenerData.java b/libjava/classpath/gnu/classpath/ListenerData.java
new file mode 100644
index 00000000000..284fa02f192
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/ListenerData.java
@@ -0,0 +1,136 @@
+/* ListenerData.java - Class to contain data about management bean listeners
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath;
+
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+
+/**
+ * Container for data on management listeners. Wraps
+ * a {@link javax.management.NotificationListener},
+ * {@link javax.management.NotificationFilter} and
+ * passback object in one class.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class ListenerData
+{
+ /**
+ * The listener itself.
+ */
+ private NotificationListener listener;
+
+ /**
+ * A filter to apply to incoming events.
+ */
+ private NotificationFilter filter;
+
+ /**
+ * An object to pass back to the listener on an
+ * event occurring.
+ */
+ private Object passback;
+
+ /**
+ * Constructs a new {@link ListenerData} with the specified
+ * listener, filter and passback object.
+ *
+ * @param listener the listener itself.
+ * @param filter the filter for incoming events.
+ * @param passback the object to passback on an incoming event.
+ */
+ public ListenerData(NotificationListener listener,
+ NotificationFilter filter, Object passback)
+ {
+ this.listener = listener;
+ this.filter = filter;
+ this.passback = passback;
+ }
+
+ /**
+ * Returns the listener.
+ *
+ * @return the listener.
+ */
+ public NotificationListener getListener()
+ {
+ return listener;
+ }
+
+ /**
+ * Returns the filter.
+ *
+ * @return the filter.
+ */
+ public NotificationFilter getFilter()
+ {
+ return filter;
+ }
+
+ /**
+ * Returns the passback object.
+ *
+ * @return the passback object.
+ */
+ public Object getPassback()
+ {
+ return passback;
+ }
+
+ /**
+ * Returns true if the supplied object is an instance of
+ * {@link ListenerData} and has the same listener, filter
+ * and passback object.
+ *
+ * @param obj the object to check.
+ * @return true if <code>obj</code> is equal to this.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof ListenerData)
+ {
+ ListenerData data = (ListenerData) obj;
+ return (data.getListener() == listener &&
+ data.getFilter() == filter &&
+ data.getPassback() == passback);
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/classpath/SystemProperties.java b/libjava/classpath/gnu/classpath/SystemProperties.java
index 991279eabb6..d091f1ed0c0 100644
--- a/libjava/classpath/gnu/classpath/SystemProperties.java
+++ b/libjava/classpath/gnu/classpath/SystemProperties.java
@@ -169,4 +169,5 @@ public class SystemProperties
{
return (String) properties.remove(name);
}
+
}
diff --git a/libjava/classpath/gnu/classpath/debug/Component.java b/libjava/classpath/gnu/classpath/debug/Component.java
index 0cc38d7096a..dce257502a7 100644
--- a/libjava/classpath/gnu/classpath/debug/Component.java
+++ b/libjava/classpath/gnu/classpath/debug/Component.java
@@ -97,8 +97,13 @@ public final class Component extends Level
* Trace details about the SSL key exchange.
*/
public static final Component SSL_KEY_EXCHANGE = new Component ("SSL KEY EXCHANGE", 2);
+
+ /**
+ * Trace running of delegated tasks.
+ */
+ public static final Component SSL_DELEGATED_TASK = new Component ("SSL DELEGATED TASK", 3);
- /* Indices 3 and 4 reserved for future use by SSL components. */
+ /* Index 4 reserved for future use by SSL components. */
/**
* Trace the operation of cryptographic primitives.
diff --git a/libjava/classpath/gnu/classpath/debug/SystemLogger.java b/libjava/classpath/gnu/classpath/debug/SystemLogger.java
index 502b488702b..8919e80c785 100644
--- a/libjava/classpath/gnu/classpath/debug/SystemLogger.java
+++ b/libjava/classpath/gnu/classpath/debug/SystemLogger.java
@@ -42,11 +42,12 @@ import gnu.java.security.action.GetPropertyAction;
import java.security.AccessController;
import java.util.StringTokenizer;
+import java.util.logging.Level;
import java.util.logging.Logger;
-public final class SystemLogger
+public final class SystemLogger extends Logger
{
- public static final Logger SYSTEM = Logger.getLogger ("gnu.classpath");
+ public static final SystemLogger SYSTEM = new SystemLogger();
static
{
@@ -62,12 +63,40 @@ public final class SystemLogger
Component c = Component.forName (tok.nextToken ());
if (c != null)
PreciseFilter.GLOBAL.enable (c);
- SYSTEM.log (java.util.logging.Level.INFO, "enabled: {0}", c);
+ SYSTEM.log (Level.INFO, "enabled: {0}", c);
}
}
+ }
- java.util.logging.Handler[] h = SYSTEM.getHandlers ();
- for (int i = 0; i < h.length; i++)
- System.out.println (h[i]);
+ /**
+ * Fetch the system logger instance. The logger returned is meant for debug
+ * and diagnostic logging for Classpath internals.
+ *
+ * @return The system logger.
+ */
+ public static SystemLogger getSystemLogger()
+ {
+ // XXX Check some permission here?
+ return SYSTEM;
+ }
+
+ /**
+ * Keep only one instance of the system logger.
+ */
+ private SystemLogger()
+ {
+ super("gnu.classpath", null);
+ }
+
+ /**
+ * Variable-arguments log method.
+ *
+ * @param level The level to log to.
+ * @param format The format string.
+ * @param args The arguments.
+ */
+ public void logv(Level level, String format, Object... args)
+ {
+ log(level, format, args);
}
}
diff --git a/libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java b/libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java
new file mode 100644
index 00000000000..8f15c851933
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java
@@ -0,0 +1,85 @@
+/* WindowResizeEvent.java -- Used to synchronize the AWT and peer sizes
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+
+/**
+ * This is used to update the AWT's knowledge about a Window's size when
+ * the user changes the window bounds.
+ *
+ * This event is _not_ posted to the eventqueue, but rather dispatched directly
+ * via Window.dispatchEvent(). It is the cleanest way we could find to update
+ * the AWT's knowledge of the window size. Small testprograms showed the
+ * following:
+ * - Component.reshape() and its derivatives are _not_ called. This makes sense
+ * as it could end up in loops,because this calls back into the peers.
+ * - Intercepting event dispatching for any events in
+ * EventQueue.dispatchEvent() showed that the size is still updated. So it
+ * is not done via an event dispatched over the eventqueue.
+ *
+ * Possible other candidates for implementation would have been:
+ * - Call a (private) callback method in Window/Component from the native
+ * side.
+ * - Call a (private) callback method in Window/Component via reflection.
+ *
+ * Both is uglier than sending this event directly. Note however that this
+ * is impossible to test, as Component.dispatchEvent() is final and can't be
+ * intercepted from outside code. But this impossibility to test the issue from
+ * outside code also means that this shouldn't raise any compatibility issues.
+ */
+public class ComponentReshapeEvent
+ extends AWTEvent
+{
+
+ public int x;
+ public int y;
+ public int width;
+ public int height;
+
+ public ComponentReshapeEvent(Component c, int x, int y, int width, int height)
+ {
+ super(c, 1999);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/LowPriorityEvent.java b/libjava/classpath/gnu/java/awt/LowPriorityEvent.java
new file mode 100644
index 00000000000..c1558f6ff58
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/LowPriorityEvent.java
@@ -0,0 +1,48 @@
+/* LowPriorityEvent.java -- Marks events with low priority
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt;
+
+/**
+ * A marker interface that marks events with low priority. LowPriority events
+ * are dispatched _after_ other (normal priority) events by the EventQueue.
+ */
+public interface LowPriorityEvent
+{
+ // Empty marker interface.
+}
diff --git a/libjava/classpath/gnu/java/awt/color/PyccConverter.java b/libjava/classpath/gnu/java/awt/color/PyccConverter.java
index cd50d8776cd..77ea28a3e92 100644
--- a/libjava/classpath/gnu/java/awt/color/PyccConverter.java
+++ b/libjava/classpath/gnu/java/awt/color/PyccConverter.java
@@ -37,7 +37,6 @@ exception statement from your version. */
package gnu.java.awt.color;
-
/**
* PyccConverter - conversion routines for the PhotoYCC colorspace
*
@@ -52,21 +51,21 @@ public class PyccConverter implements ColorSpaceConverter
{
public float[] toRGB(float[] in)
{
- return null;
+ throw new UnsupportedOperationException();
}
public float[] fromRGB(float[] in)
{
- return null;
+ throw new UnsupportedOperationException();
}
public float[] toCIEXYZ(float[] in)
{
- return null;
+ throw new UnsupportedOperationException();
}
public float[] fromCIEXYZ(float[] in)
{
- return null;
+ throw new UnsupportedOperationException();
}
}
diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java
index 4f922982273..b68fa105803 100644
--- a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java
+++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java
@@ -61,11 +61,13 @@ public class GtkDragSourceContextPeer
private ComponentPeer peer;
private Cursor cursor;
private DragSourceContext context;
+ public static Component target;
native void nativeStartDrag(Image i, int x, int y, int action, String target);
native void connectSignals(ComponentPeer comp);
native void create(ComponentPeer comp);
native void nativeSetCursor(int cursor);
+ native void setTarget(GtkDropTargetContextPeer target);
public GtkDragSourceContextPeer(DragGestureEvent e)
{
@@ -76,10 +78,18 @@ public class GtkDragSourceContextPeer
create(peer);
connectSignals(peer);
cursor = comp.getCursor();
+
+ // FIXME: Where do we set the target?
+
+ if ((target != null))
+ setTarget(new GtkDropTargetContextPeer(target));
}
ComponentPeer getComponentPeer(Component c)
{
+ if (c == null)
+ return null;
+
Component curr = c;
while (curr.getPeer() instanceof LightweightPeer)
curr = curr.getParent();
@@ -93,7 +103,7 @@ public class GtkDragSourceContextPeer
throws InvalidDnDOperationException
{
this.context = context;
-
+
if (p == null)
p = new Point();
diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java
index 50cd95d41ad..f24b3f39bcb 100644
--- a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java
+++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java
@@ -50,10 +50,10 @@ public class GtkDropTargetContextPeer
extends GtkGenericPeer
implements DropTargetContextPeer
{
-
- public GtkDropTargetContextPeer()
+
+ public GtkDropTargetContextPeer(Object obj)
{
- super(null);
+ super(obj);
}
public void setTargetActions(int actions)
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java b/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java
new file mode 100644
index 00000000000..b2c9912342b
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java
@@ -0,0 +1,45 @@
+/* AxisHints.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+class AxisHints
+{
+
+ Segment[] segments;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Constants.java b/libjava/classpath/gnu/java/awt/font/autofit/Constants.java
new file mode 100644
index 00000000000..cb3992825ab
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/Constants.java
@@ -0,0 +1,61 @@
+/* Constants.java -- Some constants used in the autofitter
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+/**
+ * Some constants used in the autofitter.
+ */
+interface Constants
+{
+
+ /**
+ * The horizontal dimension.
+ */
+ static final int DIMENSION_HORZ = 0;
+
+ /**
+ * The vertical dimension.
+ */
+ static final int DIMENSION_VERT = 1;
+
+ /**
+ * The number of dimensions.
+ */
+ static final int DIMENSION_MAX = 2;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java b/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java
new file mode 100644
index 00000000000..ad73a04a69b
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java
@@ -0,0 +1,75 @@
+/* GlyphHints.java -- Data and methods for actual hinting
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+import gnu.java.awt.font.opentype.truetype.Zone;
+
+/**
+ * The data and methods used for the actual hinting process.
+ */
+class GlyphHints
+{
+
+ int xScale;
+ int xDelta;
+ int yScale;
+ int yDelta;
+
+ AxisHints[] axis;
+
+ void rescale(ScriptMetrics metrics)
+ {
+ // TODO: Implement.
+ }
+
+ void reload(Zone outline)
+ {
+ // TODO: Implement.
+ }
+
+ void computeSegments(int dim)
+ {
+ // TODO: Implement.
+ }
+
+ void linkSegments(int dim)
+ {
+ // TODO: Implement.
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Latin.java b/libjava/classpath/gnu/java/awt/font/autofit/Latin.java
new file mode 100644
index 00000000000..0352b41a45a
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/Latin.java
@@ -0,0 +1,177 @@
+/* Latin.java -- Latin specific glyph handling
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+import java.awt.geom.AffineTransform;
+
+import gnu.java.awt.font.opentype.OpenTypeFont;
+import gnu.java.awt.font.opentype.truetype.Zone;
+
+/**
+ * Implements Latin specific glyph handling.
+ */
+class Latin
+ implements Script, Constants
+{
+
+ private static final int MAX_WIDTHS = 16;
+
+ public void applyHints(GlyphHints hints, ScriptMetrics metrics)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void doneMetrics(ScriptMetrics metrics)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Initializes the <code>hints</code> object.
+ *
+ * @param hints the hints to initialize
+ * @param metrics the metrics to use
+ */
+ public void initHints(GlyphHints hints, ScriptMetrics metrics)
+ {
+ hints.rescale(metrics);
+ LatinMetrics lm = (LatinMetrics) metrics;
+ hints.xScale = lm.axis[DIMENSION_HORZ].scale;
+ hints.xDelta = lm.axis[DIMENSION_HORZ].delta;
+ hints.yScale = lm.axis[DIMENSION_VERT].scale;
+ hints.yDelta = lm.axis[DIMENSION_VERT].delta;
+ // TODO: Set the scaler and other flags.
+ }
+
+ /**
+ * Initializes the script metrics.
+ *
+ * @param metrics the script metrics to initialize
+ * @param face the font
+ */
+ public void initMetrics(ScriptMetrics metrics, OpenTypeFont face)
+ {
+ assert metrics instanceof LatinMetrics;
+ LatinMetrics lm = (LatinMetrics) metrics;
+ lm.unitsPerEm = face.unitsPerEm;
+
+ // TODO: Check for latin charmap.
+
+ initWidths(lm, face, 'o');
+ initBlues(lm, face);
+ }
+
+ public void scaleMetrics(ScriptMetrics metrics)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Determines the standard stem widths.
+ *
+ * @param metrics the metrics to use
+ * @param face the font face
+ * @param ch the character that is used for getting the widths
+ */
+ private void initWidths(LatinMetrics metrics, OpenTypeFont face, char ch)
+ {
+ GlyphHints hints = new GlyphHints();
+ metrics.axis[DIMENSION_HORZ].widthCount = 0;
+ metrics.axis[DIMENSION_VERT].widthCount = 0;
+ int glyphIndex = face.getGlyph(ch);
+ // TODO: Avoid that AffineTransform constructor and change
+ // getRawGlyphOutline() to accept null or remove that parameter altogether.
+ // Consider this when the thing is done and we know what we need that for.
+ Zone outline = face.getRawGlyphOutline(glyphIndex, new AffineTransform());
+ LatinMetrics dummy = new LatinMetrics();
+ Scaler scaler = dummy.scaler;
+ dummy.unitsPerEm = metrics.unitsPerEm;
+ scaler.xScale = scaler.yScale = 10000;
+ scaler.xDelta = scaler.yDelta = 0;
+ scaler.face = face;
+ hints.rescale(dummy);
+ hints.reload(outline);
+ for (int dim = 0; dim < DIMENSION_MAX; dim++)
+ {
+ LatinAxis axis = metrics.axis[dim];
+ AxisHints axHints = hints.axis[dim];
+ int numWidths = 0;
+ hints.computeSegments(dim);
+ hints.linkSegments(dim);
+ Segment[] segs = axHints.segments;
+ for (int i = 0; i < segs.length; i++)
+ {
+ Segment seg = segs[i];
+ Segment link = seg.link;
+ if (link != null && link.link == seg && link.index > i)
+ {
+ int dist = Math.abs(seg.pos - link.pos);
+ if (numWidths < MAX_WIDTHS)
+ axis.widths[numWidths++].org = dist;
+ }
+ }
+ }
+ for (int dim = 0; dim < DIMENSION_MAX; dim++)
+ {
+ LatinAxis axis = metrics.axis[dim];
+ int stdw = axis.widthCount > 0 ? axis.widths[0].org
+ : constant(metrics, 50);
+ axis.edgeDistanceTreshold= stdw / 5;
+ }
+ }
+
+ /**
+ * Initializes the blue zones of the font.
+ *
+ * @param metrics the metrics to use
+ * @param face the font face to analyze
+ */
+ private void initBlues(LatinMetrics metrics, OpenTypeFont face)
+ {
+ // TODO: Implement.
+ }
+
+ private int constant(LatinMetrics metrics, int c)
+ {
+ return c * (metrics.unitsPerEm / 2048);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java
new file mode 100644
index 00000000000..8ca1e6d9ed2
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java
@@ -0,0 +1,53 @@
+/* LatinAxis.java -- Axis specific data
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+/**
+ * Some axis specific data.
+ */
+class LatinAxis
+{
+
+ int scale;
+ int delta;
+
+ int widthCount;
+ Width[] widths;
+ float edgeDistanceTreshold;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java
new file mode 100644
index 00000000000..cd955348b37
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java
@@ -0,0 +1,51 @@
+/* LatinMetrics.java -- Latin specific metrics data
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+/**
+ * Latin specific metrics data.
+ */
+class LatinMetrics
+ extends ScriptMetrics
+{
+
+ LatinAxis[] axis;
+
+ int unitsPerEm;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Scaler.java b/libjava/classpath/gnu/java/awt/font/autofit/Scaler.java
new file mode 100644
index 00000000000..10518512578
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/Scaler.java
@@ -0,0 +1,52 @@
+/* Scaler.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+import gnu.java.awt.font.opentype.OpenTypeFont;
+
+class Scaler
+{
+
+ int xScale;
+ int xDelta;
+ int yScale;
+ int yDelta;
+ OpenTypeFont face;
+
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Script.java b/libjava/classpath/gnu/java/awt/font/autofit/Script.java
new file mode 100644
index 00000000000..3b353010f2d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/Script.java
@@ -0,0 +1,62 @@
+/* Script.java -- Defines script specific interface to the autofitter
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+import gnu.java.awt.font.opentype.OpenTypeFont;
+
+/**
+ * Defines script specific methods for the auto fitter.
+ */
+interface Script
+{
+
+ /**
+ * Initializes the metrics.
+ */
+ void initMetrics(ScriptMetrics metrics, OpenTypeFont face);
+
+ void scaleMetrics(ScriptMetrics metrics/* , scaler, map this */);
+
+ void doneMetrics(ScriptMetrics metrics);
+
+ void initHints(GlyphHints hints, ScriptMetrics metrics);
+
+ void applyHints(GlyphHints hints, /* some outline object, */
+ ScriptMetrics metrics);
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java b/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java
new file mode 100644
index 00000000000..77c815ae59d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java
@@ -0,0 +1,49 @@
+/* ScriptMetrics.java -- Script specific metrics data
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+/**
+ * Script specific metrics data.
+ */
+class ScriptMetrics
+{
+
+ Script script;
+ Scaler scaler;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Segment.java b/libjava/classpath/gnu/java/awt/font/autofit/Segment.java
new file mode 100644
index 00000000000..32032a48fcc
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/Segment.java
@@ -0,0 +1,47 @@
+/* Segment.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+class Segment
+{
+
+ Segment link;
+ int index;
+ int pos;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Width.java b/libjava/classpath/gnu/java/awt/font/autofit/Width.java
new file mode 100644
index 00000000000..d4d540069ee
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/autofit/Width.java
@@ -0,0 +1,46 @@
+/* Width.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.font.autofit;
+
+public class Width
+{
+ int org;
+ int cur;
+ int fit;
+}
diff --git a/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java b/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java
index 6ada3b147c6..184075094b6 100644
--- a/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java
+++ b/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java
@@ -61,7 +61,7 @@ import java.nio.IntBuffer;
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
-abstract class CharGlyphMap
+public abstract class CharGlyphMap
{
private static final int PLATFORM_UNICODE = 0;
private static final int PLATFORM_MACINTOSH = 1;
diff --git a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java
index 9ee28d76bb4..efc30811f7b 100644
--- a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java
+++ b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java
@@ -52,6 +52,7 @@ import java.util.Locale;
import gnu.java.awt.font.FontDelegate;
import gnu.java.awt.font.GNUGlyphVector;
import gnu.java.awt.font.opentype.truetype.TrueTypeScaler;
+import gnu.java.awt.font.opentype.truetype.Zone;
/**
@@ -117,7 +118,7 @@ public final class OpenTypeFont
* OpenType fonts with PostScript outlines, other values are
* acceptable (such as 1000).
*/
- private int unitsPerEm;
+ public int unitsPerEm;
/**
@@ -697,6 +698,20 @@ public final class OpenTypeFont
antialias, fractionalMetrics);
}
+ /**
+ * Fetches the raw glyph outline for the specified glyph index. This is used
+ * for the autofitter only ATM and is otherwise not usable for outside code.
+ *
+ * @param glyph the glyph index to fetch
+ * @param transform the transform to apply
+ *
+ * @return the raw outline of that glyph
+ */
+ public synchronized Zone getRawGlyphOutline(int glyph,
+ AffineTransform transform)
+ {
+ return scaler.getRawOutline(glyph, transform);
+ }
/**
* Returns a name for the specified glyph. This is useful for
diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java
index 499c3ea526c..83a31c576c7 100644
--- a/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java
+++ b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package gnu.java.awt.font.opentype;
+import gnu.java.awt.font.opentype.truetype.Zone;
+
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
@@ -189,4 +191,14 @@ public abstract class Scaler
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
+
+ /**
+ * Returns the raw outline data. This is used for the autofitter atm.
+ *
+ * @param glyph the glyph index
+ * @param transform the transform to apply
+ *
+ * @return the raw glyph outline
+ */
+ public abstract Zone getRawOutline(int glyph, AffineTransform transform);
}
diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java
index b12d7782b23..3733afe92d8 100644
--- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java
+++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java
@@ -119,6 +119,11 @@ final class GlyphLoader
0, 0);
}
+ public void loadGlyph(int glyphIndex, AffineTransform transform,
+ Zone glyphZone)
+ {
+ loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone);
+ }
private void loadSubGlyph(int glyphIndex,
double pointSize,
diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java
index e4d7309cb55..8dfdeff0790 100644
--- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java
+++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java
@@ -198,6 +198,12 @@ public final class TrueTypeScaler
return glyphZone.getPath();
}
+ public Zone getRawOutline(int glyphIndex, AffineTransform transform)
+ {
+ Zone zone = new Zone(glyphZone.getCapacity());
+ glyphLoader.loadGlyph(glyphIndex, transform, zone);
+ return zone;
+ }
/**
* Determines the advance width and height for a glyph.
diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java
index c0a3947f684..ff5bb631619 100644
--- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java
+++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java
@@ -45,7 +45,7 @@ import java.awt.geom.PathIterator;
/**
* A collection of points with some additional information.
*/
-final class Zone
+public final class Zone
{
private final int[] pos;
private final int[] origPos;
diff --git a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
index 9d017240d60..da21253980f 100644
--- a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
+++ b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
@@ -100,6 +100,20 @@ import java.util.Map;
* {@link #updateRaster(Raster, int, int, int, int)} method, which always gets
* called after a chunk of data got painted into the raster.
* </p>
+ * <p>Alternativly the backend can provide a method for filling Shapes by
+ * overriding the protected method fillShape(). This can be accomplished
+ * by a polygon filling function of the backend. Keep in mind though that
+ * Shapes can be quite complex (i.e. non-convex and containing holes, etc)
+ * which is not supported by all polygon fillers. Also it must be noted
+ * that fillShape() is expected to handle painting and compositing as well as
+ * clipping and transformation. If your backend can't support this natively,
+ * then you can fallback to the implementation in this class. You'll need
+ * to provide a writable Raster then, see above.</p>
+ * <p>Another alternative is to implement fillScanline() which only requires
+ * the backend to be able to draw horizontal lines in device space,
+ * which is usually very cheap.
+ * The implementation should still handle painting and compositing,
+ * but no more clipping and transformation is required by the backend.</p>
* <p>The backend is free to provide implementations for the various raw*
* methods for optimized AWT 1.1 style painting of some primitives. This should
* accelerate painting of Swing greatly. When doing so, the backend must also
@@ -126,6 +140,9 @@ import java.util.Map;
* in plain Java because they involve lots of shuffling around with large
* arrays. In fact, you really would want to let the graphics card to the
* work, they are made for this.</li>
+ * <li>Provide an accelerated implementation for fillShape(). For instance,
+ * OpenGL can fill shapes very efficiently. There are some considerations
+ * to be made though, see above for details.</li>
* </ol>
* </p>
*
@@ -144,6 +161,12 @@ public abstract class AbstractGraphics2D
private static final int AA_SAMPLING = 8;
/**
+ * Caches certain shapes to avoid massive creation of such Shapes in
+ * the various draw* and fill* methods.
+ */
+ private static final ThreadLocal shapeCache = new ThreadLocal();
+
+ /**
* The transformation for this Graphics2D instance
*/
protected AffineTransform transform;
@@ -184,11 +207,6 @@ public abstract class AbstractGraphics2D
private RenderingHints renderingHints;
/**
- * The paint raster.
- */
- private Raster paintRaster;
-
- /**
* The raster of the destination surface. This is where the painting is
* performed.
*/
@@ -219,7 +237,7 @@ public abstract class AbstractGraphics2D
* AbstractGraphics2D object and will be the most commonly used setting
* in Swing rendering and should therefore be optimized as much as possible.
*/
- private boolean isOptimized;
+ private boolean isOptimized = true;
/**
* Creates a new AbstractGraphics2D instance.
@@ -270,7 +288,6 @@ public abstract class AbstractGraphics2D
public boolean drawImage(Image image, AffineTransform xform,
ImageObserver obs)
{
- boolean ret = false;
Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs),
image.getHeight(obs));
return drawImageImpl(image, xform, obs, areaOfInterest);
@@ -982,7 +999,8 @@ public abstract class AbstractGraphics2D
else
copy.clip = new GeneralPath(clip);
- copy.renderingHints = new RenderingHints(renderingHints);
+ copy.renderingHints = new RenderingHints(null);
+ copy.renderingHints.putAll(renderingHints);
copy.transform = new AffineTransform(transform);
// The remaining state is inmmutable and doesn't need to be copied.
return copy;
@@ -1143,14 +1161,31 @@ public abstract class AbstractGraphics2D
{
if (isOptimized)
{
- int tx = (int) transform.getTranslateX();
- int ty = (int) transform.getTranslateY();
- rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty);
+ rawDrawLine(x1, y1, x2, y2);
}
else
{
- Line2D line = new Line2D.Double(x1, y1, x2, y2);
- draw(line);
+ ShapeCache sc = getShapeCache();
+ if (sc.line == null)
+ sc.line = new Line2D.Float();
+ sc.line.setLine(x1, y1, x2, y2);
+ draw(sc.line);
+ }
+ }
+
+ public void drawRect(int x, int y, int w, int h)
+ {
+ if (isOptimized)
+ {
+ rawDrawRect(x, y, w, h);
+ }
+ else
+ {
+ ShapeCache sc = getShapeCache();
+ if (sc.rect == null)
+ sc.rect = new Rectangle();
+ sc.rect.setBounds(x, y, w, h);
+ draw(sc.rect);
}
}
@@ -1166,13 +1201,15 @@ public abstract class AbstractGraphics2D
{
if (isOptimized)
{
- int tx = (int) transform.getTranslateX();
- int ty = (int) transform.getTranslateY();
- rawFillRect(x + tx, y + ty, width, height);
+ rawFillRect(x, y, width, height);
}
else
{
- fill(new Rectangle(x, y, width, height));
+ ShapeCache sc = getShapeCache();
+ if (sc.rect == null)
+ sc.rect = new Rectangle();
+ sc.rect.setBounds(x, y, width, height);
+ fill(sc.rect);
}
}
@@ -1213,8 +1250,11 @@ public abstract class AbstractGraphics2D
public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
int arcHeight)
{
- draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
- arcHeight));
+ ShapeCache sc = getShapeCache();
+ if (sc.roundRect == null)
+ sc.roundRect = new RoundRectangle2D.Float();
+ sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+ draw(sc.roundRect);
}
/**
@@ -1230,8 +1270,11 @@ public abstract class AbstractGraphics2D
public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
int arcHeight)
{
- fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
- arcHeight));
+ ShapeCache sc = getShapeCache();
+ if (sc.roundRect == null)
+ sc.roundRect = new RoundRectangle2D.Float();
+ sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+ fill(sc.roundRect);
}
/**
@@ -1244,7 +1287,11 @@ public abstract class AbstractGraphics2D
*/
public void drawOval(int x, int y, int width, int height)
{
- draw(new Ellipse2D.Double(x, y, width, height));
+ ShapeCache sc = getShapeCache();
+ if (sc.ellipse == null)
+ sc.ellipse = new Ellipse2D.Float();
+ sc.ellipse.setFrame(x, y, width, height);
+ draw(sc.ellipse);
}
/**
@@ -1257,7 +1304,11 @@ public abstract class AbstractGraphics2D
*/
public void fillOval(int x, int y, int width, int height)
{
- fill(new Ellipse2D.Double(x, y, width, height));
+ ShapeCache sc = getShapeCache();
+ if (sc.ellipse == null)
+ sc.ellipse = new Ellipse2D.Float();
+ sc.ellipse.setFrame(x, y, width, height);
+ fill(sc.ellipse);
}
/**
@@ -1266,8 +1317,11 @@ public abstract class AbstractGraphics2D
public void drawArc(int x, int y, int width, int height, int arcStart,
int arcAngle)
{
- draw(new Arc2D.Double(x, y, width, height, arcStart, arcAngle,
- Arc2D.OPEN));
+ ShapeCache sc = getShapeCache();
+ if (sc.arc == null)
+ sc.arc = new Arc2D.Float();
+ sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN);
+ draw(sc.arc);
}
/**
@@ -1276,8 +1330,11 @@ public abstract class AbstractGraphics2D
public void fillArc(int x, int y, int width, int height, int arcStart,
int arcAngle)
{
- fill(new Arc2D.Double(x, y, width, height, arcStart, arcAngle,
- Arc2D.OPEN));
+ ShapeCache sc = getShapeCache();
+ if (sc.arc == null)
+ sc.arc = new Arc2D.Float();
+ sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE);
+ draw(sc.arc);
}
public void drawPolyline(int[] xPoints, int[] yPoints, int npoints)
@@ -1291,7 +1348,13 @@ public abstract class AbstractGraphics2D
*/
public void drawPolygon(int[] xPoints, int[] yPoints, int npoints)
{
- draw(new Polygon(xPoints, yPoints, npoints));
+ ShapeCache sc = getShapeCache();
+ if (sc.polygon == null)
+ sc.polygon = new Polygon();
+ sc.polygon.xpoints = xPoints;
+ sc.polygon.ypoints = yPoints;
+ sc.polygon.npoints = npoints;
+ draw(sc.polygon);
}
/**
@@ -1299,7 +1362,13 @@ public abstract class AbstractGraphics2D
*/
public void fillPolygon(int[] xPoints, int[] yPoints, int npoints)
{
- fill(new Polygon(xPoints, yPoints, npoints));
+ ShapeCache sc = getShapeCache();
+ if (sc.polygon == null)
+ sc.polygon = new Polygon();
+ sc.polygon.xpoints = xPoints;
+ sc.polygon.ypoints = yPoints;
+ sc.polygon.npoints = npoints;
+ fill(sc.polygon);
}
/**
@@ -1460,8 +1529,12 @@ public abstract class AbstractGraphics2D
}
/**
- * Fills the specified shape. The shape has already been clipped against the
- * current clip.
+ * Fills the specified shape. Override this if your backend can efficiently
+ * fill shapes. This is possible on many systems via a polygon fill
+ * method or something similar. But keep in mind that Shapes can be quite
+ * complex (non-convex, with holes etc), which is not necessarily supported
+ * by all polygon fillers. Also note that you must perform clipping
+ * before filling the shape.
*
* @param s the shape to fill
* @param isFont <code>true</code> if the shape is a font outline
@@ -1533,6 +1606,11 @@ public abstract class AbstractGraphics2D
draw(new Line2D.Float(x0, y0, x1, y1));
}
+ protected void rawDrawRect(int x, int y, int w, int h)
+ {
+ draw(new Rectangle(x, y, w, h));
+ }
+
/**
* Draws a string in optimization mode. The implementation should respect the
* clip and translation. It can assume that the clip is a rectangle and that
@@ -1627,11 +1705,7 @@ public abstract class AbstractGraphics2D
}
/**
- * Fills the specified polygon. This should be overridden by backends
- * that support accelerated (native) polygon filling, which is the
- * case for most toolkit window and offscreen image implementations.
- *
- * The polygon is already clipped when this method is called.
+ * Fills the specified polygon without anti-aliasing.
*/
private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D,
Rectangle2D userBounds,
@@ -1662,7 +1736,7 @@ public abstract class AbstractGraphics2D
for (Iterator i = segs.iterator(); i.hasNext();)
{
PolyEdge edge = (PolyEdge) i.next();
- int yindex = (int) ((int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY));
+ int yindex = (int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY);
if (edgeTable[yindex] == null) // Create bucket when needed.
edgeTable[yindex] = new ArrayList();
edgeTable[yindex].add(edge); // Add edge to the bucket of its line.
@@ -1766,7 +1840,8 @@ public abstract class AbstractGraphics2D
}
/**
- * Paints a scanline between x0 and x1.
+ * Paints a scanline between x0 and x1. Override this when your backend
+ * can efficiently draw/fill horizontal lines.
*
* @param x0 the left offset
* @param x1 the right offset
@@ -1972,8 +2047,7 @@ public abstract class AbstractGraphics2D
// Render full scanline.
//System.err.println("scanline: " + y);
if (! emptyScanline)
- fillScanlineAA(alpha, leftX, (int) y, rightX - leftX, pCtx,
- (int) minX);
+ fillScanlineAA(alpha, leftX, y, rightX - leftX, pCtx, (int) minX);
}
pCtx.dispose();
@@ -1986,7 +2060,7 @@ public abstract class AbstractGraphics2D
*
* @param alpha the alpha values in the scanline
* @param x0 the beginning of the scanline
- * @param y the y coordinate of the line
+ * @param yy the y coordinate of the line
*/
private void fillScanlineAA(int[] alpha, int x0, int yy, int numPixels,
PaintContext pCtx, int offs)
@@ -1997,7 +2071,6 @@ public abstract class AbstractGraphics2D
Raster paintRaster = pCtx.getRaster(x0, yy, numPixels, 1);
//System.err.println("paintColorModel: " + pCtx.getColorModel());
WritableRaster aaRaster = paintRaster.createCompatibleWritableRaster();
- int numBands = paintRaster.getNumBands();
ColorModel cm = pCtx.getColorModel();
double lastAlpha = 0.;
int lastAlphaInt = 0;
@@ -2156,10 +2229,10 @@ public abstract class AbstractGraphics2D
private static Rectangle computeIntersection(int x, int y, int w, int h,
Rectangle rect)
{
- int x2 = (int) rect.x;
- int y2 = (int) rect.y;
- int w2 = (int) rect.width;
- int h2 = (int) rect.height;
+ int x2 = rect.x;
+ int y2 = rect.y;
+ int w2 = rect.width;
+ int h2 = rect.height;
int dx = (x > x2) ? x : x2;
int dy = (y > y2) ? y : y2;
@@ -2266,4 +2339,20 @@ public abstract class AbstractGraphics2D
deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY);
return segs;
}
+
+ /**
+ * Returns the ShapeCache for the calling thread.
+ *
+ * @return the ShapeCache for the calling thread
+ */
+ private ShapeCache getShapeCache()
+ {
+ ShapeCache sc = (ShapeCache) shapeCache.get();
+ if (sc == null)
+ {
+ sc = new ShapeCache();
+ shapeCache.set(sc);
+ }
+ return sc;
+ }
}
diff --git a/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java b/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java
index 5e15fe881d8..97a5372f6bd 100644
--- a/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java
+++ b/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java
@@ -145,7 +145,52 @@ public class QuadSegment extends Segment
Point2D cp;
QuadSegment s;
- if( plus )
+ if(!plus)
+ {
+ n1[0] = -n1[0];
+ n1[1] = -n1[1];
+ n2[0] = -n2[0];
+ n2[1] = -n2[1];
+ }
+
+ // Handle special cases where the control point is equal to an end point
+ // or end points are equal (ie, straight lines)
+ if (curve.getP1().equals(curve.getCtrlPt()))
+ {
+ cp = curve.getCtrlPt();
+ cp.setLocation(cp.getX() + n2[0], cp.getY() + n2[1]);
+ n1[0] = n2[0];
+ n1[1] = n2[1];
+ }
+ else if (curve.getP2().equals(curve.getCtrlPt()))
+ {
+ cp = curve.getCtrlPt();
+ cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]);
+ n2[0] = n1[0];
+ n2[1] = n1[1];
+ }
+ else if (curve.getP1().equals(curve.getP2()))
+ {
+ cp = curve.getCtrlPt();
+
+ double deltaX = curve.getX1() - curve.getCtrlX();
+ double deltaY = curve.getY1() - curve.getCtrlY();
+ double length = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
+ double ratio = radius / length;
+ deltaX *= ratio;
+ deltaY *= ratio;
+
+ if (plus)
+ cp.setLocation(cp.getX() + deltaX, cp.getY() + deltaY);
+ else
+ cp.setLocation(cp.getX() - deltaX, cp.getY() - deltaY);
+ }
+ else if (n1[0] == n2[0] && n1[1] == n2[1])
+ {
+ cp = curve.getCtrlPt();
+ cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]);
+ }
+ else
{
cp = lineIntersection(curve.getX1() + n1[0],
curve.getY1() + n1[1],
@@ -155,25 +200,11 @@ public class QuadSegment extends Segment
curve.getCtrlY() + n2[1],
curve.getX2() + n2[0],
curve.getY2() + n2[1], true);
- s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
- cp.getX(), cp.getY(),
- curve.getX2() + n2[0], curve.getY2() + n2[1]);
- }
- else
- {
- cp = lineIntersection(curve.getX1() - n1[0],
- curve.getY1() - n1[1],
- curve.getCtrlX() - n1[0],
- curve.getCtrlY() - n1[1],
- curve.getCtrlX() - n2[0],
- curve.getCtrlY() - n2[1],
- curve.getX2() - n2[0],
- curve.getY2() - n2[1], true);
-
- s = new QuadSegment(curve.getX1() - n1[0], curve.getY1() - n1[1],
- cp.getX(), cp.getY(),
- curve.getX2() - n2[0], curve.getY2() - n2[1]);
}
+
+ s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
+ cp.getX(), cp.getY(),
+ curve.getX2() + n2[0], curve.getY2() + n2[1]);
return s;
}
diff --git a/libjava/classpath/gnu/java/awt/java2d/ShapeCache.java b/libjava/classpath/gnu/java/awt/java2d/ShapeCache.java
new file mode 100644
index 00000000000..034b53cadd3
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/java2d/ShapeCache.java
@@ -0,0 +1,85 @@
+/* ShapeCache.java -- Caches certain Shapes for reuse in AbstractGraphics2D
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.java2d;
+
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.RoundRectangle2D;
+
+/**
+ * Caches certain Shape objects for reuse in AbstractGraphics2D. This avoids
+ * massive creation of such objects.
+ */
+public class ShapeCache
+{
+
+ /**
+ * A cached Line2D.
+ */
+ public Line2D line;
+
+ /**
+ * A cached Rectangle.
+ */
+ public Rectangle rect;
+
+ /**
+ * A cached RoundRectangle2D.
+ */
+ public RoundRectangle2D roundRect;
+
+ /**
+ * A cached Ellipse2D.
+ */
+ public Ellipse2D ellipse;
+
+ /**
+ * A cached Arc2D.
+ */
+ public Arc2D arc;
+
+ /**
+ * A cached Polygon.
+ */
+ public Polygon polygon;
+
+}
diff --git a/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java b/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java
index 1a782ce07e3..db0a2e65804 100644
--- a/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java
+++ b/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java
@@ -104,7 +104,7 @@ public class TexturePaintContext
double scaleY = anchor.getHeight() / image.getHeight();
transform = (AffineTransform) xform.clone();
transform.scale(scaleX, scaleY);
- transform.translate(-anchor.getMinX(), -anchor.getMaxX());
+ transform.translate(-anchor.getMinX(), -anchor.getMinY());
transform = transform.createInverse();
}
catch (NoninvertibleTransformException ex)
@@ -177,6 +177,12 @@ public class TexturePaintContext
// The modulo operation gives us the replication effect.
dx = ((dx - minX) % width) + minX;
dy = ((dy - minY) % height) + minY;
+
+ // Handle possible negative values (replicating above the top-left)
+ if (dx < 0)
+ dx += width;
+ if (dy < 0)
+ dy += height;
// Copy the pixel.
pixel = source.getDataElements(dx, dy, pixel);
diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java
index dad7bb0b08f..2176f34a5f1 100644
--- a/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java
@@ -832,18 +832,4 @@ public abstract class ClasspathFontPeer
public abstract Rectangle2D getMaxCharBounds (Font font,
FontRenderContext rc);
- /**
- * Implementation of {@link Font#getStringBounds(CharacterIterator, int,
- * int, FontRenderContext)}
- *
- * @param font the font this peer is being called from. This may be
- * useful if you are sharing peers between Font objects. Otherwise it may
- * be ignored.
- */
-
- public abstract Rectangle2D getStringBounds (Font font,
- CharacterIterator ci,
- int begin, int limit,
- FontRenderContext frc);
-
}
diff --git a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java
index 88733b92f8c..f9a7bac8ee6 100644
--- a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java
@@ -54,25 +54,14 @@ import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
import java.awt.event.PaintEvent;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.awt.image.VolatileImage;
-import java.awt.peer.ComponentPeer;
import java.awt.peer.ContainerPeer;
import java.awt.peer.LightweightPeer;
-/*
- * Another possible implementation strategy for lightweight peers is
- * to make GLightweightPeer a placeholder class that implements
- * LightweightPeer. Then the Component and Container classes could
- * identify a peer as lightweight and handle it specially. The
- * current approach is probably more clear but less efficient.
- */
-
/**
* A stub class that implements the ComponentPeer and ContainerPeer
* interfaces using callbacks into the Component and Container
@@ -85,47 +74,48 @@ import java.awt.peer.LightweightPeer;
public class GLightweightPeer
implements LightweightPeer, ContainerPeer
{
- private Component comp;
-
- private Insets containerInsets;
-
- public GLightweightPeer(Component comp)
+ public GLightweightPeer()
{
- this.comp = comp;
+ // Nothing to do here.
}
// -------- java.awt.peer.ContainerPeer implementation:
public Insets insets()
{
- return getInsets ();
+ // Nothing to do here for lightweights.
+ return null;
}
public Insets getInsets()
{
- if (containerInsets == null)
- containerInsets = new Insets (0,0,0,0);
- return containerInsets;
+ // Nothing to do here for lightweights.
+ return null;
}
public void beginValidate()
{
+ // Nothing to do here for lightweights.
}
public void endValidate()
{
+ // Nothing to do here for lightweights.
}
public void beginLayout()
{
+ // Nothing to do here for lightweights.
}
public void endLayout()
{
+ // Nothing to do here for lightweights.
}
public boolean isPaintPending()
{
+ // Nothing to do here for lightweights.
return false;
}
@@ -133,122 +123,188 @@ public class GLightweightPeer
public int checkImage(Image img, int width, int height, ImageObserver o)
{
- return comp.getToolkit().checkImage(img, width, height, o);
+ // Nothing to do here for lightweights.
+ return -1;
}
public Image createImage(ImageProducer prod)
{
- return comp.getToolkit().createImage(prod);
+ // Nothing to do here for lightweights.
+ return null;
}
/* This method is not called. */
public Image createImage(int width, int height)
{
+ // Nothing to do here for lightweights.
return null;
}
- public void disable() {}
+ public void disable()
+ {
+ // Nothing to do here for lightweights.
+ }
- public void dispose() {}
+ public void dispose()
+ {
+ // Nothing to do here for lightweights.
+ }
- public void enable() {}
+ public void enable()
+ {
+ // Nothing to do here for lightweights.
+ }
public GraphicsConfiguration getGraphicsConfiguration()
{
+ // Nothing to do here for lightweights.
return null;
}
public FontMetrics getFontMetrics(Font f)
{
- return comp.getToolkit().getFontMetrics(f);
+ // We shouldn't end up here, but if we do we can still try do something
+ // reasonable.
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ return tk.getFontMetrics(f);
}
/* Returning null here tells the Component object that called us to
* use its parent's Graphics. */
public Graphics getGraphics()
{
+ // Nothing to do here for lightweights.
return null;
}
public Point getLocationOnScreen()
{
- Point parentLocation = comp.getParent().getLocationOnScreen();
- return new Point (parentLocation.x + comp.getX(),
- parentLocation.y + comp.getY());
+ // Nothing to do here for lightweights.
+ return null;
}
public Dimension getMinimumSize()
{
- return new Dimension(comp.getWidth(), comp.getHeight());
+ return minimumSize();
}
- /* A lightweight component's preferred size is equivalent to its
- * Component width and height values. */
public Dimension getPreferredSize()
{
- return new Dimension(comp.getWidth(), comp.getHeight());
+ return preferredSize();
}
/* Returning null here tells the Component object that called us to
* use its parent's Toolkit. */
public Toolkit getToolkit()
{
+ // Nothing to do here for lightweights.
return null;
}
- public void handleEvent(AWTEvent e) {}
+ public void handleEvent(AWTEvent e)
+ {
+ // This can only happen when an application posts a PaintEvent for
+ // a lightweight component directly. We still support painting for
+ // this case.
+ if (e instanceof PaintEvent)
+ {
+ PaintEvent pe = (PaintEvent) e;
+ Component target = (Component) e.getSource();
+ if (target != null && target.isShowing())
+ {
+ Graphics g = target.getGraphics();
+ if (g != null)
+ {
+ try
+ {
+ Rectangle clip = pe.getUpdateRect();
+ g.setClip(clip);
+ target.paint(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+ }
+ }
+ }
- public void hide() {}
+ public void hide()
+ {
+ // Nothing to do here for lightweights.
+ }
public boolean isFocusable()
{
+ // Nothing to do here for lightweights.
return false;
}
public boolean isFocusTraversable()
{
+ // Nothing to do here for lightweights.
return false;
}
public Dimension minimumSize()
{
- return getMinimumSize();
+ return new Dimension(0, 0);
}
public Dimension preferredSize()
{
- return getPreferredSize();
+ return new Dimension(0, 0);
}
- public void paint(Graphics graphics) {}
+ public void paint(Graphics graphics)
+ {
+ // Nothing to do here for lightweights.
+ }
public boolean prepareImage(Image img, int width, int height,
ImageObserver o)
{
- return comp.getToolkit().prepareImage(img, width, height, o);
+ // Nothing to do here for lightweights.
+ return false;
}
- public void print(Graphics graphics) {}
+ public void print(Graphics graphics)
+ {
+ // Nothing to do here for lightweights.
+ }
public void repaint(long tm, int x, int y, int width, int height)
{
- Component p = comp.getParent();
- if (p != null)
- p.repaint(tm, x + comp.getX(), y + comp.getY(), width, height);
+ // Nothing to do here for lightweights.
}
- public void requestFocus() {}
+ public void requestFocus()
+ {
+ // Nothing to do here for lightweights.
+ }
- public boolean requestFocus(Component source, boolean bool1, boolean bool2, long x)
+ public boolean requestFocus(Component source, boolean bool1, boolean bool2,
+ long x)
{
+ // Nothing to do here for lightweights.
return false;
}
- public void reshape(int x, int y, int width, int height) {}
+ public void reshape(int x, int y, int width, int height)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void setBackground(Color color) {}
+ public void setBackground(Color color)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void setBounds(int x, int y, int width, int height) {}
+ public void setBounds(int x, int y, int width, int height)
+ {
+ // Nothing to do here for lightweights.
+ }
/**
* Sets the cursor on the heavy-weight parent peer.
@@ -256,110 +312,141 @@ public class GLightweightPeer
*/
public void setCursor(Cursor cursor)
{
- Component p = comp.getParent();
- while (p != null && p.isLightweight())
- p = p.getParent();
-
- if (p != null)
- {
- // Don't actually change the cursor of the component
- // otherwise other childs inherit this cursor.
- ComponentPeer peer = p.getPeer();
- if (peer != null)
- peer.setCursor(cursor);
- }
+ // Nothing to do here for lightweights.
}
- public void setEnabled(boolean enabled) {}
+ public void setEnabled(boolean enabled)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void setEventMask(long eventMask) {}
+ public void setEventMask(long eventMask)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void setFont(Font font) {}
+ public void setFont(Font font)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void setForeground(Color color) {}
+ public void setForeground(Color color)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void setVisible(boolean visible) {}
+ public void setVisible(boolean visible)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void show() {}
+ public void show()
+ {
+ // Nothing to do here for lightweights.
+ }
- public ColorModel getColorModel ()
+ public ColorModel getColorModel()
{
- return comp.getColorModel ();
+ // Nothing to do here for lightweights.
+ return null;
}
public boolean isObscured()
{
+ // Nothing to do here for lightweights.
return false;
}
public boolean canDetermineObscurity()
{
+ // Nothing to do here for lightweights.
return false;
}
- public void coalescePaintEvent(PaintEvent e) { }
+ public void coalescePaintEvent(PaintEvent e)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void updateCursorImmediately() { }
+ public void updateCursorImmediately()
+ {
+ // Nothing to do here for lightweights.
+ }
public VolatileImage createVolatileImage(int width, int height)
{
+ // Nothing to do here for lightweights.
return null;
}
public boolean handlesWheelScrolling()
{
+ // Nothing to do here for lightweights.
return false;
}
public void createBuffers(int x, BufferCapabilities capabilities)
- throws AWTException { }
+ throws AWTException
+ {
+ // Nothing to do here for lightweights.
+ }
public Image getBackBuffer()
{
+ // Nothing to do here for lightweights.
return null;
}
- public void flip(BufferCapabilities.FlipContents contents) { }
+ public void flip(BufferCapabilities.FlipContents contents)
+ {
+ // Nothing to do here for lightweights.
+ }
- public void destroyBuffers() { }
+ public void destroyBuffers()
+ {
+ // Nothing to do here for lightweights.
+ }
public boolean isRestackSupported()
{
+ // Nothing to do here for lightweights.
return false;
}
public void cancelPendingPaint(int x, int y, int width, int height)
{
-
+ // Nothing to do here for lightweights.
}
public void restack()
{
-
+ // Nothing to do here for lightweights.
}
public Rectangle getBounds()
{
+ // Nothing to do here for lightweights.
return null;
}
public void reparent(ContainerPeer parent)
{
-
+ // Nothing to do here for lightweights.
}
public void setBounds(int x, int y, int z, int width, int height)
{
-
+ // Nothing to do here for lightweights.
}
public boolean isReparentSupported()
{
- return false;
+ // Nothing to do here for lightweights.
+ return true;
}
public void layout()
{
-
+ // Nothing to do here for lightweights.
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java b/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java
new file mode 100644
index 00000000000..962ecd9904e
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java
@@ -0,0 +1,58 @@
+/* NativeEventLoopRunningEvent.java -- communicates to EventQueue the
+ state of the native event loop
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.peer;
+
+import java.awt.AWTEvent;
+
+public class NativeEventLoopRunningEvent
+ extends AWTEvent
+{
+ private boolean running;
+
+ public NativeEventLoopRunningEvent(Object source)
+ {
+ super(source, 2999);
+ running = ((Boolean) source).booleanValue();
+ }
+
+ public boolean isRunning()
+ {
+ return running;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java
new file mode 100644
index 00000000000..5238bfe7410
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java
@@ -0,0 +1,283 @@
+/* AsyncImage.java -- Loads images asynchronously
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.peer.gtk;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Supports asynchronous loading of images.
+ */
+public class AsyncImage
+ extends Image
+{
+
+ /**
+ * Returned as source as long as the image is not complete.
+ */
+ private class NullImageSource
+ implements ImageProducer
+ {
+ private ArrayList consumers;
+
+ NullImageSource()
+ {
+ consumers = new ArrayList();
+ }
+
+ public void addConsumer(ImageConsumer ic)
+ {
+ consumers.add(ic);
+ }
+
+ public boolean isConsumer(ImageConsumer ic)
+ {
+ return consumers.contains(ic);
+ }
+
+ public void removeConsumer(ImageConsumer ic)
+ {
+ consumers.remove(ic);
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic)
+ {
+ startProduction(ic);
+ }
+
+ public void startProduction(ImageConsumer ic)
+ {
+ consumers.add(ic);
+ for (int i = consumers.size() - 1; i >= 0; i--)
+ {
+ ImageConsumer c = (ImageConsumer) consumers.get(i);
+ c.setDimensions(1, 1);
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+ }
+
+ }
+
+ /**
+ * Loads the image asynchronously.
+ */
+ private class Loader
+ implements Runnable
+ {
+ private URL url;
+ Loader(URL u)
+ {
+ url = u;
+ }
+
+ public void run()
+ {
+ Image image;
+ try
+ {
+ GtkImage gtkImage = new GtkImage(url);
+ image = CairoSurface.getBufferedImage(gtkImage);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ image = null;
+ }
+ realImage = GtkToolkit.imageOrError(image);
+ synchronized (AsyncImage.this)
+ {
+ notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT
+ | ImageObserver.WIDTH | ImageObserver.PROPERTIES);
+ observers = null; // Not needed anymore.
+ }
+ }
+ }
+
+ /**
+ * The real image. This is null as long as the image is not complete.
+ */
+ Image realImage;
+
+ /**
+ * The image observers.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ HashSet observers;
+
+ /**
+ * Creates a new AsyncImage that loads from the specified URL.
+ */
+ AsyncImage(URL url)
+ {
+ observers = new HashSet();
+ Loader l = new Loader(url);
+ Thread t = new Thread(l);
+ t.start();
+ }
+
+ public void flush()
+ {
+ // Nothing to do here.
+ }
+
+ public Graphics getGraphics()
+ {
+ Image r = realImage;
+ Graphics g = null;
+ if (r != null)
+ g = r.getGraphics(); // Should we return some dummy graphics instead?
+ return g;
+ }
+
+ public int getHeight(ImageObserver observer)
+ {
+ addObserver(observer);
+ int height = 0;
+ Image r = realImage;
+ if (r != null)
+ height = r.getHeight(observer);
+ return height;
+ }
+
+ public Object getProperty(String name, ImageObserver observer)
+ {
+ addObserver(observer);
+ Image r = realImage;
+ Object prop = null;
+ if (r != null)
+ prop = r.getProperty(name, observer);
+ return prop;
+ }
+
+ public ImageProducer getSource()
+ {
+ Image r = realImage;
+ ImageProducer source;
+ if (r == null)
+ source = new NullImageSource();
+ else
+ source = r.getSource();
+ return source;
+ }
+
+ public int getWidth(ImageObserver observer)
+ {
+ addObserver(observer);
+ int width = 0;
+ Image r = realImage;
+ if (r != null)
+ width = r.getWidth(observer);
+ return width;
+ }
+
+ void addObserver(ImageObserver obs)
+ {
+ if (obs != null)
+ {
+ synchronized (this)
+ {
+ // This field gets null when image loading is complete and we don't
+ // need to store any more observers.
+ HashSet observs = observers;
+ if (observs != null)
+ {
+ observs.add(obs);
+ }
+ else
+ {
+ // When the image is complete, notify the observer. Dunno if
+ // that's really needed, but to be sure.
+ obs.imageUpdate(this, ImageObserver.WIDTH
+ | ImageObserver.HEIGHT
+ |ImageObserver.ALLBITS
+ | ImageObserver.PROPERTIES, 0, 0,
+ realImage.getWidth(null),
+ realImage.getHeight(null));
+ }
+ }
+ }
+ }
+
+ static Image realImage(Image img, ImageObserver obs)
+ {
+ if (img instanceof AsyncImage)
+ {
+ ((AsyncImage) img).addObserver(obs);
+ Image r = ((AsyncImage) img).realImage;
+ if (r != null)
+ img = r;
+ }
+ return img;
+ }
+
+ void notifyObservers(int status)
+ {
+ assert Thread.holdsLock(this);
+ // This field gets null when image loading is complete.
+ HashSet observs = observers;
+ if (observs != null)
+ {
+ Image r = realImage;
+ Iterator i = observs.iterator();
+ while (i.hasNext())
+ {
+ ImageObserver obs = (ImageObserver) i.next();
+ obs.imageUpdate(this, status, 0, 0, r.getWidth(null),
+ r.getHeight(null));
+ }
+ }
+ }
+
+ int checkImage(ImageObserver obs)
+ {
+ addObserver(obs);
+ int flags = 0;
+ if (realImage != null)
+ flags = ImageObserver.ALLBITS | ImageObserver.WIDTH
+ | ImageObserver.HEIGHT | ImageObserver.PROPERTIES;
+ return flags;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
index 6a74eabc5d6..c792645d3e8 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
@@ -38,22 +38,27 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
+import java.awt.Toolkit;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferInt;
import java.awt.image.ColorModel;
-import java.awt.image.DirectColorModel;
-import java.awt.image.RenderedImage;
+import java.awt.image.DataBufferInt;
import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SinglePixelPackedSampleModel;
import java.util.WeakHashMap;
/**
@@ -67,7 +72,13 @@ public class BufferedImageGraphics extends CairoGraphics2D
/**
* the buffered Image.
*/
- private BufferedImage image;
+ private BufferedImage image, buffer;
+
+ /**
+ * Allows us to lock the image from updates (if we want to perform a few
+ * intermediary operations on the cairo surface, then update it all at once)
+ */
+ private boolean locked;
/**
* Image size.
@@ -89,12 +100,6 @@ public class BufferedImageGraphics extends CairoGraphics2D
*/
private long cairo_t;
- /**
- * Colormodels we recognize for fast copying.
- */
- static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
- static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
- 0xFF000000);
private boolean hasFastCM;
private boolean hasAlpha;
@@ -104,15 +109,19 @@ public class BufferedImageGraphics extends CairoGraphics2D
this.image = bi;
imageWidth = bi.getWidth();
imageHeight = bi.getHeight();
- if(bi.getColorModel().equals(rgb32))
+ locked = false;
+
+ if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel))
+ hasFastCM = false;
+ else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque))
{
hasFastCM = true;
hasAlpha = false;
}
- else if(bi.getColorModel().equals(argb32))
+ else if(bi.getColorModel().equals(CairoSurface.cairoColorModel))
{
hasFastCM = true;
- hasAlpha = false;
+ hasAlpha = true;
}
else
hasFastCM = false;
@@ -128,27 +137,45 @@ public class BufferedImageGraphics extends CairoGraphics2D
cairo_t = surface.newCairoContext();
- DataBuffer db = bi.getRaster().getDataBuffer();
+ // Get pixels out of buffered image and set in cairo surface
+ Raster raster = bi.getRaster();
int[] pixels;
- // get pixels
- if(db instanceof CairoSurface)
- pixels = ((CairoSurface)db).getPixels(imageWidth * imageHeight);
+ if (hasFastCM)
+ {
+ SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel();
+ int minX = image.getRaster().getSampleModelTranslateX();
+ int minY = image.getRaster().getSampleModelTranslateY();
+
+ // Pull pixels directly out of data buffer
+ if(raster instanceof CairoSurface)
+ pixels = ((CairoSurface)raster).getPixels(raster.getWidth() * raster.getHeight());
+ else
+ pixels = ((DataBufferInt)raster.getDataBuffer()).getData();
+
+ // Discard pixels that fall outside of the image's bounds
+ // (ie, this image is actually a subimage of a different image)
+ if (!(sm.getScanlineStride() == imageWidth && minX == 0 && minY == 0))
+ {
+ int[] pixels2 = new int[imageWidth * imageHeight];
+ int scanline = sm.getScanlineStride();
+
+ for (int i = 0; i < imageHeight; i++)
+ System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2, i * imageWidth, imageWidth);
+
+ pixels = pixels2;
+ }
+
+ // Fill the alpha channel as opaque if image does not have alpha
+ if( !hasAlpha )
+ for(int i = 0; i < pixels.length; i++)
+ pixels[i] &= 0xFFFFFFFF;
+ }
else
{
- if( hasFastCM )
- {
- pixels = ((DataBufferInt)db).getData();
- if( !hasAlpha )
- for(int i = 0; i < pixels.length; i++)
- pixels[i] &= 0xFFFFFFFF;
- }
- else
- {
- pixels = CairoGraphics2D.findSimpleIntegerArray
- (image.getColorModel(),image.getData());
- }
+ pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(),image.getData());
}
+
surface.setPixels( pixels );
setup( cairo_t );
@@ -157,12 +184,17 @@ public class BufferedImageGraphics extends CairoGraphics2D
BufferedImageGraphics(BufferedImageGraphics copyFrom)
{
+ image = copyFrom.image;
surface = copyFrom.surface;
cairo_t = surface.newCairoContext();
imageWidth = copyFrom.imageWidth;
imageHeight = copyFrom.imageHeight;
+ locked = false;
+
+ hasFastCM = copyFrom.hasFastCM;
+ hasAlpha = copyFrom.hasAlpha;
+
copy( copyFrom, cairo_t );
- setClip(0, 0, surface.width, surface.height);
}
/**
@@ -170,25 +202,82 @@ public class BufferedImageGraphics extends CairoGraphics2D
*/
private void updateBufferedImage(int x, int y, int width, int height)
{
+ if (locked)
+ return;
+
+ double[] points = new double[]{x, y, width+x, height+y};
+ transform.transform(points, 0, points, 0, 2);
+ x = (int)points[0];
+ y = (int)points[1];
+ width = (int)Math.ceil(points[2] - points[0]);
+ height = (int)Math.ceil(points[3] - points[1]);
+
int[] pixels = surface.getPixels(imageWidth * imageHeight);
if( x > imageWidth || y > imageHeight )
return;
+
+ // Deal with negative width/height.
+ if (height < 0)
+ {
+ y += height;
+ height = -height;
+ }
+ if (width < 0)
+ {
+ x += width;
+ width = -width;
+ }
+
// Clip edges.
- if( x < 0 ){ width = width + x; x = 0; }
- if( y < 0 ){ height = height + y; y = 0; }
+ if( x < 0 )
+ x = 0;
+ if( y < 0 )
+ y = 0;
+
if( x + width > imageWidth )
width = imageWidth - x;
if( y + height > imageHeight )
height = imageHeight - y;
-
- if( !hasFastCM )
- image.setRGB(x, y, width, height, pixels,
- x + y * imageWidth, imageWidth);
+
+ if(!hasFastCM)
+ {
+ image.setRGB(x, y, width, height, pixels,
+ x + y * imageWidth, imageWidth);
+ // The setRGB method assumes (or should assume) that pixels are NOT
+ // alpha-premultiplied, but Cairo stores data with premultiplication
+ // (thus the pixels returned in getPixels are premultiplied).
+ // This is ignored for consistency, however, since in
+ // CairoGrahpics2D.drawImage we also use non-premultiplied data
+
+ }
else
- System.arraycopy(pixels, y * imageWidth,
- ((DataBufferInt)image.getRaster().getDataBuffer()).
- getData(), y * imageWidth, height * imageWidth);
+ {
+ int[] db = ((DataBufferInt)image.getRaster().getDataBuffer()).
+ getData();
+
+ // This should not fail, as we check the image sample model when we
+ // set the hasFastCM flag
+ SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel() ;
+
+ int minX = image.getRaster().getSampleModelTranslateX();
+ int minY = image.getRaster().getSampleModelTranslateY();
+
+ if (sm.getScanlineStride() == imageWidth && minX == 0)
+ {
+ System.arraycopy(pixels, y * imageWidth,
+ db, (y - minY) * imageWidth,
+ height * imageWidth);
+ }
+ else
+ {
+ int scanline = sm.getScanlineStride();
+ for (int i = y; i < (height + y); i++)
+ System.arraycopy(pixels, i * imageWidth + x, db,
+ (i - minY) * scanline + x - minX, width);
+
+ }
+ }
}
/**
@@ -221,36 +310,246 @@ public class BufferedImageGraphics extends CairoGraphics2D
*/
public void draw(Shape s)
{
- super.draw(s);
- Rectangle r = s.getBounds();
- updateBufferedImage(r.x, r.y, r.width, r.height);
+ // Find total bounds of shape
+ Rectangle r = findStrokedBounds(s);
+ if (shiftDrawCalls)
+ {
+ r.width++;
+ r.height++;
+ }
+
+ // Do the drawing
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.draw(s);
+ updateBufferedImage(r.x, r.y, r.width, r.height);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setStroke(this.getStroke());
+ g2d.setColor(this.getColor());
+ g2d.setTransform(transform);
+ g2d.draw(s);
+
+ drawComposite(r.getBounds2D(), null);
+ }
}
public void fill(Shape s)
{
- super.fill(s);
- Rectangle r = s.getBounds();
- updateBufferedImage(r.x, r.y, r.width, r.height);
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.fill(s);
+ Rectangle r = s.getBounds();
+ updateBufferedImage(r.x, r.y, r.width, r.height);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.setTransform(transform);
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
}
public void drawRenderedImage(RenderedImage image, AffineTransform xform)
{
- super.drawRenderedImage(image, xform);
- updateBufferedImage(0, 0, imageWidth, imageHeight);
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.drawRenderedImage(image, xform);
+ updateBufferedImage(0, 0, imageWidth, imageHeight);
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.setTransform(transform);
+ g2d.drawRenderedImage(image, xform);
+
+ drawComposite(buffer.getRaster().getBounds(), null);
+ }
+
}
protected boolean drawImage(Image img, AffineTransform xform,
Color bgcolor, ImageObserver obs)
{
- boolean rv = super.drawImage(img, xform, bgcolor, obs);
- updateBufferedImage(0, 0, imageWidth, imageHeight);
- return rv;
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ boolean rv = super.drawImage(img, xform, bgcolor, obs);
+ updateBufferedImage(0, 0, imageWidth, imageHeight);
+ return rv;
+ }
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find translated bounds
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
+ bImg.getHeight() + bImg.getMinY());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+
+ // Perform compositing
+ return drawComposite(new Rectangle2D.Double(origin.getX(),
+ origin.getY(),
+ pt.getX(), pt.getY()),
+ obs);
+ }
}
public void drawGlyphVector(GlyphVector gv, float x, float y)
{
- super.drawGlyphVector(gv, x, y);
- updateBufferedImage(0, 0, imageWidth, imageHeight);
+ // Find absolute bounds, in user-space, of this glyph vector
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+
+ // Perform draw operation
+ if (comp == null || comp instanceof AlphaComposite)
+ {
+ super.drawGlyphVector(gv, x, y);
+ updateBufferedImage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(), (int)bounds.getHeight());
+ }
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setStroke(this.getStroke());
+ g2d.setTransform(transform);
+ g2d.drawGlyphVector(gv, x, y);
+
+ drawComposite(bounds, null);
+ }
+ }
+
+ /**
+ * Perform composite drawing from the buffer onto the main image.
+ *
+ * The image to be composited should already be drawn into the buffer, in the
+ * proper place, after all necessary transforms have been applied.
+ *
+ * @param bounds The bounds to draw, in user-space.
+ * @param observer The image observer, if any (may be null).
+ * @return True on success, false on failure.
+ */
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Find bounds in device space
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+ bounds = new Rectangle2D.Double(points[0], points[1],
+ (points[2] - points[0]),
+ (points[3] - points[1]));
+
+ // Clip bounds by the stored clip, and by the internal buffer
+ Rectangle2D devClip = this.getClipInDevSpace();
+ Rectangle2D.intersect(bounds, devClip, bounds);
+ devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, devClip, bounds);
+
+ // Round bounds as needed, but be conservative in our rounding
+ // (otherwise it may leave unpainted stripes)
+ double x = bounds.getX();
+ double y = bounds.getY();
+ double w = bounds.getWidth();
+ double h = bounds.getHeight();
+ if (Math.floor(x) != x)
+ w--;
+ if (Math.floor(y) != y)
+ h--;
+ bounds.setRect(Math.ceil(x), Math.ceil(y), Math.floor(w), Math.floor(h));
+
+ // Find subimage of internal buffer for updating
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Find subimage of main image for updating
+ BufferedImage current = image;
+ current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ current.getRaster());
+
+ // Prevent the clearRect in CairoGraphics2D.drawImage from clearing
+ // our composited image
+ locked = true;
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ boolean rv = super.drawImage(current,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ new Color(0,0,0,0), null);
+ locked = false;
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ buffer = new BufferedImage(image.getWidth(), image.getHeight(),
+ BufferedImage.TYPE_INT_ARGB);
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ return image.getColorModel();
+ }
+
+ protected ColorModel getBufferCM()
+ {
+ return ColorModel.getRGBdefault();
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java
index b665f562e25..348801800d2 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java
@@ -45,6 +45,7 @@ import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
+import java.awt.CompositeContext;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
@@ -53,6 +54,8 @@ import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
@@ -68,6 +71,7 @@ import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
@@ -131,6 +135,7 @@ public abstract class CairoGraphics2D extends Graphics2D
* The current paint
*/
Paint paint;
+ boolean customPaint;
/**
* The current stroke
@@ -161,6 +166,7 @@ public abstract class CairoGraphics2D extends Graphics2D
* The current compositing context, if any.
*/
Composite comp;
+ CompositeContext compCtx;
/**
* Rendering hint map.
@@ -172,7 +178,7 @@ public abstract class CairoGraphics2D extends Graphics2D
* coords be shifted to land on 0.5-pixel boundaries, in order to land on
* "middle of pixel" coordinates and light up complete pixels.
*/
- private boolean shiftDrawCalls = false;
+ protected boolean shiftDrawCalls = false;
/**
* Keep track if the first clip to be set, which is restored on setClip(null);
@@ -190,6 +196,18 @@ public abstract class CairoGraphics2D extends Graphics2D
0xFF000000);
/**
+ * Native constants for interpolation methods.
+ * Note, this corresponds to an enum in native/jni/gtk-peer/cairographics2d.h
+ */
+ public static final int INTERPOLATION_NEAREST = 0,
+ INTERPOLATION_BILINEAR = 1,
+ INTERPOLATION_BICUBIC = 5,
+ ALPHA_INTERPOLATION_SPEED = 2,
+ ALPHA_INTERPOLATION_QUALITY = 3,
+ ALPHA_INTERPOLATION_DEFAULT = 4;
+ // TODO: Does ALPHA_INTERPOLATION really correspond to CAIRO_FILTER_FAST/BEST/GOOD?
+
+ /**
* Constructor does nothing.
*/
public CairoGraphics2D()
@@ -204,7 +222,7 @@ public abstract class CairoGraphics2D extends Graphics2D
{
nativePointer = init(cairo_t_pointer);
setRenderingHints(new RenderingHints(getDefaultHints()));
- font = new Font("SansSerif", Font.PLAIN, 12);
+ setFont(new Font("SansSerif", Font.PLAIN, 12));
setColor(Color.black);
setBackground(Color.white);
setPaint(Color.black);
@@ -239,6 +257,8 @@ public abstract class CairoGraphics2D extends Graphics2D
bg = new Color(g.bg.getRGB());
}
+ firstClip = g.firstClip;
+ originalClip = g.originalClip;
clip = g.getClip();
if (g.transform == null)
@@ -246,14 +266,14 @@ public abstract class CairoGraphics2D extends Graphics2D
else
transform = new AffineTransform(g.transform);
- font = g.font;
-
+ setFont(g.font);
setColor(foreground);
setBackground(bg);
setPaint(paint);
setStroke(stroke);
setTransformImpl(transform);
setClip(clip);
+ setComposite(comp);
}
/**
@@ -274,6 +294,8 @@ public abstract class CairoGraphics2D extends Graphics2D
{
disposeNative(nativePointer);
nativePointer = 0;
+ if (compCtx != null)
+ compCtx.dispose();
}
/**
@@ -293,6 +315,11 @@ public abstract class CairoGraphics2D extends Graphics2D
int width, int height, int dx, int dy);
+ /**
+ * Find the bounds of this graphics context, in device space.
+ *
+ * @return the bounds in device-space
+ */
protected abstract Rectangle2D getRealBounds();
////// Native Methods ////////////////////////////////////////////////////
@@ -309,15 +336,17 @@ public abstract class CairoGraphics2D extends Graphics2D
* @param i2u - affine transform array
*/
private native void drawPixels(long pointer, int[] pixels, int w, int h,
- int stride, double[] i2u, double alpha);
+ int stride, double[] i2u, double alpha,
+ int interpolation);
private native void setGradient(long pointer, double x1, double y1,
double x2, double y2,
int r1, int g1, int b1, int a1, int r2,
int g2, int b2, int a2, boolean cyclic);
- private native void setTexturePixels(long pointer, int[] pixels, int w,
- int h, int stride);
+ private native void setPaintPixels(long pointer, int[] pixels, int w,
+ int h, int stride, boolean repeat,
+ int x, int y);
/**
* Set the current transform matrix
@@ -365,6 +394,10 @@ public abstract class CairoGraphics2D extends Graphics2D
float x, float y, int n,
int[] codes, float[] positions);
+ /**
+ * Set the font in cairo.
+ */
+ private native void cairoSetFont(long pointer, GdkFontPeer font);
private native void cairoRelCurveTo(long pointer, double dx1, double dy1,
double dx2, double dy2, double dx3,
@@ -441,11 +474,6 @@ public abstract class CairoGraphics2D extends Graphics2D
private native void cairoResetClip(long pointer);
/**
- * Set interpolation types
- */
- private native void cairoSurfaceSetFilter(long pointer, int filter);
-
- /**
* Draws a line from (x1,y1) to (x2,y2).
*
* @param pointer the native pointer
@@ -666,13 +694,14 @@ public abstract class CairoGraphics2D extends Graphics2D
public void setPaint(Paint p)
{
- if (paint == null)
+ if (p == null)
return;
paint = p;
if (paint instanceof Color)
{
setColor((Color) paint);
+ customPaint = false;
}
else if (paint instanceof TexturePaint)
{
@@ -690,7 +719,8 @@ public abstract class CairoGraphics2D extends Graphics2D
AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
BufferedImage texture = op.filter(img, null);
int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
- setTexturePixels(nativePointer, pixels, width, height, width);
+ setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0);
+ customPaint = false;
}
else if (paint instanceof GradientPaint)
{
@@ -703,9 +733,108 @@ public abstract class CairoGraphics2D extends Graphics2D
c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(),
c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(),
gp.isCyclic());
+ customPaint = false;
}
else
- throw new java.lang.UnsupportedOperationException();
+ {
+ customPaint = true;
+ }
+ }
+
+ /**
+ * Sets a custom paint
+ *
+ * @param bounds the bounding box, in user space
+ */
+ protected void setCustomPaint(Rectangle bounds)
+ {
+ if (paint instanceof Color || paint instanceof TexturePaint
+ || paint instanceof GradientPaint)
+ return;
+
+ int userX = bounds.x;
+ int userY = bounds.y;
+ int userWidth = bounds.width;
+ int userHeight = bounds.height;
+
+ // Find bounds in device space
+ Point2D origin = transform.transform(new Point2D.Double(userX, userY),
+ null);
+ Point2D extreme = transform.transform(new Point2D.Double(userWidth + userX,
+ userHeight + userY),
+ null);
+ int deviceX = (int)origin.getX();
+ int deviceY = (int)origin.getY();
+ int deviceWidth = (int)Math.ceil(extreme.getX() - origin.getX());
+ int deviceHeight = (int)Math.ceil(extreme.getY() - origin.getY());
+
+ // Get raster of the paint background
+ PaintContext pc = paint.createContext(CairoSurface.cairoColorModel,
+ new Rectangle(deviceX, deviceY,
+ deviceWidth,
+ deviceHeight),
+ bounds,
+ transform, hints);
+
+ Raster raster = pc.getRaster(deviceX, deviceY, deviceWidth,
+ deviceHeight);
+
+ // Clear the transform matrix in Cairo, since the raster returned by the
+ // PaintContext is already in device-space
+ AffineTransform oldTx = new AffineTransform(transform);
+ setTransformImpl(new AffineTransform());
+
+ // Set pixels in cairo, aligning the top-left of the background image
+ // to the top-left corner in device space
+ if (pc.getColorModel().equals(CairoSurface.cairoColorModel)
+ && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT)
+ {
+ // Use a fast copy if the paint context can uses a Cairo-compatible
+ // color model
+ setPaintPixels(nativePointer,
+ (int[])raster.getDataElements(0, 0, deviceWidth,
+ deviceHeight, null),
+ deviceWidth, deviceHeight, deviceWidth, false,
+ deviceX, deviceY);
+ }
+
+ else if (pc.getColorModel().equals(CairoSurface.cairoCM_opaque)
+ && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT)
+ {
+ // We can also optimize if the context uses a similar color model
+ // but without an alpha channel; we just add the alpha
+ int[] pixels = (int[])raster.getDataElements(0, 0, deviceWidth,
+ deviceHeight, null);
+
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] = 0xff000000 | (pixels[i] & 0x00ffffff);
+
+ setPaintPixels(nativePointer, pixels, deviceWidth, deviceHeight,
+ deviceWidth, false, deviceX, deviceY);
+ }
+
+ else
+ {
+ // Fall back on wrapping the raster in a BufferedImage, and
+ // use BufferedImage.getRGB() to do color-model conversion
+ WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(),
+ new Point(raster.getMinX(),
+ raster.getMinY()));
+ wr.setRect(raster);
+
+ BufferedImage img2 = new BufferedImage(pc.getColorModel(), wr,
+ pc.getColorModel().isAlphaPremultiplied(),
+ null);
+
+ setPaintPixels(nativePointer,
+ img2.getRGB(0, 0, deviceWidth, deviceHeight, null, 0,
+ deviceWidth),
+ deviceWidth, deviceHeight, deviceWidth, false,
+ deviceX, deviceY);
+ }
+
+ // Restore transform
+ setTransformImpl(oldTx);
}
public Stroke getStroke()
@@ -736,6 +865,33 @@ public abstract class CairoGraphics2D extends Graphics2D
}
}
+ /**
+ * Utility method to find the bounds of a shape, including the stroke width.
+ *
+ * @param s the shape
+ * @return the bounds of the shape, including stroke width
+ */
+ protected Rectangle findStrokedBounds(Shape s)
+ {
+ Rectangle r = s.getBounds();
+
+ if (stroke instanceof BasicStroke)
+ {
+ int strokeWidth = (int)Math.ceil(((BasicStroke)stroke).getLineWidth());
+ r.x -= strokeWidth / 2;
+ r.y -= strokeWidth / 2;
+ r.height += strokeWidth;
+ r.width += strokeWidth;
+ }
+ else
+ {
+ Shape s2 = stroke.createStrokedShape(s);
+ r = s2.getBounds();
+ }
+
+ return r;
+ }
+
public void setPaintMode()
{
setComposite(AlphaComposite.SrcOver);
@@ -896,25 +1052,56 @@ public abstract class CairoGraphics2D extends Graphics2D
*/
public void setComposite(Composite comp)
{
+ if (this.comp == comp)
+ return;
+
this.comp = comp;
+ if (compCtx != null)
+ compCtx.dispose();
+ compCtx = null;
if (comp instanceof AlphaComposite)
{
AlphaComposite a = (AlphaComposite) comp;
- cairoSetOperator(nativePointer, a.getRule());
+ cairoSetOperator(nativePointer, a.getRule());
}
+
else
{
- // FIXME: this check is only required "if this Graphics2D
- // context is drawing to a Component on the display screen".
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkPermission(new AWTPermission("readDisplayPixels"));
-
- // FIXME: implement general Composite support
- throw new java.lang.UnsupportedOperationException();
+ cairoSetOperator(nativePointer, AlphaComposite.SRC_OVER);
+
+ if (comp != null)
+ {
+ // FIXME: this check is only required "if this Graphics2D
+ // context is drawing to a Component on the display screen".
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new AWTPermission("readDisplayPixels"));
+
+ compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints);
+ }
}
}
+
+ /**
+ * Returns the Colour Model describing the native, raw image data for this
+ * specific peer.
+ *
+ * @return ColorModel the ColorModel of native data in this peer
+ */
+ protected abstract ColorModel getNativeCM();
+
+ /**
+ * Returns the Color Model describing the buffer that this peer uses
+ * for custom composites.
+ *
+ * @return ColorModel the ColorModel of the composite buffer in this peer.
+ */
+ protected ColorModel getBufferCM()
+ {
+ // This may be overridden by some subclasses
+ return getNativeCM();
+ }
///////////////////////// DRAWING PRIMITIVES ///////////////////////////////////
@@ -929,21 +1116,30 @@ public abstract class CairoGraphics2D extends Graphics2D
return;
}
- createPath(s);
+ if (customPaint)
+ {
+ Rectangle r = findStrokedBounds(s);
+ setCustomPaint(r);
+ }
+
+ createPath(s, true);
cairoStroke(nativePointer);
}
public void fill(Shape s)
{
- createPath(s);
+ createPath(s, false);
+ if (customPaint)
+ setCustomPaint(s.getBounds());
+
double alpha = 1.0;
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
cairoFill(nativePointer, alpha);
}
- private void createPath(Shape s)
+ private void createPath(Shape s, boolean isDraw)
{
cairoNewPath(nativePointer);
@@ -951,9 +1147,25 @@ public abstract class CairoGraphics2D extends Graphics2D
if (s instanceof Rectangle2D)
{
Rectangle2D r = (Rectangle2D) s;
- cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls),
- shifted(r.getY(), shiftDrawCalls), r.getWidth(),
- r.getHeight());
+
+ // Pixels need to be shifted in draw operations to ensure that they
+ // light up entire pixels, but we also need to make sure the rectangle
+ // does not get distorted by this shifting operation
+ double x = shiftX(r.getX(),shiftDrawCalls && isDraw);
+ double y = shiftY(r.getY(), shiftDrawCalls && isDraw);
+ double w = Math.round(r.getWidth());
+ double h = Math.round(r.getHeight());
+ cairoRectangle(nativePointer, x, y, w, h);
+ }
+
+ // Lines are easy too
+ else if (s instanceof Line2D)
+ {
+ Line2D l = (Line2D) s;
+ cairoMoveTo(nativePointer, shiftX(l.getX1(), shiftDrawCalls && isDraw),
+ shiftY(l.getY1(), shiftDrawCalls && isDraw));
+ cairoLineTo(nativePointer, shiftX(l.getX2(), shiftDrawCalls && isDraw),
+ shiftY(l.getY2(), shiftDrawCalls && isDraw));
}
// We can optimize ellipses too; however we don't bother optimizing arcs:
@@ -982,9 +1194,9 @@ public abstract class CairoGraphics2D extends Graphics2D
}
cairoArc(nativePointer,
- shifted(e.getCenterX() / xscale, shiftDrawCalls),
- shifted(e.getCenterY() / yscale, shiftDrawCalls), radius, 0,
- Math.PI * 2);
+ shiftX(e.getCenterX() / xscale, shiftDrawCalls && isDraw),
+ shiftY(e.getCenterY() / yscale, shiftDrawCalls && isDraw),
+ radius, 0, Math.PI * 2);
if (xscale != 1 || yscale != 1)
cairoRestore(nativePointer);
@@ -993,7 +1205,7 @@ public abstract class CairoGraphics2D extends Graphics2D
// All other shapes are broken down and drawn in steps using the
// PathIterator
else
- walkPath(s.getPathIterator(null), shiftDrawCalls);
+ walkPath(s.getPathIterator(null), shiftDrawCalls && isDraw);
}
/**
@@ -1006,8 +1218,14 @@ public abstract class CairoGraphics2D extends Graphics2D
{
if (bg != null)
cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0,
- bg.getGreen() / 255.0, bg.getBlue() / 255.0, 1.0);
+ bg.getGreen() / 255.0, bg.getBlue() / 255.0,
+ bg.getAlpha() / 255.0);
+
+ Composite oldcomp = comp;
+ setComposite(AlphaComposite.Src);
fillRect(x, y, width, height);
+
+ setComposite(oldcomp);
updateColor();
}
@@ -1033,15 +1251,14 @@ public abstract class CairoGraphics2D extends Graphics2D
// to draw a single pixel. This is emulated by drawing
// a one pixel sized rectangle.
if (x1 == x2 && y1 == y2)
- cairoFillRect(nativePointer, x1, y1, 1, 1);
+ fill(new Rectangle(x1, y1, 1, 1));
else
- cairoDrawLine(nativePointer, x1 + 0.5, y1 + 0.5, x2 + 0.5, y2 + 0.5);
+ draw(new Line2D.Double(x1, y1, x2, y2));
}
public void drawRect(int x, int y, int width, int height)
{
- cairoDrawRect(nativePointer, shifted(x, shiftDrawCalls),
- shifted(y, shiftDrawCalls), width, height);
+ draw(new Rectangle(x, y, width, height));
}
public void fillArc(int x, int y, int width, int height, int startAngle,
@@ -1049,12 +1266,12 @@ public abstract class CairoGraphics2D extends Graphics2D
{
fill(new Arc2D.Double((double) x, (double) y, (double) width,
(double) height, (double) startAngle,
- (double) arcAngle, Arc2D.OPEN));
+ (double) arcAngle, Arc2D.PIE));
}
public void fillRect(int x, int y, int width, int height)
{
- cairoFillRect(nativePointer, x, y, width, height);
+ fill (new Rectangle(x, y, width, height));
}
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
@@ -1117,7 +1334,7 @@ public abstract class CairoGraphics2D extends Graphics2D
Rectangle2D r = getRealBounds();
- if( width < 0 || height < 0 )
+ if( width <= 0 || height <= 0 )
return;
// Return if outside the surface
if( x + dx > r.getWidth() || y + dy > r.getHeight() )
@@ -1150,32 +1367,10 @@ public abstract class CairoGraphics2D extends Graphics2D
///////////////////////// RENDERING HINTS ///////////////////////////////////
- /**
- * FIXME- support better
- */
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
{
hints.put(hintKey, hintValue);
- if (hintKey.equals(RenderingHints.KEY_INTERPOLATION)
- || hintKey.equals(RenderingHints.KEY_ALPHA_INTERPOLATION))
- {
- if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
- cairoSurfaceSetFilter(nativePointer, 0);
-
- else if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
- cairoSurfaceSetFilter(nativePointer, 1);
-
- else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
- cairoSurfaceSetFilter(nativePointer, 2);
-
- else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
- cairoSurfaceSetFilter(nativePointer, 3);
-
- else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
- cairoSurfaceSetFilter(nativePointer, 4);
- }
-
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
}
@@ -1189,30 +1384,15 @@ public abstract class CairoGraphics2D extends Graphics2D
{
this.hints = new RenderingHints(getDefaultHints());
this.hints.add(new RenderingHints(hints));
-
- if (hints.containsKey(RenderingHints.KEY_INTERPOLATION))
- {
- if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
- cairoSurfaceSetFilter(nativePointer, 0);
-
- else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
- cairoSurfaceSetFilter(nativePointer, 1);
- }
-
- if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION))
- {
- if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
- cairoSurfaceSetFilter(nativePointer, 2);
-
- else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
- cairoSurfaceSetFilter(nativePointer, 3);
-
- else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
- cairoSurfaceSetFilter(nativePointer, 4);
- }
-
+
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
+
+ if (compCtx != null)
+ {
+ compCtx.dispose();
+ compCtx = comp.createContext(getNativeCM(), getNativeCM(), this.hints);
+ }
}
public void addRenderingHints(Map hints)
@@ -1224,6 +1404,30 @@ public abstract class CairoGraphics2D extends Graphics2D
{
return hints;
}
+
+ private int getInterpolation()
+ {
+ if (this.hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
+ return INTERPOLATION_NEAREST;
+
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
+ return INTERPOLATION_BILINEAR;
+
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC))
+ return INTERPOLATION_BICUBIC;
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
+ return ALPHA_INTERPOLATION_SPEED;
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
+ return ALPHA_INTERPOLATION_QUALITY;
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
+ return ALPHA_INTERPOLATION_DEFAULT;
+
+ // Do bilinear interpolation as default
+ return INTERPOLATION_BILINEAR;
+ }
///////////////////////// IMAGE. METHODS ///////////////////////////////////
@@ -1259,7 +1463,7 @@ public abstract class CairoGraphics2D extends Graphics2D
// Note - this can get us in trouble when the gdk lock is re-acquired.
// for example by VolatileImage. See ComponentGraphics for how we work
// around this.
-
+ img = AsyncImage.realImage(img, obs);
if( !(img instanceof BufferedImage) )
{
ImageProducer source = img.getSource();
@@ -1269,18 +1473,18 @@ public abstract class CairoGraphics2D extends Graphics2D
}
BufferedImage b = (BufferedImage) img;
- DataBuffer db;
+ Raster raster;
double[] i2u = new double[6];
int width = b.getWidth();
int height = b.getHeight();
-
+
// If this BufferedImage has a BufferedImageGraphics object,
// use the cached CairoSurface that BIG is drawing onto
if( BufferedImageGraphics.bufferedImages.get( b ) != null )
- db = (DataBuffer)BufferedImageGraphics.bufferedImages.get( b );
+ raster = (Raster)BufferedImageGraphics.bufferedImages.get( b );
else
- db = b.getRaster().getDataBuffer();
+ raster = b.getRaster();
invertedXform.getMatrix(i2u);
@@ -1288,29 +1492,37 @@ public abstract class CairoGraphics2D extends Graphics2D
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
- if(db instanceof CairoSurface)
+ if(raster instanceof CairoSurface)
{
- ((CairoSurface)db).drawSurface(nativePointer, i2u, alpha);
+ ((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha,
+ getInterpolation());
updateColor();
return true;
}
if( bgcolor != null )
{
- // Fill a rectangle with the background color
- // to composite the image onto.
- Paint oldPaint = paint;
- AffineTransform oldTransform = transform;
- setPaint( bgcolor );
- setTransform( invertedXform );
- fillRect(0, 0, width, height);
- setTransform( oldTransform );
- setPaint( oldPaint );
+ Color oldColor = bg;
+ setBackground(bgcolor);
+
+ double[] origin = new double[] {0,0};
+ double[] dimensions = new double[] {width, height};
+ xform.transform(origin, 0, origin, 0, 1);
+ xform.deltaTransform(dimensions, 0, dimensions, 0, 1);
+ clearRect((int)origin[0], (int)origin[1],
+ (int)dimensions[0], (int)dimensions[1]);
+
+ setBackground(oldColor);
}
int[] pixels = b.getRGB(0, 0, width, height, null, 0, width);
+
+ // FIXME: The above method returns data in the standard ARGB colorspace,
+ // meaning data should NOT be alpha pre-multiplied; however Cairo expects
+ // data to be premultiplied.
- drawPixels(nativePointer, pixels, width, height, width, i2u, alpha);
+ drawPixels(nativePointer, pixels, width, height, width, i2u, alpha,
+ getInterpolation());
// Cairo seems to lose the current color which must be restored.
updateColor();
@@ -1428,8 +1640,14 @@ public abstract class CairoGraphics2D extends Graphics2D
{
if (str == null || str.length() == 0)
return;
- (new TextLayout( str, getFont(), getFontRenderContext() )).
- draw(this, x, y);
+ GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
+ TextLayout tl = (TextLayout) fontPeer.textLayoutCache.get(str);
+ if (tl == null)
+ {
+ tl = new TextLayout( str, getFont(), getFontRenderContext() );
+ fontPeer.textLayoutCache.put(str, tl);
+ }
+ tl.draw(this, x, y);
}
public void drawString(String str, int x, int y)
@@ -1449,6 +1667,9 @@ public abstract class CairoGraphics2D extends Graphics2D
if( gv.getNumGlyphs() <= 0 )
return;
+ if (customPaint)
+ setCustomPaint(gv.getOutline().getBounds());
+
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
if (gv instanceof FreetypeGlyphVector && alpha == 1.0)
@@ -1458,9 +1679,10 @@ public abstract class CairoGraphics2D extends Graphics2D
float[] positions = gv.getGlyphPositions (0, n, null);
setFont (gv.getFont ());
- synchronized( this.font )
+ GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
+ synchronized (fontPeer)
{
- cairoDrawGlyphVector(nativePointer, (GdkFontPeer)getFont().getPeer(),
+ cairoDrawGlyphVector(nativePointer, fontPeer,
x, y, n, codes, positions);
}
}
@@ -1498,9 +1720,7 @@ public abstract class CairoGraphics2D extends Graphics2D
public FontMetrics getFontMetrics(Font f)
{
- // the reason we go via the toolkit here is to try to get
- // a cached object. the toolkit keeps such a cache.
- return Toolkit.getDefaultToolkit().getFontMetrics(f);
+ return ((GdkFontPeer) f.getPeer()).getFontMetrics(f);
}
public void setFont(Font f)
@@ -1516,6 +1736,12 @@ public abstract class CairoGraphics2D extends Graphics2D
font =
((ClasspathToolkit)(Toolkit.getDefaultToolkit()))
.getFont(f.getName(), f.getAttributes());
+
+ GdkFontPeer fontpeer = (GdkFontPeer) getFont().getPeer();
+ synchronized (fontpeer)
+ {
+ cairoSetFont(nativePointer, fontpeer);
+ }
}
public Font getFont()
@@ -1626,7 +1852,7 @@ public abstract class CairoGraphics2D extends Graphics2D
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(),
- r.getWidth(), i2u, alpha);
+ r.getWidth(), i2u, alpha, getInterpolation());
// Cairo seems to lose the current color which must be restored.
updateColor();
@@ -1635,12 +1861,33 @@ public abstract class CairoGraphics2D extends Graphics2D
}
/**
- * Shifts coordinates by 0.5.
+ * Shifts an x-coordinate by 0.5 in device space.
+ */
+ private double shiftX(double coord, boolean doShift)
+ {
+ if (doShift)
+ {
+ double shift = 0.5;
+ if (!transform.isIdentity())
+ shift /= transform.getScaleX();
+ return Math.round(coord) + shift;
+ }
+ else
+ return coord;
+ }
+
+ /**
+ * Shifts a y-coordinate by 0.5 in device space.
*/
- private double shifted(double coord, boolean doShift)
+ private double shiftY(double coord, boolean doShift)
{
if (doShift)
- return Math.floor(coord) + 0.5;
+ {
+ double shift = 0.5;
+ if (!transform.isIdentity())
+ shift /= transform.getScaleY();
+ return Math.round(coord) + shift;
+ }
else
return coord;
}
@@ -1661,35 +1908,35 @@ public abstract class CairoGraphics2D extends Graphics2D
switch (seg)
{
case PathIterator.SEG_MOVETO:
- x = shifted(coords[0], doShift);
- y = shifted(coords[1], doShift);
+ x = shiftX(coords[0], doShift);
+ y = shiftY(coords[1], doShift);
cairoMoveTo(nativePointer, x, y);
break;
case PathIterator.SEG_LINETO:
- x = shifted(coords[0], doShift);
- y = shifted(coords[1], doShift);
+ x = shiftX(coords[0], doShift);
+ y = shiftY(coords[1], doShift);
cairoLineTo(nativePointer, x, y);
break;
case PathIterator.SEG_QUADTO:
// splitting a quadratic bezier into a cubic:
// see: http://pfaedit.sourceforge.net/bezier.html
- double x1 = x + (2.0 / 3.0) * (shifted(coords[0], doShift) - x);
- double y1 = y + (2.0 / 3.0) * (shifted(coords[1], doShift) - y);
+ double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x);
+ double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y);
- double x2 = x1 + (1.0 / 3.0) * (shifted(coords[2], doShift) - x);
- double y2 = y1 + (1.0 / 3.0) * (shifted(coords[3], doShift) - y);
+ double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x);
+ double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y);
- x = shifted(coords[2], doShift);
- y = shifted(coords[3], doShift);
+ x = shiftX(coords[2], doShift);
+ y = shiftY(coords[3], doShift);
cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y);
break;
case PathIterator.SEG_CUBICTO:
- x = shifted(coords[4], doShift);
- y = shifted(coords[5], doShift);
- cairoCurveTo(nativePointer, shifted(coords[0], doShift),
- shifted(coords[1], doShift),
- shifted(coords[2], doShift),
- shifted(coords[3], doShift), x, y);
+ x = shiftX(coords[4], doShift);
+ y = shiftY(coords[5], doShift);
+ cairoCurveTo(nativePointer, shiftX(coords[0], doShift),
+ shiftY(coords[1], doShift),
+ shiftX(coords[2], doShift),
+ shiftY(coords[3], doShift), x, y);
break;
case PathIterator.SEG_CLOSE:
cairoClosePath(nativePointer);
@@ -1807,4 +2054,4 @@ public abstract class CairoGraphics2D extends Graphics2D
return rect;
}
-}
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java
index 78bc1e02db0..5b63e62e7ed 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java
@@ -38,14 +38,18 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
-import java.awt.Point;
+import gnu.java.awt.Buffers;
+
import java.awt.Graphics2D;
-import java.awt.image.DataBuffer;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
+import java.awt.Point;
+import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
import java.nio.ByteOrder;
import java.util.Hashtable;
@@ -54,7 +58,7 @@ import java.util.Hashtable;
*
* @author Sven de Marothy
*/
-public class CairoSurface extends DataBuffer
+public class CairoSurface extends WritableRaster
{
int width = -1, height = -1;
@@ -68,13 +72,27 @@ public class CairoSurface extends DataBuffer
*/
long bufferPointer;
-
- static ColorModel nativeModel = new DirectColorModel(32,
- 0x00FF0000,
- 0x0000FF00,
- 0x000000FF,
- 0xFF000000);
-
+ // FIXME: use only the cairoCM_pre colormodel
+ // since that's what Cairo really uses (is there a way to do this cheaply?
+ // we use a non-multiplied model most of the time to avoid costly coercion
+ // operations...)
+ static ColorModel cairoColorModel = new DirectColorModel(32, 0x00FF0000,
+ 0x0000FF00,
+ 0x000000FF,
+ 0xFF000000);
+
+ static ColorModel cairoCM_pre = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 32, 0x00FF0000,
+ 0x0000FF00,
+ 0x000000FF,
+ 0xFF000000,
+ true,
+ Buffers.smallestAppropriateTransferType(32));
+
+ // This CM corresponds to the CAIRO_FORMAT_RGB24 type in Cairo
+ static ColorModel cairoCM_opaque = new DirectColorModel(24, 0x00FF0000,
+ 0x0000FF00,
+ 0x000000FF);
/**
* Allocates and clears the buffer and creates the cairo surface.
* @param width, height - the image size
@@ -102,11 +120,13 @@ public class CairoSurface extends DataBuffer
* with an affine transform given by i2u.
*/
public native void nativeDrawSurface(long surfacePointer, long contextPointer,
- double[] i2u, double alpha);
+ double[] i2u, double alpha,
+ int interpolation);
- public void drawSurface(long contextPointer, double[] i2u, double alpha)
+ public void drawSurface(long contextPointer, double[] i2u, double alpha,
+ int interpolation)
{
- nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha);
+ nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha, interpolation);
}
/**
@@ -138,18 +158,20 @@ public class CairoSurface extends DataBuffer
*/
public CairoSurface(int width, int height)
{
- super(DataBuffer.TYPE_INT, width * height);
+ super(createCairoSampleModel(width, height),
+ null, new Point(0, 0));
if(width <= 0 || height <= 0)
throw new IllegalArgumentException("Image must be at least 1x1 pixels.");
-
+
this.width = width;
this.height = height;
-
create(width, height, width);
if(surfacePointer == 0 || bufferPointer == 0)
throw new Error("Could not allocate bitmap.");
+
+ dataBuffer = new CairoDataBuffer();
}
/**
@@ -158,18 +180,7 @@ public class CairoSurface extends DataBuffer
*/
CairoSurface(GtkImage image)
{
- super(DataBuffer.TYPE_INT, image.width * image.height);
-
- if(image.width <= 0 || image.height <= 0)
- throw new IllegalArgumentException("Image must be at least 1x1 pixels.");
-
- width = image.width;
- height = image.height;
-
- create(width, height, width);
-
- if(surfacePointer == 0 || bufferPointer == 0)
- throw new Error("Could not allocate bitmap.");
+ this(image.width, image.height);
// Copy the pixel data from the GtkImage.
int[] data = image.getPixels();
@@ -260,32 +271,37 @@ public class CairoSurface extends DataBuffer
*/
public static BufferedImage getBufferedImage(CairoSurface surface)
{
- WritableRaster raster = Raster.createPackedRaster
- (surface, surface.width, surface.height, surface.width,
- new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 },
- new Point(0,0));
-
- return new BufferedImage(nativeModel, raster, true, new Hashtable());
+ return new BufferedImage(cairoColorModel, surface,
+ cairoColorModel.isAlphaPremultiplied(),
+ new Hashtable());
}
- /**
- * DataBank.getElem implementation
- */
- public int getElem(int bank, int i)
+ private class CairoDataBuffer extends DataBuffer
{
- if(bank != 0 || i < 0 || i >= width*height)
- throw new IndexOutOfBoundsException(i+" size: "+width*height);
- return nativeGetElem(bufferPointer, i);
- }
+ public CairoDataBuffer()
+ {
+ super(DataBuffer.TYPE_INT, width * height);
+ }
+
+ /**
+ * DataBuffer.getElem implementation
+ */
+ public int getElem(int bank, int i)
+ {
+ if(bank != 0 || i < 0 || i >= width * height)
+ throw new IndexOutOfBoundsException(i+" size: "+width * height);
+ return nativeGetElem(bufferPointer, i);
+ }
- /**
- * DataBank.setElem implementation
- */
- public void setElem(int bank, int i, int val)
- {
- if(bank != 0 || i < 0 || i >= width*height)
- throw new IndexOutOfBoundsException(i+" size: "+width*height);
- nativeSetElem(bufferPointer, i, val);
+ /**
+ * DataBuffer.setElem implementation
+ */
+ public void setElem(int bank, int i, int val)
+ {
+ if(bank != 0 || i < 0 || i >= width*height)
+ throw new IndexOutOfBoundsException(i+" size: "+width * height);
+ nativeSetElem(bufferPointer, i, val);
+ }
}
/**
@@ -319,4 +335,14 @@ public class CairoSurface extends DataBuffer
{
copyAreaNative2(bufferPointer, x, y, width, height, dx, dy, stride);
}
+
+ /**
+ * Creates a SampleModel that matches Cairo's native format
+ */
+ protected static SampleModel createCairoSampleModel(int w, int h)
+ {
+ return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
+ new int[]{0x00FF0000, 0x0000FF00,
+ 0x000000FF, 0xFF000000});
+ }
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
index 7bd136c3845..36743b9c2da 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
@@ -38,10 +38,26 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
+import java.awt.Color;
import java.awt.Graphics;
-import java.awt.GraphicsEnvironment;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.RenderedImage;
+import java.util.Hashtable;
/**
* Implementation of Graphics2D on a Cairo surface.
@@ -49,6 +65,7 @@ import java.awt.geom.Rectangle2D;
public class CairoSurfaceGraphics extends CairoGraphics2D
{
protected CairoSurface surface;
+ private BufferedImage buffer;
private long cairo_t;
/**
@@ -59,6 +76,7 @@ public class CairoSurfaceGraphics extends CairoGraphics2D
this.surface = surface;
cairo_t = surface.newCairoContext();
setup( cairo_t );
+ setClip(0, 0, surface.width, surface.height);
}
/**
@@ -91,4 +109,200 @@ public class CairoSurfaceGraphics extends CairoGraphics2D
{
surface.copyAreaNative(x, y, width, height, dx, dy, surface.width);
}
+
+ /**
+ * Overloaded methods that do actual drawing need to account for custom
+ * composites
+ */
+ public void draw(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.draw(s);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setStroke(this.getStroke());
+ g2d.setColor(this.getColor());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void fill(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.fill(s);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void drawRenderedImage(RenderedImage image, AffineTransform xform)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawRenderedImage(image, xform);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawRenderedImage(image, xform);
+
+ drawComposite(buffer.getRaster().getBounds(), null);
+ }
+
+ }
+
+ protected boolean drawImage(Image img, AffineTransform xform,
+ Color bgcolor, ImageObserver obs)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ return super.drawImage(img, xform, bgcolor, obs);
+
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find translated bounds
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
+ bImg.getHeight() + bImg.getMinY());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+
+ // Perform compositing
+ return drawComposite(new Rectangle2D.Double(origin.getX(),
+ origin.getY(),
+ pt.getX(), pt.getY()),
+ obs);
+ }
+ }
+
+ public void drawGlyphVector(GlyphVector gv, float x, float y)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawGlyphVector(gv, x, y);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setStroke(this.getStroke());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
+ }
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+ clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get destination clip to bounds
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ BufferedImage current = CairoSurface.getBufferedImage(surface);
+ current = current.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ buffer2.getRaster());
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ boolean rv = super.drawImage(buffer2,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ new Color(0,0,0,0), null);
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ buffer = new BufferedImage(getBufferCM(),
+ surface.createCompatibleWritableRaster(),
+ getBufferCM().isAlphaPremultiplied(),
+ new Hashtable());
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ return CairoSurface.cairoCM_pre;
+ }
+
+ protected ColorModel getBufferCM()
+ {
+ return CairoSurface.cairoColorModel;
+ }
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java
index ffa78e9c904..763ad7dfddd 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java
@@ -38,22 +38,31 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import gnu.classpath.Pointer;
+
+import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
import java.awt.image.RenderedImage;
-import gnu.classpath.Pointer;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
/**
* ComponentGraphics - context for drawing directly to a component,
@@ -67,36 +76,11 @@ public class ComponentGraphics extends CairoGraphics2D
private GtkComponentPeer component;
protected long cairo_t;
+ private BufferedImage buffer, componentBuffer;
private static ThreadLocal hasLock = new ThreadLocal();
private static Integer ONE = Integer.valueOf(1);
- private void lock()
- {
- Integer i = (Integer) hasLock.get();
- if (i == null)
- {
- start_gdk_drawing();
- hasLock.set(ONE);
- }
- else
- hasLock.set(Integer.valueOf(i.intValue() + 1));
- }
-
- private void unlock()
- {
- Integer i = (Integer) hasLock.get();
- if (i == null)
- throw new IllegalStateException();
- if (i == ONE)
- {
- hasLock.set(null);
- end_gdk_drawing();
- }
- else
- hasLock.set(Integer.valueOf(i.intValue() - 1));
- }
-
ComponentGraphics()
{
}
@@ -128,6 +112,32 @@ public class ComponentGraphics extends CairoGraphics2D
*/
private native long initState(GtkComponentPeer component);
+ private void lock()
+ {
+ Integer i = (Integer) hasLock.get();
+ if (i == null)
+ {
+ start_gdk_drawing();
+ hasLock.set(ONE);
+ }
+ else
+ hasLock.set(Integer.valueOf(i.intValue() + 1));
+ }
+
+ private void unlock()
+ {
+ Integer i = (Integer) hasLock.get();
+ if (i == null)
+ throw new IllegalStateException();
+ if (i == ONE)
+ {
+ hasLock.set(null);
+ end_gdk_drawing();
+ }
+ else
+ hasLock.set(Integer.valueOf(i.intValue() - 1));
+ }
+
/**
* Destroys the component surface and calls dispose on the cairo
* graphics2d to destroy any super class resources.
@@ -227,7 +237,20 @@ public class ComponentGraphics extends CairoGraphics2D
lock();
try
{
- super.draw(s);
+ if (comp == null || comp instanceof AlphaComposite)
+ super.draw(s);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setStroke(this.getStroke());
+ g2d.setColor(this.getColor());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
}
finally
{
@@ -240,7 +263,20 @@ public class ComponentGraphics extends CairoGraphics2D
lock();
try
{
- super.fill(s);
+ if (comp == null || comp instanceof AlphaComposite)
+ super.fill(s);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
}
finally
{
@@ -253,7 +289,19 @@ public class ComponentGraphics extends CairoGraphics2D
lock();
try
{
- super.drawRenderedImage(image, xform);
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawRenderedImage(image, xform);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawRenderedImage(image, xform);
+
+ drawComposite(buffer.getRaster().getBounds(), null);
+ }
}
finally
{
@@ -268,7 +316,44 @@ public class ComponentGraphics extends CairoGraphics2D
lock();
try
{
- rv = super.drawImage(img, xform, bgcolor, obs);
+ if (comp == null || comp instanceof AlphaComposite)
+ rv = super.drawImage(img, xform, bgcolor, obs);
+
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find translated bounds
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
+ bImg.getHeight() + bImg.getMinY());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+
+ // Perform compositing
+ rv = drawComposite(new Rectangle2D.Double(origin.getX(),
+ origin.getY(),
+ pt.getX(), pt.getY()),
+ obs);
+ }
}
finally
{
@@ -282,7 +367,23 @@ public class ComponentGraphics extends CairoGraphics2D
lock();
try
{
- super.drawGlyphVector(gv, x, y);
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawGlyphVector(gv, x, y);
+
+ else
+ {
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setStroke(this.getStroke());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
}
finally
{
@@ -367,6 +468,7 @@ public class ComponentGraphics extends CairoGraphics2D
}
BufferedImage bimg;
+ img = AsyncImage.realImage(img, observer);
if (img instanceof BufferedImage)
bimg = (BufferedImage) img;
else
@@ -379,57 +481,112 @@ public class ComponentGraphics extends CairoGraphics2D
return super.drawImage(bimg, x, y, width, height, observer);
}
- public void drawLine(int x1, int y1, int x2, int y2)
+ public void setClip(Shape s)
{
lock();
try
{
- super.drawLine(x1, y1, x2, y2);
+ super.setClip(s);
}
finally
{
- unlock();
+ unlock();
}
}
- public void drawRect(int x, int y, int width, int height)
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
{
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+ clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get destination clip to bounds
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ // Get current image on the component
+ unlock();
+ GtkImage img = grab(component);
+ Graphics gr = componentBuffer.createGraphics();
+ gr.drawImage(img, 0, 0, null);
+ gr.dispose();
lock();
- try
- {
- super.drawRect(x, y, width, height);
- }
- finally
- {
- unlock();
- }
+
+ BufferedImage cBuffer = componentBuffer;
+ if (!deviceBounds.equals(cBuffer.getRaster().getBounds()))
+ cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(),
+ cBuffer.getRaster());
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ boolean rv = super.drawImage(cBuffer,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ null, null);
+ return rv;
}
-
- public void fillRect(int x, int y, int width, int height)
+
+ private void createBuffer()
{
- lock();
- try
- {
- super.fillRect(x, y, width, height);
- }
- finally
+ if (buffer == null)
{
- unlock();
+ WritableRaster rst;
+ rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
+ component.awtComponent.getHeight()),
+ new Point(0,0));
+
+ buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
+ GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
+ new Hashtable());
}
- }
-
- public void setClip(Shape s)
- {
- lock();
- try
+ else
{
- super.setClip(s);
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
}
- finally
+
+ if (componentBuffer == null)
{
- unlock();
+ WritableRaster rst;
+ rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
+ component.awtComponent.getHeight()),
+ new Point(0,0));
+
+ componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
+ GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
+ new Hashtable());
}
}
-
+
+ protected ColorModel getNativeCM()
+ {
+ return GtkVolatileImage.gdkColorModel;
+ }
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
index 2c9d917934f..131a964488f 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
@@ -39,14 +39,15 @@ package gnu.java.awt.peer.gtk;
import java.awt.Font;
import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.GeneralPath;
+import java.awt.font.FontRenderContext;
import java.awt.font.GlyphJustificationInfo;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
-import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
public class FreetypeGlyphVector extends GlyphVector
{
@@ -91,16 +92,17 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public FreetypeGlyphVector(Font f, String s, FontRenderContext frc)
{
- this(f, s, frc, Font.LAYOUT_LEFT_TO_RIGHT);
+ this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT);
}
/**
* Create a glyphvector from a given (Freetype) font and a String.
*/
- public FreetypeGlyphVector(Font f, String s, FontRenderContext frc,
- int flags)
+ public FreetypeGlyphVector(Font f, char[] chars, int start, int len,
+ FontRenderContext frc, int flags)
{
- this.s = s;
+ this.s = new String(chars, start, len);
+
this.font = f;
this.frc = frc;
if( !(font.getPeer() instanceof GdkFontPeer ) )
@@ -155,14 +157,15 @@ public class FreetypeGlyphVector extends GlyphVector
}
glyphCodes = new int[ nGlyphs ];
- glyphPositions = new float[ nGlyphs ];
+ glyphPositions = new float[(nGlyphs + 1) * 2];
glyphTransforms = new AffineTransform[ nGlyphs ];
for(int i = 0; i < nGlyphs; i++ )
{
- glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
- glyphCodes[i] = gv.glyphCodes[ i ];
- glyphPositions[i] = gv.glyphPositions[ i ];
+ glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
+ glyphCodes[i] = gv.glyphCodes[ i ];
}
+ System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0,
+ glyphPositions.length);
}
/**
@@ -178,10 +181,17 @@ public class FreetypeGlyphVector extends GlyphVector
for(int i = 0; i < nGlyphs; i++)
{
codePoints[i] = s.codePointAt( stringIndex );
- // UTF32 surrogate handling
+ // UTF32 surrogate handling
if( codePoints[i] != (int)s.charAt( stringIndex ) )
stringIndex ++;
stringIndex ++;
+
+ if (Character.isISOControl(codePoints[i]))
+ {
+ // Replace with 'hair space'. Should better be 'zero-width space'
+ // but that doesn't seem to be supported by default font.
+ codePoints[i] = 8202;
+ }
}
glyphCodes = getGlyphs( codePoints );
@@ -242,22 +252,31 @@ public class FreetypeGlyphVector extends GlyphVector
public void performDefaultLayout()
{
logicalBounds = null; // invalidate caches.
- glyphPositions = null;
-
- glyphTransforms = new AffineTransform[ nGlyphs ];
- double x = 0;
+ glyphTransforms = new AffineTransform[nGlyphs];
+ Arrays.fill(glyphTransforms, null);
+ glyphPositions = new float[(nGlyphs + 1) * 2];
+ GlyphMetrics gm = null;
+ float x = 0;
+ float y = 0;
for(int i = 0; i < nGlyphs; i++)
{
- GlyphMetrics gm = getGlyphMetrics( i );
- glyphTransforms[ i ] = AffineTransform.getTranslateInstance(x, 0);
- x += gm.getAdvanceX();
- if( i > 0 )
- {
- Point2D p = getKerning( glyphCodes[ i - 1 ], glyphCodes[ i ] );
- x += p.getX();
- }
+ gm = getGlyphMetrics( i );
+ glyphPositions[i*2] = x;
+ glyphPositions[i*2 + 1] = y;
+
+ x += gm.getAdvanceX();
+ y += gm.getAdvanceY();
+
+ if (i != nGlyphs-1)
+ {
+ Point2D p = getKerning(glyphCodes[i], glyphCodes[i + 1]);
+ x += p.getX();
+ y += p.getY();
+ }
}
+ glyphPositions[nGlyphs * 2] = x;
+ glyphPositions[nGlyphs * 2 + 1] = y;
}
/**
@@ -276,7 +295,7 @@ public class FreetypeGlyphVector extends GlyphVector
{
int[] rval;
- if( codeReturn == null )
+ if( codeReturn == null || codeReturn.length < numEntries)
rval = new int[ numEntries ];
else
rval = codeReturn;
@@ -286,9 +305,6 @@ public class FreetypeGlyphVector extends GlyphVector
return rval;
}
- /**
- * FIXME: Implement me.
- */
public Shape getGlyphLogicalBounds(int glyphIndex)
{
GlyphMetrics gm = getGlyphMetrics( glyphIndex );
@@ -296,10 +312,17 @@ public class FreetypeGlyphVector extends GlyphVector
return null;
Rectangle2D r = gm.getBounds2D();
Point2D p = getGlyphPosition( glyphIndex );
- return new Rectangle2D.Double( p.getX() + r.getX() - gm.getLSB(),
- p.getY() + r.getY(),
- gm.getAdvanceX(),
- r.getHeight() );
+
+ double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(),
+ p.getY() + r.getY(),
+ p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(),
+ p.getY() + r.getY() + r.getHeight()};
+
+ if (glyphTransforms[glyphIndex] != null)
+ glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 4);
+
+ return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0],
+ bounds[3] - bounds[1]);
}
/*
@@ -352,7 +375,9 @@ public class FreetypeGlyphVector extends GlyphVector
public Shape getGlyphOutline(int glyphIndex)
{
GeneralPath gp = getGlyphOutlineNative( glyphCodes[ glyphIndex ] );
- gp.transform( glyphTransforms[ glyphIndex ] );
+ if (glyphTransforms[glyphIndex] != null)
+ gp.transform( glyphTransforms[glyphIndex]);
+
return gp;
}
@@ -361,8 +386,8 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public Point2D getGlyphPosition(int glyphIndex)
{
- return glyphTransforms[ glyphIndex ].transform( new Point2D.Double(0, 0),
- null );
+ return new Point2D.Float(glyphPositions[glyphIndex*2],
+ glyphPositions[glyphIndex*2 + 1]);
}
/**
@@ -371,25 +396,12 @@ public class FreetypeGlyphVector extends GlyphVector
public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
float[] positionReturn)
{
- if( glyphPositions != null )
- return glyphPositions;
-
- float[] rval;
-
- if( positionReturn == null )
- rval = new float[2 * numEntries];
- else
- rval = positionReturn;
-
- for( int i = beginGlyphIndex; i < numEntries; i++ )
- {
- Point2D p = getGlyphPosition( i );
- rval[i * 2] = (float)p.getX();
- rval[i * 2 + 1] = (float)p.getY();
- }
-
- glyphPositions = rval;
- return rval;
+ if (positionReturn == null || positionReturn.length < (numEntries * 2))
+ positionReturn = new float[numEntries*2];
+
+ System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0,
+ numEntries*2);
+ return positionReturn;
}
/**
@@ -397,7 +409,7 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public AffineTransform getGlyphTransform(int glyphIndex)
{
- return new AffineTransform( glyphTransforms[ glyphIndex ] );
+ return glyphTransforms[glyphIndex];
}
/**
@@ -420,10 +432,12 @@ public class FreetypeGlyphVector extends GlyphVector
return logicalBounds;
Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 );
+ AffineTransform tx = new AffineTransform();
for( int i = 1; i < nGlyphs; i++ )
{
- Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
- rect = rect.createUnion( r2 );
+ Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
+
+ rect = rect.createUnion( r2 );
}
logicalBounds = rect;
@@ -444,8 +458,14 @@ public class FreetypeGlyphVector extends GlyphVector
public Shape getOutline()
{
GeneralPath path = new GeneralPath();
+ AffineTransform tx = new AffineTransform();
for( int i = 0; i < getNumGlyphs(); i++ )
- path.append( getGlyphOutline( i ), false );
+ {
+ Shape outline = getGlyphOutline(i);
+ tx.setToTranslation(glyphPositions[i*2], glyphPositions[i*2 +1]);
+ outline = tx.createTransformedShape(outline);
+ path.append(outline, false);
+ }
return path;
}
@@ -485,11 +505,9 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public void setGlyphPosition(int glyphIndex, Point2D newPos)
{
- // FIXME: Scaling, etc.?
- glyphTransforms[ glyphIndex ].setToTranslation( newPos.getX(),
- newPos.getY() );
+ glyphPositions[glyphIndex*2] = (float)(newPos.getX());
+ glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY());
logicalBounds = null;
- glyphPositions = null;
}
/**
@@ -497,8 +515,7 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public void setGlyphTransform(int glyphIndex, AffineTransform newTX)
{
- glyphTransforms[ glyphIndex ].setTransform( newTX );
logicalBounds = null;
- glyphPositions = null;
+ glyphTransforms[glyphIndex] = newTX;
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java
deleted file mode 100644
index b2ffed10ea6..00000000000
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/* GdkFontMetrics.java
- Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.java.awt.peer.gtk;
-
-import gnu.java.awt.ClasspathToolkit;
-
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Toolkit;
-
-public class GdkFontMetrics extends FontMetrics
-{
-
- private int[] font_metrics;
- GdkFontPeer peer;
-
- static final int FONT_METRICS_ASCENT = 0;
- static final int FONT_METRICS_MAX_ASCENT = 1;
- static final int FONT_METRICS_DESCENT = 2;
- static final int FONT_METRICS_MAX_DESCENT = 3;
- static final int FONT_METRICS_MAX_ADVANCE = 4;
-
- static final int TEXT_METRICS_X_BEARING = 0;
- static final int TEXT_METRICS_Y_BEARING = 1;
- static final int TEXT_METRICS_WIDTH = 2;
- static final int TEXT_METRICS_HEIGHT = 3;
- static final int TEXT_METRICS_X_ADVANCE = 4;
- static final int TEXT_METRICS_Y_ADVANCE = 5;
-
- /**
- * Makes sure to return a Font based on the given Font that has as
- * peer a GdkFontPeer. Used in the initializer.
- */
- private static Font initFont(Font font)
- {
- if (font == null)
- return new Font("Dialog", Font.PLAIN, 12);
- else if (font.getPeer() instanceof GdkFontPeer)
- return font;
- else
- {
- ClasspathToolkit toolkit;
- toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit();
- return toolkit.getFont(font.getName(), font.getAttributes());
- }
- }
-
- public GdkFontMetrics (Font font)
- {
- super(initFont(font));
- peer = (GdkFontPeer) this.font.getPeer();
-
- font_metrics = new int[5];
- double [] hires = new double[5];
- peer.getFontMetrics (hires);
- for (int i = 0; i < 5; ++i)
- font_metrics[i] = (int) hires[i];
- }
-
- public int stringWidth (String str)
- {
- double [] hires = new double[6];
- peer.getTextMetrics(str, hires);
- return (int) hires [TEXT_METRICS_WIDTH];
- }
-
- public int charWidth (char ch)
- {
- return stringWidth (new String (new char[] { ch }));
- }
-
- public int charsWidth (char data[], int off, int len)
- {
- return stringWidth (new String (data, off, len));
- }
-
- public int getLeading ()
- {
- // Sun always returns 0.
- return 0;
- }
-
- public int getAscent ()
- {
- return font_metrics[FONT_METRICS_ASCENT];
- }
-
- public int getMaxAscent ()
- {
- return font_metrics[FONT_METRICS_MAX_ASCENT];
- }
-
- public int getDescent ()
- {
- return font_metrics[FONT_METRICS_DESCENT];
- }
-
- public int getMaxDescent ()
- {
- return font_metrics[FONT_METRICS_MAX_DESCENT];
- }
-
- public int getMaxAdvance ()
- {
- return font_metrics[FONT_METRICS_MAX_ADVANCE];
- }
-}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java
index 11635c3544e..5f5126ac590 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import gnu.java.awt.ClasspathToolkit;
import gnu.java.awt.peer.ClasspathFontPeer;
import gnu.java.awt.font.opentype.NameDecoder;
@@ -48,39 +49,125 @@ import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.GlyphMetrics;
import java.awt.font.LineMetrics;
+import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.text.CharacterIterator;
import java.util.Locale;
import java.util.Map;
-import java.util.ResourceBundle;
import java.nio.ByteBuffer;
import java.util.HashMap;
public class GdkFontPeer extends ClasspathFontPeer
{
+ static final FontRenderContext DEFAULT_CTX =
+ new FontRenderContext(null, false, false);
+
+ /**
+ * Caches TextLayout instances for use in charsWidth() and drawString().
+ * The size of the cache has been chosen so that relativly large GUIs with
+ * text documents are still efficient.
+ */
+ HashMap textLayoutCache = new GtkToolkit.LRUCache(500);
+
+ private class GdkFontMetrics extends FontMetrics
+ {
+
+ public GdkFontMetrics (Font font)
+ {
+ super(initFont(font));
+ }
+
+ public int stringWidth (String str)
+ {
+ TextLayout tl = (TextLayout) textLayoutCache.get(str);
+ if (tl == null)
+ {
+ tl = new TextLayout(str, font, DEFAULT_CTX);
+ textLayoutCache.put(str, tl);
+ }
+ return (int) tl.getAdvance();
+ }
+
+ public int charWidth (char ch)
+ {
+ return stringWidth (new String (new char[] { ch }));
+ }
+
+ public int charsWidth (char data[], int off, int len)
+ {
+ return stringWidth (new String (data, off, len));
+ }
+
+ public int getHeight()
+ {
+ return (int) height;
+ }
+
+ public int getLeading ()
+ {
+ return (int) (height - (ascent + descent));
+ }
+
+ public int getAscent ()
+ {
+ return (int) ascent;
+ }
+
+ public int getMaxAscent ()
+ {
+ return (int) ascent;
+ }
+
+ public int getDescent ()
+ {
+ return (int) descent;
+ }
+
+ public int getMaxDescent ()
+ {
+ return (int) maxDescent;
+ }
+
+ public int getMaxAdvance ()
+ {
+ return (int) maxAdvance;
+ }
+ }
+
static native void initStaticState();
private final int native_state = GtkGenericPeer.getUniqueInteger ();
- private static ResourceBundle bundle;
/**
* Cache GlyphMetrics objects.
*/
private HashMap metricsCache;
-
+
+ private static final int FONT_METRICS_ASCENT = 0;
+ private static final int FONT_METRICS_MAX_ASCENT = 1;
+ private static final int FONT_METRICS_DESCENT = 2;
+ private static final int FONT_METRICS_MAX_DESCENT = 3;
+ private static final int FONT_METRICS_MAX_ADVANCE = 4;
+ private static final int FONT_METRICS_HEIGHT = 5;
+ private static final int FONT_METRICS_UNDERLINE_OFFSET = 6;
+ private static final int FONT_METRICS_UNDERLINE_THICKNESS = 7;
+
+ float ascent;
+ float descent;
+ float maxAscent;
+ float maxDescent;
+ float maxAdvance;
+ float height;
+ float underlineOffset;
+ float underlineThickness;
+
+ GdkFontMetrics metrics;
+
static
{
System.loadLibrary("gtkpeer");
initStaticState ();
- try
- {
- bundle = ResourceBundle.getBundle ("gnu.java.awt.peer.gtk.font");
- }
- catch (Throwable ignored)
- {
- bundle = null;
- }
}
private ByteBuffer nameTable = null;
@@ -89,8 +176,8 @@ public class GdkFontPeer extends ClasspathFontPeer
private native void dispose ();
private native void setFont (String family, int style, int size);
- native void getFontMetrics(double [] metrics);
- native void getTextMetrics(String str, double [] metrics);
+ native synchronized void getFontMetrics(double [] metrics);
+ native synchronized void getTextMetrics(String str, double [] metrics);
native void releasePeerGraphicsResource();
@@ -149,6 +236,7 @@ public class GdkFontPeer extends ClasspathFontPeer
initState ();
setFont (this.familyName, this.style, (int)this.size);
metricsCache = new HashMap();
+ setupMetrics();
}
public GdkFontPeer (String name, Map attributes)
@@ -157,6 +245,40 @@ public class GdkFontPeer extends ClasspathFontPeer
initState ();
setFont (this.familyName, this.style, (int)this.size);
metricsCache = new HashMap();
+ setupMetrics();
+ }
+
+
+ /**
+ * Makes sure to return a Font based on the given Font that has as
+ * peer a GdkFontPeer. Used in the initializer.
+ */
+ static Font initFont(Font font)
+ {
+ if (font == null)
+ return new Font("Dialog", Font.PLAIN, 12);
+ else if (font.getPeer() instanceof GdkFontPeer)
+ return font;
+ else
+ {
+ ClasspathToolkit toolkit;
+ toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit();
+ return toolkit.getFont(font.getName(), font.getAttributes());
+ }
+ }
+
+ private void setupMetrics()
+ {
+ double [] hires = new double[8];
+ getFontMetrics(hires);
+ ascent = (float) hires[FONT_METRICS_ASCENT];
+ maxAscent = (float) hires[FONT_METRICS_MAX_ASCENT];
+ descent = (float) hires[FONT_METRICS_DESCENT];
+ maxDescent = (float) hires[FONT_METRICS_MAX_DESCENT];
+ maxAdvance = (float) hires[FONT_METRICS_MAX_ADVANCE];
+ height = (float) hires[FONT_METRICS_HEIGHT];
+ underlineOffset = (float) hires[FONT_METRICS_UNDERLINE_OFFSET];
+ underlineThickness = (float) hires[FONT_METRICS_UNDERLINE_THICKNESS];
}
/**
@@ -261,26 +383,17 @@ public class GdkFontPeer extends ClasspathFontPeer
return Font.ROMAN_BASELINE;
}
- private static class GdkFontLineMetrics extends LineMetrics
+ private class GdkFontLineMetrics extends LineMetrics
{
- private FontMetrics fm;
- private int nchars;
- private float strikethroughOffset, strikethroughThickness,
- underlineOffset, underlineThickness;
-
- public GdkFontLineMetrics (GdkFontPeer fp, FontMetrics m, int n)
+ private int nchars;
+ public GdkFontLineMetrics (GdkFontPeer fp, int n)
{
- fm = m;
nchars = n;
- strikethroughOffset = 0f;
- underlineOffset = 0f;
- strikethroughThickness = ((float)fp.getSize(null)) / 12f;
- underlineThickness = strikethroughThickness;
}
public float getAscent()
{
- return (float) fm.getAscent ();
+ return ascent;
}
public int getBaselineIndex()
@@ -296,27 +409,52 @@ public class GdkFontPeer extends ClasspathFontPeer
public float getDescent()
{
- return (float) fm.getDescent ();
+ return descent;
}
public float getHeight()
{
- return (float) fm.getHeight ();
+ return height;
}
- public float getLeading() { return 0.f; }
- public int getNumChars() { return nchars; }
- public float getStrikethroughOffset() { return 0.f; }
- public float getStrikethroughThickness() { return 0.f; }
- public float getUnderlineOffset() { return 0.f; }
- public float getUnderlineThickness() { return 0.f; }
+ public float getLeading()
+ {
+ return height - (ascent + descent);
+ }
+
+ public int getNumChars()
+ {
+ return nchars;
+ }
+
+ public float getStrikethroughOffset()
+ {
+ // FreeType doesn't seem to provide a value here.
+ return ascent / 2;
+ }
+
+ public float getStrikethroughThickness()
+ {
+ // FreeType doesn't seem to provide a value here.
+ return 1.f;
+ }
+
+ public float getUnderlineOffset()
+ {
+ return underlineOffset;
+ }
+
+ public float getUnderlineThickness()
+ {
+ return underlineThickness;
+ }
}
public LineMetrics getLineMetrics (Font font, CharacterIterator ci,
int begin, int limit, FontRenderContext rc)
{
- return new GdkFontLineMetrics (this, getFontMetrics (font), limit - begin);
+ return new GdkFontLineMetrics (this, limit - begin);
}
public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc)
@@ -345,15 +483,6 @@ public class GdkFontPeer extends ClasspathFontPeer
return buf.getShort(4);
}
- public Rectangle2D getStringBounds (Font font, CharacterIterator ci,
- int begin, int limit, FontRenderContext frc)
- {
- GlyphVector gv = new FreetypeGlyphVector( font,
- buildString(ci, begin, limit),
- frc);
- return gv.getVisualBounds();
- }
-
public boolean hasUniformLineMetrics (Font font)
{
return true;
@@ -363,22 +492,21 @@ public class GdkFontPeer extends ClasspathFontPeer
char[] chars, int start, int limit,
int flags)
{
- return new FreetypeGlyphVector( font, new String( chars, start,
- limit - start),
+ return new FreetypeGlyphVector( font, chars, start, limit - start,
frc, flags);
}
public LineMetrics getLineMetrics (Font font, String str,
FontRenderContext frc)
{
- return new GdkFontLineMetrics (this, getFontMetrics (font), str.length ());
+ return new GdkFontLineMetrics (this, str.length ());
}
public FontMetrics getFontMetrics (Font font)
{
- // Get the font metrics through GtkToolkit to take advantage of
- // the metrics cache.
- return Toolkit.getDefaultToolkit().getFontMetrics (font);
+ if (metrics == null)
+ metrics = new GdkFontMetrics(font);
+ return metrics;
}
/**
@@ -397,4 +525,5 @@ public class GdkFontPeer extends ClasspathFontPeer
{
metricsCache.put( new Integer( glyphCode ), metrics );
}
+
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java
index e095c7dad4b..db725b697df 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java
@@ -44,7 +44,7 @@ import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.image.BufferedImage;
-import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
import java.util.Locale;
public class GdkGraphicsEnvironment extends GraphicsEnvironment
@@ -103,9 +103,9 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment
public Graphics2D createGraphics (BufferedImage image)
{
- DataBuffer db = image.getRaster().getDataBuffer();
- if(db instanceof CairoSurface)
- return ((CairoSurface)db).getGraphics();
+ Raster raster = image.getRaster();
+ if(raster instanceof CairoSurface)
+ return ((CairoSurface)raster).getGraphics();
return new BufferedImageGraphics( image );
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java
index f00461f3fc8..d866cefd33c 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java
@@ -84,7 +84,7 @@ public class GtkChoicePeer extends GtkComponentPeer
public void select (int position)
{
- if (Thread.currentThread() == GtkToolkit.mainThread)
+ if (Thread.currentThread() == GtkMainThread.mainThread)
selectNativeUnlocked (position);
else
selectNative (position);
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java
index c11c45e2070..b1ef09d6e1b 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java
@@ -90,6 +90,11 @@ public class GtkComponentPeer extends GtkGenericPeer
Insets insets;
+ /**
+ * The current repaint area. Use should be guarded by synchronizing on this.
+ */
+ private Rectangle currentPaintArea;
+
/* this isEnabled differs from Component.isEnabled, in that it
knows if a parent is disabled. In that case Component.isEnabled
may return true, but our isEnabled will always return false */
@@ -308,13 +313,30 @@ public class GtkComponentPeer extends GtkGenericPeer
// seems expensive. However, the graphics state does not carry
// over between calls to paint, and resetting the graphics object
// may even be more costly than simply creating a new one.
- Graphics g = getGraphics();
- g.setClip(event.getUpdateRect());
-
- awtComponent.paint(g);
+ // Make sure that the paintArea includes the area from the event
+ // in the case when an application sends PaintEvents directly.
+ coalescePaintEvent(event);
+ Rectangle paintArea;
+ synchronized (this)
+ {
+ paintArea = currentPaintArea;
+ currentPaintArea = null;
+ }
- g.dispose();
+ if (paintArea != null)
+ {
+ Graphics g = getGraphics();
+ try
+ {
+ g.setClip(paintArea);
+ awtComponent.paint(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
}
// This method and its overrides are the only methods in the peers
@@ -327,13 +349,29 @@ public class GtkComponentPeer extends GtkGenericPeer
|| (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
return;
- Graphics g = getGraphics();
-
- g.setClip(event.getUpdateRect());
-
- awtComponent.update(g);
+ // Make sure that the paintArea includes the area from the event
+ // in the case when an application sends PaintEvents directly.
+ coalescePaintEvent(event);
+ Rectangle paintArea;
+ synchronized (this)
+ {
+ paintArea = currentPaintArea;
+ currentPaintArea = null;
+ }
- g.dispose();
+ if (paintArea != null)
+ {
+ Graphics g = getGraphics();
+ try
+ {
+ g.setClip(paintArea);
+ awtComponent.update(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
}
public boolean isFocusTraversable ()
@@ -514,7 +552,7 @@ public class GtkComponentPeer extends GtkGenericPeer
y = 0;
}
- if (Thread.currentThread() == GtkToolkit.mainThread)
+ if (Thread.currentThread() == GtkMainThread.mainThread)
gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y);
else
gtkWidgetSetCursor(cursor.getType(), image, x, y);
@@ -562,7 +600,7 @@ public class GtkComponentPeer extends GtkGenericPeer
b = (bounds.width > 0) && (bounds.height > 0);
}
- if (Thread.currentThread() == GtkToolkit.mainThread)
+ if (Thread.currentThread() == GtkMainThread.mainThread)
setVisibleNativeUnlocked (b);
else
setVisibleNative (b);
@@ -754,7 +792,14 @@ public class GtkComponentPeer extends GtkGenericPeer
public void coalescePaintEvent (PaintEvent e)
{
-
+ synchronized (this)
+ {
+ Rectangle newRect = e.getUpdateRect();
+ if (currentPaintArea == null)
+ currentPaintArea = newRect;
+ else
+ Rectangle.union(currentPaintArea, newRect, currentPaintArea);
+ }
}
public void updateCursorImmediately ()
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java
index bb6f8b3bb3b..d113e92f5b4 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java
@@ -57,6 +57,11 @@ public class GtkFramePeer extends GtkWindowPeer
native void removeMenuBarPeer ();
native void gtkFixedSetVisible (boolean visible);
+ private native void maximize();
+ private native void unmaximize();
+ private native void iconify();
+ private native void deiconify();
+
int getMenuBarHeight ()
{
return menuBar == null ? 0 : getMenuBarHeight (menuBar);
@@ -199,12 +204,25 @@ public class GtkFramePeer extends GtkWindowPeer
public int getState ()
{
- return 0;
+ return windowState;
}
public void setState (int state)
{
-
+ switch (state)
+ {
+ case Frame.NORMAL:
+ if ((windowState & Frame.ICONIFIED) != 0)
+ deiconify();
+ if ((windowState & Frame.MAXIMIZED_BOTH) != 0)
+ unmaximize();
+ break;
+ case Frame.ICONIFIED:
+ iconify();
+ break;
+ case Frame.MAXIMIZED_BOTH:
+ maximize();
+ }
}
public void setMaximizedBounds (Rectangle r)
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java
index f1a74b8cc99..53e97bb1a8a 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java
@@ -42,6 +42,7 @@ import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.awt.image.MemoryImageSource;
+import java.nio.ByteOrder;
import java.util.Hashtable;
/**
@@ -103,7 +104,7 @@ public class GtkImageConsumer implements ImageConsumer
scansize);
}
- public synchronized void setPixels (int x, int y, int width, int height,
+ public synchronized void setPixels (int x, int y, int width, int height,
ColorModel cm, int[] pixels,
int offset, int scansize)
{
@@ -117,18 +118,34 @@ public class GtkImageConsumer implements ImageConsumer
width);
else
{
- for (int i = 0; i < height; i++)
- for (int j = 0; j < width; j++)
- {
- // get in AARRGGBB and convert to AABBGGRR
- int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]);
- byte b = (byte)(pix & 0xFF);
- byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF);
- pix &= 0xFF00FF00;
- pix |= ((b & 0xFF) << 16);
- pix |= (r & 0xFF);
- pixelCache[(y + i) * this.width + x + j] = pix;
- }
+ if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
+ {
+ for (int i = 0; i < height; i++)
+ for (int j = 0; j < width; j++)
+ {
+ // get in RRGGBBAA and convert to AARRGGBB
+ int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]);
+ int a = ((pix & 0xFF000000) >> 24) & 0xFF;
+ int rgb = (pix & 0x00FFFFFF) << 8;
+ pix = rgb | a;
+ pixelCache[(y + i) * this.width + x + j] = pix;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < height; i++)
+ for (int j = 0; j < width; j++)
+ {
+ // get in AARRGGBB and convert to AABBGGRR
+ int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]);
+ byte b = (byte)(pix & 0xFF);
+ byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF);
+ pix &= 0xFF00FF00;
+ pix |= ((b & 0xFF) << 16);
+ pix |= (r & 0xFF);
+ pixelCache[(y + i) * this.width + x + j] = pix;
+ }
+ }
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java
new file mode 100644
index 00000000000..a4e280fe45f
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java
@@ -0,0 +1,190 @@
+/* GtkMainThread.java -- Wrapper for the GTK main thread, and some utilities.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.peer.gtk;
+
+import gnu.java.awt.peer.NativeEventLoopRunningEvent;
+
+import java.awt.AWTEvent;
+
+/**
+ * The Java thread representing the native GTK main loop, that is,
+ * GtkMainThread.mainThread, terminates when GtkToolkit.gtkMain()
+ * returns. That happens in response to the last window peer being
+ * disposed (see GtkWindowPeer.dispose).
+ *
+ * When GtkMainThread.destroyWindow is called for the last window, it
+ * in turn calls GtkMainThread.endMainThread, which calls gtk_quit.
+ * gtk_quit signals gtk_main to return, which causes GtkMainThread.run
+ * to return.
+ *
+ * There should only be one native GTK main loop running at any given
+ * time. In order to safely start and stop the GTK main loop, we use
+ * a running flag and corresponding runningLock. startMainThread will
+ * not return until the native GTK main loop has started, as confirmed
+ * by the native set_running_flag callback setting the running flag to
+ * true. Without this protection, gtk_quit could be called before the
+ * main loop has actually started, which causes GTK assertion
+ * failures. Likewise endMainThread will not return until the native
+ * GTK main loop has ended.
+ *
+ * post_running_flag_callback is called during gtk_main initialization
+ * and no window can be created before startMainThread returns. This
+ * ensures that calling post_running_flag_callback is the first action
+ * taken by the native GTK main loop.
+ *
+ * GtkMainThread.mainThread is started when the window count goes from
+ * zero to one.
+ *
+ * GtkMainThread keeps the AWT event queue informed of its status by
+ * posting NativeEventLoopRunningEvents. The AWT event queue uses
+ * this status to determine whether or not the AWT exit conditions
+ * have been met (see EventQueue.isShutdown).
+ */
+public class GtkMainThread extends Thread
+{
+ /** Count of the number of open windows */
+ private static int numberOfWindows = 0;
+
+ /** Lock for the above */
+ private static Object nWindowsLock = new Object();
+
+ /** Indicates whether or not the GTK main loop is running. */
+ private static boolean running = false;
+
+ /** Lock for the above. */
+ private static Object runningLock = new Object();
+
+ /** The main thread instance (singleton) */
+ public static GtkMainThread mainThread;
+
+ /** Constructs a main thread */
+ private GtkMainThread()
+ {
+ super("GTK main thread");
+ }
+
+ public void run ()
+ {
+ GtkToolkit.gtkMain ();
+ }
+
+ private static void setRunning(boolean running)
+ {
+ synchronized (runningLock)
+ {
+ GtkMainThread.running = running;
+ runningLock.notifyAll();
+ }
+ }
+
+ private static void startMainThread()
+ {
+ synchronized (runningLock)
+ {
+ if (!running)
+ {
+ mainThread = new GtkMainThread();
+ mainThread.start();
+
+ while (!running)
+ {
+ try
+ {
+ runningLock.wait();
+ }
+ catch (InterruptedException e)
+ {
+ System.err.println ("GtkMainThread.startMainThread:"
+ + " interrupted while waiting "
+ + " for GTK main loop to start");
+ }
+ }
+ GtkGenericPeer.q()
+ .postEvent(new NativeEventLoopRunningEvent(new Boolean(true)));
+ }
+ }
+ }
+
+ private static void endMainThread()
+ {
+ synchronized (runningLock)
+ {
+ if (running)
+ {
+ GtkToolkit.gtkQuit();
+
+ while (running)
+ {
+ try
+ {
+ runningLock.wait();
+ }
+ catch (InterruptedException e)
+ {
+ System.err.println ("GtkMainThread.endMainThread:"
+ + " interrupted while waiting "
+ + " for GTK main loop to stop");
+ }
+ }
+ GtkGenericPeer.q()
+ .postEvent(new NativeEventLoopRunningEvent(new Boolean(false)));
+ }
+ }
+ }
+
+ public static void createWindow()
+ {
+ synchronized (nWindowsLock)
+ {
+ if (numberOfWindows == 0)
+ startMainThread();
+ numberOfWindows++;
+ }
+ }
+
+ public static void destroyWindow()
+ {
+ synchronized (nWindowsLock)
+ {
+ numberOfWindows--;
+ if (numberOfWindows == 0)
+ endMainThread();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java
index 6aa87fc2ecf..f746a47479f 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java
@@ -62,6 +62,7 @@ import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
+import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Label;
import java.awt.List;
@@ -83,6 +84,7 @@ import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
+import java.awt.dnd.InvalidDnDOperationException;
import java.awt.dnd.peer.DragSourceContextPeer;
import java.awt.im.InputMethodHighlight;
import java.awt.image.ColorModel;
@@ -115,7 +117,6 @@ import java.awt.peer.WindowPeer;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
@@ -131,37 +132,30 @@ import javax.imageio.spi.IIORegistry;
public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
{
- Hashtable containers = new Hashtable();
- static EventQueue q;
- static Thread mainThread;
+ private static EventQueue q;
static native void gtkInit(int portableNativeSync);
+ static native void gtkMain();
+
+ static native void gtkQuit();
+
static
{
System.loadLibrary("gtkpeer");
-
+
int portableNativeSync;
String portNatSyncProp =
System.getProperty("gnu.classpath.awt.gtk.portable.native.sync");
-
+
if (portNatSyncProp == null)
portableNativeSync = -1; // unset
else if (Boolean.valueOf(portNatSyncProp).booleanValue())
portableNativeSync = 1; // true
else
portableNativeSync = 0; // false
-
+
gtkInit(portableNativeSync);
-
- mainThread = new Thread ("GTK main thread")
- {
- public void run ()
- {
- gtkMain ();
- }
- };
- mainThread.start ();
}
public GtkToolkit ()
@@ -169,6 +163,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
}
public native void beep();
+
private native void getScreenSizeDimensions(int[] xy);
public int checkImage (Image image, int width, int height,
@@ -181,6 +176,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
if (image instanceof GtkImage)
return ((GtkImage) image).checkImage (observer);
+ if (image instanceof AsyncImage)
+ return ((AsyncImage) image).checkImage(observer);
+
if (observer != null)
observer.imageUpdate (image, status,
-1, -1,
@@ -194,7 +192,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
* Helper to return either a Image -- the argument -- or a
* GtkImage with the errorLoading flag set if the argument is null.
*/
- private Image imageOrError(Image b)
+ static Image imageOrError(Image b)
{
if (b == null)
return GtkImage.getErrorImage();
@@ -221,16 +219,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
public Image createImage (URL url)
{
- Image image;
- try
- {
- image = CairoSurface.getBufferedImage( new GtkImage( url ) );
- }
- catch (IllegalArgumentException iae)
- {
- image = null;
- }
- return imageOrError(image);
+ return new AsyncImage(url);
}
public Image createImage (ImageProducer producer)
@@ -301,7 +290,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
"SansSerif" });
}
- private class LRUCache extends LinkedHashMap
+ static class LRUCache extends LinkedHashMap
{
int max_entries;
public LRUCache(int max)
@@ -316,23 +305,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
}
private LRUCache fontCache = new LRUCache(50);
- private LRUCache metricsCache = new LRUCache(50);
private LRUCache imageCache = new LRUCache(50);
public FontMetrics getFontMetrics (Font font)
{
- synchronized (metricsCache)
- {
- if (metricsCache.containsKey(font))
- return (FontMetrics) metricsCache.get(font);
- }
-
- FontMetrics m = new GdkFontMetrics (font);
- synchronized (metricsCache)
- {
- metricsCache.put(font, m);
- }
- return m;
+ return ((GdkFontPeer) font.getPeer()).getFontMetrics(font);
}
public Image getImage (String filename)
@@ -408,6 +385,13 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
return ((((GtkImage)image).checkImage (observer) &
ImageObserver.ALLBITS) != 0);
+ if (image instanceof AsyncImage)
+ {
+ AsyncImage aImg = (AsyncImage) image;
+ aImg.addObserver(observer);
+ return aImg.realImage != null;
+ }
+
/* Assume anything else is too */
return true;
}
@@ -437,106 +421,131 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
protected ButtonPeer createButton (Button b)
{
+ checkHeadless();
return new GtkButtonPeer (b);
}
protected CanvasPeer createCanvas (Canvas c)
{
+ checkHeadless();
return new GtkCanvasPeer (c);
}
protected CheckboxPeer createCheckbox (Checkbox cb)
{
+ checkHeadless();
return new GtkCheckboxPeer (cb);
}
protected CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem cmi)
{
+ checkHeadless();
return new GtkCheckboxMenuItemPeer (cmi);
}
protected ChoicePeer createChoice (Choice c)
{
+ checkHeadless();
return new GtkChoicePeer (c);
}
protected DialogPeer createDialog (Dialog d)
{
+ checkHeadless();
+ GtkMainThread.createWindow();
return new GtkDialogPeer (d);
}
protected FileDialogPeer createFileDialog (FileDialog fd)
{
+ checkHeadless();
return new GtkFileDialogPeer (fd);
}
protected FramePeer createFrame (Frame f)
{
+ checkHeadless();
+ GtkMainThread.createWindow();
return new GtkFramePeer (f);
}
protected LabelPeer createLabel (Label label)
{
+ checkHeadless();
return new GtkLabelPeer (label);
}
protected ListPeer createList (List list)
{
+ checkHeadless();
return new GtkListPeer (list);
}
protected MenuPeer createMenu (Menu m)
{
+ checkHeadless();
return new GtkMenuPeer (m);
}
protected MenuBarPeer createMenuBar (MenuBar mb)
{
+ checkHeadless();
return new GtkMenuBarPeer (mb);
}
protected MenuItemPeer createMenuItem (MenuItem mi)
{
+ checkHeadless();
return new GtkMenuItemPeer (mi);
}
protected PanelPeer createPanel (Panel p)
{
+ checkHeadless();
return new GtkPanelPeer (p);
}
protected PopupMenuPeer createPopupMenu (PopupMenu target)
{
+ checkHeadless();
return new GtkPopupMenuPeer (target);
}
protected ScrollPanePeer createScrollPane (ScrollPane sp)
{
+ checkHeadless();
return new GtkScrollPanePeer (sp);
}
protected ScrollbarPeer createScrollbar (Scrollbar sb)
{
+ checkHeadless();
return new GtkScrollbarPeer (sb);
}
protected TextAreaPeer createTextArea (TextArea ta)
{
+ checkHeadless();
return new GtkTextAreaPeer (ta);
}
protected TextFieldPeer createTextField (TextField tf)
{
+ checkHeadless();
return new GtkTextFieldPeer (tf);
}
protected WindowPeer createWindow (Window w)
{
+ checkHeadless();
+ GtkMainThread.createWindow();
return new GtkWindowPeer (w);
}
public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w)
{
+ checkHeadless();
+ GtkMainThread.createWindow();
return new GtkEmbeddedWindowPeer (w);
}
@@ -605,6 +614,8 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
{
+ if (GraphicsEnvironment.isHeadless())
+ throw new InvalidDnDOperationException();
return new GtkDragSourceContextPeer(e);
}
@@ -614,7 +625,8 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
int actions,
DragGestureListener l)
{
- if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer"))
+ if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer")
+ && ! GraphicsEnvironment.isHeadless())
{
GtkMouseDragGestureRecognizer gestureRecognizer
= new GtkMouseDragGestureRecognizer(ds, comp, actions, l);
@@ -661,13 +673,25 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
GdkPixbufDecoder.registerSpis(reg);
}
- public static native void gtkMain();
-
protected MouseInfoPeer getMouseInfoPeer()
{
return new GtkMouseInfoPeer();
}
+ public boolean isFrameStateSupported(int state)
+ {
+ // GTK supports ICONFIED, NORMAL and MAXIMIZE_BOTH, but
+ // not (yet?) MAXIMIZE_VERT and MAXIMIZE_HORIZ.
+ return state == Frame.NORMAL || state == Frame.ICONIFIED
+ || state == Frame.MAXIMIZED_BOTH;
+ }
+
+ private void checkHeadless()
+ {
+ if (GraphicsEnvironment.isHeadless())
+ throw new HeadlessException();
+ }
+
public native int getMouseNumberOfButtons();
} // class GtkToolkit
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java
index 44e7b027b0b..8660ced8ec1 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java
@@ -37,13 +37,21 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
-import java.awt.ImageCapabilities;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
+import java.awt.ImageCapabilities;
+import java.awt.Point;
import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.VolatileImage;
+import java.awt.image.WritableRaster;
public class GtkVolatileImage extends VolatileImage
{
@@ -52,6 +60,12 @@ public class GtkVolatileImage extends VolatileImage
final GtkComponentPeer component;
+ static ColorModel gdkColorModel = new DirectColorModel(32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000);
+
/**
* Don't touch, accessed from native code.
*/
@@ -62,6 +76,17 @@ public class GtkVolatileImage extends VolatileImage
native void destroy(long pointer);
native int[] nativeGetPixels(long pointer);
+
+ /**
+ * Gets the pixels in the current image from GDK.
+ *
+ * Note that pixels are in 32-bit RGBA, non-premultiplied, which is different
+ * from Cairo's premultiplied ARGB, which is different from Java's standard
+ * non-premultiplied ARGB. Caution is advised when using this method, to
+ * ensure that the data format remains consistent with what you expect.
+ *
+ * @return the current pixels, as reported by GDK.
+ */
public int[] getPixels()
{
return nativeGetPixels(nativePointer);
@@ -113,9 +138,11 @@ public class GtkVolatileImage extends VolatileImage
public BufferedImage getSnapshot()
{
- CairoSurface cs = new CairoSurface( width, height );
- cs.setPixels( getPixels() );
- return CairoSurface.getBufferedImage( cs );
+ WritableRaster raster = Raster.createWritableRaster(createGdkSampleModel(width, height),
+ new Point(0, 0));
+ raster.setDataElements(0, 0, getPixels());
+ return new BufferedImage(gdkColorModel, raster,
+ gdkColorModel.isAlphaPremultiplied(), null);
}
public Graphics getGraphics()
@@ -167,4 +194,14 @@ public class GtkVolatileImage extends VolatileImage
{
return null;
}
+
+ /**
+ * Creates a SampleModel that matches GDK's native format
+ */
+ protected static SampleModel createGdkSampleModel(int w, int h)
+ {
+ return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
+ new int[]{0x000000FF, 0x0000FF00,
+ 0x00FF0000, 0xFF000000});
+ }
}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java
index 866d9c8816a..8d49719b1d3 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java
@@ -38,7 +38,10 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import gnu.java.awt.ComponentReshapeEvent;
+
import java.awt.Component;
+import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.KeyboardFocusManager;
@@ -62,8 +65,7 @@ public class GtkWindowPeer extends GtkContainerPeer
protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6;
protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7;
- private boolean hasBeenShown = false;
- private int oldState = Frame.NORMAL;
+ protected int windowState = Frame.NORMAL;
// Cached awt window component location, width and height.
private int x, y, width, height;
@@ -75,6 +77,12 @@ public class GtkWindowPeer extends GtkContainerPeer
native boolean gtkWindowHasFocus();
native void realize ();
+ public void dispose()
+ {
+ super.dispose();
+ GtkMainThread.destroyWindow();
+ }
+
/** Returns the cached width of the AWT window component. */
int getX ()
{
@@ -144,6 +152,8 @@ public class GtkWindowPeer extends GtkContainerPeer
public GtkWindowPeer (Window window)
{
super (window);
+ // Set reasonable font for the window.
+ window.setFont(new Font("Dialog", Font.PLAIN, 12));
}
public native void toBack();
@@ -218,9 +228,31 @@ public class GtkWindowPeer extends GtkContainerPeer
// only called from GTK thread
protected void postConfigureEvent (int x, int y, int width, int height)
{
+ int frame_x = x - insets.left;
+ int frame_y = y - insets.top;
int frame_width = width + insets.left + insets.right;
int frame_height = height + insets.top + insets.bottom;
+ // Update the component's knowledge about the size.
+ // Important: Please look at the big comment in ComponentReshapeEvent
+ // to learn why we did it this way. If you change this code, make
+ // sure that the peer->AWT bounds update still works.
+ // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 )
+
+ // We do this befor we post the ComponentEvent, because (in Window)
+ // we invalidate() / revalidate() when a ComponentEvent is seen,
+ // and the AWT must already know about the new size then.
+ if (frame_x != this.x || frame_y != this.y || frame_width != this.width
+ || frame_height != this.height)
+ {
+ ComponentReshapeEvent ev = new ComponentReshapeEvent(awtComponent,
+ frame_x,
+ frame_y,
+ frame_width,
+ frame_height);
+ awtComponent.dispatchEvent(ev);
+ }
+
if (frame_width != getWidth()
|| frame_height != getHeight())
{
@@ -230,9 +262,6 @@ public class GtkWindowPeer extends GtkContainerPeer
ComponentEvent.COMPONENT_RESIZED));
}
- int frame_x = x - insets.left;
- int frame_y = y - insets.top;
-
if (frame_x != getX()
|| frame_y != getY())
{
@@ -241,6 +270,7 @@ public class GtkWindowPeer extends GtkContainerPeer
q().postEvent(new ComponentEvent(awtComponent,
ComponentEvent.COMPONENT_MOVED));
}
+
}
public void show ()
@@ -255,23 +285,26 @@ public class GtkWindowPeer extends GtkContainerPeer
void postWindowEvent (int id, Window opposite, int newState)
{
- if (id == WindowEvent.WINDOW_OPENED)
+ if (id == WindowEvent.WINDOW_STATE_CHANGED)
{
- // Post a WINDOW_OPENED event the first time this window is shown.
- if (!hasBeenShown)
+ if (windowState != newState)
{
+ // Post old styleWindowEvent with WINDOW_ICONIFIED or
+ // WINDOW_DEICONIFIED if appropriate.
+ if ((windowState & Frame.ICONIFIED) != 0
+ && (newState & Frame.ICONIFIED) == 0)
+ q().postEvent(new WindowEvent((Window) awtComponent,
+ WindowEvent.WINDOW_DEICONIFIED,
+ opposite, 0, 0));
+ else if ((windowState & Frame.ICONIFIED) == 0
+ && (newState & Frame.ICONIFIED) != 0)
+ q().postEvent(new WindowEvent((Window) awtComponent,
+ WindowEvent.WINDOW_ICONIFIED,
+ opposite, 0, 0));
+ // Post new-style WindowStateEvent.
q().postEvent (new WindowEvent ((Window) awtComponent, id,
- opposite));
- hasBeenShown = true;
- }
- }
- else if (id == WindowEvent.WINDOW_STATE_CHANGED)
- {
- if (oldState != newState)
- {
- q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite,
- oldState, newState));
- oldState = newState;
+ opposite, windowState, newState));
+ windowState = newState;
}
}
else
@@ -350,13 +383,6 @@ public class GtkWindowPeer extends GtkContainerPeer
return g;
}
- protected void updateComponent (PaintEvent event)
- {
- // Do not clear anything before painting. Sun never calls
- // Window.update, only Window.paint.
- paintComponent(event);
- }
-
protected void postMouseEvent(int id, long when, int mods, int x, int y,
int clickCount, boolean popupTrigger)
{
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
index 58496559320..62dbb45d81a 100644
--- a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
@@ -38,15 +38,32 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
+import java.awt.Point;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
public class VolatileImageGraphics extends ComponentGraphics
{
private GtkVolatileImage owner;
+ private BufferedImage buffer;
public VolatileImageGraphics(GtkVolatileImage img)
{
@@ -77,10 +94,118 @@ public class VolatileImageGraphics extends ComponentGraphics
return new VolatileImageGraphics( this );
}
+ public void draw(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.draw(s);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setColor(this.getColor());
+ g2d.setStroke(this.getStroke());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void fill(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.fill(s);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void drawGlyphVector(GlyphVector gv, float x, float y)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawGlyphVector(gv, x, y);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
+ }
+
+ protected boolean drawImage(Image img, AffineTransform xform,
+ Color bgcolor, ImageObserver obs)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ return super.drawImage(img, xform, bgcolor, obs);
+
+ // Custom composite
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find dimensions of translation
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth(), bImg.getHeight());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+ // Perform compositing from buffer to screen
+ return drawComposite(new Rectangle2D.Double((int)origin.getX(),
+ (int)origin.getY(),
+ (int)pt.getX(),
+ (int)pt.getY()),
+ obs);
+ }
+ }
+
public boolean drawImage(Image img, int x, int y, ImageObserver observer)
{
- if( img instanceof GtkVolatileImage )
+ if (img instanceof GtkVolatileImage
+ && (comp == null || comp instanceof AlphaComposite))
{
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
x, y,
@@ -94,7 +219,8 @@ public class VolatileImageGraphics extends ComponentGraphics
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer)
{
- if( img instanceof GtkVolatileImage )
+ if ((img instanceof GtkVolatileImage)
+ && (comp == null || comp instanceof AlphaComposite))
{
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
x, y, width, height );
@@ -107,5 +233,84 @@ public class VolatileImageGraphics extends ComponentGraphics
{
return new Rectangle2D.Double(0, 0, owner.width, owner.height);
}
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get current on-screen pixels (destination) and clip to bounds
+ BufferedImage current = owner.getSnapshot();
+
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ current = current.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ buffer2.getRaster());
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ Composite oldComp = comp; // so that ComponentGraphics doesn't
+ comp = null; // process the composite again
+ boolean rv = super.drawImage(buffer2,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ null, null);
+ comp = oldComp;
+
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ WritableRaster rst;
+ rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(owner.width,
+ owner.height),
+ new Point(0,0));
+
+ buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
+ GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
+ new Hashtable());
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ // We should really return GtkVolatileImage.gdkColorModel ,
+ // but CairoGraphics2D doesn't handle alpha premultiplication properly (see
+ // the fixme in drawImage) so we use the naive Cairo model instead to trick
+ // the compositing context.
+ // Because getNativeCM() == getBufferCM() for this peer, it doesn't break.
+ return CairoSurface.cairoCM_pre;
+ }
}
diff --git a/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java
new file mode 100644
index 00000000000..b3eeb1baa84
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java
@@ -0,0 +1,118 @@
+/* HeadlessGraphicsEnvironment.java -- A graphics environment for headless mode
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.peer.headless;
+
+import gnu.java.awt.java2d.RasterGraphics;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.HeadlessException;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+public class HeadlessGraphicsEnvironment
+ extends GraphicsEnvironment
+{
+
+ public Graphics2D createGraphics(BufferedImage image)
+ {
+ Graphics2D g2d;
+ try
+ {
+ // Try to get a CairoGraphics (accellerated) when available. Do this
+ // via reflection to avoid having a hard compile time dependency.
+ Class cairoSurfaceCl =
+ Class.forName("gnu.java.awt.peer.gtk.CairoSurface");
+ Raster raster = image.getRaster();
+ if (cairoSurfaceCl.isInstance(raster))
+ {
+ Method getGraphicsM = cairoSurfaceCl.getMethod("getGraphics",
+ new Class[0]);
+ g2d = (Graphics2D) getGraphicsM.invoke(raster, new Object[0]);
+ }
+ else
+ {
+ Class bigCl =
+ Class.forName("gnu.java.awt.peer.gtk.BufferedImageGraphics");
+ Constructor bigC =
+ bigCl.getConstructor(new Class[]{BufferedImage.class });
+ g2d = (Graphics2D) bigC.newInstance(new Object[]{ image});
+ }
+ }
+ catch (Exception ex)
+ {
+ g2d = new RasterGraphics(image.getRaster(), image.getColorModel());
+ }
+ return g2d;
+ }
+
+ public Font[] getAllFonts()
+ {
+ // FIXME: Implement.
+ return null;
+ }
+
+ public String[] getAvailableFontFamilyNames()
+ {
+ // FIXME: Implement.
+ return null;
+ }
+
+ public String[] getAvailableFontFamilyNames(Locale l)
+ {
+ // FIXME: Implement.
+ return null;
+ }
+
+ public GraphicsDevice getDefaultScreenDevice()
+ {
+ throw new HeadlessException();
+ }
+
+ public GraphicsDevice[] getScreenDevices()
+ {
+ throw new HeadlessException();
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java
new file mode 100644
index 00000000000..96798c9e9d8
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java
@@ -0,0 +1,371 @@
+/* HeadlessToolkit.java -- A toolkit for headless mode
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.peer.headless;
+
+import gnu.java.awt.ClasspathToolkit;
+import gnu.java.awt.EmbeddedWindow;
+import gnu.java.awt.peer.ClasspathFontPeer;
+import gnu.java.awt.peer.EmbeddedWindowPeer;
+
+import java.awt.AWTException;
+import java.awt.Button;
+import java.awt.Canvas;
+import java.awt.Checkbox;
+import java.awt.CheckboxMenuItem;
+import java.awt.Choice;
+import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.FileDialog;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.HeadlessException;
+import java.awt.Image;
+import java.awt.Label;
+import java.awt.List;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.PopupMenu;
+import java.awt.PrintJob;
+import java.awt.ScrollPane;
+import java.awt.Scrollbar;
+import java.awt.TextArea;
+import java.awt.TextField;
+import java.awt.Window;
+import java.awt.datatransfer.Clipboard;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.peer.DragSourceContextPeer;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.ButtonPeer;
+import java.awt.peer.CanvasPeer;
+import java.awt.peer.CheckboxMenuItemPeer;
+import java.awt.peer.CheckboxPeer;
+import java.awt.peer.ChoicePeer;
+import java.awt.peer.DialogPeer;
+import java.awt.peer.FileDialogPeer;
+import java.awt.peer.FontPeer;
+import java.awt.peer.FramePeer;
+import java.awt.peer.LabelPeer;
+import java.awt.peer.ListPeer;
+import java.awt.peer.MenuBarPeer;
+import java.awt.peer.MenuItemPeer;
+import java.awt.peer.MenuPeer;
+import java.awt.peer.PanelPeer;
+import java.awt.peer.PopupMenuPeer;
+import java.awt.peer.RobotPeer;
+import java.awt.peer.ScrollPanePeer;
+import java.awt.peer.ScrollbarPeer;
+import java.awt.peer.TextAreaPeer;
+import java.awt.peer.TextFieldPeer;
+import java.awt.peer.WindowPeer;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+public class HeadlessToolkit
+ extends ClasspathToolkit
+{
+
+ /**
+ * The graphics environment for headless graphics.
+ */
+ private HeadlessGraphicsEnvironment graphicsEnv;
+
+ public void beep()
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public int checkImage(Image image, int width, int height,
+ ImageObserver observer)
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ protected ButtonPeer createButton(Button target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected CanvasPeer createCanvas(Canvas target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected CheckboxPeer createCheckbox(Checkbox target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected ChoicePeer createChoice(Choice target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected DialogPeer createDialog(Dialog target)
+ {
+ throw new HeadlessException();
+ }
+
+ public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
+ {
+ throw new HeadlessException();
+ }
+
+ protected FileDialogPeer createFileDialog(FileDialog target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected FramePeer createFrame(Frame target)
+ {
+ throw new HeadlessException();
+ }
+
+ public Image createImage(String filename)
+ {
+ // FIXME: Implement.
+ return null;
+ }
+
+ public Image createImage(URL url)
+ {
+ // FIXME: Implement.
+ return null;
+ }
+
+ public Image createImage(ImageProducer producer)
+ {
+ // FIXME: Implement.
+ return null;
+ }
+
+ public Image createImage(byte[] data, int offset, int len)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ protected LabelPeer createLabel(Label target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected ListPeer createList(List target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected MenuPeer createMenu(Menu target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected MenuBarPeer createMenuBar(MenuBar target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected MenuItemPeer createMenuItem(MenuItem target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected PanelPeer createPanel(Panel target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected PopupMenuPeer createPopupMenu(PopupMenu target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected ScrollPanePeer createScrollPane(ScrollPane target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected ScrollbarPeer createScrollbar(Scrollbar target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected TextAreaPeer createTextArea(TextArea target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected TextFieldPeer createTextField(TextField target)
+ {
+ throw new HeadlessException();
+ }
+
+ protected WindowPeer createWindow(Window target)
+ {
+ throw new HeadlessException();
+ }
+
+ public ColorModel getColorModel()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String[] getFontList()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public FontMetrics getFontMetrics(Font name)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ protected FontPeer getFontPeer(String name, int style)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Image getImage(String name)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Image getImage(URL url)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public PrintJob getPrintJob(Frame frame, String title, Properties props)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getScreenResolution()
+ {
+ throw new HeadlessException();
+ }
+
+ public Dimension getScreenSize()
+ {
+ throw new HeadlessException();
+ }
+
+ public Clipboard getSystemClipboard()
+ {
+ throw new HeadlessException();
+ }
+
+ protected EventQueue getSystemEventQueueImpl()
+ {
+ throw new HeadlessException();
+ }
+
+ public Map mapInputMethodHighlight(InputMethodHighlight highlight)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean prepareImage(Image image, int width, int height,
+ ImageObserver observer)
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void sync()
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w)
+ {
+ throw new HeadlessException();
+ }
+
+ public Font createFont(int format, InputStream stream)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public RobotPeer createRobot(GraphicsDevice screen) throws AWTException
+ {
+ throw new HeadlessException();
+ }
+
+ public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public GraphicsEnvironment getLocalGraphicsEnvironment()
+ {
+ if (graphicsEnv == null)
+ graphicsEnv = new HeadlessGraphicsEnvironment();
+ return graphicsEnv;
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java
index d847a805396..6ffe3f69176 100644
--- a/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java
@@ -194,15 +194,4 @@ public class QtFontPeer extends ClasspathFontPeer
throw new UnsupportedOperationException();
}
- public Rectangle2D getStringBounds (Font font,
- CharacterIterator ci,
- int begin, int limit,
- FontRenderContext frc)
- {
- int index = begin;
- String s = "" + ci.setIndex( index );
- while( index++ <= limit )
- s = s + ci.next();
- return metrics.getStringBounds(s);
- }
}
diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java
index 842cbbbf8ba..5694e8d2076 100644
--- a/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java
+++ b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java
@@ -669,12 +669,13 @@ public abstract class QtGraphics extends Graphics2D
public RenderingHints getRenderingHints()
{
- return new RenderingHints( renderingHints );
+ return (RenderingHints) renderingHints.clone();
}
- public void setRenderingHints(Map hints)
+ public void setRenderingHints(Map<?,?> hints)
{
- renderingHints = new RenderingHints( hints );
+ renderingHints = new RenderingHints( null );
+ renderingHints.putAll(hints);
updateRenderingHints();
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java
index 2357fcbfb0d..531d6f2db3b 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.awt.peer.swing;
import java.awt.Button;
+import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
@@ -69,6 +70,13 @@ public class SwingButtonPeer
extends JButton
implements SwingComponent
{
+ Button button;
+
+ SwingButton(Button button)
+ {
+ this.button = button;
+ }
+
/**
* Overridden so that this method returns the correct value even without a
* peer.
@@ -90,8 +98,8 @@ public class SwingButtonPeer
public boolean isShowing()
{
boolean retVal = false;
- if (SwingButtonPeer.this.awtComponent != null)
- retVal = SwingButtonPeer.this.awtComponent.isShowing();
+ if (button != null)
+ retVal = button.isShowing();
return retVal;
}
@@ -168,6 +176,14 @@ public class SwingButtonPeer
ev.setSource(this);
processKeyEvent(ev);
}
+
+ public Container getParent()
+ {
+ Container par = null;
+ if (button != null)
+ par = button.getParent();
+ return par;
+ }
}
/**
@@ -205,7 +221,7 @@ public class SwingButtonPeer
*/
public SwingButtonPeer(Button theButton)
{
- SwingButton button = new SwingButton();
+ SwingButton button = new SwingButton(theButton);
button.setText(theButton.getLabel());
button.addActionListener(new SwingButtonListener());
init(theButton, button);
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java
index a51b758adf0..04ca7294f78 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java
@@ -62,7 +62,7 @@ public interface SwingComponent
/**
* Handles a mouse event. This is usually forwarded to
- * {@link java.awt.Component#processMouseMotionEvent(MouseEvent)} of the swing
+ * {@link Component#processMouseMotionEvent(MouseEvent)} of the swing
* component.
*
* @param ev the mouse event
@@ -71,7 +71,7 @@ public interface SwingComponent
/**
* Handles a mouse motion event. This is usually forwarded to
- * {@link java.awt.Component#processMouseEvent(MouseEvent)} of the swing
+ * {@link Component#processMouseEvent(MouseEvent)} of the swing
* component.
*
* @param ev the mouse motion event
@@ -80,7 +80,7 @@ public interface SwingComponent
/**
* Handles a key event. This is usually forwarded to
- * {@link java.awt.Component#processKeyEvent(KeyEvent)} of the swing
+ * {@link Component#processKeyEvent(KeyEvent)} of the swing
* component.
*
* @param ev the key event
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java
index 96ccc00b8f0..bfa14dddee3 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java
@@ -42,6 +42,7 @@ import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.Color;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
@@ -62,6 +63,10 @@ import java.awt.image.ImageProducer;
import java.awt.image.VolatileImage;
import java.awt.peer.ComponentPeer;
import java.awt.peer.ContainerPeer;
+import java.awt.peer.LightweightPeer;
+
+import javax.swing.JComponent;
+import javax.swing.RepaintManager;
/**
* The base class for Swing based component peers. This provides the basic
@@ -97,9 +102,18 @@ public class SwingComponentPeer
protected SwingComponent swingComponent;
/**
+ * The font that is set for this peer.
+ */
+ protected Font peerFont;
+
+ /**
+ * The current repaint area.
+ */
+ protected Rectangle paintArea;
+
+ /**
* Creates a SwingComponentPeer instance. Subclasses are expected to call
- * this constructor and thereafter call
- * {@link #init(Component,SwingComponent)}
+ * this constructor and thereafter call {@link #init(Component, JComponent)}
* in order to setup the AWT and Swing components properly.
*/
protected SwingComponentPeer()
@@ -118,6 +132,38 @@ public class SwingComponentPeer
{
awtComponent = awtComp;
swingComponent = swingComp;
+ if (swingComponent != null)
+ {
+ JComponent c = swingComponent.getJComponent();
+ if (c != null)
+ {
+ c.addNotify();
+ RepaintManager.currentManager(c).setDoubleBufferingEnabled(false);
+ System.setProperty("gnu.awt.swing.doublebuffering", "true");
+ }
+ }
+
+ // Register this heavyweight component with the nearest heavyweight
+ // container, so we get peerPaint() triggered by that container.
+ if (! (this instanceof LightweightPeer))
+ {
+ Component comp = awtComponent;
+ Container parent = comp.getParent();
+ while (parent != null &&
+ ! (parent.getPeer() instanceof SwingContainerPeer))
+ {
+ comp = parent;
+ parent = comp.getParent();
+ }
+
+ // At this point we have the ancestor with a SwingContainerPeer
+ // (or null peer).
+ if (parent != null && parent.getPeer() instanceof SwingContainerPeer)
+ {
+ SwingContainerPeer p = (SwingContainerPeer) parent.getPeer();
+ p.addHeavyweightDescendent(awtComponent);
+ }
+ }
}
/**
@@ -185,6 +231,28 @@ public class SwingComponentPeer
*/
public void dispose()
{
+ // Unregister this heavyweight component from the nearest heavyweight
+ // container.
+ if (! (this instanceof LightweightPeer))
+ {
+ Component comp = awtComponent;
+ Container parent = comp.getParent();
+ while (parent != null &&
+ ! (parent.getPeer() instanceof SwingContainerPeer))
+ {
+ comp = parent;
+ parent = comp.getParent();
+ }
+
+ // At this point we have the ancestor with a SwingContainerPeer
+ // (or null peer).
+ if (parent != null && parent.getPeer() instanceof SwingContainerPeer)
+ {
+ SwingContainerPeer p = (SwingContainerPeer) parent.getPeer();
+ p.removeHeavyweightDescendent(awtComponent);
+ }
+ }
+
awtComponent = null;
swingComponent = null;
}
@@ -244,8 +312,7 @@ public class SwingComponentPeer
public Graphics getGraphics()
{
Component parent = awtComponent.getParent();
- ComponentPeer parentPeer = parent.getPeer();
- Graphics g = parentPeer.getGraphics();
+ Graphics g = parent.getGraphics();
g.translate(awtComponent.getX(), awtComponent.getY());
g.setClip(0, 0, awtComponent.getWidth(), awtComponent.getHeight());
return g;
@@ -331,23 +398,28 @@ public class SwingComponentPeer
{
case PaintEvent.UPDATE:
case PaintEvent.PAINT:
- // This only will work when the component is showing.
- if (awtComponent.isShowing())
+ // Need to synchronize to avoid threading problems on the
+ // paint event list.
+ // We must synchronize on the tree lock first to avoid deadlock,
+ // because Container.paint() will grab it anyway.
+ synchronized (this)
{
- Graphics g = getGraphics();
- Rectangle clip = ((PaintEvent)e).getUpdateRect();
- g.clipRect(clip.x, clip.y, clip.width, clip.height);
- //if (this instanceof LightweightPeer)
- // {
- if (e.getID() == PaintEvent.UPDATE)
- awtComponent.update(g);
- else
- awtComponent.paint(g);
- // }
- // We paint the 'heavyweights' at last, so that they appear on top of
- // everything else.
- peerPaint(g);
- g.dispose();
+ assert paintArea != null;
+ if (awtComponent.isShowing())
+ {
+ Graphics g = awtComponent.getGraphics();
+ try
+ {
+ Rectangle clip = paintArea;
+ g.clipRect(clip.x, clip.y, clip.width, clip.height);
+ peerPaint(g, e.getID() == PaintEvent.UPDATE);
+ }
+ finally
+ {
+ g.dispose();
+ paintArea = null;
+ }
+ }
}
break;
case MouseEvent.MOUSE_PRESSED:
@@ -451,9 +523,15 @@ public class SwingComponentPeer
return retVal;
}
+ /**
+ * Paints the component. This is triggered by
+ * {@link Component#paintAll(Graphics)}.
+ *
+ * @param graphics the graphics to paint with
+ */
public void paint(Graphics graphics)
{
- // FIXME: I don't know what this method is supposed to do.
+ peerPaint(graphics, false);
}
/**
@@ -634,6 +712,7 @@ public class SwingComponentPeer
*/
public void setFont(Font font)
{
+ peerFont = font;
if (swingComponent != null)
swingComponent.getJComponent().setFont(font);
}
@@ -741,7 +820,14 @@ public class SwingComponentPeer
*/
public void coalescePaintEvent(PaintEvent e)
{
- // Nothing to do here yet.
+ synchronized (this)
+ {
+ Rectangle newRect = e.getUpdateRect();
+ if (paintArea == null)
+ paintArea = newRect;
+ else
+ Rectangle.union(paintArea, newRect, paintArea);
+ }
}
/**
@@ -947,9 +1033,33 @@ public class SwingComponentPeer
* paint() on the Swing component.
*
* @param g the graphics context to use for painting
+ * @param update wether we need to call update or paint on the AWT component
+ */
+ protected void peerPaint(Graphics g, boolean update)
+ {
+ peerPaintComponent(g);
+
+ Graphics userGraphics = g.create();
+ try{
+ if (update)
+ awtComponent.update(userGraphics);
+ else
+ awtComponent.paint(userGraphics);
+ } finally {
+ userGraphics.dispose();
+ }
+
+ }
+
+ /**
+ * Paints the actual 'heavyweight' swing component, if there is one
+ * associated to this peer.
+ *
+ * @param g the graphics to paint the component with
*/
- protected void peerPaint(Graphics g)
+ protected void peerPaintComponent(Graphics g)
{
+ // Paint the actual Swing component if this peer has one.
if (swingComponent != null)
swingComponent.getJComponent().paint(g);
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java
index f433e1b5c2d..c78b644a765 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java
@@ -37,14 +37,20 @@ exception statement from your version. */
package gnu.java.awt.peer.swing;
+import gnu.classpath.SystemProperties;
+
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
+import java.awt.Image;
import java.awt.Insets;
-import java.awt.Shape;
+import java.awt.Rectangle;
+import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.peer.ComponentPeer;
import java.awt.peer.ContainerPeer;
+import java.util.Iterator;
+import java.util.LinkedList;
/**
* A peer for Container to be used with the Swing based AWT peers.
@@ -57,13 +63,53 @@ public class SwingContainerPeer
{
/**
+ * Stores all heavyweight descendents of the container. This is used
+ * in {@link #peerPaintChildren(Graphics)}.
+ */
+ private LinkedList heavyweightDescendents;
+
+ /**
+ * The backbuffer used for painting UPDATE events.
+ */
+ private Image backbuffer;
+
+ /**
* Creates a new SwingContainerPeer.
*
* @param awtCont
*/
- public SwingContainerPeer(Component awtCont)
+ public SwingContainerPeer(Container awtCont)
+ {
+ heavyweightDescendents = new LinkedList();
+ }
+
+ /**
+ * Registers a heavyweight descendent. This is then painted by
+ * {@link #peerPaintChildren(Graphics)}.
+ *
+ * @param comp the descendent to register
+ *
+ * @see #peerPaintChildren(Graphics)
+ * @see #removeHeavyweightDescendent(Component)
+ */
+ synchronized void addHeavyweightDescendent(Component comp)
+ {
+ heavyweightDescendents.add(comp);
+ focusOwner = null;
+ }
+
+ /**
+ * Unregisters a heavyweight descendent.
+ *
+ * @param comp the descendent to unregister
+ *
+ * @see #peerPaintChildren(Graphics)
+ * @see #addHeavyweightDescendent(Component)
+ */
+ synchronized void removeHeavyweightDescendent(Component comp)
{
- init(awtCont, null);
+ heavyweightDescendents.remove(comp);
+ focusOwner = null;
}
/**
@@ -92,12 +138,7 @@ public class SwingContainerPeer
*/
public Insets getInsets()
{
- Insets retVal;
- if (swingComponent != null)
- retVal = swingComponent.getJComponent().getInsets();
- else
- retVal = new Insets(0, 0, 0, 0);
- return retVal;
+ return insets();
}
/**
@@ -171,38 +212,83 @@ public class SwingContainerPeer
}
/**
- * Triggers painting of a component. This calls peerPaint on all the child
- * components of this container.
- *
- * @param g the graphics context to paint to
+ * Performs the super behaviour (call peerPaintComponent() and
+ * awtComponent.paint()), and forwards the paint request to the heavyweight
+ * descendents of the container.
*/
- protected void peerPaint(Graphics g)
+ protected void peerPaint(Graphics g, boolean update)
{
- Container c = (Container) awtComponent;
- Component[] children = c.getComponents();
- for (int i = children.length - 1; i >= 0; --i)
+ if (isDoubleBuffering())
{
- Component child = children[i];
- ComponentPeer peer = child.getPeer();
- boolean translated = false;
- boolean clipped = false;
- Shape oldClip = g.getClip();
+ int width = awtComponent.getWidth();
+ int height = awtComponent.getHeight();
+ if (backbuffer == null
+ || backbuffer.getWidth(awtComponent) < width
+ || backbuffer.getHeight(awtComponent) < height)
+ backbuffer = awtComponent.createImage(width, height);
+ Graphics g2 = backbuffer.getGraphics();
+ Rectangle clip = g.getClipRect();
try
- {
- g.translate(child.getX(), child.getY());
- translated = true;
- g.setClip(0, 0, child.getWidth(), child.getHeight());
- clipped = true;
- if (peer instanceof SwingComponentPeer)
- ((SwingComponentPeer) peer).peerPaint(g);
- }
+ {
+ g2.setClip(clip);
+ super.peerPaint(g2, update);
+ peerPaintChildren(g2);
+ }
finally
- {
- if (translated)
- g.translate(- child.getX(), - child.getY());
- if (clipped)
- g.setClip(oldClip);
- }
+ {
+ g2.dispose();
+ }
+ g.drawImage(backbuffer, 0, 0, awtComponent);
+ }
+ else
+ {
+ super.peerPaint(g, update);
+ peerPaintChildren(g);
+ }
+ }
+
+ /**
+ * Determines if we should do double buffering or not.
+ *
+ * @return if we should do double buffering or not
+ */
+ private boolean isDoubleBuffering()
+ {
+ Object prop =
+ SystemProperties.getProperty("gnu.awt.swing.doublebuffering", "false");
+ return prop.equals("true");
+ }
+
+ /**
+ * Paints any heavyweight child components.
+ *
+ * @param g the graphics to use for painting
+ */
+ protected synchronized void peerPaintChildren(Graphics g)
+ {
+ // TODO: Is this the right painting order?
+ for (Iterator i = heavyweightDescendents.iterator(); i.hasNext();)
+ {
+ Component child = (Component) i.next();
+ ComponentPeer peer = child.getPeer();
+
+ if (peer instanceof SwingComponentPeer && child.isVisible())
+ {
+ // TODO: The translation here doesn't work for deeper
+ // nested children. Fix this!
+ Graphics g2 = g.create(child.getX(), child.getY(),
+ child.getWidth(), child.getHeight());
+ try
+ {
+ // update() is only called for the topmost component if
+ // necessary, all other components only get paint() called.
+ ((SwingComponentPeer) peer).peerPaint(g2, false);
+ }
+ finally
+ {
+ g2.dispose();
+ }
+ }
}
}
@@ -214,17 +300,13 @@ public class SwingContainerPeer
protected void handleMouseEvent(MouseEvent ev)
{
Component comp = awtComponent.getComponentAt(ev.getPoint());
- if(comp == null)
- comp = awtComponent;
- if (comp != null)
+ if(comp == null) comp = awtComponent;
+ ComponentPeer peer = comp.getPeer();
+ if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
{
- ComponentPeer peer = comp.getPeer();
- if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
- {
- ev.translatePoint(comp.getX(), comp.getY());
- ev.setSource(comp);
- ((SwingComponentPeer) peer).handleMouseEvent(ev);
- }
+ ev.translatePoint(comp.getX(), comp.getY());
+ ev.setSource(comp);
+ ((SwingComponentPeer) peer).handleMouseEvent(ev);
}
}
@@ -246,4 +328,39 @@ public class SwingContainerPeer
}
}
}
+
+ /**
+ * Handles key events on the component. This is usually forwarded to the
+ * SwingComponent's processKeyEvent() method.
+ *
+ * @param e the key event
+ */
+ protected void handleKeyEvent(KeyEvent e)
+ {
+ Component owner = getFocusOwner();
+ if(owner != null)
+ owner.dispatchEvent(e);
+ else
+ super.handleKeyEvent(e);
+ }
+
+ private Component focusOwner = null;
+
+ private Component getFocusOwner()
+ {
+ if(focusOwner == null)
+ {
+ for(Iterator iter=heavyweightDescendents.iterator(); iter.hasNext();)
+ {
+ Component child = (Component) iter.next();
+ if(child.isFocusable())
+ {
+ focusOwner = child;
+ break;
+ }
+ }
+ }
+ return focusOwner;
+ }
+
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java
index 0d5a02d78f6..56c7417cdcf 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java
@@ -43,6 +43,7 @@ import java.awt.Insets;
import java.awt.MenuBar;
import java.awt.Point;
import java.awt.event.MouseEvent;
+import java.awt.peer.ComponentPeer;
import java.awt.peer.FramePeer;
/**
@@ -53,9 +54,9 @@ import java.awt.peer.FramePeer;
* As a minimum, a subclass must implement all the remaining abstract methods
* as well as the following methods:
* <ul>
- * <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li>
- * <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li>
- * <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li>
+ * <li>{@link ComponentPeer#getLocationOnScreen()}</li>
+ * <li>{@link ComponentPeer#getGraphics()}</li>
+ * <li>{@link ComponentPeer#createImage(int, int)}</li>
* </ul>
*
* @author Roman Kennke (kennke@aicas.com)
@@ -97,9 +98,9 @@ public abstract class SwingFramePeer
*
* @param g the graphics context to use for painting
*/
- protected void peerPaint(Graphics g)
+ protected void peerPaintComponent(Graphics g)
{
- super.peerPaint(g);
+ super.peerPaintComponent(g);
if (menuBar != null)
menuBar.peerPaint(g);
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java
index dd86fff2d10..349c5a0abe2 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package gnu.java.awt.peer.swing;
+import java.awt.Container;
+import java.awt.Graphics;
import java.awt.Image;
import java.awt.Label;
import java.awt.Point;
@@ -67,7 +69,14 @@ public class SwingLabelPeer
extends JLabel
implements SwingComponent
{
-
+ Label label;
+
+
+ SwingLabel(Label label)
+ {
+ this.label = label;
+ }
+
/**
* Returns this label.
*
@@ -131,8 +140,8 @@ public class SwingLabelPeer
public boolean isShowing()
{
boolean retVal = false;
- if (SwingLabelPeer.this.awtComponent != null)
- retVal = SwingLabelPeer.this.awtComponent.isShowing();
+ if (label != null)
+ retVal = label.isShowing();
return retVal;
}
@@ -149,7 +158,19 @@ public class SwingLabelPeer
{
return SwingLabelPeer.this.createImage(w, h);
}
-
+
+ public Graphics getGraphics()
+ {
+ return SwingLabelPeer.this.getGraphics();
+ }
+
+ public Container getParent()
+ {
+ Container par = null;
+ if (label != null)
+ par = label.getParent();
+ return par;
+ }
}
/**
@@ -160,11 +181,11 @@ public class SwingLabelPeer
public SwingLabelPeer(Label label)
{
super();
- SwingLabel swingLabel = new SwingLabel();
+ SwingLabel swingLabel = new SwingLabel(label);
swingLabel.setText(label.getText());
- swingLabel.setHorizontalAlignment(label.getAlignment());
swingLabel.setOpaque(true);
init(label, swingLabel);
+ setAlignment(label.getAlignment());
}
/**
@@ -190,7 +211,20 @@ public class SwingLabelPeer
*/
public void setAlignment(int alignment)
{
- ((JLabel) swingComponent.getJComponent()).setHorizontalAlignment(alignment);
+ JLabel swingLabel = (JLabel) swingComponent.getJComponent();
+ switch (alignment)
+ {
+ case Label.RIGHT:
+ swingLabel.setHorizontalAlignment(JLabel.RIGHT);
+ break;
+ case Label.CENTER:
+ swingLabel.setHorizontalAlignment(JLabel.CENTER);
+ break;
+ case Label.LEFT:
+ default:
+ swingLabel.setHorizontalAlignment(JLabel.LEFT);
+ break;
+ }
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java
new file mode 100644
index 00000000000..aca2070486d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java
@@ -0,0 +1,352 @@
+/* SwingListPeer.java -- A Swing based peer for AWT lists
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.peer.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.List;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.peer.ListPeer;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JComponent;
+import javax.swing.JList;
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+
+public class SwingListPeer
+ extends SwingComponentPeer
+ implements ListPeer
+{
+
+ /**
+ * A spezialized Swing scroller used to hold the list.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class SwingList
+ extends JScrollPane
+ implements SwingComponent
+ {
+
+ SwingList(Component comp)
+ {
+ super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ }
+
+ /**
+ * Returns this label.
+ *
+ * @return <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ dispatchEvent(ev);
+ }
+
+ /**
+ * Force lightweight mouse dispatching.
+ */
+ public boolean isLightweight()
+ {
+ return false;
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to <code>processKeyEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ processKeyEvent(ev);
+ }
+
+ /**
+ * Overridden so that this method returns the correct value even without a
+ * peer.
+ *
+ * @return the screen location of the button
+ */
+ public Point getLocationOnScreen()
+ {
+ return SwingListPeer.this.getLocationOnScreen();
+ }
+
+ /**
+ * Overridden so that the isShowing method returns the correct value for the
+ * swing button, even if it has no peer on its own.
+ *
+ * @return <code>true</code> if the button is currently showing,
+ * <code>false</code> otherwise
+ */
+ public boolean isShowing()
+ {
+ boolean retVal = false;
+ if (SwingListPeer.this.awtComponent != null)
+ retVal = SwingListPeer.this.awtComponent.isShowing();
+ return retVal;
+ }
+
+ /**
+ * Overridden, so that the Swing button can create an Image without its
+ * own peer.
+ *
+ * @param w the width of the image
+ * @param h the height of the image
+ *
+ * @return an image
+ */
+ public Image createImage(int w, int h)
+ {
+ return SwingListPeer.this.createImage(w, h);
+ }
+
+ public Graphics getGraphics()
+ {
+ return SwingListPeer.this.getGraphics();
+ }
+
+ public Container getParent()
+ {
+ Container par = null;
+ if (SwingListPeer.this.awtComponent != null)
+ par = SwingListPeer.this.awtComponent.getParent();
+ return par;
+ }
+ }
+
+ /**
+ * The actual Swing JList.
+ */
+ private JList jList;
+
+ private DefaultListModel listModel;
+
+ public SwingListPeer(List list)
+ {
+ super();
+ listModel = new DefaultListModel();
+ jList = new JList(listModel);
+ SwingList swingList = new SwingList(jList);
+ init(list, swingList);
+
+ // Pull over the items from the list.
+ String[] items = list.getItems();
+ for (int i = 0 ; i < items.length; i++)
+ addItem(items[i], i);
+ }
+
+ public void add(String item, int index)
+ {
+ if (listModel != null)
+ listModel.add(index, item);
+ }
+
+ public void addItem(String item, int index)
+ {
+ if (listModel != null)
+ listModel.add(index, item);
+ }
+
+ public void clear()
+ {
+ if (listModel != null)
+ listModel.clear();
+ }
+
+ public void delItems(int startIndex, int endIndex)
+ {
+ if (listModel != null)
+ listModel.removeRange(startIndex, endIndex);
+ }
+
+ public void deselect(int index)
+ {
+ if (jList != null)
+ {
+ jList.getSelectionModel().removeSelectionInterval(index, index);
+ }
+ }
+
+ public Dimension getMinimumSize(int s)
+ {
+ Dimension d = null;
+ if (jList != null)
+ {
+ d = jList.getComponent(s).getMinimumSize();
+ }
+ return d;
+ }
+
+ public Dimension getPreferredSize(int s)
+ {
+ Dimension d = null;
+ if (jList != null)
+ {
+ d = jList.getComponent(s).getPreferredSize();
+ }
+ return d;
+ }
+
+ public int[] getSelectedIndexes()
+ {
+ int[] sel = null;
+ if (jList != null)
+ {
+ sel = jList.getSelectedIndices();
+ }
+ return sel;
+ }
+
+ public void makeVisible(int index)
+ {
+ if (jList != null)
+ {
+ Component comp = jList.getComponent(index);
+ jList.scrollRectToVisible(comp.getBounds());
+ }
+ }
+
+ public Dimension minimumSize(int s)
+ {
+ Dimension d = null;
+ if (jList != null)
+ {
+ d = jList.getComponent(s).getMinimumSize();
+ }
+ return d;
+ }
+
+ public Dimension preferredSize(int s)
+ {
+ Dimension d = null;
+ if (jList != null)
+ {
+ d = jList.getComponent(s).getPreferredSize();
+ }
+ return d;
+ }
+
+ public void removeAll()
+ {
+ if (jList != null)
+ {
+ jList.removeAll();
+ }
+ }
+
+ public void select(int index)
+ {
+ if (jList != null)
+ {
+ jList.setSelectedIndex(index);
+ }
+ }
+
+ public void setMultipleMode(boolean multi)
+ {
+ if (jList != null)
+ {
+ jList.setSelectionMode(multi
+ ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
+ : ListSelectionModel.SINGLE_SELECTION);
+ }
+ }
+
+ public void setMultipleSelections(boolean multi)
+ {
+ if (jList != null)
+ {
+ jList.setSelectionMode(multi
+ ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
+ : ListSelectionModel.SINGLE_SELECTION);
+ }
+ }
+
+ public void reshape(int x, int y, int width, int height)
+ {
+ if (swingComponent != null)
+ {
+ swingComponent.getJComponent().setBounds(x, y, width, height);
+ swingComponent.getJComponent().validate();
+ }
+ }
+
+ protected void peerPaint(Graphics g, boolean update)
+ {
+ super.peerPaint(g, update);
+ jList.doLayout();
+ jList.list();
+
+ Rectangle r = getBounds();
+ g.setColor(Color.RED);
+ g.drawRect(r.x, r.y, r.width, r.height);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java
index 0033efb025f..bd9dcd77aaa 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java
@@ -174,7 +174,7 @@ public class SwingMenuBarPeer
/**
* Adds a help menu to the menu bar.
*
- * @param menu the menu to add
+ * @param m the menu to add
*/
public void addHelpMenu(Menu menu)
{
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java
index 0a0f20fe826..3cea62ac4d1 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java
@@ -39,7 +39,6 @@ exception statement from your version. */
package gnu.java.awt.peer.swing;
import java.awt.Panel;
-import java.awt.peer.LightweightPeer;
import java.awt.peer.PanelPeer;
/**
@@ -51,7 +50,7 @@ import java.awt.peer.PanelPeer;
// necessary, but might be good for more consistend Look.
public class SwingPanelPeer
extends SwingContainerPeer
- implements PanelPeer, LightweightPeer
+ implements PanelPeer
{
/**
@@ -63,5 +62,6 @@ public class SwingPanelPeer
public SwingPanelPeer(Panel panel)
{
super(panel);
+ init(panel, null);
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java
new file mode 100644
index 00000000000..04ac011419f
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java
@@ -0,0 +1,317 @@
+/* SwingTextAreaPeer.java -- A Swing based peer for AWT textareas
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.peer.swing;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.TextArea;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.im.InputMethodRequests;
+import java.awt.peer.TextAreaPeer;
+
+import javax.swing.JComponent;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.text.BadLocationException;
+
+public class SwingTextAreaPeer
+ extends SwingComponentPeer
+ implements TextAreaPeer
+{
+
+ /**
+ * A spezialized Swing scroller used to hold the textarea.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class SwingTextArea
+ extends JScrollPane
+ implements SwingComponent
+ {
+
+ SwingTextArea(Component comp)
+ {
+ super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ }
+
+ /**
+ * Returns this label.
+ *
+ * @return <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ dispatchEvent(ev);
+ }
+
+ /**
+ * Force lightweight mouse dispatching.
+ */
+ public boolean isLightweight()
+ {
+ return false;
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to <code>processKeyEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ processKeyEvent(ev);
+ }
+
+ /**
+ * Overridden so that this method returns the correct value even without a
+ * peer.
+ *
+ * @return the screen location of the button
+ */
+ public Point getLocationOnScreen()
+ {
+ return SwingTextAreaPeer.this.getLocationOnScreen();
+ }
+
+ /**
+ * Overridden so that the isShowing method returns the correct value for the
+ * swing button, even if it has no peer on its own.
+ *
+ * @return <code>true</code> if the button is currently showing,
+ * <code>false</code> otherwise
+ */
+ public boolean isShowing()
+ {
+ boolean retVal = false;
+ if (SwingTextAreaPeer.this.awtComponent != null)
+ retVal = SwingTextAreaPeer.this.awtComponent.isShowing();
+ return retVal;
+ }
+
+ /**
+ * Overridden, so that the Swing button can create an Image without its
+ * own peer.
+ *
+ * @param w the width of the image
+ * @param h the height of the image
+ *
+ * @return an image
+ */
+ public Image createImage(int w, int h)
+ {
+ return SwingTextAreaPeer.this.createImage(w, h);
+ }
+
+ public Graphics getGraphics()
+ {
+ return SwingTextAreaPeer.this.getGraphics();
+ }
+
+ public Container getParent()
+ {
+ Container par = null;
+ if (SwingTextAreaPeer.this.awtComponent != null)
+ par = SwingTextAreaPeer.this.awtComponent.getParent();
+ return par;
+ }
+ }
+
+ /**
+ * The actual JTextArea.
+ */
+ private JTextArea jTextArea;
+
+ public SwingTextAreaPeer(TextArea textArea)
+ {
+ super();
+ System.err.println("new SwingTextAreaPeer");
+ jTextArea = new JTextArea();
+ SwingTextArea swingArea = new SwingTextArea(jTextArea);
+ init(textArea, swingArea);
+
+ // Pull over the text from the text area.
+ setText(textArea.getText());
+ }
+
+ public Dimension getMinimumSize(int rows, int cols)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Dimension getPreferredSize(int rows, int cols)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void insert(String text, int pos)
+ {
+ jTextArea.insert(text, pos);
+ }
+
+ public void insertText(String text, int pos)
+ {
+ jTextArea.insert(text, pos);
+ }
+
+ public Dimension minimumSize(int rows, int cols)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Dimension preferredSize(int rows, int cols)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void replaceRange(String text, int start, int end)
+ {
+ jTextArea.replaceRange(text, start, end);
+ }
+
+ public void replaceText(String text, int start, int end)
+ {
+ jTextArea.replaceRange(text, start, end);
+ }
+
+ public long filterEvents(long filter)
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getCaretPosition()
+ {
+ return jTextArea.getCaretPosition();
+ }
+
+ public Rectangle getCharacterBounds(int pos)
+ {
+ Rectangle r;
+ try
+ {
+ return jTextArea.modelToView(pos);
+ }
+ catch (BadLocationException ex)
+ {
+ r = null;
+ }
+ return r;
+ }
+
+ public int getIndexAtPoint(int x, int y)
+ {
+ return jTextArea.viewToModel(new Point(x, y));
+ }
+
+ public InputMethodRequests getInputMethodRequests()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getSelectionEnd()
+ {
+ return jTextArea.getSelectionEnd();
+ }
+
+ public int getSelectionStart()
+ {
+ return jTextArea.getSelectionStart();
+ }
+
+ public String getText()
+ {
+ return jTextArea.getText();
+ }
+
+ public void select(int start, int end)
+ {
+ jTextArea.select(start, end);
+ }
+
+ public void setCaretPosition(int pos)
+ {
+ jTextArea.setCaretPosition(pos);
+ }
+
+ public void setEditable(boolean editable)
+ {
+ jTextArea.setEditable(editable);
+ }
+
+ public void setText(String text)
+ {
+ System.err.println("setText: " + text);
+ jTextArea.setText(text);
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java
index 0c3b4e72603..d7d574a0bb9 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java
@@ -36,7 +36,10 @@ obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.peer.swing;
+import java.awt.Component;
+import java.awt.Container;
import java.awt.Dimension;
+import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
@@ -69,6 +72,13 @@ public class SwingTextFieldPeer
implements SwingComponent
{
+ TextField textField;
+
+ SwingTextField(TextField textField)
+ {
+ this.textField = textField;
+ }
+
/**
* Overridden to provide normal behaviour even without a real peer
* attached.
@@ -90,8 +100,8 @@ public class SwingTextFieldPeer
public boolean isShowing()
{
boolean retVal = false;
- if (SwingTextFieldPeer.this.awtComponent != null)
- retVal = SwingTextFieldPeer.this.awtComponent.isShowing();
+ if (textField != null)
+ retVal = textField.isShowing();
return retVal;
}
@@ -151,7 +161,19 @@ public class SwingTextFieldPeer
ev.setSource(this);
processKeyEvent(ev);
}
-
+
+ public Container getParent()
+ {
+ Container par = null;
+ if (textField != null)
+ par = textField.getParent();
+ return par;
+ }
+
+ public Graphics getGraphics()
+ {
+ return SwingTextFieldPeer.this.getGraphics();
+ }
}
/**
@@ -162,7 +184,7 @@ public class SwingTextFieldPeer
*/
public SwingTextFieldPeer(TextField textField)
{
- SwingTextField swingTextField = new SwingTextField();
+ SwingTextField swingTextField = new SwingTextField(textField);
swingTextField.setText(textField.getText());
init(textField, swingTextField);
}
@@ -283,7 +305,7 @@ public class SwingTextFieldPeer
* @param startPos the start index of the selection
* @param endPos the start index of the selection
*/
- public void select(int startPos, int endPos)
+ public void select(int start_pos, int endPos)
{
// TODO: Must be implemented.
}
diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java
index 43a509b957d..531552d902c 100644
--- a/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.awt.peer.swing;
import java.awt.Window;
+import java.awt.peer.ComponentPeer;
import java.awt.peer.WindowPeer;
/**
@@ -48,9 +49,9 @@ import java.awt.peer.WindowPeer;
* As a minimum, a subclass must implement all the remaining abstract methods
* as well as the following methods:
* <ul>
- * <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li>
- * <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li>
- * <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li>
+ * <li>{@link ComponentPeer#getLocationOnScreen()}</li>
+ * <li>{@link ComponentPeer#getGraphics()}</li>
+ * <li>{@link ComponentPeer#createImage(int, int)}</li>
* </ul>
*
* @author Roman Kennke (kennke@aicas.com)
@@ -68,5 +69,6 @@ public abstract class SwingWindowPeer
public SwingWindowPeer(Window window)
{
super(window);
+ init(window, null);
}
}
diff --git a/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java
index fd293d8dd43..8183fed0cd2 100644
--- a/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java
+++ b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java
@@ -608,13 +608,6 @@ public class XFontPeer
throw new UnsupportedOperationException("Not yet implemented.");
}
- public Rectangle2D getStringBounds(Font font, CharacterIterator ci,
- int begin, int limit, FontRenderContext frc)
- {
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
- }
-
/**
* Encodes a font name + style + size specification into a X logical font
* description (XLFD) as described here:
diff --git a/libjava/classpath/gnu/java/awt/peer/x/XFontPeer2.java b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer2.java
index 25371de1a41..ef9507f3050 100644
--- a/libjava/classpath/gnu/java/awt/peer/x/XFontPeer2.java
+++ b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer2.java
@@ -326,10 +326,4 @@ public class XFontPeer2
throw new UnsupportedOperationException("Not yet implemented");
}
- public Rectangle2D getStringBounds(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext frc)
- {
- // FIXME: Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
}
diff --git a/libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java b/libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java
new file mode 100644
index 00000000000..08f089d7921
--- /dev/null
+++ b/libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java
@@ -0,0 +1,292 @@
+/* ObjectIdentityMapToInt.java -- Helper class for faster serialization
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.io;
+
+/**
+ * This class provides a map from Object to non-negative int values.
+ * Objects are considered equal only if their references are equal.
+ *
+ * This can be used to equip objects with an integer id. This class
+ * is implemented to use as little memory as possible, particularly
+ * not to create hashtable buckets and Integer instances for each
+ * mapping.
+ *
+ * @author Fridtjof Siebert (siebert@aicas.com)
+ */
+public class ObjectIdentityMap2Int
+{
+
+
+ /**
+ * Prime numbers used as size of array. We need the size to be a
+ * prime number since the delta used for conflict resulution must
+ * not have any common divisors with the length.
+ */
+ private static final int[] PRIMES = {
+ 0x1f,
+ 0x3d,
+ 0x7f,
+ 0xfb,
+ 0x1fd,
+ 0x3fd,
+ 0x7f7,
+ 0xffd,
+ 0x1fff,
+ 0x3ffd,
+ 0x7fed,
+ 0xfff1,
+ 0x1ffff,
+ 0x3fffb,
+ 0x7ffff,
+ 0xffffd,
+ 0x1ffff7,
+ 0x3ffffd,
+ 0x7ffff1,
+ 0xfffffd,
+ 0x1ffffd9,
+ 0x3fffffb,
+ 0x7ffffd9,
+ 0xfffffc7,
+ 0x1ffffffd,
+ 0x3fffffdd,
+ 0x7fffffff};
+
+
+ /**
+ * Object to be used instead of "null"
+ */
+ private static final Object NIL = new Object();
+
+
+ /**
+ * The objects in this map:
+ *
+ * invariant
+ * objectTable.size == PRIMES[cap]
+ */
+ private Object[] objectTable;
+
+
+ /**
+ * The corresponding integer ids.
+ *
+ * invariant
+ * intTable.size == PRIMES[cap]
+ */
+ private int[] intTable;
+
+
+ /**
+ * The number of entries in this map.
+ *
+ * invariant
+ * size < limit
+ */
+ private int size = 0;
+
+
+ /**
+ * The index in primes of the size of the tables.
+ */
+ private int cap = 0;
+
+
+ /**
+ * The limit for size at which the table size is increased.
+ *
+ * invariant
+ * limit = PRIMES[cap] / 4 * 3;
+ */
+ private int limit = 0;
+
+
+ /**
+ * Constructs an empty <code>ObjectIdentityMap2Int</code>.
+ */
+ public ObjectIdentityMap2Int()
+ {
+ alloc(0);
+ }
+
+
+ /**
+ * Helper function to alloc the object and int array for the given
+ * capacity. Set limit, reset size to 0.
+ *
+ * No elements will be stored in the newly allocated arrays.
+ *
+ * @param c the capacity: this is an index in PRIMES, PRIMES[c]
+ * gives the size of the arrays.
+ *
+ * @throws InternalError if c >= PRIMES.length (in this case, a
+ * normal Hashtable would throw an OutOfMemoryError or a
+ * NegativeArraySizeException since the array size exceeds the range
+ * of positive integers).
+ */
+ private void alloc(int c)
+ {
+ if (c >= PRIMES.length)
+ throw new InternalError("Hash table size overflow");
+
+ cap = c;
+ int len = PRIMES[c];
+ objectTable = new Object[len];
+ intTable = new int[len];
+ limit = len / 4 * 3;
+
+ size = 0;
+ }
+
+
+ /**
+ * Add a mapping to this Map.
+ *
+ * ensures
+ * (get(o) == i);
+ *
+ * @param o object reference or null that is to be mapped.
+ *
+ * @param i the integer id to be associated with o
+ *
+ * @throws IllegalArgumentException if i<0
+ *
+ * @throws InternalError if hash tables has grown to more then
+ * 0x7fffffff entries (ie., size >= 0x7fffffff*3/4).
+ */
+ public void put(Object o, int i)
+ {
+ if (i < 0)
+ throw new IllegalArgumentException("int argument must be postive: "+i);
+
+ o = (o == null) ? NIL : o;
+ int s = slot(o);
+ Object[] ot = objectTable;
+ intTable[s] = i;
+ if (objectTable[s] == null)
+ {
+ objectTable[s] = o;
+ size++;
+ if (size >= limit)
+ {
+ rehash();
+ }
+ }
+ }
+
+
+ /**
+ * Helper function to find the index of a free or existing slot for
+ * object o
+ *
+ * ensure
+ * ((objectTable[result] != null) IMPLIES (objectTable[result] == o));
+ *
+ * @param o an object, must not be null.
+ *
+ * @return an index of o
+ */
+ private int slot(Object o)
+ {
+ Object[] ot = objectTable;
+ int hc = System.identityHashCode(o);
+ int len = ot.length;
+ int result = hc % len;
+ result = result < 0 ? -result : result;
+ int delta = 16 - (hc & 15);
+ Object existing = ot[result];
+ while ((existing != null) && (existing != o))
+ {
+ result += delta;
+ if (result >= len)
+ result -= len;
+ existing = ot[result];
+ }
+ return result;
+ }
+
+
+ /**
+ * Helper function for put() to increaes the capacity of this table
+ * to the next size (approx. double the size). Keep the mapping and
+ * the size unchanged.
+ *
+ * ensure
+ * (cap == \old cap+1);
+ */
+ private void rehash()
+ {
+ Object[] ot = objectTable;
+ int [] it = intTable;
+ alloc(cap + 1);
+
+ for (int i = 0; i < ot.length; i++)
+ put(ot[i], it[i]);
+ }
+
+
+ /**
+ * Obtain an element from this map
+ *
+ * @param o an object or null
+ *
+ * @return the corresponding integer id for o or -1 if o has not
+ * been put into this map.
+ */
+ public int get(Object o)
+ {
+ o = (o == null) ? NIL : o;
+ int s = slot(o);
+ return objectTable[s] == null ? -1 : intTable[s];
+ }
+
+ /**
+ * Clear this map
+ *
+ * ensures
+ * ((size == 0) && \forall Object o: get(o) == -1)
+ */
+ public void clear()
+ {
+ Object[] ot = objectTable;
+ size = 0;
+ for (int i = 0; i < ot.length; i++)
+ ot[i] = null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/io/class-dependencies.conf b/libjava/classpath/gnu/java/io/class-dependencies.conf
new file mode 100644
index 00000000000..2500f6b14b5
--- /dev/null
+++ b/libjava/classpath/gnu/java/io/class-dependencies.conf
@@ -0,0 +1,75 @@
+# This property file contains dependencies of classes, methods, and
+# field on other methods or classes.
+#
+# Syntax:
+#
+# <used>: <needed 1> [... <needed N>]
+#
+# means that when <used> is included, <needed 1> (... <needed N>) must
+# be included as well.
+#
+# <needed X> and <used> are of the form
+#
+# <class.methodOrField(signature)>
+#
+# or just
+#
+# <class>
+#
+# Within dependencies, variables can be used. A variable is defined as
+# follows:
+#
+# {variable}: value1 value2 ... value<n>
+#
+# variables can be used on the right side of dependencies as follows:
+#
+# <used>: com.bla.blu.{variable}.Class.m()V
+#
+# The use of the variable will expand to <n> dependencies of the form
+#
+# <used>: com.bla.blu.value1.Class.m()V
+# <used>: com.bla.blu.value2.Class.m()V
+# ...
+# <used>: com.bla.blu.value<n>.Class.m()V
+#
+# Variables can be redefined when building a system to select the
+# required support for features like encodings, protocols, etc.
+#
+# Hints:
+#
+# - For methods and fields, the signature is mandatory. For
+# specification, please see the Java Virtual Machine Specification by
+# SUN. Unlike in the spec, field signatures (types) are in brackets.
+#
+# - Package names must be separated by '/' (and not '.'). E.g.,
+# java/lang/Class (this is necessary, because the '.' is used to
+# separate method or field names from classes)
+#
+# - In case <needed> refers to a class, only the class itself will be
+# included in the resulting binary, NOT necessarily all its methods
+# and fields. If you want to refer to all methods and fields, you can
+# write class.* as an abbreviation.
+#
+# - Abbreviations for packages are also possible: my/package/* means all
+# methods and fields of all classes in my/package.
+#
+# - A line with a trailing '\' continues in the next line.
+
+
+# All encodings supported are loaded via gnu/java/io/EncodingManager.findEncoderConstructor
+# or gnu/java/io/EncodingManager.findDecoderConstructor from class
+# gnu/java/io/decode/Decoder<encoding>.
+#
+# This introduces a dependency for all encodings. To allow an easy selection
+# and addition of encodings, the library variable {encodings} can be set to
+# the set of supported encodings.
+#
+{encodings}: 8859_1 8859_2 8859_3 8859_4 8859_5 UTF8
+
+gnu/java/io/EncodingManager.findEncoderConstructor(Ljava/lang/String;Z)Ljava/lang/reflect/Constructor;: \
+ gnu/java/io/decode/Decoder{encodings}.*
+
+gnu/java/io/EncodingManager.findDecoderConstructor(Ljava/lang/String;Z)Ljava/lang/reflect/Constructor;: \
+ gnu/java/io/encode/Encoder{encodings}.* \
+
+# end of file
diff --git a/libjava/classpath/gnu/java/lang/InstrumentationImpl.java b/libjava/classpath/gnu/java/lang/InstrumentationImpl.java
index 7bfed458245..2425b35c8a9 100644
--- a/libjava/classpath/gnu/java/lang/InstrumentationImpl.java
+++ b/libjava/classpath/gnu/java/lang/InstrumentationImpl.java
@@ -1,6 +1,6 @@
/* InstrumentationImpl.java -- GNU implementation of
java.lang.instrument.Instrumentation
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -63,11 +63,11 @@ public final class InstrumentationImpl implements Instrumentation
{
/* List of transformers */
- /* FIXME[GENERICS]: Should be ClassFileTransformer list */
- private ArrayList transformers = new ArrayList();
+ private ArrayList<ClassFileTransformer> transformers =
+ new ArrayList<ClassFileTransformer>();
- private InstrumentationImpl()
+ InstrumentationImpl()
{
}
@@ -210,9 +210,8 @@ public final class InstrumentationImpl implements Instrumentation
*
* @return the new class file
*/
- /* FIXME[GENERICS]: Should be Class<?> */
public byte[] callTransformers(ClassLoader loader, String className,
- Class classBeingRedefined, ProtectionDomain protectionDomain,
+ Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer)
{
byte[] newBuffer = null;
@@ -220,11 +219,10 @@ public final class InstrumentationImpl implements Instrumentation
ClassFileTransformer current;
synchronized (transformers)
{
- Iterator i = transformers.iterator();
+ Iterator<ClassFileTransformer> i = transformers.iterator();
while (i.hasNext())
{
- /* FIXME[GENERICS]: Remove cast */
- current = (ClassFileTransformer) i.next();
+ current = i.next();
try
{
newBuffer = current.transform(loader, className,
diff --git a/libjava/classpath/gnu/java/lang/management/BeanImpl.java b/libjava/classpath/gnu/java/lang/management/BeanImpl.java
index 24572a25d5d..e5b47181273 100644
--- a/libjava/classpath/gnu/java/lang/management/BeanImpl.java
+++ b/libjava/classpath/gnu/java/lang/management/BeanImpl.java
@@ -39,9 +39,50 @@ package gnu.java.lang.management;
import java.lang.management.ManagementPermission;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.TypeVariable;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanInfo;
import javax.management.NotCompliantMBeanException;
+import javax.management.ReflectionException;
import javax.management.StandardMBean;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenMBeanConstructorInfo;
+import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
+import javax.management.openmbean.OpenMBeanInfo;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanOperationInfoSupport;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenMBeanParameterInfoSupport;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
/**
* A common superclass for bean implementations.
*
@@ -51,7 +92,12 @@ import javax.management.StandardMBean;
public class BeanImpl
extends StandardMBean
{
-
+
+ /**
+ * Cached open bean information.
+ */
+ private OpenMBeanInfo openInfo;
+
/**
* Constructs a new <code>BeanImpl</code>.
*
@@ -67,6 +113,71 @@ public class BeanImpl
super(iface);
}
+ protected void cacheMBeanInfo(MBeanInfo info)
+ {
+ if (info == null)
+ return;
+ try
+ {
+ MBeanAttributeInfo[] oldA = info.getAttributes();
+ OpenMBeanAttributeInfo[] attribs =
+ new OpenMBeanAttributeInfoSupport[oldA.length];
+ for (int a = 0; a < oldA.length; ++a)
+ {
+ OpenMBeanParameterInfo param = translate(oldA[a].getType());
+ if (param.getMinValue() == null)
+ {
+ Object[] lv;
+ if (param.getLegalValues() == null)
+ lv = null;
+ else
+ lv = param.getLegalValues().toArray();
+ attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(),
+ oldA[a].getDescription(),
+ param.getOpenType(),
+ oldA[a].isReadable(),
+ oldA[a].isWritable(),
+ oldA[a].isIs(),
+ param.getDefaultValue(),
+ lv);
+ }
+ else
+ attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(),
+ oldA[a].getDescription(),
+ param.getOpenType(),
+ oldA[a].isReadable(),
+ oldA[a].isWritable(),
+ oldA[a].isIs(),
+ param.getDefaultValue(),
+ param.getMinValue(),
+ param.getMaxValue());
+ }
+ MBeanConstructorInfo[] oldC = info.getConstructors();
+ OpenMBeanConstructorInfo[] cons = new OpenMBeanConstructorInfoSupport[oldC.length];
+ for (int a = 0; a < oldC.length; ++a)
+ cons[a] =
+ new OpenMBeanConstructorInfoSupport(oldC[a].getName(),
+ oldC[a].getDescription(),
+ translateSignature(oldC[a].getSignature()));
+ MBeanOperationInfo[] oldO = info.getOperations();
+ OpenMBeanOperationInfo[] ops = new OpenMBeanOperationInfoSupport[oldO.length];
+ for (int a = 0; a < oldO.length; ++a)
+ ops[a] =
+ new OpenMBeanOperationInfoSupport(oldO[a].getName(),
+ oldO[a].getDescription(),
+ translateSignature(oldO[a].getSignature()),
+ translate(oldO[a].getReturnType()).getOpenType(),
+ oldO[a].getImpact());
+ openInfo = new OpenMBeanInfoSupport(info.getClassName(), info.getDescription(),
+ attribs, cons, ops, info.getNotifications());
+ }
+ catch (OpenDataException e)
+ {
+ throw (InternalError) (new InternalError("A problem occurred creating the open type " +
+ "descriptors.").initCause(e));
+ }
+ }
+
protected void checkMonitorPermissions()
{
SecurityManager sm = System.getSecurityManager();
@@ -81,4 +192,328 @@ public class BeanImpl
sm.checkPermission(new ManagementPermission("control"));
}
+ public Object getAttribute(String attribute)
+ throws AttributeNotFoundException, MBeanException,
+ ReflectionException
+ {
+ Object value = super.getAttribute(attribute);
+ if (value instanceof Enum)
+ return ((Enum) value).name();
+ Class vClass = value.getClass();
+ if (vClass.isArray())
+ return value;
+ String cName = vClass.getName();
+ String[] allowedTypes = OpenType.ALLOWED_CLASSNAMES;
+ for (int a = 0; a < allowedTypes.length; ++a)
+ if (cName.equals(allowedTypes[a]))
+ return value;
+ if (value instanceof List)
+ {
+ List l = (List) value;
+ Class e = null;
+ TypeVariable[] vars = vClass.getTypeParameters();
+ for (int a = 0; a < vars.length; ++a)
+ if (vars[a].getName().equals("E"))
+ e = (Class) vars[a].getGenericDeclaration();
+ if (e == null)
+ e = Object.class;
+ Object[] array = (Object[]) Array.newInstance(e, l.size());
+ return l.toArray(array);
+ }
+ OpenMBeanInfo info = (OpenMBeanInfo) getMBeanInfo();
+ OpenMBeanAttributeInfo[] attribs =
+ (OpenMBeanAttributeInfo[]) info.getAttributes();
+ OpenType type = null;
+ for (int a = 0; a < attribs.length; ++a)
+ if (attribs[a].getName().equals("attribute"))
+ type = attribs[a].getOpenType();
+ if (value instanceof Map)
+ {
+ TabularType ttype = (TabularType) type;
+ TabularData data = new TabularDataSupport(ttype);
+ Iterator it = ((Map) value).entrySet().iterator();
+ while (it.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ try
+ {
+ data.put(new CompositeDataSupport(ttype.getRowType(),
+ new String[] {
+ "key",
+ "value"
+ },
+ new Object[] {
+ entry.getKey(),
+ entry.getValue()
+ }));
+ }
+ catch (OpenDataException e)
+ {
+ throw (InternalError) (new InternalError("A problem occurred " +
+ "converting the map " +
+ "to a composite data " +
+ "structure.").initCause(e));
+ }
+ }
+ return data;
+ }
+ CompositeType cType = (CompositeType) type;
+ Set names = cType.keySet();
+ Iterator it = names.iterator();
+ List values = new ArrayList(names.size());
+ while (it.hasNext())
+ {
+ String field = (String) it.next();
+ Method getter = null;
+ try
+ {
+ getter = vClass.getMethod("get" + field, null);
+ }
+ catch (NoSuchMethodException e)
+ {
+ /* Ignored; the type tells us it's there. */
+ }
+ try
+ {
+ values.add(getter.invoke(value, null));
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ReflectionException(e, "Failed to retrieve " + field);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ReflectionException(e, "Failed to retrieve " + field);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new MBeanException((Exception) e.getCause(),
+ "The getter of " + field +
+ " threw an exception");
+ }
+ }
+ try
+ {
+ return new CompositeDataSupport(cType,
+ (String[])
+ names.toArray(new String[names.size()]),
+ values.toArray());
+ }
+ catch (OpenDataException e)
+ {
+ throw (InternalError) (new InternalError("A problem occurred " +
+ "converting the value " +
+ "to a composite data " +
+ "structure.").initCause(e));
+ }
+ }
+
+ protected MBeanInfo getCachedMBeanInfo()
+ {
+ return (MBeanInfo) openInfo;
+ }
+
+ public MBeanInfo getMBeanInfo()
+ {
+ super.getMBeanInfo();
+ return getCachedMBeanInfo();
+ }
+
+ private OpenType getTypeFromClass(Class c)
+ throws OpenDataException
+ {
+ return translate(c.getName()).getOpenType();
+ }
+
+ private OpenMBeanParameterInfo[] translateSignature(MBeanParameterInfo[] oldS)
+ throws OpenDataException
+ {
+ OpenMBeanParameterInfo[] sig = new OpenMBeanParameterInfoSupport[oldS.length];
+ for (int a = 0; a < oldS.length; ++a)
+ {
+ OpenMBeanParameterInfo param = translate(oldS[a].getType());
+ if (param.getMinValue() == null)
+ {
+ Object[] lv;
+ if (param.getLegalValues() == null)
+ lv = null;
+ else
+ lv = param.getLegalValues().toArray();
+ sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(),
+ oldS[a].getDescription(),
+ param.getOpenType(),
+ param.getDefaultValue(),
+ lv);
+ }
+ else
+ sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(),
+ oldS[a].getDescription(),
+ param.getOpenType(),
+ param.getDefaultValue(),
+ param.getMinValue(),
+ param.getMaxValue());
+ }
+ return sig;
+ }
+
+ private OpenMBeanParameterInfo translate(String type)
+ throws OpenDataException
+ {
+ if (type.equals("boolean") || type.equals(Boolean.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.BOOLEAN,
+ null,
+ new Object[] {
+ Boolean.TRUE,
+ Boolean.FALSE
+ });
+ if (type.equals("byte") || type.equals(Byte.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.BYTE,
+ null,
+ Byte.valueOf(Byte.MIN_VALUE),
+ Byte.valueOf(Byte.MAX_VALUE));
+ if (type.equals("char") || type.equals(Character.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.CHARACTER,
+ null,
+ Character.valueOf(Character.MIN_VALUE),
+ Character.valueOf(Character.MAX_VALUE));
+ if (type.equals("double") || type.equals(Double.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.DOUBLE,
+ null,
+ Double.valueOf(Double.MIN_VALUE),
+ Double.valueOf(Double.MAX_VALUE));
+ if (type.equals("float") || type.equals(Float.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.FLOAT,
+ null,
+ Float.valueOf(Float.MIN_VALUE),
+ Float.valueOf(Float.MAX_VALUE));
+ if (type.equals("int") || type.equals(Integer.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.INTEGER,
+ null,
+ Integer.valueOf(Integer.MIN_VALUE),
+ Integer.valueOf(Integer.MAX_VALUE));
+ if (type.equals("long") || type.equals(Long.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.LONG,
+ null,
+ Long.valueOf(Long.MIN_VALUE),
+ Long.valueOf(Long.MAX_VALUE));
+ if (type.equals("short") || type.equals(Short.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.SHORT,
+ null,
+ Short.valueOf(Short.MIN_VALUE),
+ Short.valueOf(Short.MAX_VALUE));
+ if (type.equals(String.class.getName()))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.STRING);
+ if (type.equals("void"))
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.VOID);
+ if (type.startsWith("java.util.Map"))
+ {
+ int lparam = type.indexOf("<");
+ int comma = type.indexOf(",", lparam);
+ int rparam = type.indexOf(">", comma);
+ String key = type.substring(lparam + 1, comma).trim();
+ OpenType k = translate(key).getOpenType();
+ OpenType v = translate(type.substring(comma + 1, rparam).trim()).getOpenType();
+ CompositeType ctype = new CompositeType(Map.class.getName(), Map.class.getName(),
+ new String[] { "key", "value" },
+ new String[] { "Map key", "Map value"},
+ new OpenType[] { k, v});
+ TabularType ttype = new TabularType(key, key, ctype,
+ new String[] { "key" });
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ ttype);
+ }
+ if (type.startsWith("java.util.List"))
+ {
+ int lparam = type.indexOf("<");
+ int rparam = type.indexOf(">");
+ OpenType e = translate(type.substring(lparam + 1, rparam).trim()).getOpenType();
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ new ArrayType(1, e)
+ );
+ }
+ Class c;
+ try
+ {
+ c = Class.forName(type);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw (InternalError)
+ (new InternalError("The class for a type used in a management bean " +
+ "could not be loaded.").initCause(e));
+ }
+ if (c.isEnum())
+ {
+ Object[] values = c.getEnumConstants();
+ String[] names = new String[values.length];
+ for (int a = 0; a < values.length; ++a)
+ names[a] = values[a].toString();
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ SimpleType.STRING,
+ null,
+ (Object[]) names);
+ }
+ try
+ {
+ c.getMethod("from", new Class[] { CompositeData.class });
+ Method[] methods = c.getMethods();
+ List names = new ArrayList();
+ List types = new ArrayList();
+ for (int a = 0; a < methods.length; ++a)
+ {
+ String name = methods[a].getName();
+ if (name.startsWith("get"))
+ {
+ names.add(name.substring(3));
+ types.add(getTypeFromClass(methods[a].getReturnType()));
+ }
+ }
+ String[] fields = (String[]) names.toArray();
+ CompositeType ctype = new CompositeType(c.getName(), c.getName(),
+ fields, fields,
+ (OpenType[]) types.toArray());
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ ctype);
+ }
+ catch (NoSuchMethodException e)
+ {
+ /* Ignored; we expect this if this isn't a from(CompositeData) class */
+ }
+ if (c.isArray())
+ {
+ int depth;
+ for (depth = 0; c.getName().charAt(depth) == '['; ++depth);
+ OpenType ot = getTypeFromClass(c.getComponentType());
+ return new OpenMBeanParameterInfoSupport("TransParam",
+ "Translated parameter",
+ new ArrayType(depth, ot)
+ );
+ }
+ throw new InternalError("The type used does not have an open type translation.");
+ }
+
}
diff --git a/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java
index 064e19a1970..8cb10420213 100644
--- a/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java
+++ b/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package gnu.java.lang.management;
+import gnu.classpath.ListenerData;
+
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryUsage;
@@ -168,49 +170,6 @@ public final class MemoryMXBeanImpl
VMMemoryMXBeanImpl.setVerbose(verbose);
}
- private class ListenerData
- {
- private NotificationListener listener;
- private NotificationFilter filter;
- private Object passback;
-
- public ListenerData(NotificationListener listener,
- NotificationFilter filter, Object passback)
- {
- this.listener = listener;
- this.filter = filter;
- this.passback = passback;
- }
-
- public NotificationListener getListener()
- {
- return listener;
- }
-
- public NotificationFilter getFilter()
- {
- return filter;
- }
-
- public Object getPassback()
- {
- return passback;
- }
-
- public boolean equals(Object obj)
- {
- if (obj instanceof ListenerData)
- {
- ListenerData data = (ListenerData) obj;
- return (data.getListener() == listener &&
- data.getFilter() == filter &&
- data.getPassback() == passback);
- }
- return false;
- }
-
- }
-
public void addNotificationListener(NotificationListener listener,
NotificationFilter filter,
Object passback)
diff --git a/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java
index ed4dccd769e..e314ca1648a 100644
--- a/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java
+++ b/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java
@@ -40,6 +40,7 @@ package gnu.java.lang.management;
import gnu.classpath.SystemProperties;
import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryType;
import java.lang.management.MemoryUsage;
import javax.management.NotCompliantMBeanException;
@@ -133,9 +134,10 @@ public final class MemoryPoolMXBeanImpl
return null;
}
- public String getType()
+ public MemoryType getType()
{
- return VMMemoryPoolMXBeanImpl.getType(name);
+ return
+ MemoryType.valueOf(VMMemoryPoolMXBeanImpl.getType(name));
}
public MemoryUsage getUsage()
diff --git a/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java
index 0c9b962921e..31f28385f44 100644
--- a/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java
+++ b/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java
@@ -61,7 +61,7 @@ public class ClassSignatureParser extends GenericSignatureParser
}
// SuperclassSignature
superclassType = readClassTypeSignature();
- ArrayList interfaces = new ArrayList();
+ ArrayList<Type> interfaces = new ArrayList<Type>();
while (peekChar() == 'L')
{
// SuperinterfaceSignature
diff --git a/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java
index 399f1bdc46f..06bc9e4ab06 100644
--- a/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java
+++ b/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java
@@ -60,7 +60,6 @@ final class TypeVariableImpl extends TypeImpl implements TypeVariable
return this;
}
- /* FIXME[GENERICS]: Remove cast */
public Type[] getBounds()
{
resolve(bounds);
@@ -141,10 +140,9 @@ final class ParameterizedTypeImpl extends TypeImpl implements ParameterizedType
return this;
}
- /* FIXME[GENERICS]: Remove cast */
public Type[] getActualTypeArguments()
{
- return (Type[]) typeArgs.clone();
+ return (Type[]) typeArgs.clone();
}
public Type getRawType()
@@ -276,12 +274,11 @@ final class UnresolvedTypeVariable extends TypeImpl implements Type
GenericDeclaration d = decl;
while (d != null)
{
- TypeVariable[] vars = d.getTypeParameters();
- for (int a = 0; a < vars.length ; ++a)
+ for (TypeVariable t : d.getTypeParameters())
{
- if (vars[a].getName().equals(name))
+ if (t.getName().equals(name))
{
- return vars[a];
+ return t;
}
}
d = getParent(d);
@@ -414,7 +411,7 @@ class GenericSignatureParser
TypeVariable[] readFormalTypeParameters()
{
consume('<');
- ArrayList params = new ArrayList();
+ ArrayList<TypeVariable> params = new ArrayList<TypeVariable>();
do
{
// TODO should we handle name clashes?
@@ -430,7 +427,7 @@ class GenericSignatureParser
{
String identifier = readIdentifier();
consume(':');
- ArrayList bounds = new ArrayList();
+ ArrayList<Type> bounds = new ArrayList<Type>();
if (peekChar() != ':')
{
bounds.add(readFieldTypeSignature());
@@ -501,7 +498,7 @@ class GenericSignatureParser
private Type[] readTypeArguments()
{
consume('<');
- ArrayList list = new ArrayList();
+ ArrayList<Type> list = new ArrayList<Type>();
do
{
list.add(readTypeArgument());
diff --git a/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java
index 16b1af99b73..50f98e29965 100644
--- a/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java
+++ b/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java
@@ -72,7 +72,7 @@ public class MethodSignatureParser extends GenericSignatureParser
typeParameters = new TypeVariable[0];
}
consume('(');
- ArrayList args = new ArrayList();
+ ArrayList<Type> args = new ArrayList<Type>();
while (peekChar() != ')')
{
args.add(readTypeSignature());
@@ -81,7 +81,7 @@ public class MethodSignatureParser extends GenericSignatureParser
args.toArray(argTypes);
consume(')');
retType = readTypeSignature();
- ArrayList throwsSigs = new ArrayList();
+ ArrayList<Type> throwsSigs = new ArrayList<Type>();
while (peekChar() == '^')
{
consume('^');
diff --git a/libjava/classpath/gnu/java/locale/.cvsignore b/libjava/classpath/gnu/java/locale/.cvsignore
new file mode 100644
index 00000000000..d41ae8d8147
--- /dev/null
+++ b/libjava/classpath/gnu/java/locale/.cvsignore
@@ -0,0 +1 @@
+LocaleData.java
diff --git a/libjava/classpath/gnu/java/net/DefaultProxySelector.java b/libjava/classpath/gnu/java/net/DefaultProxySelector.java
new file mode 100644
index 00000000000..31f861e8710
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/DefaultProxySelector.java
@@ -0,0 +1,80 @@
+/* DefaultProxySelector.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class DefaultProxySelector
+ extends ProxySelector
+{
+ private static final List<Proxy> proxies = new ArrayList<Proxy>();
+
+ static
+ {
+ // The default proxy selector supports only direct connections.
+ proxies.add(Proxy.NO_PROXY);
+ }
+
+ public DefaultProxySelector()
+ {
+ // Do nothing by default.
+ }
+
+ public void connectFailed(URI uri, SocketAddress sa, IOException ioe)
+ {
+ if (uri == null || sa == null || ioe == null)
+ throw new IllegalArgumentException();
+
+ // Do nothing by default.
+ }
+
+ public List<Proxy> select(URI uri)
+ {
+ if (uri == null)
+ throw new IllegalArgumentException();
+
+ return proxies;
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java b/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java
index 0fcd780dfb9..a84525e18b8 100644
--- a/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java
+++ b/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java
@@ -1,5 +1,5 @@
/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
- Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,13 +38,19 @@ exception statement from your version. */
package gnu.java.net;
+import gnu.java.nio.VMChannel;
+
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocketImpl;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -62,11 +68,12 @@ import java.net.SocketException;
*/
public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
-
+ private final VMChannel channel;
+
/**
- * This is the actual underlying file descriptor
+ * The platform-specific socket implementation.
*/
- int native_fd = -1;
+ private final VMPlainSocketImpl impl;
/**
* Lock object to serialize threads wanting to receive
@@ -81,25 +88,26 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
/**
* Default do nothing constructor
*/
- public PlainDatagramSocketImpl()
+ public PlainDatagramSocketImpl() throws IOException
{
- // Nothing to do here.
+ channel = new VMChannel();
+ impl = new VMPlainSocketImpl(channel);
}
- protected void finalize() throws Throwable
+ /*protected void finalize() throws Throwable
{
synchronized (this)
{
- if (native_fd != -1)
+ if (channel.getState().isValid())
close();
}
super.finalize();
- }
+ }*/
- public int getNativeFD()
+ /*public int getNativeFD()
{
return native_fd;
- }
+ }*/
/**
* Binds this socket to a particular port and interface
@@ -109,20 +117,46 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception SocketException If an error occurs
*/
- protected synchronized void bind(int port, InetAddress addr)
+ protected synchronized void bind(int port, InetAddress addr)
throws SocketException
- {
- VMPlainDatagramSocketImpl.bind(this, port, addr);
- }
+ {
+ try
+ {
+ impl.bind(new InetSocketAddress(addr, port));
+ }
+ catch (SocketException se)
+ {
+ throw se;
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
/**
* Creates a new datagram socket
*
* @exception SocketException If an error occurs
*/
- protected synchronized void create() throws SocketException
+ protected synchronized void create() throws SocketException
{
- VMPlainDatagramSocketImpl.create(this);
+ try
+ {
+ channel.initSocket(false);
+ }
+ catch (SocketException se)
+ {
+ throw se;
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
}
/**
@@ -135,7 +169,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected void connect(InetAddress addr, int port) throws SocketException
{
- VMPlainDatagramSocketImpl.connect(this, addr, port);
+ channel.connect(new InetSocketAddress(addr, port), 0);
}
/**
@@ -147,8 +181,14 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
synchronized (this)
{
- if (native_fd != -1)
- close();
+ try
+ {
+ if (channel.getState().isValid())
+ channel.disconnect();
+ }
+ catch (IOException ioe)
+ {
+ }
}
}
@@ -161,7 +201,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void setTimeToLive(int ttl) throws IOException
{
- setOption(VMPlainDatagramSocketImpl.IP_TTL, new Integer(ttl));
+ impl.setTimeToLive(ttl);
}
/**
@@ -173,15 +213,27 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized int getTimeToLive() throws IOException
{
- Object obj = getOption(VMPlainDatagramSocketImpl.IP_TTL);
+ return impl.getTimeToLive();
+ }
- if (! (obj instanceof Integer))
- throw new IOException("Internal Error");
+ protected int getLocalPort()
+ {
+ if (channel == null)
+ return -1;
- return ((Integer) obj).intValue();
+ try
+ {
+ InetSocketAddress local = channel.getLocalAddress();
+ if (local == null)
+ return -1;
+ return local.getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
}
-
/**
* Sends a packet of data to a remote host
*
@@ -191,13 +243,30 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected void send(DatagramPacket packet) throws IOException
{
- if (native_fd != -1)
+ synchronized (SEND_LOCK)
{
- synchronized(SEND_LOCK)
+ ByteBuffer buf = ByteBuffer.wrap(packet.getData(),
+ packet.getOffset(),
+ packet.getLength());
+ InetAddress remote = packet.getAddress();
+ int port = packet.getPort();
+ if (remote == null)
+ throw new NullPointerException();
+ if (port <= 0)
+ throw new SocketException("invalid port " + port);
+ while (true)
{
- VMPlainDatagramSocketImpl.send(this, packet);
+ try
+ {
+ channel.send(buf, new InetSocketAddress(remote, port));
+ break;
+ }
+ catch (InterruptedIOException ioe)
+ {
+ // Ignore; interrupted system call.
+ }
}
- }
+ }
}
/**
@@ -210,48 +279,123 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
protected void receive(DatagramPacket packet)
throws IOException
{
- synchronized(RECEIVE_LOCK)
- {
- VMPlainDatagramSocketImpl.receive(this, packet);
- }
+ synchronized(RECEIVE_LOCK)
+ {
+ ByteBuffer buf = ByteBuffer.wrap(packet.getData(),
+ packet.getOffset(),
+ packet.getLength());
+ SocketAddress addr = null;
+ while (true)
+ {
+ try
+ {
+ addr = channel.receive(buf);
+ break;
+ }
+ catch (SocketTimeoutException ste)
+ {
+ throw ste;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignore. Loop.
+ }
+ }
+ if (addr != null)
+ packet.setSocketAddress(addr);
+ packet.setLength(buf.position() - packet.getOffset());
+ }
}
/**
* Sets the value of an option on the socket
*
- * @param option_id The identifier of the option to set
- * @param val The value of the option to set
+ * @param optionId The identifier of the option to set
+ * @param value The value of the option to set
*
* @exception SocketException If an error occurs
*/
- public synchronized void setOption(int option_id, Object val)
+ public synchronized void setOption(int optionId, Object value)
throws SocketException
- {
- VMPlainDatagramSocketImpl.setOption(this, option_id, val);
- }
+ {
+ switch (optionId)
+ {
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_IF2:
+ impl.setMulticastInterface(optionId, (InetAddress) value);
+ break;
+
+ case IP_MULTICAST_LOOP:
+ case SO_BROADCAST:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case TCP_NODELAY:
+ case IP_TOS:
+ case SO_LINGER:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ case SO_TIMEOUT:
+ case SO_REUSEADDR:
+ impl.setOption(optionId, value);
+ return;
+
+ default:
+ throw new SocketException("cannot set option " + optionId);
+ }
+ }
/**
* Retrieves the value of an option on the socket
*
- * @param option_id The identifier of the option to retrieve
+ * @param optionId The identifier of the option to retrieve
*
* @return The value of the option
*
* @exception SocketException If an error occurs
*/
- public synchronized Object getOption(int option_id)
+ public synchronized Object getOption(int optionId)
throws SocketException
- {
- return VMPlainDatagramSocketImpl.getOption(this, option_id);
- }
+ {
+ if (optionId == SO_BINDADDR)
+ {
+ try
+ {
+ InetSocketAddress local = channel.getLocalAddress();
+ if (local == null)
+ return null;
+ return local.getAddress();
+ }
+ catch (SocketException se)
+ {
+ throw se;
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
+ if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
+ return impl.getMulticastInterface(optionId);
+
+ return impl.getOption(optionId);
+ }
/**
* Closes the socket
*/
protected synchronized void close()
{
- VMPlainDatagramSocketImpl.close(this);
+ try
+ {
+ if (channel.getState().isValid())
+ channel.close();
+ }
+ catch (IOException ioe)
+ {
+ }
}
/**
@@ -291,7 +435,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void join(InetAddress addr) throws IOException
{
- VMPlainDatagramSocketImpl.join(this,addr);
+ impl.join(addr);
}
/**
@@ -303,7 +447,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void leave(InetAddress addr) throws IOException
{
- VMPlainDatagramSocketImpl.leave(this, addr);
+ impl.leave(addr);
}
/**
@@ -323,12 +467,20 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
public void joinGroup(SocketAddress address, NetworkInterface netIf)
throws IOException
{
- VMPlainDatagramSocketImpl.joinGroup(this, address, netIf);
+ if (address == null)
+ throw new NullPointerException();
+ if (!(address instanceof InetSocketAddress))
+ throw new SocketException("unknown address type");
+ impl.joinGroup((InetSocketAddress) address, netIf);
}
public void leaveGroup(SocketAddress address, NetworkInterface netIf)
throws IOException
{
- VMPlainDatagramSocketImpl.leaveGroup(this, address, netIf);
+ if (address == null)
+ throw new NullPointerException();
+ if (!(address instanceof InetSocketAddress))
+ throw new SocketException("unknown address type");
+ impl.leaveGroup((InetSocketAddress) address, netIf);
}
}
diff --git a/libjava/classpath/gnu/java/net/PlainSocketImpl.java b/libjava/classpath/gnu/java/net/PlainSocketImpl.java
index 47d05aa410d..5bda0a5e9bf 100644
--- a/libjava/classpath/gnu/java/net/PlainSocketImpl.java
+++ b/libjava/classpath/gnu/java/net/PlainSocketImpl.java
@@ -39,13 +39,20 @@ exception statement from your version. */
package gnu.java.net;
+import gnu.java.nio.SocketChannelImpl;
+import gnu.java.nio.VMChannel;
+
import java.io.InputStream;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -63,17 +70,13 @@ import java.net.SocketImpl;
* @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
* @author Aaron M. Renn (arenn@urbanophile.com)
*/
-public final class PlainSocketImpl extends SocketImpl
+public class PlainSocketImpl extends SocketImpl
{
/**
- * The OS file handle representing the socket.
- * This is used for reads and writes to/from the socket and
- * to close it.
- *
- * When the socket is closed this is reset to -1.
+ * The underlying plain socket VM implementation.
*/
- int native_fd = -1;
+ protected VMPlainSocketImpl impl;
/**
* A cached copy of the in stream for reading from the socket.
@@ -90,7 +93,13 @@ public final class PlainSocketImpl extends SocketImpl
* is being invoked on this socket.
*/
private boolean inChannelOperation;
-
+
+ /**
+ * The socket channel we use for IO operation. Package-private for
+ * use by inner classes.
+ */
+ SocketChannelImpl channel;
+
/**
* Indicates whether we should ignore whether any associated
* channel is set to non-blocking mode. Certain operations
@@ -117,29 +126,7 @@ public final class PlainSocketImpl extends SocketImpl
*/
public PlainSocketImpl()
{
- // Nothing to do here.
- }
-
- protected void finalize() throws Throwable
- {
- synchronized (this)
- {
- if (native_fd != -1)
- try
- {
- close();
- }
- catch (IOException ex)
- {
- // Nothing we can do about it.
- }
- }
- super.finalize();
- }
-
- public int getNativeFD()
- {
- return native_fd;
+ this.impl = new VMPlainSocketImpl();
}
/**
@@ -155,7 +142,24 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void setOption(int optionId, Object value) throws SocketException
{
- VMPlainSocketImpl.setOption(this, optionId, value);
+ switch (optionId)
+ {
+ case SO_LINGER:
+ case IP_MULTICAST_LOOP:
+ case SO_BROADCAST:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case TCP_NODELAY:
+ case IP_TOS:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ case SO_TIMEOUT:
+ case SO_REUSEADDR:
+ impl.setOption(optionId, value);
+ return;
+ default:
+ throw new SocketException("Unrecognized TCP option: " + optionId);
+ }
}
/**
@@ -171,17 +175,49 @@ public final class PlainSocketImpl extends SocketImpl
*/
public Object getOption(int optionId) throws SocketException
{
- return VMPlainSocketImpl.getOption(this, optionId);
+ if (optionId == SO_BINDADDR)
+ {
+ try
+ {
+ return channel.getVMChannel().getLocalAddress().getAddress();
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
+
+ // This filters options which are invalid for TCP.
+ switch (optionId)
+ {
+ case SO_LINGER:
+ case IP_MULTICAST_LOOP:
+ case SO_BROADCAST:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case TCP_NODELAY:
+ case IP_TOS:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ case SO_TIMEOUT:
+ case SO_REUSEADDR:
+ return impl.getOption(optionId);
+ default:
+ throw new SocketException("Unrecognized TCP option: " + optionId);
+ }
+
}
public void shutdownInput() throws IOException
{
- VMPlainSocketImpl.shutdownInput(this);
+ impl.shutdownInput();
}
public void shutdownOutput() throws IOException
{
- VMPlainSocketImpl.shutdownOutput(this);
+ impl.shutdownOutput();
}
/**
@@ -195,7 +231,11 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected synchronized void create(boolean stream) throws IOException
{
- VMPlainSocketImpl.create(this);
+ channel = new SocketChannelImpl(false);
+ VMChannel vmchannel = channel.getVMChannel();
+ vmchannel.initSocket(stream);
+ channel.configureBlocking(true);
+ impl.getState().setChannelFD(vmchannel.getState());
}
/**
@@ -222,7 +262,7 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected void connect(InetAddress addr, int port) throws IOException
{
- VMPlainSocketImpl.connect(this, addr, port);
+ connect(new InetSocketAddress(addr, port), 0);
}
/**
@@ -236,7 +276,17 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void connect(SocketAddress address, int timeout)
throws IOException
{
- VMPlainSocketImpl.connect(this, address, timeout);
+ if (channel == null)
+ create(true);
+ boolean connected = channel.connect(address, timeout);
+ if (!connected)
+ throw new SocketTimeoutException("connect timed out");
+
+ // Using the given SocketAddress is important to preserve
+ // hostnames given by the caller.
+ InetSocketAddress addr = (InetSocketAddress) address;
+ this.address = addr.getAddress();
+ this.port = addr.getPort();
}
/**
@@ -251,7 +301,10 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void bind(InetAddress addr, int port)
throws IOException
{
- VMPlainSocketImpl.bind(this, addr, port);
+ if (channel == null)
+ create(true);
+ impl.bind(new InetSocketAddress(addr, port));
+ localport = channel.getVMChannel().getLocalAddress().getPort();
}
/**
@@ -267,7 +320,7 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void listen(int queuelen)
throws IOException
{
- VMPlainSocketImpl.listen(this, queuelen);
+ impl.listen(queuelen);
}
/**
@@ -279,7 +332,19 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void accept(SocketImpl impl)
throws IOException
{
- VMPlainSocketImpl.accept(this, impl);
+ if (channel == null)
+ create(true);
+ if (!(impl instanceof PlainSocketImpl))
+ throw new IOException("incompatible SocketImpl: "
+ + impl.getClass().getName());
+ PlainSocketImpl that = (PlainSocketImpl) impl;
+ VMChannel c = channel.getVMChannel().accept();
+ that.impl.getState().setChannelFD(c.getState());
+ that.channel = new SocketChannelImpl(c);
+ that.setOption(SO_REUSEADDR, Boolean.TRUE);
+ // Reset the inherited timeout.
+ that.setOption(SO_TIMEOUT, Integer.valueOf(0));
+
}
/**
@@ -292,7 +357,9 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected int available() throws IOException
{
- return VMPlainSocketImpl.available(this);
+ if (channel == null)
+ throw new SocketException("not connected");
+ return channel.getVMChannel().available();
}
/**
@@ -308,65 +375,16 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected void close() throws IOException
{
- VMPlainSocketImpl.close(this);
- }
-
- public void sendUrgentData(int data)
- {
- VMPlainSocketImpl.sendUrgendData(this, data);
- }
-
- /**
- * Internal method used by SocketInputStream for reading data from
- * the connection. Reads up to len bytes of data into the buffer
- * buf starting at offset bytes into the buffer.
- *
- * @return the actual number of bytes read or -1 if end of stream.
- *
- * @throws IOException if an error occurs
- */
- protected int read(byte[] buf, int offset, int len)
- throws IOException
- {
- return VMPlainSocketImpl.read(this, buf, offset, len);
- }
-
- /**
- * Internal method used by SocketInputStream for reading data from
- * the connection. Reads and returns one byte of data.
- *
- * @return the read byte
- *
- * @throws IOException if an error occurs
- */
- protected int read()
- throws IOException
- {
- return VMPlainSocketImpl.read(this);
- }
-
- /**
- * Internal method used by SocketOuputStream for writing data to
- * the connection. Writes up to len bytes of data from the buffer
- * buf starting at offset bytes into the buffer.
- *
- * @throws IOException If an error occurs
- */
- protected void write(byte[] buf, int offset, int len)
- throws IOException
- {
- VMPlainSocketImpl.write(this, buf, offset, len);
+ if (impl.getState().isValid())
+ impl.close();
+
+ address = null;
+ port = -1;
}
- /**
- * Internal method used by SocketOuputStream for writing data to
- * the connection. Writes up one byte to the socket.
- *
- * @throws IOException If an error occurs
- */
- protected void write(int data) throws IOException
+ public void sendUrgentData(int data) throws IOException
{
- VMPlainSocketImpl.write(this, data);
+ impl.sendUrgentData(data);
}
/**
@@ -400,6 +418,95 @@ public final class PlainSocketImpl extends SocketImpl
return out;
}
+
+ public VMChannel getVMChannel()
+ {
+ if (channel == null)
+ return null;
+ return channel.getVMChannel();
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getInetAddress()
+ */
+ protected InetAddress getInetAddress()
+ {
+ if (channel == null)
+ return null;
+
+ try
+ {
+ InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
+ if (remote == null)
+ return null;
+ // To mimic behavior of the RI the InetAddress instance which was
+ // used to establish the connection is returned instead of one that
+ // was created by the native layer (this preserves exact hostnames).
+ if (address != null)
+ return address;
+
+ return remote.getAddress();
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getLocalPort()
+ */
+ protected int getLocalPort()
+ {
+ if (channel == null)
+ return -1;
+ try
+ {
+ InetSocketAddress local = channel.getVMChannel().getLocalAddress();
+ if (local == null)
+ return -1;
+ return local.getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ }
+
+ public InetSocketAddress getLocalAddress()
+ {
+ if (channel == null)
+ return null;
+ try
+ {
+ return channel.getVMChannel().getLocalAddress();
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getPort()
+ */
+ protected int getPort()
+ {
+ if (channel == null)
+ return -1;
+
+ try
+ {
+ InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
+ if (remote == null)
+ return -1;
+ return remote.getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ }
/**
* This class contains an implementation of <code>InputStream</code> for
@@ -437,7 +544,23 @@ public final class PlainSocketImpl extends SocketImpl
*/
public int read() throws IOException
{
- return PlainSocketImpl.this.read();
+ if (channel == null)
+ throw new SocketException("not connected");
+ while (true)
+ {
+ try
+ {
+ return channel.getVMChannel().read();
+ }
+ catch (SocketTimeoutException ste)
+ {
+ throw ste;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignore; NIO may throw this; net io shouldn't
+ }
+ }
}
/**
@@ -454,12 +577,24 @@ public final class PlainSocketImpl extends SocketImpl
*/
public int read (byte[] buf, int offset, int len) throws IOException
{
- int bytes_read = PlainSocketImpl.this.read (buf, offset, len);
-
- if (bytes_read == 0)
- return -1;
-
- return bytes_read;
+ if (channel == null)
+ throw new SocketException("not connected");
+ ByteBuffer b = ByteBuffer.wrap(buf, offset, len);
+ while (true)
+ {
+ try
+ {
+ return channel.read(b);
+ }
+ catch (SocketTimeoutException ste)
+ {
+ throw ste;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignored; NIO may throw this; net IO not.
+ }
+ }
}
}
@@ -495,7 +630,20 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void write(int b) throws IOException
{
- PlainSocketImpl.this.write(b);
+ if (channel == null)
+ throw new SocketException("not connected");
+ while (true)
+ {
+ try
+ {
+ channel.getVMChannel().write(b);
+ return;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignored.
+ }
+ }
}
/**
@@ -510,7 +658,21 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void write (byte[] buf, int offset, int len) throws IOException
{
- PlainSocketImpl.this.write (buf, offset, len);
+ if (channel == null)
+ throw new SocketException("not connected");
+ ByteBuffer b = ByteBuffer.wrap(buf, offset, len);
+ while (b.hasRemaining())
+ {
+ try
+ {
+ if (channel.write(b) == -1)
+ throw new IOException("channel has been closed");
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignored.
+ }
+ }
}
}
}
diff --git a/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java b/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java
index f43305a8027..f49b79947b7 100644
--- a/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java
+++ b/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.java.net.local;
+import gnu.classpath.Configuration;
+
import java.io.FileDescriptor;
import java.io.InputStream;
import java.io.IOException;
@@ -66,7 +68,10 @@ final class LocalSocketImpl extends SocketImpl
{
try
{
- System.loadLibrary ("javanet");
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary ("javanet");
+ }
}
catch (Exception x)
{
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java
index f5e831c6a01..3956d2aba3a 100644
--- a/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java
@@ -48,6 +48,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.net.SocketException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -227,10 +228,16 @@ public class HTTPConnection
* @param secure whether to use a secure connection
* @param connectionTimeout the connection timeout
* @param timeout the socket read timeout
+ *
+ * @throws IllegalArgumentException if either connectionTimeout or
+ * timeout less than zero.
*/
public HTTPConnection(String hostname, int port, boolean secure,
int connectionTimeout, int timeout)
{
+ if (connectionTimeout < 0 || timeout < 0)
+ throw new IllegalArgumentException();
+
this.hostname = hostname;
this.port = port;
this.secure = secure;
@@ -471,14 +478,32 @@ public class HTTPConnection
{
String ttl =
SystemProperties.getProperty("classpath.net.http.keepAliveTTL");
- connectionTTL = (ttl != null && ttl.length() > 0) ?
- 1000 * Math.max(1, Integer.parseInt(ttl)) : 10000;
+ connectionTTL = 10000;
+ if (ttl != null && ttl.length() > 0)
+ try
+ {
+ int v = 1000 * Integer.parseInt(ttl);
+ if (v >= 0)
+ connectionTTL = v;
+ }
+ catch (NumberFormatException _)
+ {
+ // Ignore.
+ }
String mc = SystemProperties.getProperty("http.maxConnections");
- maxConnections = (mc != null && mc.length() > 0) ?
- Math.max(Integer.parseInt(mc), 1) : 5;
- if (maxConnections < 1)
- maxConnections = 1;
+ maxConnections = 5;
+ if (mc != null && mc.length() > 0)
+ try
+ {
+ int v = Integer.parseInt(mc);
+ if (v > 0)
+ maxConnections = v;
+ }
+ catch (NumberFormatException _)
+ {
+ // Ignore.
+ }
HTTPConnection c = null;
@@ -490,12 +515,23 @@ public class HTTPConnection
{
c = cc;
it.remove();
+ // Update the timeout.
+ if (c.socket != null)
+ try
+ {
+ c.socket.setSoTimeout(timeout);
+ }
+ catch (SocketException _)
+ {
+ // Ignore.
+ }
break;
}
}
if (c == null)
{
- c = new HTTPConnection(host, port, secure, connectionTimeout, timeout);
+ c = new HTTPConnection(host, port, secure,
+ connectionTimeout, timeout);
c.setPool(this);
}
return c;
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
index cc68a3bac30..6c926b72fb4 100644
--- a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
@@ -75,7 +75,7 @@ public class HTTPURLConnection
// These are package private for use in anonymous inner classes.
String proxyHostname;
- int proxyPort;
+ int proxyPort = -1;
String agent;
boolean keepAlive;
@@ -99,18 +99,21 @@ public class HTTPURLConnection
{
super(url);
requestHeaders = new Headers();
- proxyHostname = SystemProperties.getProperty("http.proxyHost");
- if (proxyHostname != null && proxyHostname.length() > 0)
+ String proxy = SystemProperties.getProperty("http.proxyHost");
+ if (proxy != null && proxy.length() > 0)
{
String port = SystemProperties.getProperty("http.proxyPort");
if (port != null && port.length() > 0)
{
- proxyPort = Integer.parseInt(port);
- }
- else
- {
- proxyHostname = null;
- proxyPort = -1;
+ try
+ {
+ proxyPort = Integer.parseInt(port);
+ proxyHostname = proxy;
+ }
+ catch (NumberFormatException _)
+ {
+ // Ignore.
+ }
}
}
agent = SystemProperties.getProperty("http.agent");
@@ -354,11 +357,14 @@ public class HTTPURLConnection
HTTPConnection connection;
if (keepAlive)
{
- connection = HTTPConnection.Pool.instance.get(host, port, secure, getConnectTimeout(), 0);
+ connection = HTTPConnection.Pool.instance.get(host, port, secure,
+ getConnectTimeout(),
+ getReadTimeout());
}
else
{
- connection = new HTTPConnection(host, port, secure, 0, getConnectTimeout());
+ connection = new HTTPConnection(host, port, secure,
+ getConnectTimeout(), getReadTimeout());
}
return connection;
}
@@ -662,23 +668,23 @@ public class HTTPURLConnection
}
/**
- * Set the connection timeout speed, in milliseconds, or zero if the timeout
+ * Set the read timeout, in milliseconds, or zero if the timeout
* is to be considered infinite.
*
* Overloaded.
*
*/
- public void setConnectTimeout(int timeout)
+ public void setReadTimeout(int timeout)
throws IllegalArgumentException
{
- super.setConnectTimeout( timeout );
- if( connection == null )
+ super.setReadTimeout(timeout);
+ if (connection == null)
return;
try
{
- connection.getSocket().setSoTimeout( timeout );
+ connection.getSocket().setSoTimeout(timeout);
}
- catch(IOException se)
+ catch (IOException se)
{
// Ignore socket exceptions.
}
diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java
index 316d8cb02be..7c09766a557 100644
--- a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java
+++ b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java
@@ -1,5 +1,5 @@
/* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net
- Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -45,6 +45,9 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
/**
* @author Kresten Krab Thorup (krab@gnu.org)
@@ -114,7 +117,7 @@ public class Handler extends URLStreamHandler
file = file.substring(0, idx + 1) + url_string;
}
- setURL (url, "jar", url.getHost(), url.getPort(), file, null);
+ setURL (url, "jar", url.getHost(), url.getPort(), flat(file), null);
return;
}
@@ -149,6 +152,45 @@ public class Handler extends URLStreamHandler
}
/**
+ * Makes the given jar url string 'flat' by removing any . and .. from
+ * jar file path because ZipFile entries can only handle flat paths.
+ * Inside jar files '/' is always the path separator.
+ */
+ private static String flat(String url_string)
+ {
+ int jar_stop = url_string.indexOf("!/");
+ String jar_path = url_string.substring(jar_stop + 1, url_string.length());
+
+ if (jar_path.indexOf("/.") < 0)
+ return url_string;
+
+ ArrayList tokens = new ArrayList();
+ StringTokenizer st = new StringTokenizer(jar_path, "/");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if (token.equals("."))
+ continue;
+ else if (token.equals(".."))
+ {
+ if (! tokens.isEmpty())
+ tokens.remove(tokens.size() - 1);
+ }
+ else
+ tokens.add(token);
+ }
+
+ StringBuffer path = new StringBuffer(url_string.length());
+ path.append(url_string.substring(0, jar_stop + 1));
+
+ Iterator it = tokens.iterator();
+ while (it.hasNext())
+ path.append('/').append(it.next());
+
+ return path.toString();
+ }
+
+ /**
* This method converts a Jar URL object into a String.
*
* @param url The URL object to convert
diff --git a/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java b/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java
index 4687bf3f59e..268ee0a8aa7 100644
--- a/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java
+++ b/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java
@@ -55,8 +55,10 @@ import java.nio.channels.spi.SelectorProvider;
* @author Michael Koch
*/
public final class DatagramChannelImpl extends DatagramChannel
+ implements VMChannelOwner
{
private NIODatagramSocket socket;
+ private VMChannel channel;
/**
* Indicates whether this channel initiated whatever operation
@@ -64,6 +66,16 @@ public final class DatagramChannelImpl extends DatagramChannel
*/
private boolean inChannelOperation;
+ protected DatagramChannelImpl (SelectorProvider provider)
+ throws IOException
+ {
+ super (provider);
+ socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
+ channel = new VMChannel();
+ channel.initSocket(false);
+ configureBlocking(true);
+ }
+
/**
* Indicates whether our datagram socket should ignore whether
* we are set to non-blocking mode. Certain operations on our
@@ -85,14 +97,6 @@ public final class DatagramChannelImpl extends DatagramChannel
inChannelOperation = b;
}
- protected DatagramChannelImpl (SelectorProvider provider)
- throws IOException
- {
- super (provider);
- socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
- configureBlocking(true);
- }
-
public DatagramSocket socket ()
{
return socket;
@@ -101,13 +105,13 @@ public final class DatagramChannelImpl extends DatagramChannel
protected void implCloseSelectableChannel ()
throws IOException
{
- socket.close ();
+ channel.close();
}
protected void implConfigureBlocking (boolean blocking)
throws IOException
{
- socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ channel.setBlocking(blocking);
}
public DatagramChannel connect (SocketAddress remote)
@@ -116,20 +120,34 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isOpen())
throw new ClosedChannelException();
- socket.connect (remote);
+ try
+ {
+ channel.connect((InetSocketAddress) remote, 0);
+ }
+ catch (ClassCastException cce)
+ {
+ throw new IOException("unsupported socked address type");
+ }
return this;
}
public DatagramChannel disconnect ()
throws IOException
{
- socket.disconnect ();
+ channel.disconnect();
return this;
}
- public boolean isConnected ()
+ public boolean isConnected()
{
- return socket.isConnected ();
+ try
+ {
+ return channel.getPeerAddress() != null;
+ }
+ catch (IOException ioe)
+ {
+ return false;
+ }
}
public int write (ByteBuffer src)
@@ -138,7 +156,7 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isConnected ())
throw new NotYetConnectedException ();
- return send (src, socket.getRemoteSocketAddress());
+ return channel.write(src);
}
public long write (ByteBuffer[] srcs, int offset, int length)
@@ -152,13 +170,11 @@ public final class DatagramChannelImpl extends DatagramChannel
|| (length < 0)
|| (length > (srcs.length - offset)))
throw new IndexOutOfBoundsException();
-
- long result = 0;
-
- for (int index = offset; index < offset + length; index++)
- result += write (srcs [index]);
- return result;
+ /* We are connected, meaning we will write these bytes to
+ * the host we connected to, so we don't need to explicitly
+ * give the host. */
+ return channel.writeGathering(srcs, offset, length);
}
public int read (ByteBuffer dst)
@@ -167,9 +183,7 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isConnected ())
throw new NotYetConnectedException ();
- int remaining = dst.remaining();
- receive (dst);
- return remaining - dst.remaining();
+ return channel.read(dst);
}
public long read (ByteBuffer[] dsts, int offset, int length)
@@ -184,12 +198,8 @@ public final class DatagramChannelImpl extends DatagramChannel
|| (length > (dsts.length - offset)))
throw new IndexOutOfBoundsException();
- long result = 0;
-
- for (int index = offset; index < offset + length; index++)
- result += read (dsts [index]);
-
- return result;
+ /* Likewise, see the comment int write above. */
+ return channel.readScattering(dsts, offset, length);
}
public SocketAddress receive (ByteBuffer dst)
@@ -200,49 +210,12 @@ public final class DatagramChannelImpl extends DatagramChannel
try
{
- DatagramPacket packet;
- int len = dst.remaining();
-
- if (dst.hasArray())
- {
- packet = new DatagramPacket (dst.array(),
- dst.arrayOffset() + dst.position(),
- len);
- }
- else
- {
- packet = new DatagramPacket (new byte [len], len);
- }
-
- boolean completed = false;
-
- try
- {
- begin();
- setInChannelOperation(true);
- socket.receive (packet);
- completed = true;
- }
- finally
- {
- end (completed);
- setInChannelOperation(false);
- }
-
- if (!dst.hasArray())
- {
- dst.put (packet.getData(), packet.getOffset(), packet.getLength());
- }
- else
- {
- dst.position (dst.position() + packet.getLength());
- }
-
- return packet.getSocketAddress();
+ begin();
+ return channel.receive(dst);
}
- catch (SocketTimeoutException e)
+ finally
{
- return null;
+ end(true);
}
}
@@ -252,46 +225,18 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isOpen())
throw new ClosedChannelException();
- if (target instanceof InetSocketAddress
- && ((InetSocketAddress) target).isUnresolved())
- throw new IOException("Target address not resolved");
-
- byte[] buffer;
- int offset = 0;
- int len = src.remaining();
+ if (!(target instanceof InetSocketAddress))
+ throw new IOException("can only send to inet socket addresses");
- if (src.hasArray())
- {
- buffer = src.array();
- offset = src.arrayOffset() + src.position();
- }
- else
- {
- buffer = new byte [len];
- src.get (buffer);
- }
-
- DatagramPacket packet = new DatagramPacket (buffer, offset, len, target);
-
- boolean completed = false;
- try
- {
- begin();
- setInChannelOperation(true);
- socket.send(packet);
- completed = true;
- }
- finally
- {
- end (completed);
- setInChannelOperation(false);
- }
-
- if (src.hasArray())
- {
- src.position (src.position() + len);
- }
+ InetSocketAddress dst = (InetSocketAddress) target;
+ if (dst.isUnresolved())
+ throw new IOException("Target address not resolved");
- return len;
+ return channel.send(src, dst);
+ }
+
+ public VMChannel getVMChannel()
+ {
+ return channel;
}
}
diff --git a/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java
index 698e07e348f..f192e5002d4 100644
--- a/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java
+++ b/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
import java.nio.channels.spi.AbstractSelectableChannel;
/**
@@ -52,10 +53,16 @@ public final class DatagramChannelSelectionKey
super (channel, selector);
}
+ // FIXME don't use file descriptor integers
public int getNativeFD()
{
- NIODatagramSocket socket =
- (NIODatagramSocket) ((DatagramChannelImpl) ch).socket();
- return socket.getPlainDatagramSocketImpl().getNativeFD();
+ try
+ {
+ return ((DatagramChannelImpl) ch).getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalStateException(ioe);
+ }
}
}
diff --git a/libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java
new file mode 100644
index 00000000000..11113f3975c
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java
@@ -0,0 +1,122 @@
+/* EpollSelectionKeyImpl.java -- selection key for the epoll selector.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+import java.io.IOException;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EpollSelectionKeyImpl extends AbstractSelectionKey
+{
+ final int fd;
+ private final EpollSelectorImpl selector;
+ private final SelectableChannel channel;
+ int interestOps;
+ int selectedOps;
+ int key;
+ boolean valid;
+ boolean cancelled;
+
+ EpollSelectionKeyImpl(EpollSelectorImpl selector,
+ SelectableChannel channel, int fd)
+ {
+ this.selector = selector;
+ this.channel = channel;
+ this.fd = fd;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#channel()
+ */
+ public SelectableChannel channel()
+ {
+ return channel;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps()
+ */
+ public int interestOps()
+ {
+ return interestOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps(int)
+ */
+ public SelectionKey interestOps(int ops)
+ {
+ if (cancelled)
+ throw new CancelledKeyException();
+ if ((ops & ~(channel.validOps())) != 0)
+ throw new IllegalArgumentException("unsupported channel ops");
+ try
+ {
+ selector.epoll_modify(this, ops);
+ interestOps = ops;
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException(ioe);
+ }
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#readyOps()
+ */
+ public int readyOps()
+ {
+ return selectedOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#selector()
+ */
+ public Selector selector()
+ {
+ return selector;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/EpollSelectorImpl.java b/libjava/classpath/gnu/java/nio/EpollSelectorImpl.java
new file mode 100644
index 00000000000..2b3c9bbb1b6
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/EpollSelectorImpl.java
@@ -0,0 +1,399 @@
+/* EpollSelectorImpl.java -- selector implementation using epoll
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+import gnu.classpath.Configuration;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * An implementation of {@link Selector} that uses the epoll event
+ * notification mechanism on GNU/Linux.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EpollSelectorImpl extends AbstractSelector
+{
+ // XXX is this reasonable? Does it matter?
+ private static final int DEFAULT_EPOLL_SIZE = 128;
+ private static final int sizeof_struct_epoll_event;
+
+ private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT;
+ private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
+ private static final int OP_READ = SelectionKey.OP_READ;
+ private static final int OP_WRITE = SelectionKey.OP_WRITE;
+
+ /** our epoll file descriptor. */
+ private int epoll_fd;
+
+ private final HashMap keys;
+ private Set selectedKeys;
+ private Thread waitingThread;
+ private ByteBuffer events;
+
+ private static final int INITIAL_CAPACITY;
+ private static final int MAX_DOUBLING_CAPACITY;
+ private static final int CAPACITY_INCREMENT;
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ System.loadLibrary("javanio");
+
+ if (epoll_supported())
+ sizeof_struct_epoll_event = sizeof_struct();
+ else
+ sizeof_struct_epoll_event = -1;
+
+ INITIAL_CAPACITY = 64 * sizeof_struct_epoll_event;
+ MAX_DOUBLING_CAPACITY = 1024 * sizeof_struct_epoll_event;
+ CAPACITY_INCREMENT = 128 * sizeof_struct_epoll_event;
+ }
+
+ public EpollSelectorImpl(SelectorProvider provider)
+ throws IOException
+ {
+ super(provider);
+ epoll_fd = epoll_create(DEFAULT_EPOLL_SIZE);
+ keys = new HashMap();
+ selectedKeys = null;
+ events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#keys()
+ */
+ public Set keys()
+ {
+ return new HashSet(keys.values());
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select()
+ */
+ public int select() throws IOException
+ {
+ return doSelect(-1);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select(long)
+ */
+ public int select(long timeout) throws IOException
+ {
+ if (timeout > Integer.MAX_VALUE)
+ throw new IllegalArgumentException("timeout is too large");
+ if (timeout < 0)
+ throw new IllegalArgumentException("invalid timeout");
+ return doSelect((int) timeout);
+ }
+
+ private int doSelect(int timeout) throws IOException
+ {
+ synchronized (keys)
+ {
+ Set cancelledKeys = cancelledKeys();
+ synchronized (cancelledKeys)
+ {
+ for (Iterator it = cancelledKeys.iterator(); it.hasNext(); )
+ {
+ EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next();
+ epoll_delete(epoll_fd, key.fd);
+ key.valid = false;
+ keys.remove(Integer.valueOf(key.fd));
+ it.remove();
+ deregister(key);
+ }
+
+ // Clear out closed channels. The fds are removed from the epoll
+ // fd when closed, so there is no need to remove them manually.
+ for (Iterator it = keys.values().iterator(); it.hasNext(); )
+ {
+ EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next();
+ SelectableChannel ch = key.channel();
+ if (ch instanceof VMChannelOwner)
+ {
+ if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
+ it.remove();
+ }
+ }
+
+ // Don't bother if we have nothing to select.
+ if (keys.isEmpty())
+ return 0;
+
+ int ret;
+ try
+ {
+ begin();
+ waitingThread = Thread.currentThread();
+ ret = epoll_wait(epoll_fd, events, keys.size(), timeout);
+ }
+ finally
+ {
+ Thread.interrupted();
+ waitingThread = null;
+ end();
+ }
+
+ HashSet s = new HashSet(ret);
+ for (int i = 0; i < ret; i++)
+ {
+ events.position(i * sizeof_struct_epoll_event);
+ ByteBuffer b = events.slice();
+ int fd = selected_fd(b);
+ EpollSelectionKeyImpl key
+ = (EpollSelectionKeyImpl) keys.get(Integer.valueOf(fd));
+ if (key == null)
+ throw new IOException("fd was selected, but no key found");
+ key.selectedOps = selected_ops(b) & key.interestOps;
+ s.add(key);
+ }
+
+ reallocateBuffer();
+
+ selectedKeys = s;
+ return ret;
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectedKeys()
+ */
+ public Set selectedKeys()
+ {
+ if (selectedKeys == null)
+ return Collections.EMPTY_SET;
+ return selectedKeys;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectNow()
+ */
+ public int selectNow() throws IOException
+ {
+ return doSelect(0);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#wakeup()
+ */
+ public Selector wakeup()
+ {
+ try
+ {
+ waitingThread.interrupt();
+ }
+ catch (NullPointerException npe)
+ {
+ // Ignored, thrown if we are not in a blocking op.
+ }
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.spi.AbstractSelector#implCloseSelector()
+ */
+ protected void implCloseSelector() throws IOException
+ {
+ VMChannel.close(epoll_fd);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object)
+ */
+ protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object att)
+ {
+ if (!(ch instanceof VMChannelOwner))
+ throw new IllegalArgumentException("unsupported channel type");
+
+ VMChannel channel = ((VMChannelOwner) ch).getVMChannel();
+ try
+ {
+ int native_fd = channel.getState().getNativeFD();
+ synchronized (keys)
+ {
+ if (keys.containsKey(Integer.valueOf(native_fd)))
+ throw new IllegalArgumentException("channel already registered");
+ EpollSelectionKeyImpl result =
+ new EpollSelectionKeyImpl(this, ch, native_fd);
+ if ((ops & ~(ch.validOps())) != 0)
+ throw new IllegalArgumentException("invalid ops for channel");
+ result.interestOps = ops;
+ result.selectedOps = 0;
+ result.valid = true;
+ result.attach(att);
+ result.key = System.identityHashCode(result);
+ epoll_add(epoll_fd, result.fd, ops);
+ keys.put(Integer.valueOf(native_fd), result);
+ reallocateBuffer();
+ return result;
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException(ioe);
+ }
+ }
+
+ private void reallocateBuffer()
+ {
+ // Ensure we have enough space for all potential events that may be
+ // returned.
+ if (events.capacity() < keys.size() * sizeof_struct_epoll_event)
+ {
+ int cap = events.capacity();
+ if (cap < MAX_DOUBLING_CAPACITY)
+ cap <<= 1;
+ else
+ cap += CAPACITY_INCREMENT;
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ // Ensure that the events buffer is not too large, given the number of
+ // events registered.
+ else if (events.capacity() > keys.size() * sizeof_struct_epoll_event * 2 + 1
+ && events.capacity() > INITIAL_CAPACITY)
+ {
+ int cap = events.capacity() >>> 1;
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ }
+
+ void epoll_modify(EpollSelectionKeyImpl key, int ops) throws IOException
+ {
+ epoll_modify(epoll_fd, key.fd, ops);
+ }
+
+ /**
+ * Tell if epoll is supported by this system, and support was compiled in.
+ *
+ * @return True if this system supports event notification with epoll.
+ */
+ public static native boolean epoll_supported();
+
+
+ /**
+ * Returns the size of `struct epoll_event'.
+ *
+ * @return The size of `struct epoll_event'.
+ */
+ private static native int sizeof_struct();
+
+
+ /**
+ * Open a new epoll file descriptor.
+ *
+ * @param size The size hint for the new epoll descriptor.
+ * @return The new file descriptor integer.
+ * @throws IOException If allocating a new epoll descriptor fails.
+ */
+ private static native int epoll_create(int size) throws IOException;
+
+ /**
+ * Add a file descriptor to this selector.
+ *
+ * @param efd The epoll file descriptor.
+ * @param fd The file descriptor to add (or modify).
+ * @param ops The interest opts.
+ */
+ private static native void epoll_add(int efd, int fd, int ops)
+ throws IOException;
+
+ /**
+ * Modify the interest ops of the key selecting for the given FD.
+ *
+ * @param efd The epoll file descriptor.
+ * @param fd The file descriptor to modify.
+ * @param ops The ops.
+ * @throws IOException
+ */
+ private static native void epoll_modify(int efd, int fd, int ops)
+ throws IOException;
+
+ /**
+ * Remove a file descriptor from this selector.
+ *
+ * @param efd The epoll file descriptor.
+ * @param fd The file descriptor.
+ * @throws IOException
+ */
+ private static native void epoll_delete(int efd, int fd) throws IOException;
+
+ /**
+ * Select events.
+ *
+ * @param efd The epoll file descriptor.
+ * @param state The buffer to hold selected events.
+ * @param n The number of events that may be put in `state'.
+ * @param timeout The timeout.
+ * @return The number of events selected.
+ * @throws IOException
+ */
+ private static native int epoll_wait(int efd, ByteBuffer state, int n, int timeout)
+ throws IOException;
+
+ /**
+ * Fetch the fd value from a selected struct epoll_event.
+ *
+ * @param struct The direct buffer holding the struct.
+ * @return The fd value.
+ */
+ private static native int selected_fd(ByteBuffer struct);
+
+ /**
+ * Fetch the enabled operations from a selected struct epoll_event.
+ *
+ * @param struct The direct buffer holding the struct.
+ * @return The selected operations.
+ */
+ private static native int selected_ops(ByteBuffer struct);
+}
diff --git a/libjava/classpath/gnu/java/nio/channels/FileChannelImpl.java b/libjava/classpath/gnu/java/nio/FileChannelImpl.java
index ed439e141ef..41912405078 100644
--- a/libjava/classpath/gnu/java/nio/channels/FileChannelImpl.java
+++ b/libjava/classpath/gnu/java/nio/FileChannelImpl.java
@@ -36,7 +36,7 @@ obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-package gnu.java.nio.channels;
+package gnu.java.nio;
import gnu.classpath.Configuration;
import gnu.java.nio.FileLockImpl;
@@ -74,11 +74,11 @@ public final class FileChannelImpl extends FileChannel
public static final int SYNC = 16;
public static final int DSYNC = 32;
- public static FileChannelImpl in;
- public static FileChannelImpl out;
- public static FileChannelImpl err;
+ public static final FileChannelImpl in;
+ public static final FileChannelImpl out;
+ public static final FileChannelImpl err;
- private static native void init();
+ //private static native void init();
static
{
@@ -87,22 +87,45 @@ public final class FileChannelImpl extends FileChannel
System.loadLibrary("javanio");
}
- init();
+ //init();
- in = new FileChannelImpl(0, READ);
- out = new FileChannelImpl(1, WRITE);
- err = new FileChannelImpl(2, WRITE);
+ FileChannelImpl ch = null;
+ try
+ {
+ ch = new FileChannelImpl(VMChannel.getStdin(), READ);
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ in = ch;
+
+ ch = null;
+ try
+ {
+ ch = new FileChannelImpl(VMChannel.getStdout(), WRITE);
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ out = ch;
+
+ ch = null;
+ try
+ {
+ ch = new FileChannelImpl(VMChannel.getStderr(), WRITE);
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ err = ch;
}
/**
* This is the actual native file descriptor value
*/
- // System's notion of file descriptor. It might seem redundant to
- // initialize this given that it is reassigned in the constructors.
- // However, this is necessary because if open() throws an exception
- // we want to make sure this has the value -1. This is the most
- // efficient way to accomplish that.
- private int fd = -1;
private VMChannel ch;
private int mode;
@@ -113,19 +136,19 @@ public final class FileChannelImpl extends FileChannel
/* This is a static factory method, so that VM implementors can decide
* substitute subclasses of FileChannelImpl. */
public static FileChannelImpl create(File file, int mode)
- throws FileNotFoundException
+ throws IOException
{
return new FileChannelImpl(file, mode);
}
private FileChannelImpl(File file, int mode)
- throws FileNotFoundException
+ throws IOException
{
String path = file.getPath();
description = path;
- fd = open (path, mode);
this.mode = mode;
- this.ch = VMChannel.getVMChannel(this);
+ this.ch = new VMChannel();
+ ch.openFile(path, mode);
// First open the file and then check if it is a a directory
// to avoid race condition.
@@ -133,11 +156,11 @@ public final class FileChannelImpl extends FileChannel
{
try
{
- close();
+ close();
}
catch (IOException e)
{
- /* ignore it */
+ /* ignore it */
}
throw new FileNotFoundException(description + " is a directory");
@@ -153,49 +176,59 @@ public final class FileChannelImpl extends FileChannel
*
* @param mode READ or WRITE
*/
- FileChannelImpl (int fd, int mode)
+ FileChannelImpl (VMChannel ch, int mode)
{
- this.fd = fd;
this.mode = mode;
- this.description = "descriptor(" + fd + ")";
- this.ch = VMChannel.getVMChannel(this);
+ this.description = "descriptor(" + ch.getState() + ")";
+ this.ch = ch;
}
- private native int open (String path, int mode) throws FileNotFoundException;
+ public int available() throws IOException
+ {
+ return ch.available();
+ }
+
+ private long implPosition() throws IOException
+ {
+ return ch.position();
+ }
- public native int available () throws IOException;
- private native long implPosition () throws IOException;
- private native void seek (long newPosition) throws IOException;
- private native void implTruncate (long size) throws IOException;
+ private void seek(long newPosition) throws IOException
+ {
+ ch.seek(newPosition);
+ }
+
+ private void implTruncate(long size) throws IOException
+ {
+ ch.truncate(size);
+ }
- public native void unlock (long pos, long len) throws IOException;
+ public void unlock(long pos, long len) throws IOException
+ {
+ ch.unlock(pos, len);
+ }
- public native long size () throws IOException;
+ public long size () throws IOException
+ {
+ return ch.size();
+ }
- protected native void implCloseChannel() throws IOException;
+ protected void implCloseChannel() throws IOException
+ {
+ ch.close();
+ }
/**
* Makes sure the Channel is properly closed.
*/
protected void finalize() throws IOException
{
- if (fd != -1)
+ if (ch.getState().isValid())
close();
}
public int read (ByteBuffer dst) throws IOException
{
- /*
- int result;
- byte[] buffer = new byte [dst.remaining ()];
-
- result = read (buffer, 0, buffer.length);
-
- if (result > 0)
- dst.put (buffer, 0, result);
-
- return result;
- */
return ch.read(dst);
}
@@ -212,11 +245,10 @@ public final class FileChannelImpl extends FileChannel
return result;
}
- public native int read ()
- throws IOException;
-
- public native int read (byte[] buffer, int offset, int length)
- throws IOException;
+ public int read() throws IOException
+ {
+ return ch.read();
+ }
public long read (ByteBuffer[] dsts, int offset, int length)
throws IOException
@@ -252,19 +284,16 @@ public final class FileChannelImpl extends FileChannel
return result;
}
- public native void write (byte[] buffer, int offset, int length)
- throws IOException;
-
- public native void write (int b) throws IOException;
+ public void write (int b) throws IOException
+ {
+ ch.write(b);
+ }
public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException
{
return ch.writeGathering(srcs, offset, length);
}
-
- public native MappedByteBuffer mapImpl (char mode, long position, int size)
- throws IOException;
public MappedByteBuffer map (FileChannel.MapMode mode,
long position, long size)
@@ -291,7 +320,7 @@ public final class FileChannelImpl extends FileChannel
if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
throw new IllegalArgumentException ("position: " + position
+ ", size: " + size);
- return mapImpl(nmode, position, (int) size);
+ return ch.map(nmode, position, (int) size);
}
/**
@@ -302,11 +331,9 @@ public final class FileChannelImpl extends FileChannel
if (!isOpen ())
throw new ClosedChannelException ();
- force ();
+ ch.flush(metaData);
}
- private native void force ();
-
// like transferTo, but with a count of less than 2Gbytes
private int smallTransferTo (long position, int count,
WritableByteChannel target)
@@ -453,7 +480,7 @@ public final class FileChannelImpl extends FileChannel
try
{
begin();
- boolean lockable = lock(position, size, shared, false);
+ boolean lockable = ch.lock(position, size, shared, false);
completed = true;
return (lockable
? new FileLockImpl(this, position, size, shared)
@@ -464,14 +491,6 @@ public final class FileChannelImpl extends FileChannel
end(completed);
}
}
-
- /** Try to acquire a lock at the given position and size.
- * On success return true.
- * If wait as specified, block until we can get it.
- * Otherwise return false.
- */
- private native boolean lock(long position, long size,
- boolean shared, boolean wait) throws IOException;
public FileLock lock (long position, long size, boolean shared)
throws IOException
@@ -481,7 +500,7 @@ public final class FileChannelImpl extends FileChannel
boolean completed = false;
try
{
- boolean lockable = lock(position, size, shared, true);
+ boolean lockable = ch.lock(position, size, shared, true);
completed = true;
return (lockable
? new FileLockImpl(this, position, size, shared)
@@ -537,17 +556,17 @@ public final class FileChannelImpl extends FileChannel
public String toString()
{
- return (this.getClass()
- + "[fd=" + fd
- + ",mode=" + mode + ","
- + description + "]");
+ return (super.toString()
+ + "[ fd: " + ch.getState()
+ + "; mode: " + Integer.toOctalString(mode)
+ + "; " + description + " ]");
}
/**
* @return The native file descriptor.
- */
+ * /
public int getNativeFD()
{
return fd;
- }
+ }*/
}
diff --git a/libjava/classpath/gnu/java/nio/FileLockImpl.java b/libjava/classpath/gnu/java/nio/FileLockImpl.java
index 673ca2522df..768906ce973 100644
--- a/libjava/classpath/gnu/java/nio/FileLockImpl.java
+++ b/libjava/classpath/gnu/java/nio/FileLockImpl.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package gnu.java.nio;
-import gnu.java.nio.channels.FileChannelImpl;
-
import java.io.IOException;
import java.nio.channels.FileLock;
diff --git a/libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java
new file mode 100644
index 00000000000..2f93c50cc19
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java
@@ -0,0 +1,189 @@
+/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class KqueueSelectionKeyImpl extends AbstractSelectionKey
+{
+ int interestOps;
+ int readyOps;
+ int activeOps = 0;
+ int key;
+ int fd;
+
+ /** The selector we were created for. */
+ private final KqueueSelectorImpl selector;
+
+ /** The channel we are attached to. */
+ private final SelectableChannel channel;
+
+ private final VMChannelOwner natChannel;
+
+ public KqueueSelectionKeyImpl(KqueueSelectorImpl selector,
+ SelectableChannel channel)
+ {
+ this.selector = selector;
+ this.channel = channel;
+ natChannel = (VMChannelOwner) channel;
+ interestOps = 0;
+ readyOps = 0;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#channel()
+ */
+ //@Override
+ public SelectableChannel channel()
+ {
+ return channel;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps()
+ */
+ //@Override
+ public int interestOps()
+ {
+ return interestOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps(int)
+ */
+ //@Override
+ public SelectionKey interestOps(int ops)
+ {
+ if (!isValid())
+ throw new IllegalStateException("key is invalid");
+ if ((ops & ~channel.validOps()) != 0)
+ throw new IllegalArgumentException("channel does not support all operations");
+
+ selector.setInterestOps(this, ops);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#readyOps()
+ */
+ //@Override
+ public int readyOps()
+ {
+ return readyOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#selector()
+ */
+ //@Override
+ public Selector selector()
+ {
+ return selector;
+ }
+
+ public String toString()
+ {
+ if (!isValid())
+ return super.toString() + " [ fd: " + fd + " <<invalid>> ]";
+ return super.toString() + " [ fd: " + fd + " interest ops: {"
+ + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
+ + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
+ + ((interestOps & OP_READ) != 0 ? " OP_READ" : "")
+ + ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
+ + " }; ready ops: {"
+ + ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
+ + ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
+ + ((readyOps & OP_READ) != 0 ? " OP_READ" : "")
+ + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
+ + " } ]";
+ }
+
+ public int hashCode()
+ {
+ return fd;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof KqueueSelectionKeyImpl))
+ return false;
+ KqueueSelectionKeyImpl that = (KqueueSelectionKeyImpl) o;
+ return that.fd == this.fd && that.channel.equals(this.channel);
+ }
+
+
+ boolean isReadActive()
+ {
+ return (activeOps & (OP_READ | OP_ACCEPT)) != 0;
+ }
+
+ boolean isReadInterested()
+ {
+ return (interestOps & (OP_READ | OP_ACCEPT)) != 0;
+ }
+
+ boolean isWriteActive()
+ {
+ return (activeOps & (OP_WRITE | OP_CONNECT)) != 0;
+ }
+
+ boolean isWriteInterested()
+ {
+ return (interestOps & (OP_WRITE | OP_CONNECT)) != 0;
+ }
+
+ boolean needCommitRead()
+ {
+ return isReadActive() == (!isReadInterested());
+ }
+
+ boolean needCommitWrite()
+ {
+ return isWriteActive() == (!isWriteInterested());
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java b/libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java
new file mode 100644
index 00000000000..34ca1dc596d
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java
@@ -0,0 +1,527 @@
+/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A {@link Selector} implementation that uses the <code>kqueue</code>
+ * event notification facility.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class KqueueSelectorImpl extends AbstractSelector
+{
+ // Prepended underscore to field name to make it distinct
+ // from the method with the similar name.
+ private static final int _sizeof_struct_kevent;
+
+ private static final int MAX_DOUBLING_CAPACITY = 16384;
+ private static final int CAP_INCREMENT = 1024;
+ private static final int INITIAL_CAPACITY;
+
+ static
+ {
+ try
+ {
+ System.loadLibrary("javanio");
+ }
+ catch (Exception x)
+ {
+ x.printStackTrace();
+ }
+
+ if (kqueue_supported ())
+ _sizeof_struct_kevent = sizeof_struct_kevent();
+ else
+ _sizeof_struct_kevent = -1;
+ INITIAL_CAPACITY = 16 * _sizeof_struct_kevent;
+ }
+
+ /**
+ * Tell if kqueue-based selectors are supported on this system.
+ *
+ * @return True if this system has kqueue support, and support for it was
+ * compiled in to Classpath.
+ */
+ public static native boolean kqueue_supported();
+
+ /* Our native file descriptor. */
+ private int kq;
+
+ private HashMap/*<Integer,KqueueSelectionKeyImpl>*/ keys;
+ private HashSet/*<KqueueSelectionKeyImpl>*/ selected;
+ private Thread blockedThread;
+ private ByteBuffer events;
+
+ private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT;
+ private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
+ private static final int OP_READ = SelectionKey.OP_READ;
+ private static final int OP_WRITE = SelectionKey.OP_WRITE;
+
+ public KqueueSelectorImpl(SelectorProvider provider) throws IOException
+ {
+ super(provider);
+ kq = implOpen();
+ keys = new HashMap/*<KqueueSelectionKeyImpl>*/();
+ events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
+ }
+
+ protected void implCloseSelector() throws IOException
+ {
+ implClose(kq);
+ kq = -1;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#keys()
+ */
+ public Set keys()
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ return new HashSet(keys.values());
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select()
+ */
+ public int select() throws IOException
+ {
+ return doSelect(-1);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select(long)
+ */
+ public int select(long timeout) throws IOException
+ {
+ if (timeout == 0)
+ timeout = -1;
+ return doSelect(timeout);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectedKeys()
+ */
+ public Set selectedKeys()
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ return selected;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectNow()
+ */
+ public int selectNow() throws IOException
+ {
+ return doSelect(0);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#wakeup()
+ */
+ public Selector wakeup()
+ {
+ if (blockedThread != null)
+ blockedThread.interrupt();
+ return this;
+ }
+
+ public String toString()
+ {
+ return super.toString() + " [ fd: " + kq + " ]";
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof KqueueSelectorImpl))
+ return false;
+
+ return ((KqueueSelectorImpl) o).kq == kq;
+ }
+
+ int doSelect(long timeout) throws IOException
+ {
+ Set cancelled = cancelledKeys();
+ synchronized (cancelled)
+ {
+ synchronized (keys)
+ {
+ for (Iterator it = cancelled.iterator(); it.hasNext(); )
+ {
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+ key.interestOps = 0;
+ }
+
+ int events_size = (2 * _sizeof_struct_kevent) * keys.size();
+ int num_events = 0;
+
+ for (Iterator it = keys.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry e = (Map.Entry) it.next();
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue();
+
+ SelectableChannel ch = key.channel();
+ if (ch instanceof VMChannelOwner)
+ {
+ if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
+ {
+ // closed channel; removed from kqueue automatically.
+ it.remove();
+ continue;
+ }
+ }
+
+ // If this key is registering a read filter, add it to the buffer.
+ if (key.needCommitRead())
+ {
+ kevent_set(events, num_events, key.fd,
+ key.interestOps & (OP_READ | OP_ACCEPT),
+ key.activeOps & (OP_READ | OP_ACCEPT), key.key);
+ num_events++;
+ }
+
+ // If this key is registering a write filter, add it to the buffer.
+ if (key.needCommitWrite())
+ {
+ kevent_set(events, num_events, key.fd,
+ key.interestOps & (OP_WRITE | OP_CONNECT),
+ key.activeOps & (OP_WRITE | OP_CONNECT), key.key);
+ num_events++;
+ }
+ }
+ events.rewind().limit(events.capacity());
+
+ //System.out.println("dump of keys to select:");
+ //dump_selection_keys(events.duplicate());
+
+ int n = 0;
+ try
+ {
+ //System.out.println("[" + kq + "] kevent enter selecting from " + keys.size());
+ begin();
+ blockedThread = Thread.currentThread();
+ if (blockedThread.isInterrupted())
+ timeout = 0;
+ n = kevent(kq, events, num_events,
+ events.capacity() / _sizeof_struct_kevent, timeout);
+ }
+ finally
+ {
+ end();
+ blockedThread = null;
+ Thread.interrupted();
+ //System.out.println("[" + kq + "kevent exit selected " + n);
+ }
+
+ //System.out.println("dump of keys selected:");
+ //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * _sizeof_struct_kevent));
+
+ // Commit the operations we've just added in the call to kevent.
+ for (Iterator it = keys.values().iterator(); it.hasNext(); )
+ {
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+ key.activeOps = key.interestOps;
+ }
+
+ selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n);
+ int x = 0;
+ for (int i = 0; i < n; i++)
+ {
+ events.position(x).limit(x + _sizeof_struct_kevent);
+ x += _sizeof_struct_kevent;
+ int y = fetch_key(events.slice());
+ KqueueSelectionKeyImpl key =
+ (KqueueSelectionKeyImpl) keys.get(new Integer(y));
+
+ if (key == null)
+ {
+ System.out.println("WARNING! no key found for selected key " + y);
+ continue;
+ }
+ // Keys that have been cancelled may be returned here; don't
+ // add them to the selected set.
+ if (!key.isValid())
+ continue;
+ key.readyOps = ready_ops(events.slice(), key.interestOps);
+ selected.add(key);
+ }
+
+ // Finally, remove the cancelled keys.
+ for (Iterator it = cancelled.iterator(); it.hasNext(); )
+ {
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+ keys.remove(new Integer(key.key));
+ deregister(key);
+ it.remove();
+ }
+
+ reallocateBuffer();
+
+ return selected.size();
+ }
+ }
+ }
+
+ protected SelectionKey register(AbstractSelectableChannel channel,
+ int interestOps,
+ Object attachment)
+ {
+ int native_fd = -1;
+ try
+ {
+ if (channel instanceof VMChannelOwner)
+ native_fd = ((VMChannelOwner) channel).getVMChannel()
+ .getState().getNativeFD();
+ else
+ throw new IllegalArgumentException("cannot handle channel type " +
+ channel.getClass().getName());
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException("channel is closed or invalid");
+ }
+
+ KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel);
+ result.interestOps = interestOps;
+ result.attach(attachment);
+ result.fd = native_fd;
+ result.key = System.identityHashCode(result);
+ synchronized (keys)
+ {
+ while (keys.containsKey(new Integer(result.key)))
+ result.key++;
+ keys.put(new Integer(result.key), result);
+ reallocateBuffer();
+ }
+ return result;
+ }
+
+ void setInterestOps(KqueueSelectionKeyImpl key, int ops)
+ {
+ synchronized (keys)
+ {
+ key.interestOps = ops;
+ }
+ }
+
+ /**
+ * Reallocate the events buffer. This is the destination buffer for
+ * events returned by kevent. This method will:
+ *
+ * * Grow the buffer if there is insufficent space for all registered
+ * events.
+ * * Shrink the buffer if it is more than twice the size needed.
+ *
+ */
+ private void reallocateBuffer()
+ {
+ synchronized (keys)
+ {
+ if (events.capacity() < (2 * _sizeof_struct_kevent) * keys.size())
+ {
+ int cap = events.capacity();
+ if (cap >= MAX_DOUBLING_CAPACITY)
+ cap += CAP_INCREMENT;
+ else
+ cap = cap << 1;
+
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ else if (events.capacity() > 4 * (_sizeof_struct_kevent) * keys.size() + 1
+ && events.capacity() > INITIAL_CAPACITY)
+ {
+ int cap = events.capacity();
+ cap = cap >>> 1;
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ }
+ }
+
+ //synchronized void updateOps(KqueueSelectionKeyImpl key, int interestOps)
+ //{
+ // updateOps(key, interestOps, 0, false);
+ //}
+
+ /*void updateOps(KqueueSelectionKeyImpl key, int interestOps,
+ int activeOps, int fd)
+ {
+ //System.out.println(">> updating kqueue selection key:");
+ //dump_selection_keys(key.nstate.duplicate());
+ //System.out.println("<<");
+ synchronized (keys)
+ {
+ kevent_set(key.nstate, fd, interestOps, activeOps, key.key);
+ }
+ //System.out.println(">> updated kqueue selection key:");
+ //dump_selection_keys(key.nstate.duplicate());
+ //System.out.println("<<");
+ }*/
+
+ private void dump_selection_keys(ByteBuffer keys)
+ {
+ // WARNING! This method is not guaranteed to be portable! This works
+ // on darwin/x86, but the sizeof and offsetof these fields may be
+ // different on other platforms!
+ int i = 0;
+ keys.order(ByteOrder.nativeOrder());
+ while (keys.hasRemaining())
+ {
+ System.out.println("struct kevent { ident: "
+ + Integer.toString(keys.getInt())
+ + " filter: "
+ + Integer.toHexString(keys.getShort() & 0xFFFF)
+ + " flags: "
+ + Integer.toHexString(keys.getShort() & 0xFFFF)
+ + " fflags: "
+ + Integer.toHexString(keys.getInt())
+ + " data: "
+ + Integer.toHexString(keys.getInt())
+ + " udata: "
+ + Integer.toHexString(keys.getInt())
+ + " }");
+ }
+ }
+
+ /**
+ * Return the size of a <code>struct kevent</code> on this system.
+ *
+ * @return The size of <code>struct kevent</code>.
+ */
+ private static native int sizeof_struct_kevent();
+
+ /**
+ * Opens a kqueue descriptor.
+ *
+ * @return The new kqueue descriptor.
+ * @throws IOException If opening fails.
+ */
+ private static native int implOpen() throws IOException;
+
+ /**
+ * Closes the kqueue file descriptor.
+ *
+ * @param kq The kqueue file descriptor.
+ * @throws IOException
+ */
+ private static native void implClose(int kq) throws IOException;
+
+ /**
+ * Initialize the specified native state for the given interest ops.
+ *
+ * @param nstate The native state structures; in this buffer should be
+ * the <code>struct kevent</code>s created for a key.
+ * @param fd The file descriptor. If 0, the native FD is unmodified.
+ * @param interestOps The operations to enable.
+ * @param key A unique key that will reference the associated key later.
+ * @param delete Set to true if this event should be deleted from the
+ * kqueue (if false, this event is added/updated).
+ */
+ private static native void kevent_set(ByteBuffer nstate, int i, int fd,
+ int interestOps, int activeOps, int key);
+
+ /**
+ * Poll for events. The source events are stored in <code>events</code>,
+ * which is also where polled events will be placed.
+ *
+ * @param events The events to poll. This buffer is also the destination
+ * for events read from the queue.
+ * @param nevents The number of events to poll (that is, the number of
+ * events in the <code>events</code> buffer).
+ * @param nout The maximum number of events that may be returned.
+ * @param timeout The timeout. A timeout of -1 returns immediately; a timeout
+ * of 0 waits indefinitely.
+ * @return The number of events read.
+ */
+ private static native int kevent(int kq, ByteBuffer events, int nevents,
+ int nout, long timeout);
+
+ /**
+ * Fetch a polled key from a native state buffer. For each kevent key we
+ * create, we put the native state info (one or more <code>struct
+ * kevent</code>s) in that key's {@link KqueueSelectionKeyImpl#nstate}
+ * buffer, and place the pointer of the key in the <code>udata</code> field
+ * of that structure. This method fetches that pointer from the given
+ * buffer (assumed to be a <code>struct kqueue</code>) and returns it.
+ *
+ * @param nstate The buffer containing the <code>struct kqueue</code> to read.
+ * @return The key object.
+ */
+ private static native int fetch_key(ByteBuffer nstate);
+
+ /**
+ * Fetch the ready ops of the associated native state. That is, this
+ * inspects the first argument as a <code>struct kevent</code>, looking
+ * at its operation (the input is assumed to have been returned via a
+ * previous call to <code>kevent</code>), and translating that to the
+ * appropriate Java bit set, based on the second argument.
+ *
+ * @param nstate The native state.
+ * @param interestOps The enabled operations for the key.
+ * @return The bit set representing the ready operations.
+ */
+ private static native int ready_ops(ByteBuffer nstate, int interestOps);
+
+ /**
+ * Check if kevent returned EV_EOF for a selection key.
+ *
+ * @param nstate The native state.
+ * @return True if the kevent call returned EOF.
+ */
+ private static native boolean check_eof(ByteBuffer nstate);
+}
diff --git a/libjava/classpath/gnu/java/nio/NIOSocket.java b/libjava/classpath/gnu/java/nio/NIOSocket.java
index 4d812bf44ba..060a3a89c1c 100644
--- a/libjava/classpath/gnu/java/nio/NIOSocket.java
+++ b/libjava/classpath/gnu/java/nio/NIOSocket.java
@@ -48,30 +48,33 @@ import java.nio.channels.SocketChannel;
*/
public final class NIOSocket extends Socket
{
- private PlainSocketImpl impl;
private SocketChannelImpl channel;
- protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel)
+ protected NIOSocket (SocketChannelImpl channel)
throws IOException
{
- super (impl);
- this.impl = impl;
+ super (new NIOSocketImpl(channel));
this.channel = channel;
}
- public final PlainSocketImpl getPlainSocketImpl()
- {
- return impl;
- }
+ //public final PlainSocketImpl getPlainSocketImpl()
+ //{
+ // return impl;
+ //}
- final void setChannel (SocketChannelImpl channel)
- {
- this.impl = channel.getPlainSocketImpl();
- this.channel = channel;
- }
+ //final void setChannel (SocketChannelImpl channel)
+ //{
+ // this.impl = channel.getPlainSocketImpl();
+ // this.channel = channel;
+ //}
public final SocketChannel getChannel()
{
return channel;
}
+
+ public boolean isConnected()
+ {
+ return channel.isConnected();
+ }
}
diff --git a/libjava/classpath/gnu/java/nio/NIOSocketImpl.java b/libjava/classpath/gnu/java/nio/NIOSocketImpl.java
new file mode 100644
index 00000000000..4b26561a212
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/NIOSocketImpl.java
@@ -0,0 +1,110 @@
+/* NIOSocketImpl.java -- subclass of PlainSocketImpl for NIO.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+import gnu.java.net.PlainSocketImpl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class NIOSocketImpl extends PlainSocketImpl
+{
+
+ private final SocketChannelImpl channel;
+
+ NIOSocketImpl(SocketChannelImpl channel) throws IOException
+ {
+ this.channel = channel;
+ impl.getState().setChannelFD(channel.getVMChannel().getState());
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getInetAddress()
+ */
+ //@Override
+ protected InetAddress getInetAddress()
+ {
+ try
+ {
+ return channel.getVMChannel().getPeerAddress().getAddress();
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ catch (NullPointerException npe)
+ {
+ // Socket is not connected yet.
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getPort()
+ */
+ //@Override
+ protected int getPort()
+ {
+ try
+ {
+ return channel.getVMChannel().getPeerAddress().getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ catch (NullPointerException npe)
+ {
+ // Socket is not connected yet.
+ return -1;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.java.net.PlainSocketImpl#create(boolean)
+ */
+ //@Override
+ protected synchronized void create(boolean stream)
+ {
+ // Ignored; the socket has already been created.
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/PipeImpl.java b/libjava/classpath/gnu/java/nio/PipeImpl.java
index cccaa39885f..8a95b9622ae 100644
--- a/libjava/classpath/gnu/java/nio/PipeImpl.java
+++ b/libjava/classpath/gnu/java/nio/PipeImpl.java
@@ -46,22 +46,21 @@ import java.nio.channels.spi.SelectorProvider;
class PipeImpl extends Pipe
{
public static final class SourceChannelImpl extends Pipe.SourceChannel
+ implements VMChannelOwner
{
- private int native_fd;
private VMChannel vmch;
public SourceChannelImpl (SelectorProvider selectorProvider,
- int native_fd)
+ VMChannel channel)
{
super (selectorProvider);
- this.native_fd = native_fd;
- vmch = VMChannel.getVMChannel(this);
+ vmch = channel;
}
protected final void implCloseSelectableChannel()
throws IOException
{
- throw new Error ("Not implemented");
+ vmch.close();
}
protected void implConfigureBlocking (boolean blocking)
@@ -94,30 +93,29 @@ class PipeImpl extends Pipe
return vmch.readScattering(srcs, offset, len);
}
-
- public final int getNativeFD()
+
+ public VMChannel getVMChannel()
{
- return native_fd;
+ return vmch;
}
}
public static final class SinkChannelImpl extends Pipe.SinkChannel
+ implements VMChannelOwner
{
- private int native_fd;
private VMChannel vmch;
public SinkChannelImpl (SelectorProvider selectorProvider,
- int native_fd)
+ VMChannel channel)
{
super (selectorProvider);
- this.native_fd = native_fd;
- vmch = VMChannel.getVMChannel(this);
+ vmch = channel;
}
protected final void implCloseSelectableChannel()
throws IOException
{
- throw new Error ("Not implemented");
+ vmch.close();
}
protected final void implConfigureBlocking (boolean blocking)
@@ -149,10 +147,10 @@ class PipeImpl extends Pipe
return vmch.writeGathering(srcs, offset, len);
}
-
- public final int getNativeFD()
+
+ public VMChannel getVMChannel()
{
- return native_fd;
+ return vmch;
}
}
@@ -163,7 +161,9 @@ class PipeImpl extends Pipe
throws IOException
{
super();
- VMPipe.init (this, provider);
+ VMChannel[] pipe = VMPipe.pipe();
+ sink = new SinkChannelImpl(provider, pipe[0]);
+ source = new SourceChannelImpl(provider, pipe[1]);
}
public Pipe.SinkChannel sink()
diff --git a/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java
index 8745377c58f..c927f319644 100644
--- a/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java
+++ b/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java
@@ -106,5 +106,6 @@ public abstract class SelectionKeyImpl extends AbstractSelectionKey
return impl;
}
+ /* @deprecated */
public abstract int getNativeFD();
}
diff --git a/libjava/classpath/gnu/java/nio/SelectorImpl.java b/libjava/classpath/gnu/java/nio/SelectorImpl.java
index d0ec4871367..c08478c9968 100644
--- a/libjava/classpath/gnu/java/nio/SelectorImpl.java
+++ b/libjava/classpath/gnu/java/nio/SelectorImpl.java
@@ -54,8 +54,8 @@ import java.util.Set;
public class SelectorImpl extends AbstractSelector
{
- private Set keys;
- private Set selected;
+ private Set<SelectionKey> keys;
+ private Set<SelectionKey> selected;
/**
* A dummy object whose monitor regulates access to both our
@@ -83,8 +83,8 @@ public class SelectorImpl extends AbstractSelector
{
super (provider);
- keys = new HashSet ();
- selected = new HashSet ();
+ keys = new HashSet<SelectionKey> ();
+ selected = new HashSet<SelectionKey> ();
}
protected void finalize() throws Throwable
@@ -110,7 +110,7 @@ public class SelectorImpl extends AbstractSelector
}
}
- public final Set keys()
+ public final Set<SelectionKey> keys()
{
if (!isOpen())
throw new ClosedSelectorException();
@@ -136,7 +136,7 @@ public class SelectorImpl extends AbstractSelector
{
int[] result;
int counter = 0;
- Iterator it = keys.iterator ();
+ Iterator<SelectionKey> it = keys.iterator ();
// Count the number of file descriptors needed
while (it.hasNext ())
@@ -253,7 +253,7 @@ public class SelectorImpl extends AbstractSelector
selectThread = null;
}
- Iterator it = keys.iterator ();
+ Iterator<SelectionKey> it = keys.iterator ();
while (it.hasNext ())
{
@@ -317,7 +317,7 @@ public class SelectorImpl extends AbstractSelector
}
}
- public final Set selectedKeys()
+ public final Set<SelectionKey> selectedKeys()
{
if (!isOpen())
throw new ClosedSelectorException();
@@ -350,10 +350,10 @@ public class SelectorImpl extends AbstractSelector
private final void deregisterCancelledKeys()
{
- Set ckeys = cancelledKeys ();
+ Set<SelectionKey> ckeys = cancelledKeys ();
synchronized (ckeys)
{
- Iterator it = ckeys.iterator();
+ Iterator<SelectionKey> it = ckeys.iterator();
while (it.hasNext ())
{
diff --git a/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java
index 47521107e90..56167b69ea8 100644
--- a/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java
+++ b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java
@@ -37,6 +37,9 @@ exception statement from your version. */
package gnu.java.nio;
+
+import gnu.classpath.SystemProperties;
+
import java.io.IOException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.Pipe;
@@ -47,6 +50,11 @@ import java.nio.channels.spi.SelectorProvider;
public class SelectorProviderImpl extends SelectorProvider
{
+ private static final String SELECTOR_IMPL_KQUEUE = "kqueue";
+ private static final String SELECTOR_IMPL_EPOLL = "epoll";
+ private static final String SELECTOR_IMPL = "gnu.java.nio.selectorImpl";
+ private static boolean epoll_failed = false;
+
public SelectorProviderImpl ()
{
}
@@ -66,6 +74,35 @@ public class SelectorProviderImpl extends SelectorProvider
public AbstractSelector openSelector ()
throws IOException
{
+ String selectorImpl = "default";
+ if (KqueueSelectorImpl.kqueue_supported())
+ selectorImpl = SELECTOR_IMPL_KQUEUE;
+ if (EpollSelectorImpl.epoll_supported() && !epoll_failed)
+ selectorImpl = SELECTOR_IMPL_EPOLL;
+ selectorImpl = SystemProperties.getProperty(SELECTOR_IMPL, selectorImpl);
+
+ if (selectorImpl.equals(SELECTOR_IMPL_KQUEUE))
+ return new KqueueSelectorImpl(this);
+
+ if (selectorImpl.equals(SELECTOR_IMPL_EPOLL))
+ {
+ // We jump through these hoops because even though epoll may look
+ // like it's available (sys/epoll.h exists, and you can link against
+ // all the epoll functions) it may not be available in the kernel
+ // (especially 2.4 kernels), meaning you will get ENOSYS at run time.
+ //
+ // Madness!
+ try
+ {
+ return new EpollSelectorImpl(this);
+ }
+ catch (InternalError e)
+ {
+ // epoll_create throws this on ENOSYS.
+ epoll_failed = true;
+ }
+ }
+
return new SelectorImpl (this);
}
diff --git a/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java b/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java
index c538ea802e1..1e8e0901d7c 100644
--- a/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java
+++ b/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java
@@ -48,7 +48,9 @@ import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
public final class ServerSocketChannelImpl extends ServerSocketChannel
+ implements VMChannelOwner
{
+ private VMChannel channel;
private NIOServerSocket serverSocket;
private boolean connected;
@@ -56,13 +58,15 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
throws IOException
{
super (provider);
- serverSocket = new NIOServerSocket (this);
+ serverSocket = new NIOServerSocket(this);
+ channel = serverSocket.getPlainSocketImpl().getVMChannel();
configureBlocking(true);
}
+ // XXX do we need this?
public void finalizer()
{
- if (connected)
+ if (channel.getState().isValid())
{
try
{
@@ -77,12 +81,12 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
protected void implCloseSelectableChannel () throws IOException
{
connected = false;
- serverSocket.close();
+ channel.close();
}
protected void implConfigureBlocking (boolean blocking) throws IOException
{
- serverSocket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ channel.setBlocking(blocking);
}
public SocketChannel accept () throws IOException
@@ -98,27 +102,28 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
try
{
begin();
- serverSocket.getPlainSocketImpl().setInChannelOperation(true);
- // indicate that a channel is initiating the accept operation
- // so that the socket ignores the fact that we might be in
- // non-blocking mode.
- NIOSocket socket = (NIOSocket) serverSocket.accept();
- completed = true;
- return socket.getChannel();
- }
- catch (SocketTimeoutException e)
- {
- return null;
+ VMChannel client = channel.accept();
+ if (client == null)
+ return null;
+ else
+ {
+ completed = true;
+ return new SocketChannelImpl(provider(), client, false);
+ }
}
finally
{
- serverSocket.getPlainSocketImpl().setInChannelOperation(false);
end (completed);
}
}
- public ServerSocket socket ()
+ public ServerSocket socket()
{
return serverSocket;
}
+
+ public VMChannel getVMChannel()
+ {
+ return channel;
+ }
}
diff --git a/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java
index d00c2b7482a..5b510cb6f4d 100644
--- a/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java
+++ b/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
import java.nio.channels.spi.AbstractSelectableChannel;
public final class ServerSocketChannelSelectionKey
@@ -49,10 +50,16 @@ public final class ServerSocketChannelSelectionKey
super (channel, selector);
}
+ // FIXME don't use file descriptor integers
public int getNativeFD()
{
- NIOServerSocket socket =
- (NIOServerSocket) ((ServerSocketChannelImpl) ch).socket();
- return socket.getPlainSocketImpl().getNativeFD();
+ try
+ {
+ return ((ServerSocketChannelImpl) ch).getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalStateException(ioe);
+ }
}
}
diff --git a/libjava/classpath/gnu/java/nio/SocketChannelImpl.java b/libjava/classpath/gnu/java/nio/SocketChannelImpl.java
index 680eba2f92b..1c563ac097c 100644
--- a/libjava/classpath/gnu/java/nio/SocketChannelImpl.java
+++ b/libjava/classpath/gnu/java/nio/SocketChannelImpl.java
@@ -39,15 +39,20 @@ exception statement from your version. */
package gnu.java.nio;
import gnu.java.net.PlainSocketImpl;
+import gnu.java.net.VMPlainSocketImpl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
+import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ConnectionPendingException;
@@ -61,28 +66,57 @@ import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.channels.spi.SelectorProvider;
public final class SocketChannelImpl extends SocketChannel
+ implements VMChannelOwner
{
- private PlainSocketImpl impl;
+ private VMChannel channel;
+ //private PlainSocketImpl impl;
private NIOSocket socket;
private boolean connectionPending;
+ private boolean connected;
+ private InetSocketAddress connectAddress;
+
+ public SocketChannelImpl(boolean create) throws IOException
+ {
+ // XXX consider adding security check; this is used by
+ // PlainSocketImpl.
+ this(new SelectorProviderImpl(), create);
+ }
+
+ public SocketChannelImpl(VMChannel channel) throws IOException
+ {
+ this(new SelectorProviderImpl(), channel, false);
+ }
+
+ SocketChannelImpl(SelectorProvider provider) throws IOException
+ {
+ this(provider, true);
+ }
- SocketChannelImpl (SelectorProvider provider)
+ SocketChannelImpl(SelectorProvider provider, boolean create)
+ throws IOException
+ {
+ this(provider, new VMChannel(), create);
+ }
+
+ SocketChannelImpl(SelectorProvider provider, VMChannel channel, boolean create)
throws IOException
{
super (provider);
- impl = new PlainSocketImpl();
- socket = new NIOSocket (impl, this);
+ this.channel = channel;
+ if (create)
+ channel.initSocket(true);
+ socket = new NIOSocket(this);
configureBlocking(true);
}
- SocketChannelImpl (SelectorProvider provider,
+ /*SocketChannelImpl (SelectorProvider provider,
NIOSocket socket)
throws IOException
{
super (provider);
this.impl = socket.getPlainSocketImpl();
this.socket = socket;
- }
+ }*/
public void finalizer()
{
@@ -98,23 +132,28 @@ public final class SocketChannelImpl extends SocketChannel
}
}
- PlainSocketImpl getPlainSocketImpl()
- {
- return impl;
- }
+ //PlainSocketImpl getPlainSocketImpl()
+ //{
+ // return null; // XXX
+ //}
- protected void implCloseSelectableChannel () throws IOException
+ protected void implCloseSelectableChannel() throws IOException
{
- socket.close();
+ channel.close();
}
protected void implConfigureBlocking (boolean blocking) throws IOException
{
- socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ channel.setBlocking(blocking);
}
public boolean connect (SocketAddress remote) throws IOException
{
+ return connect(remote, 0);
+ }
+
+ public boolean connect (SocketAddress remote, int timeout) throws IOException
+ {
if (!isOpen())
throw new ClosedChannelException();
@@ -126,79 +165,52 @@ public final class SocketChannelImpl extends SocketChannel
if (!(remote instanceof InetSocketAddress))
throw new UnsupportedAddressTypeException();
+
+ connectAddress = (InetSocketAddress) remote;
- if (((InetSocketAddress) remote).isUnresolved())
+ if (connectAddress.isUnresolved())
throw new UnresolvedAddressException();
- try
- {
- socket.getPlainSocketImpl().setInChannelOperation(true);
- // indicate that a channel is initiating the accept operation
- // so that the socket ignores the fact that we might be in
- // non-blocking mode.
-
- if (isBlocking())
- {
- // Do blocking connect.
- socket.connect (remote);
- return true;
- }
-
- // Do non-blocking connect.
- try
- {
- socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
- return true;
- }
- catch (SocketTimeoutException e)
- {
- connectionPending = true;
- return false;
- }
- }
- finally
- {
- socket.getPlainSocketImpl().setInChannelOperation(false);
- }
+ connected = channel.connect(connectAddress, timeout);
+ connectionPending = !connected;
+ return connected;
}
-
- public boolean finishConnect ()
+
+ public boolean finishConnect()
throws IOException
{
if (!isOpen())
throw new ClosedChannelException();
-
- if (!isConnected() && !connectionPending)
- throw new NoConnectionPendingException();
-
- if (isConnected())
- return true;
- // FIXME: Handle blocking/non-blocking mode.
-
- Selector selector = provider().openSelector();
- register(selector, SelectionKey.OP_CONNECT);
-
- if (isBlocking())
+ InetSocketAddress remote = channel.getPeerAddress();
+ if (remote != null)
{
- selector.select(); // blocking until channel is connected.
connectionPending = false;
return true;
}
-
- int ready = selector.selectNow(); // non-blocking
- if (ready == 1)
- {
- connectionPending = false;
- return true;
- }
-
+
+ if (!connectionPending)
+ throw new NoConnectionPendingException();
+
return false;
}
- public boolean isConnected ()
+ public boolean isConnected()
{
- return socket.isConnected();
+ // Wait until finishConnect is called before transitioning to
+ // connected.
+ if (connectionPending)
+ return false;
+ try
+ {
+ InetSocketAddress remote = channel.getPeerAddress();
+ return remote != null;
+ }
+ catch (IOException ioe)
+ {
+ ioe.printStackTrace(System.out);
+ return false;
+ }
}
public boolean isConnectionPending ()
@@ -216,52 +228,7 @@ public final class SocketChannelImpl extends SocketChannel
if (!isConnected())
throw new NotYetConnectedException();
- byte[] data;
- int offset = 0;
- InputStream input = socket.getInputStream();
- int available = input.available();
- int len = dst.remaining();
-
- if ((! isBlocking()) && available == 0)
- return 0;
-
- if (dst.hasArray())
- {
- offset = dst.arrayOffset() + dst.position();
- data = dst.array();
- }
- else
- {
- data = new byte [len];
- }
-
- int readBytes = 0;
- boolean completed = false;
-
- try
- {
- begin();
- socket.getPlainSocketImpl().setInChannelOperation(true);
- readBytes = input.read (data, offset, len);
- completed = true;
- }
- finally
- {
- end (completed);
- socket.getPlainSocketImpl().setInChannelOperation(false);
- }
-
- if (readBytes > 0)
- if (dst.hasArray())
- {
- dst.position (dst.position() + readBytes);
- }
- else
- {
- dst.put (data, offset, readBytes);
- }
-
- return readBytes;
+ return channel.read(dst);
}
public long read (ByteBuffer[] dsts, int offset, int length)
@@ -275,61 +242,19 @@ public final class SocketChannelImpl extends SocketChannel
|| (length < 0)
|| (length > (dsts.length - offset)))
throw new IndexOutOfBoundsException();
-
- long readBytes = 0;
-
- for (int index = offset; index < length; index++)
- readBytes += read (dsts [index]);
-
- return readBytes;
+
+ return channel.readScattering(dsts, offset, length);
}
- public int write (ByteBuffer src)
- throws IOException
+ public int write(ByteBuffer src) throws IOException
{
if (!isConnected())
throw new NotYetConnectedException();
-
- byte[] data;
- int offset = 0;
- int len = src.remaining();
-
- if (!src.hasArray())
- {
- data = new byte [len];
- src.get (data, 0, len);
- }
- else
- {
- offset = src.arrayOffset() + src.position();
- data = src.array();
- }
- OutputStream output = socket.getOutputStream();
- boolean completed = false;
-
- try
- {
- begin();
- socket.getPlainSocketImpl().setInChannelOperation(true);
- output.write (data, offset, len);
- completed = true;
- }
- finally
- {
- end (completed);
- socket.getPlainSocketImpl().setInChannelOperation(false);
- }
-
- if (src.hasArray())
- {
- src.position (src.position() + len);
- }
-
- return len;
+ return channel.write(src);
}
- public long write (ByteBuffer[] srcs, int offset, int length)
+ public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException
{
if (!isConnected())
@@ -340,12 +265,13 @@ public final class SocketChannelImpl extends SocketChannel
|| (length < 0)
|| (length > (srcs.length - offset)))
throw new IndexOutOfBoundsException();
-
- long writtenBytes = 0;
-
- for (int index = offset; index < length; index++)
- writtenBytes += write (srcs [index]);
- return writtenBytes;
+ return channel.writeGathering(srcs, offset, length);
+ }
+
+ public VMChannel getVMChannel()
+ {
+ // XXX security check?
+ return channel;
}
}
diff --git a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java
index 75b4dfd87e5..9ceebdec90f 100644
--- a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java
+++ b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
import java.nio.channels.spi.AbstractSelectableChannel;
public final class SocketChannelSelectionKey
@@ -49,10 +50,16 @@ public final class SocketChannelSelectionKey
super (channel, selector);
}
+ // FIXME don't use file descriptor integers
public int getNativeFD()
{
- NIOSocket socket =
- (NIOSocket) ((SocketChannelImpl) ch).socket();
- return socket.getPlainSocketImpl().getNativeFD();
+ try
+ {
+ return ((SocketChannelImpl) ch).getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalStateException(ioe);
+ }
}
}
diff --git a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java
index 30fb2dfba44..31a96ed7d88 100644
--- a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java
+++ b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
+
/**
* @author Michael Barker <mike@middlesoft.co.uk>
@@ -63,7 +65,14 @@ public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl
*/
public int getNativeFD()
{
- return ch.getPlainSocketImpl().getNativeFD();
+ try
+ {
+ return ch.getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ return 0; // FIXME
+ }
}
}
diff --git a/libjava/classpath/gnu/java/nio/VMChannelOwner.java b/libjava/classpath/gnu/java/nio/VMChannelOwner.java
new file mode 100644
index 00000000000..363dea2b214
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/VMChannelOwner.java
@@ -0,0 +1,57 @@
+/* NativeFD.java -- interface for Channels that have an underlying file descriptor.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio;
+
+/**
+ * This interface is meant to be implemented by any {@link Channel}
+ * implementation we support that uses a platform-specific {@link VMChannel}
+ * at their core. This is primarily used by {@link Selector} implementations,
+ * for easier access to the native state.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+interface VMChannelOwner
+{
+ /**
+ * Return the underlying platform-specific Channel instance.
+ *
+ * @return The platform channel object.
+ */
+ VMChannel getVMChannel();
+}
diff --git a/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java b/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java
index d191c0c1717..e7580bcd79d 100644
--- a/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java
+++ b/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java
@@ -112,8 +112,10 @@ public class ActivatableRef extends UnicastRef
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException
{
- super.readExternal(in);
actId = (ActivationID) in.readObject();
+ String type = in.readUTF();
+ // XXX handle type.equals("") (null reference)
+ super.readExternal(in);
}
/**
@@ -121,8 +123,10 @@ public class ActivatableRef extends UnicastRef
*/
public void writeExternal(ObjectOutput out) throws IOException
{
- super.writeExternal(out);
out.writeObject(actId);
+ // XXX write a "" if the "nested" reference is a null reference
+ out.writeUTF("UnicastRef2");
+ super.writeExternal(out);
}
/**
diff --git a/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java b/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java
index 2e1e7805531..82f0ff69e4e 100644
--- a/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java
+++ b/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java
@@ -1,5 +1,5 @@
/* RMIClassLoaderImpl.java -- FIXME: briefly describe file purpose
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.rmi.server;
+import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
@@ -186,6 +187,7 @@ public class RMIClassLoaderImpl extends RMIClassLoaderSpi
{
defaultClassLoader = new MyClassLoader (new URL[] { defaultCodebase }, null,
defaultAnnotation);
+ // XXX using getContextClassLoader here *cannot* be right
cacheLoaders.put (new CacheKey (defaultAnnotation,
Thread.currentThread().getContextClassLoader()),
defaultClassLoader);
@@ -216,47 +218,53 @@ public class RMIClassLoaderImpl extends RMIClassLoaderSpi
ClassLoader defaultLoader)
throws MalformedURLException, ClassNotFoundException
{
- ClassLoader loader;
- if (defaultLoader == null)
- loader = Thread.currentThread().getContextClassLoader();
- else
- loader = defaultLoader;
-
- //try context class loader first
try
{
- return Class.forName(name, false, loader);
+ if (defaultLoader != null)
+ return Class.forName(name, false, defaultLoader);
}
catch (ClassNotFoundException e)
{
- // class not found in the local classpath
+ }
+
+ return Class.forName(name, false, getClassLoader(codeBase));
+ }
+
+ public Class loadProxyClass(String codeBase, String[] interfaces,
+ ClassLoader defaultLoader)
+ throws MalformedURLException, ClassNotFoundException
+ {
+ Class clss[] = new Class[interfaces.length];
+
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ clss[i] = loadClass(codeBase, interfaces[i], defaultLoader);
}
- if (codeBase.length() == 0) //==""
+ // Chain all class loaders (they may differ).
+ ArrayList loaders = new ArrayList(clss.length);
+ ClassLoader loader = null;
+ for (int i = 0; i < clss.length; i++)
{
- loader = defaultClassLoader;
+ loader = clss[i].getClassLoader();
+ if (! loaders.contains(loader))
+ {
+ loaders.add(0, loader);
+ }
}
- else
+ if (loaders.size() > 1)
{
- loader = getClassLoader(codeBase);
+ loader = new CombinedClassLoader(loaders);
}
- if (loader == null)
+ try
{
- //do not throw NullPointerException
- throw new ClassNotFoundException ("Could not find class (" + name +
- ") at codebase (" + codeBase + ")");
+ return Proxy.getProxyClass(loader, clss);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ClassNotFoundException(null, e);
}
-
- return Class.forName(name, false, loader);
- }
-
- public Class loadProxyClass(String codeBase, String[] interfaces,
- ClassLoader defaultLoader)
- throws MalformedURLException, ClassNotFoundException
- {
- // FIXME: Implement this.
- return null;
}
/**
@@ -272,6 +280,9 @@ public class RMIClassLoaderImpl extends RMIClassLoaderSpi
public ClassLoader getClassLoader(String codebase)
throws MalformedURLException
{
+ if (codebase == null || codebase.length() == 0)
+ return Thread.currentThread().getContextClassLoader();
+
ClassLoader loader;
CacheKey loaderKey = new CacheKey
(codebase, Thread.currentThread().getContextClassLoader());
diff --git a/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java b/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java
index e76535447be..75f4f120236 100644
--- a/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java
+++ b/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java
@@ -1,5 +1,5 @@
/* RMIObjectInputStream.java --
- Copyright (c) 1996, 1997, 1998, 1999, 2002, 2004
+ Copyright (c) 1996, 1997, 1998, 1999, 2002, 2004, 2006
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,11 +39,11 @@ exception statement from your version. */
package gnu.java.rmi.server;
+import gnu.classpath.VMStackWalker;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
-import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.rmi.server.RMIClassLoader;
import java.util.ArrayList;
@@ -57,16 +57,14 @@ public RMIObjectInputStream(InputStream strm) throws IOException {
}
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
- String annotation = (String)getAnnotation();
-
try {
- if(annotation == null)
- return (RMIClassLoader.loadClass(desc.getName()));
- else
- return (RMIClassLoader.loadClass(annotation, desc.getName()));
+ return RMIClassLoader.loadClass(
+ (String)getAnnotation(),
+ desc.getName(),
+ VMStackWalker.firstNonNullClassLoader());
}
- catch (MalformedURLException _) {
- throw new ClassNotFoundException(desc.getName());
+ catch (MalformedURLException x) {
+ throw new ClassNotFoundException(desc.getName(), x);
}
}
@@ -81,45 +79,16 @@ protected Object getAnnotation()
protected Class resolveProxyClass(String intfs[]) throws IOException,
ClassNotFoundException
{
- String annotation = (String) getAnnotation();
-
- Class clss[] = new Class[intfs.length];
-
- for (int i = 0; i < intfs.length; i++)
- {
- if (annotation == null)
- clss[i] = RMIClassLoader.loadClass(intfs[i]);
- else
- clss[i] = RMIClassLoader.loadClass(annotation, intfs[i]);
- }
-
- ClassLoader loader;
-
- if (clss.length > 0)
- {
- // Chain all class loaders (they may differ).
- ArrayList loaders = new ArrayList(intfs.length);
- ClassLoader cx;
- for (int i = 0; i < clss.length; i++)
- {
- cx = clss[i].getClassLoader();
- if (!loaders.contains(cx))
- {
- loaders.add(0, cx);
- }
- }
- loader = new CombinedClassLoader(loaders);
- }
- else
- loader = ClassLoader.getSystemClassLoader();
-
- try
+ try
{
- return Proxy.getProxyClass(loader, clss);
+ return RMIClassLoader.loadProxyClass(
+ (String)getAnnotation(),
+ intfs,
+ VMStackWalker.firstNonNullClassLoader());
}
- catch (IllegalArgumentException e)
+ catch (MalformedURLException x)
{
- throw new ClassNotFoundException(null, e);
+ throw new ClassNotFoundException(null, x);
}
}
diff --git a/libjava/classpath/gnu/java/security/.cvsignore b/libjava/classpath/gnu/java/security/.cvsignore
new file mode 100644
index 00000000000..11f6639ebbd
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/.cvsignore
@@ -0,0 +1 @@
+Configuration.java
diff --git a/libjava/classpath/gnu/java/security/Engine.java b/libjava/classpath/gnu/java/security/Engine.java
index c6271e3f219..44318af8ec7 100644
--- a/libjava/classpath/gnu/java/security/Engine.java
+++ b/libjava/classpath/gnu/java/security/Engine.java
@@ -79,158 +79,170 @@ public final class Engine
/** This class cannot be instantiated. */
private Engine() { }
- // Class method.
- // ------------------------------------------------------------------------
-
/**
- * Get the implementation for <i>algorithm</i> for service
- * <i>service</i> from <i>provider</i>. The service is e.g.
- * "Signature", and the algorithm "DSA".
- *
- * @param service The service name.
+ * Return the implementation for <i>algorithm</i> for service <i>service</i>
+ * from <i>provider</i>. The service is e.g. "Signature", and the algorithm
+ * "DSA".
+ *
+ * @param service The service name.
* @param algorithm The name of the algorithm to get.
- * @param provider The provider to get the implementation from.
- * @return The engine class for the specified algorithm; the object
- * returned is typically a subclass of the SPI class for that
- * service, but callers should check that this is so.
- * @throws NoSuchAlgorithmException If the implementation cannot be
- * found or cannot be instantiated.
- * @throws InvocationTargetException If the SPI class's constructor
- * throws an exception.
- * @throws IllegalArgumentException If any of the three arguments are null.
+ * @param provider The provider to get the implementation from.
+ * @return The engine class for the specified algorithm; the object returned
+ * is typically a subclass of the SPI class for that service, but
+ * callers should check that this is so.
+ * @throws NoSuchAlgorithmException If the implementation cannot be found or
+ * cannot be instantiated.
+ * @throws InvocationTargetException If the SPI class's constructor throws an
+ * exception.
+ * @throws IllegalArgumentException If any of the three arguments is null.
*/
public static Object getInstance(String service, String algorithm,
Provider provider)
- throws InvocationTargetException, NoSuchAlgorithmException
+ throws InvocationTargetException, NoSuchAlgorithmException
{
return getInstance(service, algorithm, provider, NO_ARGS);
}
/**
- * Get the implementation for <i>algorithm</i> for service
- * <i>service</i> from <i>provider</i>, passing <i>initArgs</i> to the
- * SPI class's constructor (which cannot be null; pass a zero-length
- * array if the SPI takes no arguments). The service is e.g.
- * "Signature", and the algorithm "DSA".
- *
- * @param service The service name.
+ * Return the implementation for <i>algorithm</i> for service <i>service</i>
+ * from <i>provider</i>, passing <i>initArgs</i> to the SPI class's
+ * constructor (which cannot be null; pass a zero-length array if the SPI
+ * takes no arguments). The service is e.g. "Signature", and the algorithm
+ * "DSA".
+ *
+ * @param service The service name.
* @param algorithm The name of the algorithm to get.
- * @param provider The provider to get the implementation from.
- * @param initArgs The arguments to pass to the SPI class's
- * constructor (cannot be null).
- * @return The engine class for the specified algorithm; the object
- * returned is typically a subclass of the SPI class for that
- * service, but callers should check that this is so.
- * @throws NoSuchAlgorithmException If the implementation cannot be
- * found or cannot be instantiated.
- * @throws InvocationTargetException If the SPI class's constructor
- * throws an exception.
- * @throws IllegalArgumentException If any of the four arguments are null.
+ * @param provider The provider to get the implementation from.
+ * @param initArgs The arguments to pass to the SPI class's constructor
+ * (cannot be null).
+ * @return The engine class for the specified algorithm; the object returned
+ * is typically a subclass of the SPI class for that service, but
+ * callers should check that this is so.
+ * @throws NoSuchAlgorithmException If the implementation cannot be found or
+ * cannot be instantiated.
+ * @throws InvocationTargetException If the SPI class's constructor throws an
+ * exception.
+ * @throws IllegalArgumentException If any of the four arguments is
+ * <code>null</code> or if either <code>service</code>, or
+ * <code>algorithm</code> is an empty string.
*/
public static Object getInstance(String service, String algorithm,
Provider provider, Object[] initArgs)
- throws InvocationTargetException, NoSuchAlgorithmException
+ throws InvocationTargetException, NoSuchAlgorithmException
{
- if (service != null)
- service = service.trim();
+ if (service == null)
+ throw new IllegalArgumentException("service MUST NOT be null");
+ service = service.trim();
+ if (service.length() == 0)
+ throw new IllegalArgumentException("service MUST NOT be empty");
+ if (algorithm == null)
+ throw new IllegalArgumentException("algorithm MUST NOT be null");
+ algorithm = algorithm.trim();
+ if (algorithm.length() == 0)
+ throw new IllegalArgumentException("algorithm MUST NOT be empty");
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
+ if (initArgs == null)
+ throw new IllegalArgumentException("Constructor's parameters MUST NOT be null");
- if (algorithm != null)
- algorithm = algorithm.trim();
-
- if (service == null || service.length() == 0
- || algorithm == null || algorithm.length() == 0
- || provider == null || initArgs == null)
- throw new IllegalArgumentException();
-
-
Enumeration enumer = provider.propertyNames();
String key;
String alias;
int count = 0;
boolean algorithmFound = false;
-
+ StringBuilder sb = new StringBuilder();
while (enumer.hasMoreElements())
{
key = (String) enumer.nextElement();
-
if (key.equalsIgnoreCase(service + "." + algorithm))
{
// remove the service portion from the key
algorithm = key.substring(service.length() + 1);
-
algorithmFound = true;
break;
-
}
else if (key.equalsIgnoreCase(ALG_ALIAS + service + "." + algorithm))
{
-
alias = (String) provider.getProperty(key);
-
if (! algorithm.equalsIgnoreCase(alias)) // does not refer to itself
{
algorithm = alias;
if (count++ > MAX_ALIASES)
- throw new NoSuchAlgorithmException("too many aliases");
-
+ {
+ sb.append("Algorithm [").append(algorithm)
+ .append("] of type [").append(service)
+ .append("] from provider [").append(provider)
+ .append("] has too many aliases");
+ throw new NoSuchAlgorithmException(sb.toString());
+ }
// need to reset enumeration to now look for the alias
enumer = provider.propertyNames();
}
}
}
-
+
if (! algorithmFound)
{
- throw new NoSuchAlgorithmException(algorithm);
+ sb.append("Algorithm [").append(algorithm).append("] of type [")
+ .append(service).append("] from provider [")
+ .append(provider).append("] is not found");
+ throw new NoSuchAlgorithmException(sb.toString());
}
-
-
- // Find and instantiate the implementation.
+
+ // Find and instantiate the implementation
Class clazz = null;
ClassLoader loader = provider.getClass().getClassLoader();
Constructor constructor = null;
- String error = algorithm;
-
+ String className = provider.getProperty(service + "." + algorithm);
+ sb.append("Class [").append(className).append("] for algorithm [")
+ .append(algorithm).append("] of type [").append(service)
+ .append("] from provider [").append(provider).append("] ");
+ Throwable cause = null;
try
{
if (loader != null)
- clazz = loader.loadClass(provider.getProperty(service+"."+algorithm));
+ clazz = loader.loadClass(className);
else
- clazz = Class.forName(provider.getProperty(service+"."+algorithm));
+ clazz = Class.forName(className);
constructor = getCompatibleConstructor(clazz, initArgs);
return constructor.newInstance(initArgs);
}
- catch (ClassNotFoundException cnfe)
+ catch (ClassNotFoundException x)
{
- error = "class not found: " + algorithm;
+ sb.append("cannot not be found");
+ cause = x;
}
- catch (IllegalAccessException iae)
+ catch (IllegalAccessException x)
{
- error = "illegal access: " + iae.getMessage();
+ sb.append("cannot be accessed");
+ cause = x;
}
- catch (InstantiationException ie)
+ catch (InstantiationException x)
{
- error = "instantiation exception: " + ie.getMessage();
+ sb.append("cannot be instantiated");
+ cause = x;
}
- catch (ExceptionInInitializerError eiie)
+ catch (ExceptionInInitializerError x)
{
- error = "exception in initializer: " + eiie.getMessage();
+ sb.append("cannot be initialized");
+ cause = x;
}
- catch (SecurityException se)
+ catch (SecurityException x)
{
- error = "security exception: " + se.getMessage();
+ sb.append("caused a security violation");
+ cause = x;
}
- catch (NoSuchMethodException nsme)
+ catch (NoSuchMethodException x)
{
- error = "no appropriate constructor found";
+ sb.append("does not have/expose an appropriate constructor");
+ cause = x;
}
- throw new NoSuchAlgorithmException(error);
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
- // Own methods.
- // ------------------------------------------------------------------------
-
/**
* Find a constructor in the given class that can take the specified
* argument list, allowing any of which to be null.
diff --git a/libjava/classpath/gnu/java/security/Requires.java b/libjava/classpath/gnu/java/security/Requires.java
new file mode 100644
index 00000000000..c820336c01e
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/Requires.java
@@ -0,0 +1,59 @@
+/* Requires.java -- mark methods as requiring permission.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+import java.security.Permission;
+
+/**
+ *
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+@Documented @Retention(CLASS) @Target(METHOD)
+public @interface Requires
+{
+ Class<? extends Permission> permissionClass();
+ String target();
+ String action();
+}
diff --git a/libjava/classpath/gnu/java/security/action/GetPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java
index 2886deb3474..0c8141a4d9b 100644
--- a/libjava/classpath/gnu/java/security/action/GetPropertyAction.java
+++ b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java
@@ -49,7 +49,7 @@ import java.security.PrivilegedAction;
* String port = AccessController.doPrivileged(action);
* </code>
*/
-public class GetPropertyAction implements PrivilegedAction
+public class GetPropertyAction implements PrivilegedAction<String>
{
String name;
String value = null;
@@ -68,7 +68,7 @@ public class GetPropertyAction implements PrivilegedAction
setParameters(propName, defaultValue);
}
- public Object run()
+ public String run()
{
return System.getProperty(name, value);
}
diff --git a/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java
index 97fa15d03e5..ac928ca336f 100644
--- a/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java
+++ b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java
@@ -50,7 +50,7 @@ import java.security.Security;
* String passwd = AccessController.doPrivileged(action);
* </code>
*/
-public class GetSecurityPropertyAction implements PrivilegedAction
+public class GetSecurityPropertyAction implements PrivilegedAction<String>
{
private String name;
private String value;
@@ -83,7 +83,7 @@ public class GetSecurityPropertyAction implements PrivilegedAction
return this;
}
- public Object run()
+ public String run()
{
String val = Security.getProperty(name);
if (val == null)
diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java
index c2650e6a49c..95220236617 100644
--- a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java
+++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java
@@ -81,11 +81,11 @@ public class RSAKeyPairRawCodec
* the <code>toByteArray()</code> method on the RSA parameter <code>e</code>.
* </li>
* </ol>
- *
+ *
* @param key the key to encode.
* @return the <i>Raw</i> format encoding of the designated key.
* @exception IllegalArgumentException if the designated key is not an RSA
- * one.
+ * one.
*/
public byte[] encodePublicKey(PublicKey key)
{
diff --git a/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java b/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java
new file mode 100644
index 00000000000..be4d0a98d67
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java
@@ -0,0 +1,118 @@
+/* ByteBufferOutputStream.java -- output stream with a growable underlying
+ byte buffer.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An output stream that writes bytes to a ByteBuffer, which will be resized
+ * if more space is needed.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ByteBufferOutputStream extends OutputStream
+{
+ private ByteBuffer buffer;
+
+ public ByteBufferOutputStream()
+ {
+ this(256);
+ }
+
+ public ByteBufferOutputStream(int initialCapacity)
+ {
+ buffer = ByteBuffer.allocate(initialCapacity);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#write(int)
+ */
+ public @Override synchronized void write(int b) throws IOException
+ {
+ if (!buffer.hasRemaining())
+ growBuffer();
+ buffer.put((byte) b);
+ }
+
+ public @Override synchronized void write(byte[] b, int offset, int length)
+ {
+ if (buffer.remaining() < length)
+ growBuffer();
+ buffer.put(b, offset, length);
+ }
+
+ public @Override void write(byte[] b)
+ {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Get the current state of the buffer. The returned buffer will have
+ * its position set to zero, its capacity set to the current limit,
+ * and its limit set to its capacity.
+ *
+ * @return The buffer.
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().flip()).slice();
+ }
+
+ public String toString()
+ {
+ return super.toString() + " [ buffer: " + buffer + " ]";
+ }
+
+ private void growBuffer()
+ {
+ int newCapacity = buffer.capacity();
+ if (newCapacity < 16384) // If the buffer isn't huge yet, double its size
+ newCapacity = newCapacity << 1;
+ else // Otherwize, increment by a bit.
+ newCapacity += 4096;
+ ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+ buffer.flip();
+ newBuffer.put(buffer);
+ buffer = newBuffer;
+ }
+}
diff --git a/libjava/classpath/gnu/java/util/DoubleEnumeration.java b/libjava/classpath/gnu/java/util/DoubleEnumeration.java
index 1fc37f8e0f8..94efb923d2a 100644
--- a/libjava/classpath/gnu/java/util/DoubleEnumeration.java
+++ b/libjava/classpath/gnu/java/util/DoubleEnumeration.java
@@ -1,5 +1,5 @@
/* gnu.java.util.DoubleEnumeration
- Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2001, 2004 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -63,7 +63,7 @@ import java.util.NoSuchElementException;
* @author Jochen Hoenicke
* @author Mark Wielaard (mark@klomp.org)
*/
-public class DoubleEnumeration implements Enumeration
+public class DoubleEnumeration<T> implements Enumeration<T>
{
/**
* This is true as long as one of the enumerations has more
@@ -82,17 +82,17 @@ public class DoubleEnumeration implements Enumeration
/**
* The first enumeration.
*/
- private Enumeration e1;
+ private Enumeration<T> e1;
/**
* The second enumeration.
*/
- private Enumeration e2;
+ private Enumeration<T> e2;
/**
* Creates a new Enumeration combining the given two enumerations.
* The enumerations mustn't be accessed by other classes.
*/
- public DoubleEnumeration(Enumeration e1, Enumeration e2)
+ public DoubleEnumeration(Enumeration<T> e1, Enumeration<T> e2)
{
this.e1 = e1;
this.e2 = e2;
@@ -126,7 +126,7 @@ public class DoubleEnumeration implements Enumeration
* element of the second enumeration. If both enumeration don't have
* any elements it throws a <code>NoSuchElementException</code>.
*/
- public Object nextElement()
+ public T nextElement()
{
if (!hasMoreElements())
throw new NoSuchElementException();
diff --git a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java
index 5702751cf5c..a7e2322b524 100644
--- a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java
+++ b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java
@@ -72,7 +72,6 @@ import java.util.prefs.BackingStoreException;
* <br />
*
* @author Mario Torre <neugens@limasoftware.net>
- * @version 1.0.1
*/
public class GConfBasedPreferences
extends AbstractPreferences
@@ -136,12 +135,20 @@ public class GConfBasedPreferences
absolutePath = absolutePath.substring(0, absolutePath.length() - 1);
}
+ // strip invalid characters
+ // please, note that all names are unescaped into the native peer
+ int index = absolutePath.lastIndexOf('/');
+ if (index > -1)
+ {
+ absolutePath = absolutePath.substring(0, index + 1);
+ absolutePath = absolutePath + GConfNativePeer.escapeString(name);
+ }
+
this.node = this.getRealRoot(isUser) + absolutePath;
boolean nodeExist = backend.nodeExist(this.node);
this.newNode = !nodeExist;
- backend.startWatchingNode(this.node);
}
/**
@@ -156,7 +163,15 @@ public class GConfBasedPreferences
// we don't check anything here, if the node is a new node this will be
// detected in the constructor, so we simply return a new reference to
// the requested node.
- return new GConfBasedPreferences(this, name, this.isUser);
+
+ GConfBasedPreferences preferenceNode
+ = new GConfBasedPreferences(this, name, this.isUser);
+
+ // register the node for to GConf so that it can listen
+ // events outside the scope of the application
+ backend.startWatchingNode(this.node);
+
+ return preferenceNode;
}
/**
@@ -365,6 +380,10 @@ public class GConfBasedPreferences
{
String nodeName = "";
+ // strip key
+ // please, note that all names are unescaped into the native peer
+ key = GConfNativePeer.escapeString(key);
+
if (this.node.endsWith("/"))
{
nodeName = this.node + key;
@@ -373,7 +392,7 @@ public class GConfBasedPreferences
{
nodeName = this.node + "/" + key;
}
-
+
return nodeName;
}
diff --git a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java
index f1cb6278767..6049863e916 100644
--- a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java
+++ b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java
@@ -45,7 +45,6 @@ import java.util.prefs.BackingStoreException;
* Native peer for GConf based preference backend.
*
* @author Mario Torre <neugens@limasoftware.net>
- * @version 1.0.1
*/
public final class GConfNativePeer
{
@@ -150,7 +149,7 @@ public final class GConfNativePeer
*/
public List getKeys(String node) throws BackingStoreException
{
- return gconf_client_gconf_client_all_keys(node);
+ return gconf_client_all_keys(node);
}
/**
@@ -162,10 +161,26 @@ public final class GConfNativePeer
*/
public List getChildrenNodes(String node) throws BackingStoreException
{
- return gconf_client_gconf_client_all_nodes(node);
+ return gconf_client_all_nodes(node);
}
/**
+ * Escape the given string so the it is a valid GConf name.
+ */
+ public static String escapeString(String plain)
+ {
+ return gconf_escape_key(plain);
+ }
+
+ /**
+ * Unescape a string escaped with {@link #escapeString}.
+ */
+ public static String unescapeString(String escaped)
+ {
+ return gconf_unescape_key(escaped);
+ }
+
+ /**
* Suggest to the backend GConf daemon to synch with the database.
*/
public void suggestSync() throws BackingStoreException
@@ -270,8 +285,9 @@ public final class GConfNativePeer
* Suggest to the GConf native peer a sync with the database.
*
*/
- native static final protected void gconf_client_suggest_sync();
-
+ native static final protected void gconf_client_suggest_sync()
+ throws BackingStoreException;
+
/**
* Returns a list of all nodes under the given node.
*
@@ -279,8 +295,9 @@ public final class GConfNativePeer
* @return A list of nodes under the given source node.
*/
native
- static final protected List gconf_client_gconf_client_all_nodes(String node);
-
+ static final protected List gconf_client_all_nodes(String node)
+ throws BackingStoreException;
+
/**
* Returns a list of all keys stored in the given node.
*
@@ -288,8 +305,28 @@ public final class GConfNativePeer
* @return A list of all keys stored in the given node.
*/
native
- static final protected List gconf_client_gconf_client_all_keys(String node);
+ static final protected List gconf_client_all_keys(String node)
+ throws BackingStoreException;
+ /**
+ * Escape the input String so that it's a valid element for GConf.
+ *
+ * @param plain the String to escape.
+ * @return An escaped String for use with GConf.
+ */
+ native
+ static final protected String gconf_escape_key(String plain);
+
+ /**
+ * Converts a string escaped with gconf_escape_key back into its
+ * original form.
+ *
+ * @param escaped key as returned by gconf_escape_key
+ * @return An unescaped key.
+ */
+ native
+ static final protected String gconf_unescape_key(String escaped);
+
static
{
System.loadLibrary("gconfpeer");
diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexed.java b/libjava/classpath/gnu/java/util/regex/CharIndexed.java
index 6cd857e3bc0..27e07b2f8ff 100644
--- a/libjava/classpath/gnu/java/util/regex/CharIndexed.java
+++ b/libjava/classpath/gnu/java/util/regex/CharIndexed.java
@@ -77,6 +77,13 @@ public interface CharIndexed {
boolean move(int index);
/**
+ * Shifts the input buffer by a given number of positions. Returns
+ * true if the new cursor position is valid or cursor position is at
+ * the end of input.
+ */
+ boolean move1(int index); // I cannot think of a better name for this.
+
+ /**
* Returns true if the most recent move() operation placed the cursor
* position at a valid position in the input.
*/
@@ -105,6 +112,16 @@ public interface CharIndexed {
REMatch getLastMatch();
/**
+ * Sets the information used for hitEnd().
+ */
+ void setHitEnd(REMatch match);
+
+ /**
+ * Returns whether the matcher has hit the end of input.
+ */
+ boolean hitEnd();
+
+ /**
* Returns the anchor.
*/
int getAnchor();
diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java
index 2eb753b0f5c..8a0578eb80f 100644
--- a/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java
+++ b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java
@@ -62,6 +62,10 @@ class CharIndexedCharSequence implements CharIndexed, Serializable {
return ((anchor += index) < len);
}
+ public boolean move1(int index) {
+ return ((anchor += index) <= len);
+ }
+
public CharIndexed lookBehind(int index, int length) {
if (length > (anchor + index)) length = anchor + index;
return new CharIndexedCharSequence(s, anchor + index - length);
@@ -77,6 +81,15 @@ class CharIndexedCharSequence implements CharIndexed, Serializable {
lastMatch.anchor = anchor;
}
public REMatch getLastMatch() { return lastMatch; }
+
+ private int rightmostTriedPosition = 0;
+ public void setHitEnd(REMatch match) {
+ int pos = anchor + match.index;
+ if (pos > rightmostTriedPosition) rightmostTriedPosition = pos;
+ }
+ public boolean hitEnd() { return rightmostTriedPosition >= len; }
+
public int getAnchor() { return anchor; }
public void setAnchor(int anchor) { this.anchor = anchor; }
+
}
diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java
index 77cd1abd5cc..844fada51fc 100644
--- a/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java
+++ b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java
@@ -166,6 +166,16 @@ class CharIndexedInputStream implements CharIndexed {
"difficult to support getLastMatch for an input stream");
}
+ public void setHitEnd(REMatch match) {
+ throw new UnsupportedOperationException(
+ "difficult to support setHitEnd for an input stream");
+ }
+
+ public boolean hitEnd() {
+ throw new UnsupportedOperationException(
+ "difficult to support hitEnd for an input stream");
+ }
+
public int getAnchor() {
throw new UnsupportedOperationException(
"difficult to support getAnchor for an input stream");
@@ -176,6 +186,10 @@ class CharIndexedInputStream implements CharIndexed {
"difficult to support setAnchor for an input stream");
}
+ public boolean move1(int index) {
+ throw new UnsupportedOperationException(
+ "difficult to support move1 for an input stream");
+ }
}
diff --git a/libjava/classpath/gnu/java/util/regex/RE.java b/libjava/classpath/gnu/java/util/regex/RE.java
index 1aab3b781a2..09ff74b908f 100644
--- a/libjava/classpath/gnu/java/util/regex/RE.java
+++ b/libjava/classpath/gnu/java/util/regex/RE.java
@@ -130,7 +130,11 @@ public class RE extends REToken {
private static final String VERSION = "1.1.5-dev";
// The localized strings are kept in a separate file
- private static ResourceBundle messages = PropertyResourceBundle.getBundle("gnu/java/util/regex/MessagesBundle", Locale.getDefault());
+ // Used by getLocalizedMessage().
+ private static ResourceBundle messages;
+
+ // Name of the bundle that contains the localized messages.
+ private static final String bundle = "gnu/java/util/regex/MessagesBundle";
// These are, respectively, the first and last tokens in our linked list
// If there is only one token, firstToken == lastToken
@@ -252,6 +256,13 @@ public class RE extends REToken {
*/
public static final int REG_ICASE_USASCII = 0x0800;
+ /**
+ * Execution flag.
+ * Do not move the position at which the search begins. If not set,
+ * the starting position will be moved until a match is found.
+ */
+ public static final int REG_FIX_STARTING_POSITION = 0x1000;
+
/** Returns a string representing the version of the gnu.regexp package. */
public static final String version() {
return VERSION;
@@ -259,6 +270,8 @@ public class RE extends REToken {
// Retrieves a message from the ResourceBundle
static final String getLocalizedMessage(String key) {
+ if (messages == null)
+ messages = PropertyResourceBundle.getBundle(bundle, Locale.getDefault());
return messages.getString(key);
}
@@ -1643,6 +1656,7 @@ public class RE extends REToken {
/* Implements abstract method REToken.match() */
boolean match(CharIndexed input, REMatch mymatch) {
+ input.setHitEnd(mymatch);
if (firstToken == null) {
return next(input, mymatch);
}
@@ -1720,15 +1734,23 @@ public class RE extends REToken {
REMatch getMatchImpl(CharIndexed input, int anchor, int eflags, StringBuffer buffer) {
boolean tryEntireMatch = ((eflags & REG_TRY_ENTIRE_MATCH) != 0);
+ boolean doMove = ((eflags & REG_FIX_STARTING_POSITION) == 0);
RE re = (tryEntireMatch ? (RE) this.clone() : this);
if (tryEntireMatch) {
- re.chain(new RETokenEnd(0, null));
+ RETokenEnd reEnd = new RETokenEnd(0, null);
+ reEnd.setFake(true);
+ re.chain(reEnd);
}
// Create a new REMatch to hold results
REMatch mymatch = new REMatch(numSubs, anchor, eflags);
do {
+ /* The following potimization is commented out because
+ the matching should be tried even if the length of
+ input is obviously too short in order that
+ java.util.regex.Matcher#hitEnd() may work correctly.
// Optimization: check if anchor + minimumLength > length
if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) {
+ */
if (re.match(input, mymatch)) {
REMatch best = mymatch;
// We assume that the match that coms first is the best.
@@ -1749,13 +1771,17 @@ public class RE extends REToken {
input.setLastMatch(best);
return best;
}
- }
+ /* End of the optimization commented out
+ }
+ */
mymatch.clear(++anchor);
// Append character to buffer if needed
if (buffer != null && input.charAt(0) != CharIndexed.OUT_OF_BOUNDS) {
buffer.append(input.charAt(0));
}
- } while (input.move(1));
+ // java.util.regex.Matcher#hitEnd() requires that the search should
+ // be tried at the end of input, so we use move1(1) instead of move(1)
+ } while (doMove && input.move1(1));
// Special handling at end of input for e.g. "$"
if (minimumLength == 0) {
diff --git a/libjava/classpath/gnu/java/util/regex/REMatch.java b/libjava/classpath/gnu/java/util/regex/REMatch.java
index 3ff5ad794b8..d8994829323 100644
--- a/libjava/classpath/gnu/java/util/regex/REMatch.java
+++ b/libjava/classpath/gnu/java/util/regex/REMatch.java
@@ -307,12 +307,12 @@ public final class REMatch implements Serializable, Cloneable {
}
/* The following are used for debugging purpose
- static String d(REMatch m) {
+ public static String d(REMatch m) {
if (m == null) return "null";
else return "[" + m.index + "]";
}
- String substringUptoIndex(CharIndexed input) {
+ public String substringUptoIndex(CharIndexed input) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < index; i++) {
sb.append(input.charAt(i));
diff --git a/libjava/classpath/gnu/java/util/regex/RESyntax.java b/libjava/classpath/gnu/java/util/regex/RESyntax.java
index b66b32f5878..db11e2db450 100644
--- a/libjava/classpath/gnu/java/util/regex/RESyntax.java
+++ b/libjava/classpath/gnu/java/util/regex/RESyntax.java
@@ -54,8 +54,6 @@ import java.util.BitSet;
public final class RESyntax implements Serializable {
static final String DEFAULT_LINE_SEPARATOR = System.getProperty("line.separator");
- private static final String SYNTAX_IS_FINAL = RE.getLocalizedMessage("syntax.final");
-
private BitSet bits;
// true for the constant defined syntaxes
@@ -513,7 +511,8 @@ public final class RESyntax implements Serializable {
* @return a reference to this object for easy chaining.
*/
public RESyntax set(int index) {
- if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL);
+ if (isFinal)
+ throw new IllegalAccessError(RE.getLocalizedMessage("syntax.final"));
bits.set(index);
return this;
}
@@ -525,7 +524,8 @@ public final class RESyntax implements Serializable {
* @return a reference to this object for easy chaining.
*/
public RESyntax clear(int index) {
- if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL);
+ if (isFinal)
+ throw new IllegalAccessError(RE.getLocalizedMessage("syntax.final"));
bits.clear(index);
return this;
}
@@ -548,7 +548,8 @@ public final class RESyntax implements Serializable {
* @return this object for convenient chaining
*/
public RESyntax setLineSeparator(String aSeparator) {
- if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL);
+ if (isFinal)
+ throw new IllegalAccessError(RE.getLocalizedMessage("syntax.final"));
lineSeparator = aSeparator;
return this;
}
diff --git a/libjava/classpath/gnu/java/util/regex/REToken.java b/libjava/classpath/gnu/java/util/regex/REToken.java
index 155c01878e8..9affd4ee3c9 100644
--- a/libjava/classpath/gnu/java/util/regex/REToken.java
+++ b/libjava/classpath/gnu/java/util/regex/REToken.java
@@ -72,6 +72,16 @@ abstract class REToken implements Serializable, Cloneable {
/** Returns true if the match succeeded, false if it failed. */
boolean match(CharIndexed input, REMatch mymatch) {
+ return match(input, mymatch, false);
+ }
+ boolean matchFake(CharIndexed input, REMatch mymatch) {
+ return match(input, mymatch, true);
+ }
+
+ private boolean match(CharIndexed input, REMatch mymatch, boolean fake) {
+ if (!fake) {
+ setHitEnd(input, mymatch);
+ }
REMatch m = matchThis(input, mymatch);
if (m == null) return false;
if (next(input, m)) {
@@ -81,6 +91,11 @@ abstract class REToken implements Serializable, Cloneable {
return false;
}
+ /** Sets whether the matching occurs at the end of input */
+ void setHitEnd(CharIndexed input, REMatch mymatch) {
+ input.setHitEnd(mymatch);
+ }
+
/** Returns true if the match succeeded, false if it failed.
* The matching is done against this REToken only. Chained
* tokens are not checked.
diff --git a/libjava/classpath/gnu/java/util/regex/RETokenChar.java b/libjava/classpath/gnu/java/util/regex/RETokenChar.java
index 92d3efcf85b..b70e6b1d843 100644
--- a/libjava/classpath/gnu/java/util/regex/RETokenChar.java
+++ b/libjava/classpath/gnu/java/util/regex/RETokenChar.java
@@ -58,15 +58,20 @@ final class RETokenChar extends REToken {
}
REMatch matchThis(CharIndexed input, REMatch mymatch) {
- int z = ch.length;
if (matchOneString(input, mymatch.index)) {
- mymatch.index += z;
+ mymatch.index += matchedLength;
return mymatch;
}
+ // java.util.regex.Matcher#hitEnd() requires that the length of
+ // partial match be counted.
+ mymatch.index += matchedLength;
+ input.setHitEnd(mymatch);
return null;
}
- boolean matchOneString(CharIndexed input, int index) {
+ private int matchedLength;
+ private boolean matchOneString(CharIndexed input, int index) {
+ matchedLength = 0;
int z = ch.length;
char c;
for (int i=0; i<z; i++) {
@@ -74,6 +79,7 @@ final class RETokenChar extends REToken {
if (! charEquals(c, ch[i])) {
return false;
}
+ ++matchedLength;
}
return true;
}
diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEnd.java b/libjava/classpath/gnu/java/util/regex/RETokenEnd.java
index 00efdb6a712..294e32085b5 100644
--- a/libjava/classpath/gnu/java/util/regex/RETokenEnd.java
+++ b/libjava/classpath/gnu/java/util/regex/RETokenEnd.java
@@ -45,6 +45,12 @@ final class RETokenEnd extends REToken {
private String newline;
private boolean check_java_line_terminators;
+ /**
+ * Indicates whether this token is a real one generated at compile time,
+ * or a fake one temporarily added by RE#getMatchImpl.
+ */
+ private boolean fake = false;
+
RETokenEnd(int subIndex,String newline) {
super(subIndex);
this.newline = newline;
@@ -57,10 +63,19 @@ final class RETokenEnd extends REToken {
this.check_java_line_terminators = b;
}
+ void setFake(boolean fake) {
+ this.fake = fake;
+ }
+
int getMaximumLength() {
return 0;
}
+ boolean match(CharIndexed input, REMatch mymatch) {
+ if (!fake) return super.match(input, mymatch);
+ return super.matchFake(input, mymatch);
+ }
+
REMatch matchThis(CharIndexed input, REMatch mymatch) {
char ch = input.charAt(mymatch.index);
if (ch == CharIndexed.OUT_OF_BOUNDS)
diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java b/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java
index 57a146d03b9..b3a28a3e82e 100644
--- a/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java
+++ b/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java
@@ -58,6 +58,10 @@ final class RETokenEndSub extends REToken {
return super.findMatch(input, mymatch);
}
+ void setHitEnd(CharIndexed input, REMatch mymatch) {
+ // Do nothing
+ }
+
void dump(StringBuffer os) {
// handled by RE
// But add something for debugging.
diff --git a/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java b/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java
index a286c5be8c6..aec27583a58 100644
--- a/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java
+++ b/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java
@@ -260,6 +260,14 @@ final class RETokenNamedProperty extends REToken {
return new UnicodeCategoryHandler(Character.UNASSIGNED);
if (name.equals("Lu"))
return new UnicodeCategoryHandler(Character.UPPERCASE_LETTER);
+ if (name.equals("all"))
+ return new Handler()
+ {
+ public boolean includes(char c)
+ {
+ return true;
+ }
+ };
throw new REException("unsupported name " + name, REException.REG_ESCAPE, 0);
}
diff --git a/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java b/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java
index bccc783118a..239c2201ca7 100644
--- a/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java
+++ b/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java
@@ -120,6 +120,7 @@ final class RETokenOneOf extends REToken {
}
boolean match(CharIndexed input, REMatch mymatch) {
+ setHitEnd(input, mymatch);
if (matchesOneChar) return matchOneChar(input, mymatch);
else return matchOneRE(input, mymatch);
}
diff --git a/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java b/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java
index 531c4a31124..7f5e5626f1e 100644
--- a/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java
+++ b/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java
@@ -38,8 +38,7 @@ exception statement from your version. */
package gnu.java.util.regex;
-// import java.util.Vector;
-// import java.util.Stack;
+import java.util.ArrayList;
final class RETokenRepeated extends REToken {
private REToken token;
@@ -168,19 +167,63 @@ final class RETokenRepeated extends REToken {
}
}
+ private static class FindMatchControlStack extends ArrayList {
+ private void push(FindMatchControl control) {
+ add(control);
+ }
+ private FindMatchControl pop() {
+ return (FindMatchControl)remove(size()-1);
+ }
+ private boolean empty() {
+ return isEmpty();
+ }
+ }
+
+ private static class FindMatchControl {
+ DoablesFinder finder;
+ FindMatchControl(DoablesFinder finder) {
+ this.finder = finder;
+ }
+ }
+
private REMatch findMatch(BacktrackStack stack) {
- // Avoid using recursive calls.
+ return findMatch(stack, new FindMatchControlStack());
+ }
+
+ private REMatch findMatch(BacktrackStack stack,
+ FindMatchControlStack controlStack) {
+ REMatch result = null;
+ StackedInfo si = null;
+ CharIndexed input = null;
+ int numRepeats = 0;
+ REMatch mymatch = null;
+ int[] visited = null;
+ DoablesFinder finder = null;
+
+ // Avoid using recursive calls because a match can be very long.
+
+ // This is the first entry point of this method.
+ // If you want to call this method recursively and you need the
+ // result returned, save necessary information in a FindMatchControl
+ // object and push it to controlStack, then continue from this point.
+ // You can check the result after exiting MAIN_LOOP.
+ MAIN_LOOP0:
+ while (true) {
+
+ // This is the second entry point of this method.
+ // If you want to call this method recursively but you do not need the
+ // result returned, just continue from this point.
MAIN_LOOP:
while (true) {
- if (stack.empty()) return null;
- StackedInfo si = (StackedInfo)(stack.peek());
- CharIndexed input = si.input;
- int numRepeats = si.numRepeats;
- REMatch mymatch = si.match;
- int[] visited = si.visited;
- DoablesFinder finder = si.finder;
-
+ if (stack.empty()) break MAIN_LOOP;
+ si = (StackedInfo)(stack.peek());
+ input = si.input;
+ numRepeats = si.numRepeats;
+ mymatch = si.match;
+ visited = si.visited;
+ finder = si.finder;
+
if (mymatch.backtrackStack == null)
mymatch.backtrackStack = new BacktrackStack();
@@ -192,12 +235,13 @@ final class RETokenRepeated extends REToken {
m1.backtrackStack.push(new BacktrackStack.Backtrack(
this, input, mymatch, stack));
}
- return m1;
+ result = m1;
+ break MAIN_LOOP;
}
if (stingy) {
continue MAIN_LOOP;
}
- return null;
+ break MAIN_LOOP;
}
if (finder == null) {
@@ -238,7 +282,8 @@ final class RETokenRepeated extends REToken {
m1.backtrackStack.push(new BacktrackStack.Backtrack(
this, input, mymatch, stack));
}
- return m1;
+ result = m1;
+ break MAIN_LOOP;
}
else {
continue MAIN_LOOP;
@@ -247,8 +292,82 @@ final class RETokenRepeated extends REToken {
visited = addVisited(mymatch.index, visited);
+ TryAnotherResult taresult = tryAnother(stack, input, mymatch, numRepeats, finder, visited);
+ visited = taresult.visited;
+ switch (taresult.status) {
+ case TryAnotherResult.TRY_FURTHER:
+ controlStack.push(new FindMatchControl(
+ finder));
+ continue MAIN_LOOP0;
+ case TryAnotherResult.RESULT_FOUND:
+ result = taresult.result;
+ break MAIN_LOOP;
+ }
+
+ if (!stack.empty()) {
+ stack.pop();
+ }
+ if (possessive) {
+ stack.clear();
+ }
+ REMatch m1 = matchRest(input, mymatch);
+ if (m1 != null) {
+ if (! stack.empty()) {
+ m1.backtrackStack.push(new BacktrackStack.Backtrack(
+ this, input, mymatch, stack));
+ }
+ result = m1;
+ break MAIN_LOOP;
+ }
+
+ } // MAIN_LOOP
+
+ if (controlStack.empty()) return result;
+ FindMatchControl control = controlStack.pop();
+ if (possessive) {
+ return result;
+ }
+ if (result != null) {
+ result.backtrackStack.push(new BacktrackStack.Backtrack(
+ this, input, mymatch, stack));
+ return result;
+ }
+
+ finder = control.finder;
+
+ TryAnotherResult taresult = tryAnother(stack, input, mymatch, numRepeats, finder, visited);
+ visited = taresult.visited;
+ switch (taresult.status) {
+ case TryAnotherResult.TRY_FURTHER:
+ controlStack.push(new FindMatchControl(
+ finder));
+ continue MAIN_LOOP0;
+ case TryAnotherResult.RESULT_FOUND:
+ return taresult.result;
+ }
+ continue MAIN_LOOP0;
+
+ } // MAIN_LOOP0
+ }
+
+ private static class TryAnotherResult {
+ REMatch result;
+ int status;
+ static final int RESULT_FOUND = 1;
+ static final int TRY_FURTHER = 2;
+ static final int NOTHING_FOUND = 3;
+ int[] visited;
+ }
+
+ private TryAnotherResult tryAnother(BacktrackStack stack,
+ CharIndexed input, REMatch mymatch, int numRepeats,
+ DoablesFinder finder, int[] visited) {
+
+ TryAnotherResult taresult = new TryAnotherResult();
+ taresult.visited = visited;
+
DO_THIS:
- do {
+ {
boolean emptyMatchFound = false;
@@ -263,61 +382,45 @@ final class RETokenRepeated extends REToken {
if (!emptyMatchFound) {
int n = doable.index;
- if (! visitedContains(n, visited)) {
- visited = addVisited(n, visited);
- }
- else {
+ if (visitedContains(n, visited)) {
continue DO_ONE_DOABLE;
}
+ visited = addVisited(n, visited);
stack.push(new StackedInfo(
- input, numRepeats + 1, doable, visited, null));
- REMatch m1 = findMatch(stack);
- if (possessive) {
- return m1;
- }
- if (m1 != null) {
- m1.backtrackStack.push(new BacktrackStack.Backtrack(
- this, input, mymatch, stack));
- return m1;
- }
+ input, numRepeats + 1, doable, visited, null));
+ taresult.visited = visited;
+ taresult.status = TryAnotherResult.TRY_FURTHER;
+ return taresult;
}
else {
REMatch m1 = matchRest(input, doable);
if (possessive) {
- return m1;
+ taresult.result = m1;
+ taresult.status = TryAnotherResult.RESULT_FOUND;
+ return taresult;
}
if (m1 != null) {
if (! stack.empty()) {
m1.backtrackStack.push(new BacktrackStack.Backtrack(
this, input, mymatch, stack));
- }
- return m1;
+ }
+ taresult.result = m1;
+ taresult.status = TryAnotherResult.RESULT_FOUND;
+ return taresult;
}
}
} // DO_ONE_DOABLE
- } while (false); // DO_THIS only once;
+ } // DO_THIS
- if (!stack.empty()) {
- stack.pop();
- }
- if (possessive) {
- stack.clear();
- }
- REMatch m1 = matchRest(input, mymatch);
- if (m1 != null) {
- if (! stack.empty()) {
- m1.backtrackStack.push(new BacktrackStack.Backtrack(
- this, input, mymatch, stack));
- }
- return m1;
- }
+ taresult.status = TryAnotherResult.NOTHING_FOUND;
+ return taresult;
- } // MAIN_LOOP
}
boolean match(CharIndexed input, REMatch mymatch) {
+ setHitEnd(input, mymatch);
REMatch m1 = findMatch(input, mymatch);
if (m1 != null) {
mymatch.assignFrom(m1);
diff --git a/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java
index 60504ecce85..a4adff00779 100644
--- a/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java
+++ b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java
@@ -40,6 +40,7 @@ package gnu.javax.crypto;
import gnu.classpath.debug.Component;
import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
import gnu.java.security.util.ByteArray;
import java.math.BigInteger;
@@ -53,7 +54,6 @@ import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
-import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -65,7 +65,8 @@ import javax.crypto.ShortBufferException;
public class RSACipherImpl
extends CipherSpi
{
- private static final Logger logger = SystemLogger.SYSTEM;
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+
private static final byte[] EMPTY = new byte[0];
private int opmode = -1;
private RSAPrivateKey decipherKey = null;
@@ -199,22 +200,12 @@ public class RSACipherImpl
engineUpdate(in, offset, length);
if (opmode == Cipher.DECRYPT_MODE)
{
- if (pos < dataBuffer.length)
- throw new IllegalBlockSizeException("expecting exactly "
- + dataBuffer.length + " bytes");
- BigInteger enc = new BigInteger(1, dataBuffer);
- byte[] dec = rsaDecrypt(enc);
- logger.log(Component.CRYPTO, "RSA: decryption produced\n{0}",
- new ByteArray(dec));
- if (dec[0] != 0x02)
- throw new BadPaddingException("expected padding type 2");
- int i;
- for (i = 1; i < dec.length && dec[i] != 0x00; i++)
- ; // keep incrementing i
- int len = dec.length - i - 1; // skip the 0x00 byte
- byte[] result = new byte[len];
- System.arraycopy(dec, i + 1, result, 0, len);
- pos = 0;
+ BigInteger enc = new BigInteger (1, dataBuffer);
+ byte[] dec = rsaDecrypt (enc);
+ logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}",
+ new ByteArray (dec));
+ EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey);
+ byte[] result = pkcs.decode(dec);
return result;
}
else
@@ -222,24 +213,18 @@ public class RSACipherImpl
offset = dataBuffer.length - pos;
if (offset < 3)
throw new IllegalBlockSizeException("input is too large to encrypt");
- byte[] dec = new byte[dataBuffer.length];
- dec[0] = 0x02;
+ EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey);
if (random == null)
random = new SecureRandom();
- byte[] pad = new byte[offset - 2];
- random.nextBytes(pad);
- for (int i = 0; i < pad.length; i++)
- if (pad[i] == 0)
- pad[i] = 1;
- System.arraycopy(pad, 0, dec, 1, pad.length);
- dec[dec.length - pos] = 0x00;
- System.arraycopy(dataBuffer, 0, dec, offset, pos);
- logger.log(Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
- new ByteArray(dec));
- BigInteger x = new BigInteger(1, dec);
- BigInteger y = x.modPow(encipherKey.getPublicExponent(),
- encipherKey.getModulus());
- byte[] enc = y.toByteArray();
+ byte[] em = new byte[pos];
+ System.arraycopy(dataBuffer, 0, em, 0, pos);
+ byte[] dec = pkcs.encode(em, random);
+ logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
+ new ByteArray (dec));
+ BigInteger x = new BigInteger (1, dec);
+ BigInteger y = x.modPow (encipherKey.getPublicExponent (),
+ encipherKey.getModulus ());
+ byte[] enc = y.toByteArray ();
if (enc[0] == 0x00)
{
byte[] tmp = new byte[enc.length - 1];
@@ -298,7 +283,17 @@ public class RSACipherImpl
}
BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n);
if (pubExp != null)
- dec = dec.multiply(r.modInverse(n)).mod(n);
- return dec.toByteArray();
+ {
+ dec = dec.multiply (r.modInverse (n)).mod (n);
+ }
+
+ byte[] decb = dec.toByteArray();
+ if (decb[0] != 0x00)
+ {
+ byte[] b = new byte[decb.length + 1];
+ System.arraycopy(decb, 0, b, 1, decb.length);
+ decb = b;
+ }
+ return decb;
}
}
diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java
index b7cd755f5b4..0863b1f1c88 100644
--- a/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java
+++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java
@@ -373,14 +373,24 @@ class CipherAdapter
engineInit(opmode, key, spec, random);
}
- protected byte[] engineUpdate(byte[] input, int off, int len)
+ protected byte[] engineUpdate(byte[] input, int inOff, int inLen)
{
+ if (inLen == 0) // nothing to process
+ return new byte[0];
final int blockSize = mode.currentBlockSize();
- final int count = (partLen + len) / blockSize;
- final byte[] out = new byte[count * blockSize];
+ int blockCount = (partLen + inLen) / blockSize;
+
+ // always keep data for unpadding in padded decryption mode;
+ // might even be a complete block
+ if (pad != null
+ && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION
+ && (partLen + inLen) % blockSize == 0)
+ blockCount--;
+
+ final byte[] out = new byte[blockCount * blockSize];
try
{
- engineUpdate(input, off, len, out, 0);
+ engineUpdate(input, inOff, inLen, out, 0);
}
catch (ShortBufferException x) // should not happen
{
@@ -395,7 +405,15 @@ class CipherAdapter
if (inLen == 0) // nothing to process
return 0;
final int blockSize = mode.currentBlockSize();
- final int blockCount = (partLen + inLen) / blockSize;
+ int blockCount = (partLen + inLen) / blockSize;
+
+ // always keep data for unpadding in padded decryption mode;
+ // might even be a complete block
+ if (pad != null
+ && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION
+ && (partLen + inLen) % blockSize == 0)
+ blockCount--;
+
final int result = blockCount * blockSize;
if (result > out.length - outOff)
throw new ShortBufferException();
@@ -447,16 +465,21 @@ class CipherAdapter
break;
case IMode.DECRYPTION:
int padLen;
+ byte[] buf3 = new byte[buf.length + partLen];
try
{
- padLen = pad.unpad(buf, 0, buf.length);
+ if (partLen != mode.currentBlockSize())
+ throw new WrongPaddingException();
+ System.arraycopy(buf, 0, buf3, 0, buf.length);
+ mode.update(partBlock, 0, buf3, buf.length);
+ padLen = pad.unpad(buf3, 0, buf3.length);
}
catch (WrongPaddingException wpe)
{
throw new BadPaddingException(wpe.getMessage());
}
- result = new byte[buf.length - padLen];
- System.arraycopy(buf, 0, result, 0, result.length);
+ result = new byte[buf3.length - padLen];
+ System.arraycopy(buf3, 0, result, 0, result.length);
break;
default:
throw new IllegalStateException();
diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java
new file mode 100644
index 00000000000..6f4bcb1b37e
--- /dev/null
+++ b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java
@@ -0,0 +1,95 @@
+/* GnuPBEKey.java -- A password-based encryption key.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.key;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * An implementation of a password-based encryption key.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class GnuPBEKey
+ implements PBEKey
+{
+ private final PBEKeySpec spec;
+
+ public GnuPBEKey (final PBEKeySpec spec)
+ {
+ if (spec == null)
+ throw new NullPointerException ();
+ this.spec = spec;
+ }
+
+ public GnuPBEKey (char[] password, byte[] salt, int iterationCount)
+ {
+ this (new PBEKeySpec (password, salt, iterationCount));
+ }
+
+ public int getIterationCount ()
+ {
+ return spec.getIterationCount ();
+ }
+
+ public char[] getPassword ()
+ {
+ return spec.getPassword ();
+ }
+
+ public byte[] getSalt ()
+ {
+ return spec.getSalt ();
+ }
+
+ public String getAlgorithm ()
+ {
+ return "PBE";
+ }
+
+ public String getFormat ()
+ {
+ return "NONE"; // FIXME?
+ }
+
+ public byte[] getEncoded ()
+ {
+ return null; // FIXME?
+ }
+}
diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java
index bef1784eeb3..8fce5b8b0c6 100644
--- a/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java
+++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java
@@ -100,8 +100,8 @@ public final class PKCS7
throws WrongPaddingException
{
int limit = offset + length;
- int result = in[limit - 1] & 0xFF;
- for (int i = 0; i < result; i++)
+ int result = in[--limit] & 0xFF;
+ for (int i = 0; i < result - 1; i++)
if (result != (in[--limit] & 0xFF))
throw new WrongPaddingException();
if (Configuration.DEBUG)
diff --git a/libjava/classpath/gnu/javax/management/Server.java b/libjava/classpath/gnu/javax/management/Server.java
new file mode 100644
index 00000000000..5501b4af7c0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/management/Server.java
@@ -0,0 +1,2200 @@
+/* Server.java -- A GNU Classpath management server.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.management;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.io.StreamCorruptedException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.BadAttributeValueExpException;
+import javax.management.BadBinaryOpValueExpException;
+import javax.management.BadStringOperationException;
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidApplicationException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MalformedObjectNameException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanPermission;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanTrustPermission;
+import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.StandardMBean;
+
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * This class provides an {@link javax.management.MBeanServer}
+ * implementation for GNU Classpath.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class Server
+ implements MBeanServer
+{
+
+ /**
+ * The name of the delegate bean.
+ */
+ private static final ObjectName DELEGATE_NAME;
+
+ /**
+ * The registered beans, represented as a map of
+ * {@link javax.management.ObjectName}s to
+ * {@link java.lang.Object}s.
+ */
+ private final Map beans = new HashMap();
+
+ /**
+ * The default domain.
+ */
+ private String defaultDomain;
+
+ /**
+ * The outer server.
+ */
+ private MBeanServer outer;
+
+ /**
+ * The class loader repository.
+ */
+ private ClassLoaderRepository repository;
+
+ /**
+ * The map of listener delegates to the true
+ * listener.
+ */
+ private Map listeners;
+
+ /**
+ * Initialise the delegate name.
+ */
+ static
+ {
+ try
+ {
+ DELEGATE_NAME =
+ new ObjectName("JMImplementation:type=MBeanServerDelegate");
+ }
+ catch (MalformedObjectNameException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to construct " +
+ "the delegate's object name.").initCause(e));
+ }
+ }
+
+ /**
+ * Constructs a new management server using the specified
+ * default domain, delegate bean and outer server.
+ *
+ * @param domain the default domain to use for beans constructed
+ * with no specified domain.
+ * @param outer an {@link javax.management.MBeanServer} to pass
+ * to beans implementing the {@link MBeanRegistration}
+ * interface, or <code>null</code> if <code>this</code>
+ * should be passed.
+ * @param delegate the delegate bean for this server.
+ */
+ public Server(String defaultDomain, MBeanServer outer,
+ MBeanServerDelegate delegate)
+ {
+ this.defaultDomain = defaultDomain;
+ this.outer = outer;
+ try
+ {
+ registerMBean(delegate, DELEGATE_NAME);
+ }
+ catch (InstanceAlreadyExistsException e)
+ {
+ throw (Error)
+ (new InternalError("The delegate bean is " +
+ "already registered.").initCause(e));
+ }
+ catch (MBeanRegistrationException e)
+ {
+ throw (Error)
+ (new InternalError("The delegate bean's preRegister " +
+ "methods threw an exception.").initCause(e));
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("The delegate bean is " +
+ "not compliant.").initCause(e));
+ }
+ }
+
+ /**
+ * Checks for the necessary security privileges to perform an
+ * operation.
+ *
+ * @param name the name of the bean being accessed.
+ * @param member the name of the operation or attribute being
+ * accessed, or <code>null</code> if one is not
+ * involved.
+ * @param action the action being performed.
+ * @throws SecurityException if the action is denied.
+ */
+ private void checkSecurity(ObjectName name, String member,
+ String action)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ try
+ {
+ MBeanInfo info = null;
+ if (name != null)
+ {
+ Object bean = getBean(name);
+ Method method = bean.getClass().getMethod("getMBeanInfo", null);
+ info = (MBeanInfo) method.invoke(bean, null);
+ }
+ sm.checkPermission(new MBeanPermission((info == null) ?
+ null : info.getClassName(),
+ member, name, action));
+ }
+ catch (InstanceNotFoundException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to get bean.").initCause(e));
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to get bean info.").initCause(e));
+ }
+ catch (IllegalAccessException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to get bean info.").initCause(e));
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to get bean info.").initCause(e));
+ }
+ catch (InvocationTargetException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to get bean info.").initCause(e));
+ }
+ }
+
+ /**
+ * Retrieves the specified bean.
+ *
+ * @param name the name of the bean.
+ * @return the bean.
+ * @throws InstanceNotFoundException if the name of the management bean
+ * could not be resolved.
+ */
+ private Object getBean(ObjectName name)
+ throws InstanceNotFoundException
+ {
+ ServerInfo bean = (ServerInfo) beans.get(name);
+ if (bean == null)
+ throw new InstanceNotFoundException("The bean, " + name +
+ ", was not found.");
+ return bean.getObject();
+ }
+
+ /**
+ * Registers the supplied listener with the specified management
+ * bean. Notifications emitted by the management bean are forwarded
+ * to the listener via the server, which will convert an MBean
+ * references in the source to a portable {@link ObjectName}
+ * instance. The notification is otherwise unchanged.
+ *
+ * @param name the name of the management bean with which the listener
+ * should be registered.
+ * @param listener the listener which will handle notifications from
+ * the bean.
+ * @param filter the filter to apply to incoming notifications, or
+ * <code>null</code> if no filtering should be applied.
+ * @param passback an object to be passed to the listener when a
+ * notification is emitted.
+ * @throws InstanceNotFoundException if the name of the management bean
+ * could not be resolved.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "addNotificationListener")</code>}.
+ * @see #removeNotificationListener(ObjectName, NotificationListener)
+ * @see #removeNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object)
+ * @see NotificationBroadcaster#addNotificationListener(NotificationListener,
+ * NotificationFilter,
+ * Object)
+ */
+ public void addNotificationListener(ObjectName name, NotificationListener listener,
+ NotificationFilter filter, Object passback)
+ throws InstanceNotFoundException
+ {
+ Object bean = getBean(name);
+ checkSecurity(name, null, "addNotificationListener");
+ if (bean instanceof NotificationBroadcaster)
+ {
+ NotificationBroadcaster bbean = (NotificationBroadcaster) bean;
+ if (listeners == null)
+ listeners = new HashMap();
+ NotificationListener indirection = new ServerNotificationListener(bean, name,
+ listener);
+ bbean.addNotificationListener(indirection, filter, passback);
+ listeners.put(listener, indirection);
+ }
+ }
+
+ /**
+ * <p>
+ * Registers the supplied listener with the specified management
+ * bean. Notifications emitted by the management bean are forwarded
+ * to the listener via the server, which will convert any MBean
+ * references in the source to portable {@link ObjectName}
+ * instances. The notification is otherwise unchanged.
+ * </p>
+ * <p>
+ * The listener that receives notifications will be the one that is
+ * registered with the given name at the time this method is called.
+ * Even if it later unregisters and ceases to use that name, it will
+ * still receive notifications.
+ * </p>
+ *
+ * @param name the name of the management bean with which the listener
+ * should be registered.
+ * @param listener the name of the listener which will handle
+ * notifications from the bean.
+ * @param filter the filter to apply to incoming notifications, or
+ * <code>null</code> if no filtering should be applied.
+ * @param passback an object to be passed to the listener when a
+ * notification is emitted.
+ * @throws InstanceNotFoundException if the name of the management bean
+ * could not be resolved.
+ * @throws RuntimeOperationsException if the bean associated with the given
+ * object name is not a
+ * {@link NotificationListener}. This
+ * exception wraps an
+ * {@link IllegalArgumentException}.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "addNotificationListener")</code>}.
+ * @see #removeNotificationListener(ObjectName, NotificationListener)
+ * @see #removeNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object)
+ * @see NotificationBroadcaster#addNotificationListener(NotificationListener,
+ * NotificationFilter,
+ * Object)
+ */
+ public void addNotificationListener(ObjectName name, ObjectName listener,
+ NotificationFilter filter, Object passback)
+ throws InstanceNotFoundException
+ {
+ Object lbean = getBean(listener);
+ if (!(lbean instanceof NotificationListener))
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The supplied listener name does not " +
+ "correspond to a notification listener.");
+ throw new RuntimeOperationsException(e);
+ }
+ addNotificationListener(name, ((NotificationListener) lbean), filter, passback);
+ }
+
+ /**
+ * <p>
+ * Instantiates a new instance of the specified management bean
+ * using the default constructor and registers it with the server
+ * under the supplied name. The class is loaded using the
+ * {@link javax.management.loading.ClassLoaderRepository default
+ * loader repository} of the server.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, then the bean is
+ * expected to implement the {@link MBeanRegistration} interface.
+ * The {@link MBeanRegistration#preRegister preRegister} method
+ * of this interface will be used to obtain the name in this case.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #createMBean(String, ObjectName, Object[], String[])
+ * <code>createMBean(className, name, (Object[]) null,
+ * (String[]) null)</code>} with <code>null</code> parameters
+ * and signature.
+ * </p>
+ *
+ * @param className the class of the management bean, of which
+ * an instance should be created.
+ * @param name the name to register the new bean with.
+ * @return an {@link ObjectInstance} containing the {@link ObjectName}
+ * and Java class name of the created instance.
+ * @throws ReflectionException if an exception occurs in creating
+ * an instance of the bean.
+ * @throws InstanceAlreadyExistsException if a matching instance
+ * already exists.
+ * @throws MBeanRegistrationException if an exception occurs in
+ * calling the preRegister
+ * method.
+ * @throws MBeanException if the bean's constructor throws an exception.
+ * @throws NotCompliantMBeanException if the created bean is not
+ * compliant with the JMX specification.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> class name or object
+ * name or if the object name is a pattern.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply the
+ * use of the <code>instantiate</code>
+ * and <code>registerMBean</code> methods.
+ * @see #createMBean(String, ObjectName, Object[], String[])
+ */
+ public ObjectInstance createMBean(String className, ObjectName name)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException
+ {
+ return createMBean(className, name, (Object[]) null, (String[]) null);
+ }
+
+ /**
+ * <p>
+ * Instantiates a new instance of the specified management bean
+ * using the given constructor and registers it with the server
+ * under the supplied name. The class is loaded using the
+ * {@link javax.management.loading.ClassLoaderRepository default
+ * loader repository} of the server.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, then the bean is
+ * expected to implement the {@link MBeanRegistration} interface.
+ * The {@link MBeanRegistration#preRegister preRegister} method
+ * of this interface will be used to obtain the name in this case.
+ * </p>
+ *
+ * @param className the class of the management bean, of which
+ * an instance should be created.
+ * @param name the name to register the new bean with.
+ * @param params the parameters for the bean's constructor.
+ * @param sig the signature of the constructor to use.
+ * @return an {@link ObjectInstance} containing the {@link ObjectName}
+ * and Java class name of the created instance.
+ * @throws ReflectionException if an exception occurs in creating
+ * an instance of the bean.
+ * @throws InstanceAlreadyExistsException if a matching instance
+ * already exists.
+ * @throws MBeanRegistrationException if an exception occurs in
+ * calling the preRegister
+ * method.
+ * @throws MBeanException if the bean's constructor throws an exception.
+ * @throws NotCompliantMBeanException if the created bean is not
+ * compliant with the JMX specification.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> class name or object
+ * name or if the object name is a pattern.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply the
+ * use of the <code>instantiate</code>
+ * and <code>registerMBean</code> methods.
+ */
+ public ObjectInstance createMBean(String className, ObjectName name,
+ Object[] params, String[] sig)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException
+ {
+ return registerMBean(instantiate(className, params, sig), name);
+ }
+
+ /**
+ * <p>
+ * Instantiates a new instance of the specified management bean
+ * using the default constructor and registers it with the server
+ * under the supplied name. The class is loaded using the
+ * given class loader. If this argument is <code>null</code>,
+ * then the same class loader as was used to load the server
+ * is used.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, then the bean is
+ * expected to implement the {@link MBeanRegistration} interface.
+ * The {@link MBeanRegistration#preRegister preRegister} method
+ * of this interface will be used to obtain the name in this case.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #createMBean(String, ObjectName, ObjectName, Object[], String)
+ * <code>createMBean(className, name, loaderName, (Object[]) null,
+ * (String) null)</code>} with <code>null</code> parameters
+ * and signature.
+ * </p>
+ *
+ * @param className the class of the management bean, of which
+ * an instance should be created.
+ * @param name the name to register the new bean with.
+ * @param loaderName the name of the class loader.
+ * @return an {@link ObjectInstance} containing the {@link ObjectName}
+ * and Java class name of the created instance.
+ * @throws ReflectionException if an exception occurs in creating
+ * an instance of the bean.
+ * @throws InstanceAlreadyExistsException if a matching instance
+ * already exists.
+ * @throws MBeanRegistrationException if an exception occurs in
+ * calling the preRegister
+ * method.
+ * @throws MBeanException if the bean's constructor throws an exception.
+ * @throws NotCompliantMBeanException if the created bean is not
+ * compliant with the JMX specification.
+ * @throws InstanceNotFoundException if the specified class loader is not
+ * registered with the server.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> class name or object
+ * name or if the object name is a pattern.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply the
+ * use of the <code>instantiate</code>
+ * and <code>registerMBean</code> methods.
+ * @see #createMBean(String, ObjectName, ObjectName, Object[], String[])
+ */
+ public ObjectInstance createMBean(String className, ObjectName name,
+ ObjectName loaderName)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException
+ {
+ return createMBean(className, name, loaderName, (Object[]) null,
+ (String[]) null);
+ }
+
+ /**
+ * <p>
+ * Instantiates a new instance of the specified management bean
+ * using the given constructor and registers it with the server
+ * under the supplied name. The class is loaded using the
+ * given class loader. If this argument is <code>null</code>,
+ * then the same class loader as was used to load the server
+ * is used.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, then the bean is
+ * expected to implement the {@link MBeanRegistration} interface.
+ * The {@link MBeanRegistration#preRegister preRegister} method
+ * of this interface will be used to obtain the name in this case.
+ * </p>
+ *
+ * @param className the class of the management bean, of which
+ * an instance should be created.
+ * @param name the name to register the new bean with.
+ * @param loaderName the name of the class loader.
+ * @param params the parameters for the bean's constructor.
+ * @param sig the signature of the constructor to use.
+ * @return an {@link ObjectInstance} containing the {@link ObjectName}
+ * and Java class name of the created instance.
+ * @throws ReflectionException if an exception occurs in creating
+ * an instance of the bean.
+ * @throws InstanceAlreadyExistsException if a matching instance
+ * already exists.
+ * @throws MBeanRegistrationException if an exception occurs in
+ * calling the preRegister
+ * method.
+ * @throws MBeanException if the bean's constructor throws an exception.
+ * @throws NotCompliantMBeanException if the created bean is not
+ * compliant with the JMX specification.
+ * @throws InstanceNotFoundException if the specified class loader is not
+ * registered with the server.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> class name or object
+ * name or if the object name is a pattern.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply the
+ * use of the <code>instantiate</code>
+ * and <code>registerMBean</code> methods.
+ */
+ public ObjectInstance createMBean(String className, ObjectName name,
+ ObjectName loaderName, Object[] params,
+ String[] sig)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException
+ {
+ return registerMBean(instantiate(className, loaderName, params, sig),
+ name);
+ }
+
+ /**
+ * Deserializes a byte array using the class loader of the specified
+ * management bean as its context.
+ *
+ * @param name the name of the bean whose class loader should be used.
+ * @param data the byte array to be deserialized.
+ * @return the deserialized object stream.
+ * @deprecated {@link #getClassLoaderFor(ObjectName)} should be used
+ * to obtain the class loader of the bean, which can then
+ * be used to perform deserialization in the user's code.
+ * @throws InstanceNotFoundException if the specified bean is not
+ * registered with the server.
+ * @throws OperationsException if any I/O error is thrown by the
+ * deserialization process.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "getClassLoaderFor")</code>
+ */
+ public ObjectInputStream deserialize(ObjectName name, byte[] data)
+ throws InstanceNotFoundException, OperationsException
+ {
+ try
+ {
+ return new ServerInputStream(new ByteArrayInputStream(data),
+ getClassLoaderFor(name));
+ }
+ catch (IOException e)
+ {
+ throw new OperationsException("An I/O error occurred: " + e);
+ }
+ }
+
+ /**
+ * Deserializes a byte array using the same class loader for its context
+ * as was used to load the given class. This class loader is obtained by
+ * loading the specified class using the {@link
+ * javax.management.loading.ClassLoaderRepository Class Loader Repository}
+ * and then using the class loader of the resulting {@link Class} instance.
+ *
+ * @param name the name of the class which should be loaded to obtain the
+ * class loader.
+ * @param data the byte array to be deserialized.
+ * @return the deserialized object stream.
+ * @deprecated {@link #getClassLoaderRepository} should be used
+ * to obtain the class loading repository, which can then
+ * be used to obtain the {@link Class} instance and deserialize
+ * the array using its class loader.
+ * @throws OperationsException if any I/O error is thrown by the
+ * deserialization process.
+ * @throws ReflectionException if an error occurs in obtaining the
+ * {@link Class} instance.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null, null,
+ * "getClassLoaderRepository")</code>
+ */
+ public ObjectInputStream deserialize(String name, byte[] data)
+ throws OperationsException, ReflectionException
+ {
+ try
+ {
+ Class c = getClassLoaderRepository().loadClass(name);
+ return new ServerInputStream(new ByteArrayInputStream(data),
+ c.getClassLoader());
+ }
+ catch (IOException e)
+ {
+ throw new OperationsException("An I/O error occurred: " + e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new ReflectionException(e, "The class could not be found.");
+ }
+ }
+
+ /**
+ * Deserializes a byte array using the same class loader for its context
+ * as was used to load the given class. The name of the class loader to
+ * be used is supplied, and may be <code>null</code> if the server's
+ * class loader should be used instead.
+ *
+ * @param name the name of the class which should be loaded to obtain the
+ * class loader.
+ * @param loader the name of the class loader to use, or <code>null</code>
+ * if the class loader of the server should be used.
+ * @param data the byte array to be deserialized.
+ * @return the deserialized object stream.
+ * @deprecated {@link #getClassLoader(ObjectName} can be used to obtain
+ * the named class loader and deserialize the array.
+ * @throws InstanceNotFoundException if the specified class loader is not
+ * registered with the server.
+ * @throws OperationsException if any I/O error is thrown by the
+ * deserialization process.
+ * @throws ReflectionException if an error occurs in obtaining the
+ * {@link Class} instance.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, loader,
+ * "getClassLoader")</code>
+ */
+ public ObjectInputStream deserialize(String name, ObjectName loader, byte[] data)
+ throws InstanceNotFoundException, ReflectionException,
+ OperationsException
+ {
+ try
+ {
+ Class c = getClassLoader(loader).loadClass(name);
+ return new ServerInputStream(new ByteArrayInputStream(data),
+ c.getClassLoader());
+ }
+ catch (IOException e)
+ {
+ throw new OperationsException("An I/O error occurred: " + e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new ReflectionException(e, "The class could not be found.");
+ }
+ }
+
+ /**
+ * Returns the value of the supplied attribute from the specified
+ * management bean.
+ *
+ * @param bean the bean to retrieve the value from.
+ * @param name the name of the attribute to retrieve.
+ * @return the value of the attribute.
+ * @throws AttributeNotFoundException if the attribute could not be
+ * accessed from the bean.
+ * @throws MBeanException if the management bean's accessor throws
+ * an exception.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws ReflectionException if an exception was thrown in trying
+ * to invoke the bean's accessor.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> bean or attribute
+ * name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, name, bean,
+ * "getAttribute")</code>}.
+ * @see DynamicMBean#getAttribute(String)
+ */
+ public Object getAttribute(ObjectName bean, String name)
+ throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException
+ {
+ if (bean == null || name == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("One of the supplied arguments was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ Object abean = getBean(bean);
+ checkSecurity(bean, name, "getAttribute");
+ if (abean instanceof DynamicMBean)
+ return ((DynamicMBean) abean).getAttribute(name);
+ else
+ try
+ {
+ return new StandardMBean(abean, null).getAttribute(name);
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to create dynamic bean.").initCause(e));
+ }
+ }
+
+
+ /**
+ * Returns the values of the named attributes from the specified
+ * management bean.
+ *
+ * @param bean the bean to retrieve the value from.
+ * @param names the names of the attributes to retrieve.
+ * @return the values of the attributes.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws ReflectionException if an exception was thrown in trying
+ * to invoke the bean's accessor.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> bean or attribute
+ * name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, bean,
+ * "getAttribute")</code>}. Additionally,
+ * for an attribute name, <code>n</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, n, bean,
+ * "getAttribute")</code>} or that attribute will
+ * not be included.
+ *
+ * @see DynamicMBean#getAttributes(String[])
+ */
+ public AttributeList getAttributes(ObjectName bean, String[] names)
+ throws InstanceNotFoundException, ReflectionException
+ {
+ if (bean == null || names == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("One of the supplied arguments was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ Object abean = getBean(bean);
+ checkSecurity(bean, null, "getAttribute");
+ AttributeList list = new AttributeList(names.length);
+ for (int a = 0; a < names.length; ++a)
+ {
+ if (names[a] == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("Argument " + a + " was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ checkSecurity(bean, names[a], "getAttribute");
+ try
+ {
+ Object value;
+ if (abean instanceof DynamicMBean)
+ value = ((DynamicMBean) abean).getAttribute(names[a]);
+ else
+ try
+ {
+ value = new StandardMBean(abean, null).getAttribute(names[a]);
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to create dynamic bean.").initCause(e));
+ }
+ list.add(new Attribute(names[a], value));
+ }
+ catch (AttributeNotFoundException e)
+ {
+ /* Ignored */
+ }
+ catch (MBeanException e)
+ {
+ /* Ignored */
+ }
+ }
+ return list;
+ }
+
+
+ /**
+ * Returns the specified class loader. If the specified value is
+ * <code>null</code>, then the class loader of the server will be
+ * returned. If <code>l</code> is the requested class loader,
+ * and <code>r</code> is the actual class loader returned, then
+ * either <code>l</code> and <code>r</code> will be identical,
+ * or they will at least return the same class from
+ * {@link ClassLoader#loadClass(String)} for any given string.
+ * They may not be identical due to one or the other
+ * being wrapped in another class loader (e.g. for security).
+ *
+ * @param name the name of the class loader to return.
+ * @return the class loader.
+ * @throws InstanceNotFoundException if the class loader can not
+ * be found.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "getClassLoader")</code>
+ */
+ public ClassLoader getClassLoader(ObjectName name)
+ throws InstanceNotFoundException
+ {
+ if (name == null)
+ {
+ checkSecurity(null, null, "getClassLoader");
+ return getClass().getClassLoader();
+ }
+ Object bean = getBean(name);
+ checkSecurity(name, null, "getClassLoader");
+ return (ClassLoader) bean;
+ }
+
+ /**
+ * Returns the class loader of the specified management bean. If
+ * <code>l</code> is the requested class loader, and <code>r</code>
+ * is the actual class loader returned, then either <code>l</code>
+ * and <code>r</code> will be identical, or they will at least
+ * return the same class from {@link ClassLoader#loadClass(String)}
+ * for any given string. They may not be identical due to one or
+ * the other being wrapped in another class loader (e.g. for
+ * security).
+ *
+ * @param name the name of the bean whose class loader should be
+ * returned.
+ * @return the class loader.
+ * @throws InstanceNotFoundException if the bean is not registered
+ * with the server.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "getClassLoaderFor")</code>
+ */
+ public ClassLoader getClassLoaderFor(ObjectName name)
+ throws InstanceNotFoundException
+ {
+ Object bean = getBean(name);
+ checkSecurity(name, null, "getClassLoaderFor");
+ return bean.getClass().getClassLoader();
+ }
+
+ /**
+ * Returns the class loader repository used by this server.
+ *
+ * @return the class loader repository.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null, null,
+ * "getClassLoaderRepository")</code>
+ */
+ public ClassLoaderRepository getClassLoaderRepository()
+ {
+ return repository;
+ }
+
+ /**
+ * Returns the default domain this server applies to beans that have
+ * no specified domain.
+ *
+ * @return the default domain.
+ */
+ public String getDefaultDomain()
+ {
+ return defaultDomain;
+ }
+
+
+ /**
+ * Returns an array containing all the domains used by beans registered
+ * with this server. The ordering of the array is undefined.
+ *
+ * @return the list of domains.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null, name,
+ * "getDomains")</code>}. Additionally,
+ * for an domain, <code>d</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null,
+ * new ObjectName("d:x=x"), "getDomains")</code>}
+ * or that domain will not be included. Note
+ * that "x=x" is an arbitrary key-value pair
+ * provided to satisfy the constructor.
+ * @see ObjectName#getDomain()
+ */
+ public String[] getDomains()
+ {
+ checkSecurity(null, null, "getDomains");
+ Set domains = new HashSet();
+ Iterator iterator = beans.keySet().iterator();
+ while (iterator.hasNext())
+ {
+ String d = ((ObjectName) iterator.next()).getDomain();
+ try
+ {
+ checkSecurity(new ObjectName(d + ":x=x"), null, "getDomains");
+ domains.add(d);
+ }
+ catch (MalformedObjectNameException e)
+ {
+ /* Ignored */
+ }
+ }
+ return (String[]) domains.toArray(new String[domains.size()]);
+ }
+
+ /**
+ * Returns the number of management beans registered with this server.
+ * This may be less than the real number if the caller's access is
+ * restricted.
+ *
+ * @return the number of registered beans.
+ */
+ public Integer getMBeanCount()
+ {
+ return Integer.valueOf(beans.size());
+ }
+
+ /**
+ * Returns information on the given management bean.
+ *
+ * @param name the name of the management bean.
+ * @return an instance of {@link MBeanInfo} for the bean.
+ * @throws IntrospectionException if an exception occurs in examining
+ * the bean.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws ReflectionException if an exception occurs when trying
+ * to invoke {@link DynamicMBean#getMBeanInfo()}
+ * on the bean.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "getMBeanInfo")</code>}.
+ * @see DynamicMBean#getMBeanInfo()
+ */
+ public MBeanInfo getMBeanInfo(ObjectName name)
+ throws InstanceNotFoundException, IntrospectionException,
+ ReflectionException
+ {
+ Object bean = getBean(name);
+ checkSecurity(name, null, "getMBeanInfo");
+ try
+ {
+ Method method = bean.getClass().getMethod("getMBeanInfo", null);
+ return (MBeanInfo) method.invoke(bean, null);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new IntrospectionException("The getMBeanInfo method " +
+ "could not be found.");
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ReflectionException(e, "Failed to call getMBeanInfo");
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ReflectionException(e, "Failed to call getMBeanInfo");
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new ReflectionException(e, "The method threw an exception");
+ }
+ }
+
+ /**
+ * Returns the {@link ObjectInstance} created for the specified
+ * management bean on registration.
+ *
+ * @param name the name of the bean.
+ * @return the corresponding {@link ObjectInstance} instance.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "getObjectInstance")</code>
+ * @see #createMBean(String, ObjectName)
+ */
+ public ObjectInstance getObjectInstance(ObjectName name)
+ throws InstanceNotFoundException
+ {
+ ServerInfo bean = (ServerInfo) beans.get(name);
+ if (bean == null)
+ throw new InstanceNotFoundException("The bean, " + name +
+ ", was not found.");
+ return bean.getInstance();
+ }
+
+ /**
+ * <p>
+ * Creates an instance of the specified class using the list of
+ * class loaders from the {@link
+ * javax.management.loading.ClassLoaderRepository Class Loader
+ * Repository}. The class should have a public constructor
+ * with no arguments. A reference to the new instance is returned,
+ * but the instance is not yet registered with the server.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #instantiate(String, Object[], String[])
+ * <code>instantiate(name, (Object[]) null, (String[]) null)</code>}
+ * with <code>null</code> parameters and signature.
+ * </p>
+ *
+ * @param name the name of the class of bean to be instantiated.
+ * @return an instance of the given class.
+ * @throws ReflectionException if an exception is thrown during
+ * loading the class or calling the
+ * constructor.
+ * @throws MBeanException if the constructor throws an exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ * @see #instantiate(String, Object[], String[])
+ */
+ public Object instantiate(String name)
+ throws ReflectionException, MBeanException
+ {
+ return instantiate(name, (Object[]) null, (String[]) null);
+ }
+
+ /**
+ * Creates an instance of the specified class using the list of
+ * class loaders from the {@link
+ * javax.management.loading.ClassLoaderRepository Class Loader
+ * Repository}. The class should have a public constructor
+ * matching the supplied signature. A reference to the new
+ * instance is returned, but the instance is not yet
+ * registered with the server.
+ *
+ * @param name the name of the class of bean to be instantiated.
+ * @param params the parameters for the constructor.
+ * @param sig the signature of the constructor.
+ * @return an instance of the given class.
+ * @throws ReflectionException if an exception is thrown during
+ * loading the class or calling the
+ * constructor.
+ * @throws MBeanException if the constructor throws an exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ */
+ public Object instantiate(String name, Object[] params, String[] sig)
+ throws ReflectionException, MBeanException
+ {
+ checkSecurity(null, null, "instantiate");
+ if (name == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The name was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ Class[] sigTypes = new Class[sig.length];
+ for (int a = 0; a < sigTypes.length; ++a)
+ {
+ try
+ {
+ sigTypes[a] = repository.loadClass(sig[a]);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new ReflectionException(e, "The class, " + sigTypes[a] +
+ ", in the method signature " +
+ "could not be loaded.");
+ }
+ }
+ try
+ {
+ Constructor cons =
+ repository.loadClass(name).getConstructor(sigTypes);
+ return cons.newInstance(params);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new ReflectionException(e, "The class, " + name +
+ ", of the constructor " +
+ "could not be loaded.");
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new ReflectionException(e, "The method, " + name +
+ ", could not be found.");
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ReflectionException(e, "Failed to instantiate the object");
+ }
+ catch (InstantiationException e)
+ {
+ throw new ReflectionException(e, "Failed to instantiate the object");
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new MBeanException((Exception) e.getCause(), "The constructor "
+ + name + " threw an exception");
+ }
+ }
+
+ /**
+ * <p>
+ * Creates an instance of the specified class using the supplied
+ * class loader. If the class loader given is <code>null</code>,
+ * then the class loader of the server will be used. The class
+ * should have a public constructor with no arguments. A reference
+ * to the new instance is returned, but the instance is not yet
+ * registered with the server.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #instantiate(String, ObjectName, Object[], String[])
+ * <code>instantiate(name, loaderName, (Object[]) null,
+ * (String[]) null)</code>} with <code>null</code> parameters
+ * and signature.
+ * </p>
+ *
+ * @param name the name of the class of bean to be instantiated.
+ * @param loaderName the name of the class loader to use.
+ * @return an instance of the given class.
+ * @throws InstanceNotFoundException if the class loader is not
+ * registered with the server.
+ * @throws ReflectionException if an exception is thrown during
+ * loading the class or calling the
+ * constructor.
+ * @throws MBeanException if the constructor throws an exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ * @see #instantiate(String, Object[], String[])
+ */
+ public Object instantiate(String name, ObjectName loaderName)
+ throws InstanceNotFoundException, ReflectionException,
+ MBeanException
+ {
+ return instantiate(name, loaderName);
+ }
+
+ /**
+ * Creates an instance of the specified class using the supplied
+ * class loader. If the class loader given is <code>null</code>,
+ * then the class loader of the server will be used. The class
+ * should have a public constructor matching the supplied
+ * signature. A reference to the new instance is returned,
+ * but the instance is not yet registered with the server.
+ *
+ * @param name the name of the class of bean to be instantiated.
+ * @param loaderName the name of the class loader to use.
+ * @param params the parameters for the constructor.
+ * @param sig the signature of the constructor.
+ * @return an instance of the given class.
+ * @throws InstanceNotFoundException if the class loader is not
+ * registered with the server.
+ * @throws ReflectionException if an exception is thrown during
+ * loading the class or calling the
+ * constructor.
+ * @throws MBeanException if the constructor throws an exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ */
+ public Object instantiate(String name, ObjectName loaderName,
+ Object[] params, String[] sig)
+ throws InstanceNotFoundException, ReflectionException,
+ MBeanException
+ {
+ checkSecurity(null, null, "instantiate");
+ if (name == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The name was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ ClassLoader loader = getClassLoader(loaderName);
+ Class[] sigTypes = new Class[sig.length];
+ for (int a = 0; a < sig.length; ++a)
+ {
+ try
+ {
+ sigTypes[a] = Class.forName(sig[a], true, loader);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new ReflectionException(e, "The class, " + sig[a] +
+ ", in the method signature " +
+ "could not be loaded.");
+ }
+ }
+ try
+ {
+ Constructor cons =
+ Class.forName(name, true, loader).getConstructor(sigTypes);
+ return cons.newInstance(params);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new ReflectionException(e, "The class, " + name +
+ ", of the constructor " +
+ "could not be loaded.");
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new ReflectionException(e, "The method, " + name +
+ ", could not be found.");
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ReflectionException(e, "Failed to instantiate the object");
+ }
+ catch (InstantiationException e)
+ {
+ throw new ReflectionException(e, "Failed to instantiate the object");
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new MBeanException((Exception) e.getCause(), "The constructor "
+ + name + " threw an exception");
+ }
+ }
+
+ /**
+ * Invokes the supplied operation on the specified management
+ * bean. The class objects specified in the signature are loaded
+ * using the same class loader as was used for the management bean.
+ *
+ * @param bean the management bean whose operation should be invoked.
+ * @param name the name of the operation to invoke.
+ * @param params the parameters of the operation.
+ * @param sig the signature of the operation.
+ * @return the return value of the method.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws MBeanException if the method invoked throws an exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> name.
+ * @throws ReflectionException if an exception is thrown in invoking the
+ * method.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, name, bean,
+ * "invoke")</code>}.
+ * @see DynamicMBean#invoke(String, Object[], String[])
+ */
+ public Object invoke(ObjectName bean, String name, Object[] params, String[] sig)
+ throws InstanceNotFoundException, MBeanException,
+ ReflectionException
+ {
+ if (bean == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The bean was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ Object abean = getBean(bean);
+ checkSecurity(bean, name, "invoke");
+ if (abean instanceof DynamicMBean)
+ return ((DynamicMBean) abean).invoke(name, params, sig);
+ else
+ try
+ {
+ return new StandardMBean(abean, null).invoke(name, params, sig);
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to create dynamic bean.").initCause(e));
+ }
+ }
+
+ /**
+ * <p>
+ * Returns true if the specified management bean is an instance
+ * of the supplied class.
+ * </p>
+ * <p>
+ * A bean, B, is an instance of a class, C, if either of the following
+ * conditions holds:
+ * </p>
+ * <ul>
+ * <li>The class name in B's {@link MBeanInfo} is equal to the supplied
+ * name.</li>
+ * <li>Both the class of B and C were loaded by the same class loader,
+ * and B is assignable to C.</li>
+ * </ul>
+ *
+ * @param name the name of the management bean.
+ * @param className the name of the class to test if <code>name</code> is
+ * an instance of.
+ * @return true if either B is directly an instance of the named class,
+ * or B is assignable to the class, given that both it and B's
+ * current class were loaded using the same class loader.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "isInstanceOf")</code>
+ */
+ public boolean isInstanceOf(ObjectName name, String className)
+ throws InstanceNotFoundException
+ {
+ Object bean = getBean(name);
+ checkSecurity(name, null, "isInstanceOf");
+ MBeanInfo info;
+ if (bean instanceof DynamicMBean)
+ info = ((DynamicMBean) bean).getMBeanInfo();
+ else
+ try
+ {
+ info = new StandardMBean(bean, null).getMBeanInfo();
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to create dynamic bean.").initCause(e));
+ }
+ if (info.getClassName().equals(className))
+ return true;
+ Class bclass = bean.getClass();
+ try
+ {
+ Class oclass = Class.forName(className);
+ return (bclass.getClassLoader().equals(oclass.getClassLoader()) &&
+ oclass.isAssignableFrom(bclass));
+ }
+ catch (ClassNotFoundException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the specified management bean is registered with
+ * the server.
+ *
+ * @param name the name of the management bean.
+ * @return true if the bean is registered.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> bean name.
+ */
+ public boolean isRegistered(ObjectName name)
+ {
+ if (name == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The name was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ return beans.containsKey(name);
+ }
+
+ /**
+ * <p>
+ * Returns a set of {@link ObjectInstance}s matching the specified
+ * criteria. The full set of beans registered with the server
+ * are passed through two filters:
+ * </p>
+ * <ol>
+ * <li>Pattern matching is performed using the supplied
+ * {@link ObjectName}.</li>
+ * <li>The supplied query expression is applied.</li>
+ * </ol>
+ * <p>
+ * If both the object name and the query expression are <code>null</code>,
+ * or the object name has no domain and no key properties,
+ * no filtering will be performed and all beans are returned.
+ * </p>
+ *
+ * @param name an {@link ObjectName} to use as a filter.
+ * @param query a query expression to apply to each of the beans that match
+ * the given object name.
+ * @return a set of {@link ObjectInstance}s matching the filtered beans.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null, name,
+ * "queryMBeans")</code>}. Additionally,
+ * for an bean, <code>b</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, b, name,
+ * "queryMBeans")</code>} or that bean will
+ * not be included. Such an exception may also
+ * arise from the execution of the query, in which
+ * case that particular bean will again be excluded.
+ */
+ public Set queryMBeans(ObjectName name, QueryExp query)
+ {
+ checkSecurity(name, null, "queryMBeans");
+ Set results = new HashSet();
+ Iterator iterator = beans.entrySet().iterator();
+ while (iterator.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ ObjectName nextName = (ObjectName) entry.getKey();
+ checkSecurity(name, nextName.toString(), "queryMBeans");
+ try
+ {
+ if ((name == null || name.apply(nextName)) &&
+ (query == null || query.apply(nextName)))
+ results.add(((ServerInfo) entry.getValue()).getInstance());
+ }
+ catch (BadStringOperationException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ catch (BadBinaryOpValueExpException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ catch (BadAttributeValueExpException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ catch (InvalidApplicationException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ }
+ return results;
+ }
+
+ /**
+ * <p>
+ * Returns a set of {@link ObjectName}s matching the specified
+ * criteria. The full set of beans registered with the server
+ * are passed through two filters:
+ * </p>
+ * <ol>
+ * <li>Pattern matching is performed using the supplied
+ * {@link ObjectName}.</li>
+ * <li>The supplied query expression is applied.</li>
+ * </ol>
+ * <p>
+ * If both the object name and the query expression are <code>null</code>,
+ * or the object name has no domain and no key properties,
+ * no filtering will be performed and all beans are returned.
+ * </p>
+ *
+ * @param name an {@link ObjectName} to use as a filter.
+ * @param query a query expression to apply to each of the beans that match
+ * the given object name.
+ * @return a set of {@link ObjectName}s matching the filtered beans.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null, name,
+ * "queryNames")</code>}. Additionally,
+ * for an name, <code>n</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, n, name,
+ * "queryNames")</code>} or that name will
+ * not be included. Such an exception may also
+ * arise from the execution of the query, in which
+ * case that particular bean will again be excluded.
+ * Note that these permissions are implied if the
+ * <code>queryMBeans</code> permissions are available.
+ */
+ public Set queryNames(ObjectName name, QueryExp query)
+ {
+ checkSecurity(name, null, "queryNames");
+ Set results = new HashSet();
+ Iterator iterator = beans.entrySet().iterator();
+ while (iterator.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ ObjectName nextName = (ObjectName) entry.getKey();
+ checkSecurity(name, nextName.toString(), "queryNames");
+ try
+ {
+ if ((name == null || name.apply(nextName)) &&
+ (query == null || query.apply(nextName)))
+ results.add(nextName);
+ }
+ catch (BadStringOperationException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ catch (BadBinaryOpValueExpException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ catch (BadAttributeValueExpException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ catch (InvalidApplicationException e)
+ {
+ /* Ignored -- assume false result */
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Registers the supplied instance with the server, using the specified
+ * {@link ObjectName}. If the name given is <code>null</code>, then
+ * the bean supplied is expected to implement the {@link MBeanRegistration}
+ * interface and provide the name via the
+ * {@link MBeanRegistration#preRegister preRegister} method
+ * of this interface.
+ *
+ * @param obj the object to register with the server.
+ * @param name the name under which to register the object,
+ * or <code>null</code> if the {@link MBeanRegistration}
+ * interface should be used.
+ * @return an {@link ObjectInstance} containing the supplied
+ * {@link ObjectName} along with the name of the bean's class.
+ * @throws InstanceAlreadyExistsException if a matching instance
+ * already exists.
+ * @throws MBeanRegistrationException if an exception occurs in
+ * calling the preRegister
+ * method.
+ * @throws NotCompliantMBeanException if the created bean is not
+ * compliant with the JMX specification.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> object.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "registerMBean")</code>}. <code>className</code>
+ * here corresponds to the result of
+ * {@link MBeanInfo#getClassName()} for objects of
+ * this class. If this check succeeds, a check
+ * is also made on its
+ * {@link java.security.ProtectionDomain} to ensure
+ * it implies {@link MBeanTrustPermission(String)
+ * <code>MBeanTrustPermission("register")</code>}.
+ * The use of the {@link MBeanRegistration} interface
+ * results in another {@link MBeanPermission} check
+ * being made on the returned {@link ObjectName}.
+ */
+ public ObjectInstance registerMBean(Object obj, ObjectName name)
+ throws InstanceAlreadyExistsException, MBeanRegistrationException,
+ NotCompliantMBeanException
+ {
+ SecurityManager sm = System.getSecurityManager();
+ Class cl = obj.getClass();
+ String className = cl.getName();
+ if (sm != null)
+ {
+ sm.checkPermission(new MBeanPermission(className, null, name,
+ "registerMBean"));
+ if (!(cl.getProtectionDomain().implies(new MBeanTrustPermission("register"))))
+ throw new SecurityException("The protection domain of the object's class" +
+ "does not imply the trust permission," +
+ "register");
+ }
+ if (obj == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The object was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ MBeanRegistration register = null;
+ if (obj instanceof MBeanRegistration)
+ register = (MBeanRegistration) obj;
+ if (name == null)
+ {
+ if (register == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The name was null and " +
+ "the bean does not implement " +
+ "MBeanRegistration.");
+ throw new RuntimeOperationsException(e);
+ }
+ try
+ {
+ name = register.preRegister(this, null);
+ if (sm != null)
+ sm.checkPermission(new MBeanPermission(className, null, name,
+ "registerMBean"));
+ }
+ catch (SecurityException e)
+ {
+ register.postRegister(Boolean.FALSE);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ register.postRegister(Boolean.FALSE);
+ throw new MBeanRegistrationException(e, "Pre-registration failed.");
+ }
+ }
+ if (beans.containsKey(name))
+ {
+ if (register != null)
+ register.postRegister(Boolean.FALSE);
+ throw new InstanceAlreadyExistsException(name + "is already registered.");
+ }
+ ObjectInstance obji = new ObjectInstance(name, className);
+ beans.put(name, new ServerInfo(obji, obj));
+ if (register != null)
+ register.postRegister(Boolean.TRUE);
+ return obji;
+ }
+
+ /**
+ * Removes the specified listener from the list of recipients
+ * of notifications from the supplied bean. This includes all
+ * combinations of filters and passback objects registered for
+ * this listener. For more specific removal of listeners, see
+ * {@link #removeNotificationListener(ObjectName,
+ * NotificationListener,NotificationFilter,Object)}
+ *
+ * @param name the name of the management bean from which the
+ * listener should be removed.
+ * @param listener the listener to remove.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws ListenerNotFoundException if the specified listener
+ * is not registered with the bean.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @see #addNotificationListener(NotificationListener, NotificationFilter,
+ * java.lang.Object)
+ * @see NotificationBroadcaster#removeNotificationListener(NotificationListener)
+ */
+ public void removeNotificationListener(ObjectName name,
+ NotificationListener listener)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ Object bean = getBean(name);
+ checkSecurity(name, null, "removeNotificationListener");
+ if (bean instanceof NotificationBroadcaster)
+ {
+ NotificationBroadcaster bbean = (NotificationBroadcaster) bean;
+ NotificationListener indirection = (NotificationListener)
+ listeners.get(listener);
+ if (indirection == null)
+ bbean.removeNotificationListener(listener);
+ else
+ {
+ bbean.removeNotificationListener(indirection);
+ listeners.remove(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified listener from the list of recipients
+ * of notifications from the supplied bean. Only the first instance with
+ * the supplied filter and passback object is removed.
+ * <code>null</code> is used as a valid value for these parameters,
+ * rather than as a way to remove all registration instances for
+ * the specified listener; for this behaviour instead, see
+ * {@link #removeNotificationListener(ObjectName, NotificationListener)}.
+ *
+ * @param name the name of the management bean from which the
+ * listener should be removed.
+ * @param listener the listener to remove.
+ * @param filter the filter of the listener to remove.
+ * @param passback the passback object of the listener to remove.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws ListenerNotFoundException if the specified listener
+ * is not registered with the bean.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @see #addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object)
+ * @see NotificationEmitter#removeNotificationListener(NotificationListener,
+ * NotificationFilter,
+ * Object)
+ */
+ public void removeNotificationListener(ObjectName name,
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object passback)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ Object bean = getBean(name);
+ checkSecurity(name, null, "removeNotificationListener");
+ if (bean instanceof NotificationEmitter)
+ {
+ NotificationEmitter bbean = (NotificationEmitter) bean;
+ NotificationListener indirection = (NotificationListener)
+ listeners.get(listener);
+ if (indirection == null)
+ bbean.removeNotificationListener(listener, filter, passback);
+ else
+ {
+ bbean.removeNotificationListener(indirection, filter, passback);
+ listeners.remove(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified listener from the list of recipients
+ * of notifications from the supplied bean. This includes all
+ * combinations of filters and passback objects registered for
+ * this listener. For more specific removal of listeners, see
+ * {@link #removeNotificationListener(ObjectName,
+ * ObjectName,NotificationFilter,Object)}
+ *
+ * @param name the name of the management bean from which the
+ * listener should be removed.
+ * @param listener the name of the listener to remove.
+ * @throws InstanceNotFoundException if a name doesn't match a registered
+ * bean.
+ * @throws ListenerNotFoundException if the specified listener
+ * is not registered with the bean.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @see #addNotificationListener(NotificationListener, NotificationFilter,
+ * java.lang.Object)
+ * @see NotificationBroadcaster#removeNotificationListener(NotificationListener)
+ */
+ public void removeNotificationListener(ObjectName name, ObjectName listener)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ Object lbean = getBean(listener);
+ if (!(lbean instanceof NotificationListener))
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The supplied listener name does not " +
+ "correspond to a notification listener.");
+ throw new RuntimeOperationsException(e);
+ }
+ removeNotificationListener(name, ((NotificationListener) lbean));
+ }
+
+ /**
+ * Removes the specified listener from the list of recipients
+ * of notifications from the supplied bean. Only the first instance with
+ * the supplied filter and passback object is removed.
+ * <code>null</code> is used as a valid value for these parameters,
+ * rather than as a way to remove all registration instances for
+ * the specified listener; for this behaviour instead, see
+ * {@link #removeNotificationListener(ObjectName, ObjectName)}.
+ *
+ * @param name the name of the management bean from which the
+ * listener should be removed.
+ * @param listener the name of the listener to remove.
+ * @param filter the filter of the listener to remove.
+ * @param passback the passback object of the listener to remove.
+ * @throws InstanceNotFoundException if a name doesn't match a registered
+ * bean.
+ * @throws ListenerNotFoundException if the specified listener
+ * is not registered with the bean.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @see #addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object)
+ * @see NotificationEmitter#removeNotificationListener(NotificationListener,
+ * NotificationFilter,
+ * Object)
+ */
+ public void removeNotificationListener(ObjectName name,
+ ObjectName listener,
+ NotificationFilter filter,
+ Object passback)
+ throws InstanceNotFoundException, ListenerNotFoundException
+ {
+ Object lbean = getBean(listener);
+ if (!(lbean instanceof NotificationListener))
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The supplied listener name does not " +
+ "correspond to a notification listener.");
+ throw new RuntimeOperationsException(e);
+ }
+ removeNotificationListener(name, ((NotificationListener) lbean), filter,
+ passback);
+ }
+
+ /**
+ * Sets the value of the specified attribute of the supplied
+ * management bean.
+ *
+ * @param name the name of the management bean.
+ * @param attribute the attribute to set.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws AttributeNotFoundException if the attribute does not
+ * correspond to an attribute
+ * of the bean.
+ * @throws InvalidAttributeValueException if the value is invalid
+ * for this particular
+ * attribute of the bean.
+ * @throws MBeanException if setting the attribute causes
+ * the bean to throw an exception (which
+ * becomes the cause of this exception).
+ * @throws ReflectionException if an exception occurred in trying
+ * to use the reflection interface
+ * to lookup the attribute. The
+ * thrown exception is the cause of
+ * this exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> bean or attribute
+ * name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, name, bean,
+ * "setAttribute")</code>}.
+ * @see #getAttribute(ObjectName, String)
+ * @see DynamicMBean#setAttribute(Attribute)
+ */
+ public void setAttribute(ObjectName name, Attribute attribute)
+ throws InstanceNotFoundException, AttributeNotFoundException,
+ InvalidAttributeValueException, MBeanException,
+ ReflectionException
+ {
+ if (attribute == null || name == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("One of the supplied arguments was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ Object bean = getBean(name);
+ checkSecurity(name, attribute.getName(), "setAttribute");
+ if (bean instanceof DynamicMBean)
+ ((DynamicMBean) bean).setAttribute(attribute);
+ else
+ try
+ {
+ new StandardMBean(bean, null).setAttribute(attribute);
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to create dynamic bean.").initCause(e));
+ }
+ }
+
+ /**
+ * Sets the value of each of the specified attributes
+ * of the supplied management bean to that specified by
+ * the {@link Attribute} object. The returned list contains
+ * the attributes that were set and their new values.
+ *
+ * @param name the name of the management bean.
+ * @param attributes the attributes to set.
+ * @return a list of the changed attributes.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws ReflectionException if an exception occurred in trying
+ * to use the reflection interface
+ * to lookup the attribute. The
+ * thrown exception is the cause of
+ * this exception.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> bean or attribute
+ * list.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, bean,
+ * "setAttribute")</code>}. Additionally,
+ * for an attribute name, <code>n</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, n, bean,
+ * "setAttribute")</code>} or that attribute will
+ * not be included.
+ * @see #getAttributes(ObjectName, String[])
+ * @see DynamicMBean#setAttributes(AttributeList)
+ */
+ public AttributeList setAttributes(ObjectName name, AttributeList attributes)
+ throws InstanceNotFoundException, ReflectionException
+ {
+ if (name == null || attributes == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("One of the supplied arguments was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ Object abean = getBean(name);
+ checkSecurity(name, null, "setAttribute");
+ AttributeList list = new AttributeList(attributes.size());
+ Iterator it = attributes.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ Attribute attrib = (Attribute) it.next();
+ if (attrib == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("An attribute was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ checkSecurity(name, attrib.getName(), "setAttribute");
+ if (abean instanceof DynamicMBean)
+ ((DynamicMBean) abean).setAttribute(attrib);
+ else
+ try
+ {
+ new StandardMBean(abean, null).setAttribute(attrib);
+ }
+ catch (NotCompliantMBeanException e)
+ {
+ throw (Error)
+ (new InternalError("Failed to create dynamic bean.").initCause(e));
+ }
+ list.add(attrib);
+ }
+ catch (AttributeNotFoundException e)
+ {
+ /* Ignored */
+ }
+ catch (InvalidAttributeValueException e)
+ {
+ /* Ignored */
+ }
+ catch (MBeanException e)
+ {
+ /* Ignored */
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Unregisters the specified management bean. Following this operation,
+ * the bean instance is no longer accessible from the server via this
+ * name. Prior to unregistering the bean, the
+ * {@link MBeanRegistration#preDeregister()} method will be called if
+ * the bean implements the {@link MBeanRegistration} interface.
+ *
+ * @param name the name of the management bean.
+ * @throws InstanceNotFoundException if the bean can not be found.
+ * @throws MBeanRegistrationException if an exception occurs in
+ * calling the preDeregister
+ * method.
+ * @throws RuntimeOperationsException if an {@link IllegalArgumentException}
+ * is thrown by the server due to a
+ * <code>null</code> bean name or a
+ * request being made to unregister the
+ * {@link MBeanServerDelegate} bean.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "unregisterMBean")</code>}.
+ */
+ public void unregisterMBean(ObjectName name)
+ throws InstanceNotFoundException, MBeanRegistrationException
+ {
+ if (name == null)
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The name was null.");
+ throw new RuntimeOperationsException(e);
+ }
+ if (name.equals(DELEGATE_NAME))
+ {
+ RuntimeException e =
+ new IllegalArgumentException("The delegate can not be unregistered.");
+ throw new RuntimeOperationsException(e);
+ }
+ Object bean = getBean(name);
+ checkSecurity(name, null, "unregisterMBean");
+ MBeanRegistration register = null;
+ if (bean instanceof MBeanRegistration)
+ {
+ register = (MBeanRegistration) bean;
+ try
+ {
+ register.preDeregister();
+ }
+ catch (Exception e)
+ {
+ throw new MBeanRegistrationException(e, "Pre-deregistration failed.");
+ }
+ }
+ beans.remove(name);
+ if (register != null)
+ register.postDeregister();
+ }
+
+ /**
+ * Input stream which deserializes using the given classloader.
+ */
+ private class ServerInputStream
+ extends ObjectInputStream
+ {
+
+ private ClassLoader cl;
+
+ public ServerInputStream(InputStream is, ClassLoader cl)
+ throws IOException, StreamCorruptedException
+ {
+ super(is);
+ this.cl = cl;
+ }
+
+ protected Class resolveClass(ObjectStreamClass osc)
+ throws ClassNotFoundException, IOException
+ {
+ try
+ {
+ return Class.forName(osc.getName(), true, cl);
+ }
+ catch (ClassNotFoundException e)
+ {
+ return super.resolveClass(osc);
+ }
+ }
+
+ }
+
+ /**
+ * Holder for information on registered beans.
+ */
+ private class ServerInfo
+ {
+ private ObjectInstance instance;
+
+ private Object object;
+
+ public ServerInfo(ObjectInstance instance, Object object)
+ {
+ this.instance = instance;
+ this.object = object;
+ }
+
+ public Object getObject()
+ {
+ return object;
+ }
+
+ public ObjectInstance getInstance()
+ {
+ return instance;
+ }
+ }
+
+ /**
+ * Notification listener which removes direct references
+ * to beans.
+ */
+ private class ServerNotificationListener
+ implements NotificationListener
+ {
+
+ /**
+ * The bean from which notifications are emitted.
+ */
+ Object bean;
+
+ /**
+ * The {@link ObjectName} of the emitting bean.
+ */
+ ObjectName name;
+
+ /**
+ * The real {@link NotificationListener}.
+ */
+ NotificationListener listener;
+
+ /**
+ * Constructs a new {@link ServerNotificationListener} replacing
+ * occurrences of <code>bean</code> with its name.
+ *
+ * @param bean the bean emitting notifications.
+ * @param name the object name of the emitting bean.
+ * @param listener the listener events eventually reach.
+ */
+ public ServerNotificationListener(Object bean, ObjectName name,
+ NotificationListener listener)
+ {
+ this.bean = bean;
+ this.name = name;
+ this.listener = listener;
+ }
+
+ /**
+ * Replace a direct reference to <code>bean</code> with its
+ * object reference, if necessary, before calling the listener.
+ *
+ * @param notif the notification being emitted.
+ * @param handback an object that will be returned to the notification
+ * listener when an event occurs.
+ */
+ public void handleNotification(Notification notif, Object handback)
+ {
+ if (notif.getSource() == bean)
+ notif.setSource(name);
+ listener.handleNotification(notif, handback);
+ }
+
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java b/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java
new file mode 100644
index 00000000000..7d7a785fd2f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java
@@ -0,0 +1,956 @@
+/* ContextContinuation.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.giop;
+
+import gnu.CORBA.NamingService.Ext;
+import gnu.CORBA.NamingService.NameTransformer;
+
+import java.util.Hashtable;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.ContextNotEmptyException;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.directory.InvalidAttributesException;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.portable.Delegate;
+import org.omg.CORBA.portable.ObjectImpl;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContext;
+import org.omg.CosNaming.NamingContextExt;
+import org.omg.CosNaming.NamingContextExtHelper;
+import org.omg.CosNaming.NamingContextHelper;
+import org.omg.CosNaming._NamingContextExtStub;
+import org.omg.CosNaming._NamingContextStub;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+
+/**
+ * The context to represent the corba naming service. Being the naming service,
+ * the returned context supports creating the subcontexts, forwarding this task
+ * to the existing naming service. When listing bindings, it uses the
+ * {@link Context#BATCHSIZE} property to determine, how many bindings should
+ * be returned at once (the process is transparend)
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+public class ContextContinuation implements Context
+{
+ /**
+ * This number of bindings will be requested from the naming server at once,
+ * while the subsequent bindings will be requested via binding iterator one by
+ * one. Use {@link Context#BATCHSIZE} to override the value of this constant.
+ */
+ public int DEFAULT_BATCH_SIZE = 20;
+
+ /**
+ * The actual CORBA naming service.
+ */
+ NamingContextExt service;
+
+ /**
+ * The object request broker, used to access the naming service. This field
+ * is only initialised when the context is constructed from the URL.
+ */
+ ORB orb;
+
+ /**
+ * The properties.
+ */
+ Hashtable properties;
+
+ /**
+ * The parent factory.
+ */
+ GiopNamingServiceFactory factory;
+
+ /**
+ * The name transformer to obtain the name from its string representation. The
+ * to_name method of the naming service is avoided as it may be remote and
+ * hence expensive. The conversion rules are standard and cannot be service
+ * specific.
+ */
+ static NameTransformer transformer = new NameTransformer();
+
+ /**
+ * The batch size for list operations - how many to return at once.
+ */
+ public final int howMany;
+
+ /**
+ * Creates a new naming context that uses naming service, represented by the
+ * given CORBA object.
+ *
+ * @param namingService
+ * the naming service object. It must be possible to narrow it into
+ * the NamingContextExt.
+ * @param props
+ * the environment table.
+ * @param orb
+ * the associated ORB. This reference is used during cleanup.
+ * @param the
+ * parent factory. This reference is used during cleanup.
+ */
+ public ContextContinuation(org.omg.CORBA.Object nsObject,
+ Hashtable props, ORB anOrb,
+ GiopNamingServiceFactory aFactory)
+ {
+ factory = aFactory;
+ orb = anOrb;
+
+ Delegate delegate = ((ObjectImpl) nsObject)._get_delegate();
+
+ // If the IOR provides the IDL ID, we can check if our name
+ // service is old NamingContext or new NamingContextExt.
+ // Not all forms of the URL always provide the IDL id.
+ if (!nsObject._is_a(NamingContextExtHelper.id())
+ && nsObject._is_a(NamingContextHelper.id()))
+ {
+ // We are surely working with the old version.
+ _NamingContextStub stub = new _NamingContextStub();
+ stub._set_delegate(delegate);
+ // The Ext object will add the necessary extensions.
+ service = new Ext(stub);
+ }
+ else
+ {
+ // We expecte the service to be the NamingContextExt (this is true
+ // for both Sun's and our implementations). There is no easy way
+ // to check the version.
+ _NamingContextExtStub stub = new _NamingContextExtStub();
+ stub._set_delegate(delegate);
+ service = stub;
+ }
+ properties = props;
+ howMany = getBatchSize();
+ }
+
+ /**
+ * Give the specified name for the specified object. The passed name must not
+ * be already bound to some other object. The components of the name are
+ * mapped into the components of the CORBA name.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws NameAlreadyBoundException
+ * if this name is already used to name some object.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ try
+ {
+ org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj;
+ service.bind(toGiop(name), object);
+ }
+ catch (ClassCastException e)
+ {
+ throw new NamingException(org.omg.CORBA.Object.class + " required ");
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (AlreadyBound e)
+ {
+ throw new NameAlreadyBoundException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Give the specified name for the specified object. The passed name must not
+ * be already bound to some other object.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws NameAlreadyBoundException
+ * if this name is already used to name some object.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj;
+ service.bind(transformer.toName(name), object);
+ }
+ catch (ClassCastException e)
+ {
+ throw new NamingException(org.omg.CORBA.Object.class + " required ");
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (AlreadyBound e)
+ {
+ throw new NameAlreadyBoundException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Releases all resources, associated with this context. The close() method
+ * can be called several times, but after it has been once invoked, it is not
+ * allowed to call any other method of this context. This method destroys
+ * the ORB, if we have one.
+ *
+ * @throws NamingException
+ */
+ public void close() throws NamingException
+ {
+ if (orb != null && factory !=null)
+ {
+ factory.checkIfReferenced(orb);
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported
+ */
+ public String composeName(String name1, String name2) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Creates the new naming subcontext and binds it to the current (this)
+ * context. The returned object will wrap around the newly created CORBA
+ * subcontext
+ *
+ * @param name
+ * the name of the new context being created
+ * @return the newly created context, bound to the instance of the context on
+ * that the method has been called
+ * @throws NameAlreadyBoundException
+ * if this name is already bound
+ * @throws InvalidAttributesException
+ * if the creation of the new context requires the missing mandatory
+ * attributes
+ * @throws NamingException
+ */
+ public Context createSubcontext(Name subContext) throws NamingException
+ {
+ try
+ {
+ org.omg.CORBA.Object subcontext = service.bind_new_context(
+ toGiop(subContext));
+ Hashtable clonedProps = new Hashtable();
+ clonedProps.putAll(properties);
+
+ // Nulls are passed both for orb and factory, as the child contexts
+ // need not to do any cleanup.
+ return new ContextContinuation(subcontext, clonedProps, null, null);
+ }
+ catch (AlreadyBound e)
+ {
+ throw new NameAlreadyBoundException();
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception ex)
+ {
+ throw new NamingException(ex.toString());
+ }
+ }
+
+ /**
+ * Creates the new naming subcontext and binds it to the current (this)
+ * context. The returned object will wrap around the newly created CORBA
+ * subcontext
+ *
+ * @param name
+ * the name of the new context being created
+ * @return the newly created context, bound to the instance of the context on
+ * that the method has been called
+ * @throws NameAlreadyBoundException
+ * if this name is already bound
+ * @throws InvalidAttributesException
+ * if the creation of the new context requires the missing mandatory
+ * attributes
+ * @throws NamingException
+ */
+ public Context createSubcontext(String subContext) throws NamingException
+ {
+ try
+ {
+ org.omg.CORBA.Object subcontext =
+ service.bind_new_context(transformer.toName(subContext));
+ Hashtable clonedProps = new Hashtable();
+ clonedProps.putAll(properties);
+
+ // Nulls are passed both for orb and factory, as the child contexts
+ // need not to do any cleanup.
+ return new ContextContinuation(subcontext, clonedProps, null,
+ null);
+ }
+ catch (AlreadyBound e)
+ {
+ throw new NameAlreadyBoundException(subContext);
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException(subContext);
+ }
+ catch (Exception ex)
+ {
+ throw new NamingException(ex.toString());
+ }
+ }
+
+ /**
+ * Removes the naming subcontext from this naming context. Returns without
+ * action if such subcontext does not exist. The context being destroyed must
+ * be empty.
+ *
+ * @param name
+ * the name of the subcontext beig removed.
+ * @throws ContextNotEmptyException
+ * if the named context is not empty.
+ * @throws NamingException
+ */
+ public void destroySubcontext(Name subContext) throws NamingException
+ {
+ unbind(subContext);
+ }
+
+ /**
+ * Removes the naming subcontext from this naming context. Returns without
+ * action if such subcontext does not exist. The context being destroyed must
+ * be empty.
+ *
+ * @param name
+ * the name of the subcontext beig removed.
+ * @throws ContextNotEmptyException
+ * if the named context is not empty.
+ * @throws NamingException
+ */
+ public void destroySubcontext(String subContext) throws NamingException
+ {
+ unbind(subContext);
+ }
+
+ /**
+ * Returs the full name of this naming context. The returned string is not a
+ * JNDI composite name and should not be passed directly to the methods of the
+ * naming context. This implementation returns the IOR.
+ *
+ * @return the full name of this naming context, in its own namespace.
+ * @throws OperationNotSupportedException
+ * if the naming system, represented by this context, does not
+ * support the notation of the full name.
+ * @throws NamingException
+ */
+ public String getNameInNamespace() throws NamingException
+ {
+ if (orb != null)
+ return orb.object_to_string(service);
+ else
+ {
+ try
+ {
+ ObjectImpl impl = (ObjectImpl) service;
+ return impl._orb().object_to_string(impl);
+ }
+ catch (ClassCastException e)
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public NameParser getNameParser(Name name) throws NamingException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public NameParser getNameParser(String name) throws NamingException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Creates and returns the enumeration over the name bindings that are present
+ * the given subcontext. The enumeration elements have the type of
+ * {@link NameClassPair}, providing also information about the class of the
+ * bound object. The behaviour in the case if the bindings are added or
+ * removed later is not defined. The contents of the subcontexts are not
+ * included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ BindingIteratorHolder bi = new BindingIteratorHolder();
+ BindingListHolder bl = new BindingListHolder();
+
+ NamingContext subcontext;
+
+ if (name.size() == 0)
+ subcontext = service;
+ else
+ {
+ try
+ {
+ subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name))));
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+
+ }
+
+ subcontext.list(howMany, bl, bi);
+
+ return new ListEnumeration(bl, bi, howMany);
+ }
+
+ /**
+ * Creates and returns the enumeration over the name bindings that are present
+ * the given subcontext. The enumeration elements have the type of
+ * {@link NameClassPair}, providing also information about the class of the
+ * bound object. The behaviour in the case if the bindings are added or
+ * removed later is not defined. The contents of the subcontexts are not
+ * included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ BindingIteratorHolder bi = new BindingIteratorHolder();
+ BindingListHolder bl = new BindingListHolder();
+
+ NamingContext subcontext;
+
+ if (name.length() == 0)
+ subcontext = service;
+ else
+ {
+ try
+ {
+ subcontext = (NamingContextHelper.narrow(service.resolve_str(name)));
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+
+ }
+
+ subcontext.list(howMany, bl, bi);
+
+ return new ListEnumeration(bl, bi, howMany);
+ }
+
+ /**
+ * Creates and returns the enumeration over the name - object bindings that
+ * are present the given subcontext. The enumeration elements have the type of
+ * {@link Binding}, providing also information about the class of the bound
+ * object. The behaviour in the case if the bindings are added or removed
+ * later is not defined. The contents of the subcontexts are not included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ BindingIteratorHolder bi = new BindingIteratorHolder();
+ BindingListHolder bl = new BindingListHolder();
+
+ NamingContext subcontext;
+
+ if (name.size() == 0)
+ subcontext = service;
+ else
+ {
+ try
+ {
+ subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name))));
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ subcontext.list(howMany, bl, bi);
+
+ return new ListBindingsEnumeration(bl, bi, howMany, subcontext);
+ }
+
+ /**
+ * Creates and returns the enumeration over the name - object bindings that
+ * are present the given subcontext. The enumeration elements have the type of
+ * {@link Binding}, providing also information about the class of the bound
+ * object. The behaviour in the case if the bindings are added or removed
+ * later is not defined. The contents of the subcontexts are not included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ BindingIteratorHolder bi = new BindingIteratorHolder();
+ BindingListHolder bl = new BindingListHolder();
+
+ NamingContext subcontext;
+
+ if (name.length() == 0)
+ subcontext = service;
+ else
+ {
+ try
+ {
+ subcontext = (NamingContextHelper.narrow(service.resolve_str(name)));
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+
+ }
+
+ subcontext.list(howMany, bl, bi);
+
+ return new ListBindingsEnumeration(bl, bi, howMany, subcontext);
+ }
+
+ /**
+ * Gets the previously named object by name. If the passed name is empty, the
+ * method should return a cloned instance of this naming context.
+ *
+ * @param name
+ * the name of the object being searched in this context
+ * @return the named object
+ * @throws NameNotFountException
+ * if the name is not found
+ */
+ public Object lookup(Name name) throws NamingException
+ {
+ try
+ {
+ return service.resolve(toGiop(name));
+ }
+ catch (NotFound e)
+ {
+ throw new NameNotFoundException();
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Gets the previously named object by name. If the passed name is empty, the
+ * method should return a cloned instance of this naming context.
+ *
+ * @param name
+ * the name of the object being searched in this context
+ * @return the named object
+ * @throws NamingException
+ * if the naming fails.
+ */
+ public Object lookup(String name) throws NamingException
+ {
+ try
+ {
+ return service.resolve_str(name);
+ }
+ catch (NotFound e)
+ {
+ throw new NameNotFoundException();
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Give the specified name for the specified object. Unlike bind, this method
+ * silently replaces the existing binding for this name, if one exists.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ try
+ {
+ org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj;
+ service.rebind(toGiop(name), object);
+ }
+ catch (ClassCastException e)
+ {
+ throw new NamingException(org.omg.CORBA.Object.class + " required ");
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Give the specified name for the specified object. Unlike bind, this method
+ * silently replaces the existing binding for this name, if one exists.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj;
+ service.rebind(transformer.toName(name), object);
+ }
+ catch (ClassCastException e)
+ {
+ throw new NamingException(org.omg.CORBA.Object.class + " required ");
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Renames the existing binding, removing the existing and giving the new name
+ * for the same object.
+ *
+ * @param oldName
+ * the existing name of the known object
+ * @param newName
+ * the new name of the same object
+ * @throws NameNotFoundException
+ * if the oldName is unknown for this context
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ Object object = lookup(oldName);
+ unbind(oldName);
+ bind(newName, object);
+ }
+
+ /**
+ * Renames the existing binding, removing the existing and giving the new name
+ * for the same object.
+ *
+ * @param oldName
+ * the existing name of the known object
+ * @param newName
+ * the new name of the same object
+ * @throws NameNotFoundException
+ * if the oldName is unknown for this context
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rename(String oldName, String newName) throws NamingException
+ {
+ Object object = lookup(oldName);
+ unbind(oldName);
+ bind(newName, object);
+ }
+
+ /**
+ * Removes the name - object mapping from the current context. This method
+ * returns without action if the name is not bound to an object in the
+ * terminal context, but throws {@link NameNotFoundException} if one of the
+ * intermadiate contexts does not exist.
+ *
+ * @param name
+ * the name to be removed
+ * @throws NameNotFoundException
+ * if one of the intermediate naming contexts does not exist. Will
+ * not be thrown if just the terminal binding is missing.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void unbind(Name name) throws NamingException
+ {
+ try
+ {
+ service.unbind(toGiop(name));
+ }
+ catch (NotFound e)
+ {
+ throw new NameNotFoundException();
+ }
+ catch (CannotProceed e)
+ {
+ throw new ContextNotEmptyException();
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ }
+
+ /**
+ * Removes the name - object mapping from the current context. This method
+ * returns without action if the name is not bound to an object in the
+ * terminal context, but throws {@link NameNotFoundException} if one of the
+ * intermadiate contexts does not exist.
+ *
+ * @param name
+ * the name to be removed
+ * @throws NameNotFoundException
+ * if one of the intermediate naming contexts does not exist. Will
+ * not be thrown if just the terminal binding is missing.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void unbind(String name) throws NamingException
+ {
+ try
+ {
+ service.unbind(transformer.toName(name));
+ }
+ catch (NotFound e)
+ {
+ throw new NameNotFoundException(name);
+ }
+ catch (CannotProceed e)
+ {
+ throw new ContextNotEmptyException(name);
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException(name);
+ }
+ }
+
+ /**
+ * Add new environment property to the environment of this context. Both name
+ * and value of the new property must not be null. If the property is already
+ * defined, is current value is replaced by the propVal.
+ *
+ * @param propName
+ * the name of the new property
+ * @param propVal
+ * the value of the new property
+ * @return the previous value of this property or null if the property has not
+ * been previously defined
+ * @throws NamingException
+ */
+ public Object addToEnvironment(String key, Object value)
+ throws NamingException
+ {
+ if (key == null || value == null)
+ throw new NullPointerException();
+ return properties.put(key, value);
+ }
+
+ /**
+ * Returns the environment, associated with this naming context. The returned
+ * table should never be modified by the caller. Use {@link #addToEnvironment}
+ * and {@link #removeFromEnvironment} to modify the environement, if needed.
+ *
+ * @return the table, representing the environment of this context
+ * @throws NamingException
+ */
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return properties;
+ }
+
+ /**
+ * Removes the property with the given name from the environment. Returns
+ * without action if this property is not defined.
+ *
+ * @param propName
+ * the name of the property being removed.
+ * @return the value of the property that has been removed or null if the
+ * property was not defined.
+ * @throws NamingException
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ return properties.remove(propName);
+ }
+
+ /**
+ * Convert the {@link Name} into array of the name components, required to the
+ * CORBA naming service. First the string representation is obtained, then
+ * it is converted using parsing rules of the CORBA name.
+ *
+ * @param name
+ * then name to convert
+ * @return the converted array of components.
+ */
+ public NameComponent[] toGiop(Name name) throws InvalidName
+ {
+ return transformer.toName(name.toString());
+ }
+
+ /**
+ * Get the batch size from the environment properties. The batch size is used
+ * for listing operations.
+ *
+ * @return the batch size, or some default value if not specified.
+ */
+ public int getBatchSize()
+ {
+ int batchSize = DEFAULT_BATCH_SIZE;
+ Object bs = properties.get(Context.BATCHSIZE);
+ if (bs != null)
+ {
+ try
+ {
+ int b = Integer.parseInt(bs.toString());
+ if (b >= 0)
+ batchSize = b;
+ }
+ catch (NumberFormatException e)
+ {
+ // OK, use default value.
+ }
+ }
+ return batchSize;
+ }
+
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java b/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java
new file mode 100644
index 00000000000..397b1c7d9e4
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java
@@ -0,0 +1,439 @@
+/* CorbalocParser.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.giop;
+
+import gnu.CORBA.IOR;
+import gnu.CORBA.Minor;
+import gnu.CORBA.Unexpected;
+import gnu.CORBA.Version;
+import gnu.CORBA.NamingService.NameTransformer;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.StringTokenizer;
+
+import javax.naming.InvalidNameException;
+
+import org.omg.CORBA.BAD_PARAM;
+import org.omg.CORBA.DATA_CONVERSION;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Object;
+import org.omg.CORBA.ORBPackage.InvalidName;
+
+/**
+ * Parses the alternative IOR representations into our IOR structure.
+ *
+ * TODO This parser currently supports only one address per target string. A
+ * string with the multiple addresses will be accepted, but only the last
+ * address will be taken into consideration. The fault tolerance is not yet
+ * implemented.
+ *
+ * The key string is filtered using {@link java.net.URLDecoder} that replaces
+ * the agreed escape sequences by the corresponding non alphanumeric characters.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class CorbalocParser
+ extends NameTransformer
+{
+ /**
+ * The corbaloc prefix.
+ */
+ public static final String pxCORBALOC = "corbaloc";
+
+ /**
+ * The corbaname prefix.
+ */
+ public static final String pxCORBANAME = "corbaname";
+
+ /**
+ * The IOR prefix.
+ */
+ public static final String pxIOR = "ior";
+
+ /**
+ * The file:// prefix.
+ */
+ public static final String pxFILE = "file://";
+
+ /**
+ * The ftp:// prefix.
+ */
+ public static final String pxFTP = "ftp://";
+
+ /**
+ * The http:// prefix.
+ */
+ public static final String pxHTTP = "http://";
+
+ /**
+ * Marks iiop protocol.
+ */
+ public static final String IIOP = "iiop";
+
+ /**
+ * Marks rir protocol.
+ */
+ public static final String RIR = "rir";
+
+ /**
+ * The default port value, as specified in OMG documentation.
+ */
+ public static final int DEFAULT_PORT = 2809;
+
+ /**
+ * The default name.
+ */
+ public static final String DEFAULT_NAME = "NameService";
+
+ /**
+ * The string to name converter, initialized on demand.
+ */
+ static NameTransformer converter;
+
+ /**
+ * The current position.
+ */
+ int p;
+
+ /**
+ * The address being parsed, splitted into tokens.
+ */
+ String[] t;
+
+ /**
+ * Parse CORBALOC.
+ *
+ * The expected format is: <br>
+ * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key <br>
+ * 2. corbaloc:rir:[/key] <br>
+ * 3. corbaname:[iiop][version.subversion@]:host[:port]/key <br>
+ * 4. corbaname:rir:[/key] <br>
+ * 5. file://[file name]<br>
+ * 6. http://[url]<br>
+ * 7. ftp://[url]<br>
+ *
+ * Protocol defaults to IOP, the object key defaults to the NameService.
+ *
+ * @param corbaloc the string to parse.
+ * @param orb the ORB, needed to create IORs and resolve rir references.
+ *
+ * @return the arrey of strings, first member being the IOR of the
+ * naming service, second member the name in the naming service.
+ */
+ public synchronized String[] corbaloc(String corbaloc,
+ ORB orb)
+ throws InvalidNameException
+ {
+ return corbaloc(corbaloc, orb, 0);
+ }
+
+ /**
+ * Parse controlling against the infinite recursion loop.
+ */
+ private String[] corbaloc(String corbaloc,
+ ORB orb, int recursion) throws InvalidNameException
+ {
+ // The used CORBA specification does not state how many times we should to
+ //redirect, but the infinite loop may be used to knock out the system.
+ // by malicious attempt.
+ if (recursion > 10)
+ throw new DATA_CONVERSION("More than 10 redirections");
+
+ if (corbaloc.startsWith(pxFILE))
+ return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1);
+ else if (corbaloc.startsWith(pxHTTP))
+ return corbaloc(readUrl(corbaloc), orb, recursion+1);
+ else if (corbaloc.startsWith(pxFTP))
+ return corbaloc(readUrl(corbaloc), orb, recursion+1);
+
+ // The version numbers with default values.
+ int major = 1;
+ int minor = 0;
+
+ // The host address.
+ String host;
+
+ // The port.
+ int port = DEFAULT_PORT;
+
+ // The object key as string.
+ String key;
+
+ StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true);
+
+ t = new String[st.countTokens()];
+
+ for (int i = 0; i < t.length; i++)
+ {
+ t[i] = st.nextToken();
+ }
+
+ p = 0;
+
+ if (!t[p].startsWith(pxCORBANAME))
+ throw new InvalidNameException(corbaloc+" must start with "+pxCORBANAME);
+
+ p++;
+
+ if (!t[p++].equals(":"))
+ throw new BAD_PARAM("Syntax (':' expected after name prefix)");
+
+ // Check for rir:
+ if (t[p].equals(RIR))
+ {
+ p++;
+ if (!t[p++].equals(":"))
+ throw new BAD_PARAM("':' expected after 'rir'");
+
+ key = readKey("/");
+
+ Object object;
+ try
+ {
+ object = orb.resolve_initial_references(key);
+ return resolve(orb.object_to_string(object));
+ }
+ catch (InvalidName e)
+ {
+ throw new BAD_PARAM("Unknown initial reference '" + key + "'");
+ }
+ }
+ else
+ // Check for iiop.
+ if (t[p].equals(IIOP) || t[p].equals(":"))
+ {
+ IOR ior = new IOR();
+
+ Addresses: do
+ { // Read addresses.
+ if (t[p].equals(":"))
+ {
+ p++;
+ }
+ else
+ {
+ p++;
+ if (!t[p++].equals(":"))
+ throw new BAD_PARAM("':' expected after 'iiop'");
+ // Check if version is present.
+ if (t[p + 1].equals("."))
+ if (t[p + 3].equals("@"))
+ {
+ // Version info present.
+ try
+ {
+ major = Integer.parseInt(t[p++]);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new BAD_PARAM("Major version number '"
+ + t[p - 1] + "'");
+ }
+ p++; // '.' at this point.
+ try
+ {
+ minor = Integer.parseInt(t[p++]);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new BAD_PARAM("Major version number '"
+ + t[p - 1] + "'");
+ }
+ p++; // '@' at this point.
+ }
+ }
+
+ ior.Internet.version = new Version(major, minor);
+
+ // Then host data goes till '/' or ':'.
+ StringBuffer bhost = new StringBuffer(corbaloc.length());
+ while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(","))
+ bhost.append(t[p++]);
+
+ host = bhost.toString();
+
+ ior.Internet.host = host;
+
+ if (t[p].equals(":"))
+ {
+ // Port specified.
+ p++;
+ try
+ {
+ port = Integer.parseInt(t[p++]);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'");
+ }
+ }
+
+ ior.Internet.port = port;
+
+ // Id is not listed.
+ ior.Id = "";
+
+ if (t[p].equals(","))
+ p++;
+ else
+ break Addresses;
+ }
+ while (true);
+
+ key = readKey("/");
+ ior.key = key.getBytes();
+
+ return resolve(ior.toStringifiedReference());
+ }
+
+ else
+ throw new InvalidNameException("Unsupported protocol '" + t[p] +
+ "' (iiop expected)");
+ }
+
+ /**
+ * Read IOR from the file in the local file system.
+ */
+ String readFile(String file)
+ {
+ File f = new File(file);
+ if (!f.exists())
+ {
+ DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath()
+ + " does not exist.");
+ err.minor = Minor.Missing_IOR;
+ }
+ try
+ {
+ char[] c = new char[(int) f.length()];
+ FileReader fr = new FileReader(f);
+ fr.read(c);
+ fr.close();
+ return new String(c).trim();
+ }
+ catch (IOException ex)
+ {
+ DATA_CONVERSION d = new DATA_CONVERSION();
+ d.initCause(ex);
+ d.minor = Minor.Missing_IOR;
+ throw (d);
+ }
+ }
+
+ /**
+ * Read IOR from the remote URL.
+ */
+ String readUrl(String url)
+ {
+ URL u;
+ try
+ {
+ u = new URL(url);
+ }
+ catch (MalformedURLException mex)
+ {
+ throw new BAD_PARAM("Malformed URL: '" + url + "'");
+ }
+
+ try
+ {
+ InputStreamReader r = new InputStreamReader(u.openStream());
+
+ StringBuffer b = new StringBuffer();
+ int c;
+
+ while ((c = r.read()) > 0)
+ b.append((char) c);
+
+ return b.toString().trim();
+ }
+ catch (Exception exc)
+ {
+ DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed.");
+ d.minor = Minor.Missing_IOR;
+ throw d;
+ }
+ }
+
+ private String[] resolve(String nsIor)
+ {
+ String [] n = new String[2];
+ n[0] = nsIor;
+ n[1] = readKey("#");
+ return n;
+ }
+
+ private String readKey(String delimiter)
+ throws BAD_PARAM
+ {
+ if (p < t.length)
+ if (!t[p].equals(delimiter))
+ {
+ if (t[p].equals("#"))
+ return DEFAULT_NAME;
+ else
+ throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p]
+ + "' found");
+ }
+
+ StringBuffer bKey = new StringBuffer();
+ p++;
+
+ while (p < t.length && !t[p].equals("#"))
+ bKey.append(t[p++]);
+
+ if (bKey.length() == 0)
+ return DEFAULT_NAME;
+
+ try
+ {
+ return URLDecoder.decode(bKey.toString(), "UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new Unexpected("URLDecoder does not support UTF-8", e);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java
new file mode 100644
index 00000000000..9b93f8bb6a8
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java
@@ -0,0 +1,187 @@
+/* GiopNamingEnumeration.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.giop;
+
+import java.util.NoSuchElementException;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.omg.CosNaming.Binding;
+import org.omg.CosNaming.BindingIterator;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+
+/**
+ * Iterates over name class pairs, obtaining values first from the binding list
+ * and then from the binding iterator.
+ *
+ * @author Audrius Meskauskas
+ */
+public abstract class GiopNamingEnumeration implements NamingEnumeration
+{
+ /**
+ * The array of bindings, returned at once.
+ */
+ Binding[] list;
+
+ /**
+ * The binding iterator to obtain the subsequent bindings. May be null,
+ * if all values are stored in the <code>list</code>.
+ */
+ BindingIterator iterator;
+
+ /**
+ * The batch size.
+ */
+ int batch;
+
+ /**
+ * The position of the element in the binding list, that must be returned
+ * during the subsequent call of the next(). If this field is grater or equal
+ * to the lenght of the list, the subsequent values must be requested from the
+ * iterator.
+ */
+ int p;
+
+ GiopNamingEnumeration(BindingListHolder bh, BindingIteratorHolder bih, int batchSize)
+ {
+ list = bh.value;
+ iterator = bih.value;
+ batch = batchSize;
+ }
+
+ /**
+ * Convert from the CORBA binding into that this enumeration should return.
+ *
+ * @param binding
+ * the binding to convert
+ * @return the value, that must be returned by the {@link #next()}.
+ */
+ public abstract Object convert(Binding binding);
+
+ public void close() throws NamingException
+ {
+ if (iterator != null)
+ {
+ iterator.destroy();
+ iterator = null;
+ }
+ }
+
+ /**
+ * Checks if there are more elements to return.
+ *
+ * @throws NamingException
+ * never
+ */
+ public boolean hasMore() throws NamingException
+ {
+ return hasMoreElements();
+ }
+
+ /**
+ * Returns the next element.
+ *
+ * @throws NamingException
+ * never
+ */
+ public Object next() throws NamingException
+ {
+ return nextElement();
+ }
+
+ /**
+ * Checks if there are more elements to return.
+ */
+ public boolean hasMoreElements()
+ {
+ if (p < 0)
+ return false;
+ else if (p < list.length)
+ return true;
+ else
+ return getMore();
+ }
+
+ /**
+ * Returns the next element.
+ */
+ public Object nextElement()
+ {
+ if (p < 0)
+ throw new NoSuchElementException();
+ else if (p < list.length)
+ return convert(list[p++]);
+ else if (getMore())
+ // getMore updates p
+ return convert(list[p++]);
+ else
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Tries to obtain more elements, return true on success. Updates the fields
+ * accordingly.
+ */
+ boolean getMore()
+ {
+ if (iterator != null)
+ {
+ BindingListHolder holder = new BindingListHolder();
+ boolean rt = iterator.next_n(batch, holder);
+ if (rt)
+ {
+ // The new pack of the bindings arrived.
+ p = 0;
+ list = holder.value;
+ return true;
+ }
+ else
+ {
+ iterator.destroy();
+ iterator = null;
+ p = -1;
+ return false;
+ }
+ }
+ else
+ return false;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java
new file mode 100644
index 00000000000..84aa3241365
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java
@@ -0,0 +1,177 @@
+/* GiopNamingServiceFactory.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.giop;
+
+import gnu.CORBA.OrbFunctional;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import javax.naming.Context;
+import javax.naming.Name;
+
+import org.omg.CORBA.ORB;
+
+/**
+ * The context factory to represent the corbaname: style urls. Such URL states
+ * that the CORBA naming service exists on the given host. This service can
+ * return the required object, finding it by the given name. The names are
+ * parsed using the specification of the corbaname urls. Being the naming
+ * service, the returned context supports creating the subcontexts, forwarding
+ * this task to the existing naming service.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+public class GiopNamingServiceFactory
+{
+ /**
+ * The default naming service provider. It is assumed, that the naming service
+ * is running on the port 900 of the local host, using the GIOP version 1.2
+ */
+ public static final String DEFAULT_PROVIDER =
+ "corbaloc:iiop:1.2@127.0.0.1:900/NameService";
+
+ /**
+ * The table of all instantiated ORB's that are found by they ORB
+ * properties signatures. If all ORB related properties are the same,
+ * the ORB's are shared.
+ */
+ public static Hashtable orbs = new Hashtable();
+
+
+ /**
+ * Create a new instance of the corbaname URL context.
+ */
+ public Object getObjectInstance(Object refObj, Name name, Context nameCtx,
+ Hashtable environment)
+ {
+ String provider = (String) environment.get(Context.PROVIDER_URL);
+ if (provider == null)
+ provider = DEFAULT_PROVIDER;
+
+ String orbSignature = getOrbSignature(environment);
+
+ ORB orb;
+ synchronized (orbs)
+ {
+ orb = (ORB) orbs.get(orbSignature);
+ if (orb == null)
+ {
+ Properties props = new Properties();
+ props.putAll(environment);
+ orb = ORB.init(new String[0], props);
+ orbs.put(orbSignature, orb);
+ final ORB runIt = orb;
+ new Thread()
+ {
+ public void run()
+ {
+ runIt.run();
+ }
+ }.start();
+ }
+ }
+
+ return new GiopNamingServiceURLContext(environment, this, orb);
+ }
+
+ /**
+ * Check if this ORB is still in use (maybe it is time to shutdown it). This
+ * method only works when the Classpath CORBA implementation is used
+ * (otherwise it return without action). The method is called from the close()
+ * method of the created context.
+ *
+ * @param orb
+ * the ORB that maybe is no longer referenced.
+ */
+ public void checkIfReferenced(ORB orb)
+ {
+ synchronized (orbs)
+ {
+ // We can only do this with the Classpath implementation.
+ if (orb instanceof OrbFunctional)
+ {
+ OrbFunctional cOrb = (OrbFunctional) orb;
+ // If there are no connected objects, we can destroy the orb.
+ if (cOrb.countConnectedObjects() == 0)
+ {
+ cOrb.shutdown(false);
+ cOrb.destroy();
+
+ Enumeration keys = orbs.keys();
+ Object key;
+ Remove: while (keys.hasMoreElements())
+ {
+ key = keys.nextElement();
+ if (orbs.get(key) == orb)
+ {
+ orbs.remove(key);
+ break Remove;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get all properties.
+ */
+ public String getOrbSignature(Map props)
+ {
+ TreeMap map = new TreeMap();
+ map.putAll(props);
+ StringBuffer b = new StringBuffer(50*props.size());
+
+ Iterator iter = map.entrySet().iterator();
+ Map.Entry m;
+ while (iter.hasNext())
+ {
+ m = (Map.Entry) iter.next();
+ b.append(m.getKey());
+ b.append('=');
+ b.append(m.getValue());
+ }
+ return b.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java
new file mode 100644
index 00000000000..50446ac7edd
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java
@@ -0,0 +1,840 @@
+/* GiopNamingServiceURLContext.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.giop;
+
+import gnu.CORBA.NamingService.Ext;
+import gnu.CORBA.NamingService.NameTransformer;
+
+import java.util.Hashtable;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.ContextNotEmptyException;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.directory.InvalidAttributesException;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.portable.Delegate;
+import org.omg.CORBA.portable.ObjectImpl;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContext;
+import org.omg.CosNaming.NamingContextExt;
+import org.omg.CosNaming.NamingContextExtHelper;
+import org.omg.CosNaming.NamingContextHelper;
+import org.omg.CosNaming._NamingContextExtStub;
+import org.omg.CosNaming._NamingContextStub;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+
+/**
+ * The context to represent the corba naming service. Being the naming service,
+ * the returned context supports creating the subcontexts, forwarding this task
+ * to the existing naming service. When listing bindings, it uses the
+ * {@link Context#BATCHSIZE} property to determine, how many bindings should
+ * be returned at once (the process is transparend)
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+public class GiopNamingServiceURLContext extends CorbalocParser implements
+ Context
+{
+ /**
+ * This number of bindings will be requested from the naming server at once,
+ * while the subsequent bindings will be requested via binding iterator one by
+ * one. Use {@link Context#BATCHSIZE} to override the value of this constant.
+ */
+ public int DEFAULT_BATCH_SIZE = 20;
+
+ /**
+ * The object request broker, used to access the naming service. This field
+ * is only initialised when the context is constructed from the URL.
+ */
+ ORB orb;
+
+ /**
+ * The properties.
+ */
+ Hashtable properties;
+
+ /**
+ * The parent factory.
+ */
+ GiopNamingServiceFactory factory;
+
+ /**
+ * The name transformer to obtain the name from its string representation. The
+ * to_name method of the naming service is avoided as it may be remote and
+ * hence expensive. The conversion rules are standard and cannot be service
+ * specific.
+ */
+ static NameTransformer transformer = new NameTransformer();
+
+ /**
+ * The batch size for list operations - how many to return at once.
+ */
+ public final int howMany;
+
+ /**
+ * Creates a new naming context that uses naming service, represented by the
+ * given CORBA object.
+ *
+ * @param props
+ * the environment table.
+ * @param aFactory
+ * parent factory. This reference is used during cleanup.
+ * @param anOrb
+ * the associated ORB. This reference is used during cleanup.
+ */
+ public GiopNamingServiceURLContext(Hashtable props,
+ GiopNamingServiceFactory aFactory,
+ ORB anOrb)
+ {
+ factory = aFactory;
+ orb = anOrb;
+
+ properties = props;
+ howMany = getBatchSize();
+ }
+
+ public NamingContextExt getService(String address)
+ {
+ org.omg.CORBA.Object nsObject = orb.string_to_object(address);
+ Delegate delegate = ((ObjectImpl) nsObject)._get_delegate();
+
+ // If the IOR provides the IDL ID, we can check if our name
+ // service is old NamingContext or new NamingContextExt.
+ // Not all forms of the URL always provide the IDL id.
+ if (!nsObject._is_a(NamingContextExtHelper.id())
+ && nsObject._is_a(NamingContextHelper.id()))
+ {
+ // We are surely working with the old version.
+ _NamingContextStub stub = new _NamingContextStub();
+ stub._set_delegate(delegate);
+ // The Ext object will add the necessary extensions.
+ return new Ext(stub);
+ }
+ else
+ {
+ // We expecte the service to be the NamingContextExt (this is true
+ // for both Sun's and our implementations). There is no easy way
+ // to check the version.
+ _NamingContextExtStub stub = new _NamingContextExtStub();
+ stub._set_delegate(delegate);
+ return stub;
+ }
+ }
+
+ /**
+ * Split the corbaname name into the address of the naming service (first
+ * part) and the name of the object in the naming service (second part)
+ */
+ public String[] split(String corbaloc) throws InvalidNameException
+ {
+ if (corbaloc.endsWith("#"))
+ corbaloc = corbaloc.substring(0, corbaloc.length() - 1);
+
+ // No name part - parse as corbaname.
+ if (corbaloc.indexOf('#') < 0)
+ {
+ if (!corbaloc.regionMatches(true, 0, pxCORBANAME, 0,
+ pxCORBANAME.length()))
+ throw new InvalidNameException(corbaloc + " must start with "
+ + pxCORBANAME);
+ corbaloc = pxCORBALOC + corbaloc.substring(pxCORBANAME.length());
+ return new String[] { corbaloc, "" };
+ }
+
+ return corbaloc(corbaloc, orb);
+ }
+
+ /**
+ * Give the specified name for the specified object. The passed name must not
+ * be already bound to some other object. The components of the name are
+ * mapped into the components of the CORBA name.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws NameAlreadyBoundException
+ * if this name is already used to name some object.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ bind(name.toString(), obj);
+ }
+
+ /**
+ * Give the specified name for the specified object. The passed name must not
+ * be already bound to some other object.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws NameAlreadyBoundException
+ * if this name is already used to name some object.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ String[] n = split(name);
+ org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj;
+ getService(n[0]).bind(transformer.toName(n[1]), object);
+ }
+ catch (ClassCastException e)
+ {
+ throw new NamingException(org.omg.CORBA.Object.class + " required ");
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (AlreadyBound e)
+ {
+ throw new NameAlreadyBoundException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Releases all resources, associated with this context. The close() method
+ * can be called several times, but after it has been once invoked, it is not
+ * allowed to call any other method of this context. This method destroys
+ * the ORB, if we have one.
+ *
+ * @throws NamingException
+ */
+ public void close() throws NamingException
+ {
+ if (orb != null && factory != null)
+ {
+ factory.checkIfReferenced(orb);
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported
+ */
+ public String composeName(String name1, String name2) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Creates the new naming subcontext and binds it to the current (this)
+ * context. The returned object will wrap around the newly created CORBA
+ * subcontext
+ *
+ * @param subContext
+ * the name of the new context being created
+ * @return the newly created context, bound to the instance of the context on
+ * that the method has been called
+ * @throws NameAlreadyBoundException
+ * if this name is already bound
+ * @throws InvalidAttributesException
+ * if the creation of the new context requires the missing mandatory
+ * attributes
+ * @throws NamingException
+ */
+ public Context createSubcontext(Name subContext) throws NamingException
+ {
+ return createSubcontext(subContext.toString());
+ }
+
+ /**
+ * Creates the new naming subcontext and binds it to the current (this)
+ * context. The returned object will wrap around the newly created CORBA
+ * subcontext
+ *
+ * @param subContext
+ * the name of the new context being created
+ * @return the newly created context, bound to the instance of the context on
+ * that the method has been called
+ * @throws NameAlreadyBoundException
+ * if this name is already bound
+ * @throws InvalidAttributesException
+ * if the creation of the new context requires the missing mandatory
+ * attributes
+ * @throws NamingException
+ */
+ public Context createSubcontext(String subContext) throws NamingException
+ {
+ try
+ {
+ String[] n = split(subContext);
+ org.omg.CORBA.Object subcontext = getService(n[0]).bind_new_context(
+ transformer.toName(n[1]));
+ Hashtable clonedProps = new Hashtable();
+ clonedProps.putAll(properties);
+
+ // Nulls are passed both for orb and factory, as the child contexts
+ // need not to do any cleanup.
+ return new ContextContinuation(subcontext, clonedProps, null, null);
+ }
+ catch (AlreadyBound e)
+ {
+ throw new NameAlreadyBoundException(subContext);
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException(subContext);
+ }
+ catch (Exception ex)
+ {
+ throw new NamingException(ex.toString());
+ }
+ }
+
+ /**
+ * Removes the naming subcontext from this naming context. Returns without
+ * action if such subcontext does not exist. The context being destroyed must
+ * be empty.
+ *
+ * @param subContext
+ * the name of the subcontext beig removed.
+ * @throws ContextNotEmptyException
+ * if the named context is not empty.
+ * @throws NamingException
+ */
+ public void destroySubcontext(Name subContext) throws NamingException
+ {
+ unbind(subContext);
+ }
+
+ /**
+ * Removes the naming subcontext from this naming context. Returns without
+ * action if such subcontext does not exist. The context being destroyed must
+ * be empty.
+ *
+ * @param subContext
+ * the name of the subcontext beig removed.
+ * @throws ContextNotEmptyException
+ * if the named context is not empty.
+ * @throws NamingException
+ */
+ public void destroySubcontext(String subContext) throws NamingException
+ {
+ unbind(subContext);
+ }
+
+ /**
+ * Returs the empty string.
+ */
+ public String getNameInNamespace() throws NamingException
+ {
+ return "";
+ }
+
+ /**
+ * Not supported.
+ */
+ public NameParser getNameParser(Name name) throws NamingException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public NameParser getNameParser(String name) throws NamingException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Creates and returns the enumeration over the name bindings that are present
+ * the given subcontext. The enumeration elements have the type of
+ * {@link NameClassPair}, providing also information about the class of the
+ * bound object. The behaviour in the case if the bindings are added or
+ * removed later is not defined. The contents of the subcontexts are not
+ * included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ return list(name.toString());
+ }
+
+ /**
+ * Creates and returns the enumeration over the name bindings that are present
+ * the given subcontext. The enumeration elements have the type of
+ * {@link NameClassPair}, providing also information about the class of the
+ * bound object. The behaviour in the case if the bindings are added or
+ * removed later is not defined. The contents of the subcontexts are not
+ * included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ BindingIteratorHolder bi = new BindingIteratorHolder();
+ BindingListHolder bl = new BindingListHolder();
+
+ NamingContext subcontext;
+
+ String [] n = split(name);
+ NamingContextExt service = getService(n[0]);
+
+ if (n[1].length() == 0)
+ subcontext = service;
+ else
+ {
+ try
+ {
+ subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1])));
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+
+ }
+
+ subcontext.list(howMany, bl, bi);
+
+ return new ListEnumeration(bl, bi, howMany);
+ }
+
+ /**
+ * Creates and returns the enumeration over the name - object bindings that
+ * are present the given subcontext. The enumeration elements have the type of
+ * {@link Binding}, providing also information about the class of the bound
+ * object. The behaviour in the case if the bindings are added or removed
+ * later is not defined. The contents of the subcontexts are not included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ return listBindings(name.toString());
+ }
+
+ /**
+ * Creates and returns the enumeration over the name - object bindings that
+ * are present the given subcontext. The enumeration elements have the type of
+ * {@link Binding}, providing also information about the class of the bound
+ * object. The behaviour in the case if the bindings are added or removed
+ * later is not defined. The contents of the subcontexts are not included.
+ *
+ * @param name
+ * the name of the subcontext
+ * @return the enumeration over the names, known for the given subcontext.
+ * @throws NamingException
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ BindingIteratorHolder bi = new BindingIteratorHolder();
+ BindingListHolder bl = new BindingListHolder();
+
+ NamingContext subcontext;
+
+ String [] n = split(name);
+ NamingContextExt service = getService(n[0]);
+
+ if (n[1].length() == 0)
+ subcontext = service;
+ else
+ {
+ try
+ {
+ subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1])));
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+
+ }
+
+ subcontext.list(howMany, bl, bi);
+
+ return new ListBindingsEnumeration(bl, bi, howMany, subcontext);
+ }
+
+ /**
+ * Gets the previously named object by name. If the passed name is empty, the
+ * method should return a cloned instance of this naming context.
+ *
+ * @param name
+ * the name of the object being searched in this context
+ * @return the named object
+ * @throws NameNotFoundException
+ * if the name is not found
+ */
+ public Object lookup(Name name) throws NamingException
+ {
+ return lookup(name.toString());
+ }
+
+ /**
+ * Gets the previously named object by name. If the passed name is empty, the
+ * method should return a cloned instance of this naming context.
+ *
+ * @param name
+ * the name of the object being searched in this context
+ * @return the named object
+ * @throws NamingException
+ * if the naming fails.
+ */
+ public Object lookup(String name) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ NamingContextExt service = getService(n[0]);
+ return service.resolve_str(n[1]);
+ }
+ catch (NotFound e)
+ {
+ throw new NameNotFoundException();
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Give the specified name for the specified object. Unlike bind, this method
+ * silently replaces the existing binding for this name, if one exists.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ rebind(name.toString(), obj);
+ }
+
+ /**
+ * Give the specified name for the specified object. Unlike bind, this method
+ * silently replaces the existing binding for this name, if one exists.
+ *
+ * @param name
+ * the name that will be given to the object (in the scope of this
+ * context).
+ * @param obj
+ * the object being named.
+ * @throws InvalidAttributesException
+ * if the object does not supply all required attributes.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ String[] n = split(name);
+ NamingContextExt service = getService(n[0]);
+
+ org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj;
+ service.rebind(transformer.toName(n[1]), object);
+ }
+ catch (ClassCastException e)
+ {
+ throw new NamingException(org.omg.CORBA.Object.class + " required ");
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException();
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Renames the existing binding, removing the existing and giving the new name
+ * for the same object.
+ *
+ * @param oldName
+ * the existing name of the known object
+ * @param newName
+ * the new name of the same object
+ * @throws NameNotFoundException
+ * if the oldName is unknown for this context
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ Object object = lookup(oldName);
+ unbind(oldName);
+ bind(newName, object);
+ }
+
+ /**
+ * Renames the existing binding, removing the existing and giving the new name
+ * for the same object.
+ *
+ * @param oldName
+ * the existing name of the known object
+ * @param newName
+ * the new name of the same object
+ * @throws NameNotFoundException
+ * if the oldName is unknown for this context
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void rename(String oldName, String newName) throws NamingException
+ {
+ Object object = lookup(oldName);
+ unbind(oldName);
+ bind(newName, object);
+ }
+
+ /**
+ * Removes the name - object mapping from the current context. This method
+ * returns without action if the name is not bound to an object in the
+ * terminal context, but throws {@link NameNotFoundException} if one of the
+ * intermadiate contexts does not exist.
+ *
+ * @param name
+ * the name to be removed
+ * @throws NameNotFoundException
+ * if one of the intermediate naming contexts does not exist. Will
+ * not be thrown if just the terminal binding is missing.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void unbind(Name name) throws NamingException
+ {
+ unbind(name.toString());
+ }
+
+ /**
+ * Removes the name - object mapping from the current context. This method
+ * returns without action if the name is not bound to an object in the
+ * terminal context, but throws {@link NameNotFoundException} if one of the
+ * intermadiate contexts does not exist.
+ *
+ * @param name
+ * the name to be removed
+ * @throws NameNotFoundException
+ * if one of the intermediate naming contexts does not exist. Will
+ * not be thrown if just the terminal binding is missing.
+ * @throws NamingException
+ * if the naming operation has failed due other reasons.
+ */
+ public void unbind(String name) throws NamingException
+ {
+ try
+ {
+ String[] n = split(name);
+ NamingContextExt service = getService(n[0]);
+
+ service.unbind(transformer.toName(n[1]));
+ }
+ catch (NotFound e)
+ {
+ throw new NameNotFoundException(name);
+ }
+ catch (CannotProceed e)
+ {
+ throw new ContextNotEmptyException(name);
+ }
+ catch (InvalidName e)
+ {
+ throw new InvalidNameException(name);
+ }
+ }
+
+ /**
+ * Add new environment property to the environment of this context. Both name
+ * and value of the new property must not be null. If the property is already
+ * defined, is current value is replaced by the propVal.
+ *
+ * @param key
+ * the name of the new property
+ * @param value
+ * the value of the new property
+ * @return the previous value of this property or null if the property has not
+ * been previously defined
+ * @throws NamingException
+ */
+ public Object addToEnvironment(String key, Object value)
+ throws NamingException
+ {
+ if (key == null || value == null)
+ throw new NullPointerException();
+ return properties.put(key, value);
+ }
+
+ /**
+ * Returns the environment, associated with this naming context. The returned
+ * table should never be modified by the caller. Use {@link #addToEnvironment}
+ * and {@link #removeFromEnvironment} to modify the environement, if needed.
+ *
+ * @return the table, representing the environment of this context
+ * @throws NamingException
+ */
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return properties;
+ }
+
+ /**
+ * Removes the property with the given name from the environment. Returns
+ * without action if this property is not defined.
+ *
+ * @param propName
+ * the name of the property being removed.
+ * @return the value of the property that has been removed or null if the
+ * property was not defined.
+ * @throws NamingException
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ return properties.remove(propName);
+ }
+
+ /**
+ * Convert the {@link Name} into array of the name components, required to the
+ * CORBA naming service. First the string representation is obtained, then
+ * it is converted using parsing rules of the CORBA name.
+ *
+ * @param name
+ * then name to convert
+ * @return the converted array of components.
+ */
+ public NameComponent[] toGiop(Name name) throws InvalidName
+ {
+ return transformer.toName(name.toString());
+ }
+
+ /**
+ * Get the batch size from the environment properties. The batch size is used
+ * for listing operations.
+ *
+ * @return the batch size, or some default value if not specified.
+ */
+ public int getBatchSize()
+ {
+ int batchSize = DEFAULT_BATCH_SIZE;
+ Object bs = properties.get(Context.BATCHSIZE);
+ if (bs != null)
+ {
+ try
+ {
+ int b = Integer.parseInt(bs.toString());
+ if (b >= 0)
+ batchSize = b;
+ }
+ catch (NumberFormatException e)
+ {
+ // OK, use default value.
+ }
+ }
+ return batchSize;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java
new file mode 100644
index 00000000000..00f4a0779c7
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java
@@ -0,0 +1,116 @@
+/* ListBindingsEnumeration.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.giop;
+
+import javax.naming.NamingEnumeration;
+
+import org.omg.CosNaming.Binding;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.NamingContext;
+
+/**
+ * Iterates over bindings, obtaining values first from the binding list and then
+ * from the binding iterator.
+ *
+ * @author Audrius Meskauskas
+ */
+public class ListBindingsEnumeration extends GiopNamingEnumeration implements
+ NamingEnumeration
+{
+ /**
+ * The naming service, to resolve the objects.
+ */
+ NamingContext service;
+
+ /**
+ * Create the new enumeration
+ *
+ * @param bh
+ * holder, containing the first portion of the bindings
+ * @param bih
+ * the iterator, containing the remaining bindings
+ * @param batchSize
+ * the number of bindings the the iterator will be requested to
+ * return as a single pack
+ * @param aService
+ * the naming service, used to obtain the objects, bound to the
+ * names.
+ */
+ public ListBindingsEnumeration(BindingListHolder bh,
+ BindingIteratorHolder bih, int batchSize,
+ NamingContext aService)
+ {
+ super(bh, bih, batchSize);
+ service = aService;
+ }
+
+ /**
+ * Convert from the CORBA binding into the javax.naming binding. As the CORBA
+ * naming service binding does not contain the object itself, this method
+ * makes the additional calls to the naming service.
+ *
+ * @param binding
+ * the binding to convert
+ * @return the value, that must be returned by the {@link #next()}.
+ */
+ public Object convert(Binding binding)
+ {
+ StringBuffer name = new StringBuffer();
+
+ for (int i = 0; i < binding.binding_name.length; i++)
+ {
+ name.append(binding.binding_name[i]);
+ if (i < binding.binding_name.length - 1)
+ name.append('/');
+ }
+
+ try
+ {
+ Object object = service.resolve(binding.binding_name);
+ return new javax.naming.Binding(name.toString(), object);
+ }
+ catch (Exception e)
+ {
+ // Probably was removed by the concurent thread.
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java
new file mode 100644
index 00000000000..2e64e67d393
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java
@@ -0,0 +1,116 @@
+/* ListEnumeration.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.giop;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+
+import org.omg.CosNaming.Binding;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.BindingType;
+import org.omg.CosNaming.NamingContext;
+
+/**
+ * Iterates over name class pairs, obtaining values first from the binding list
+ * and then from the binding iterator.
+ *
+ * @author Audrius Meskauskas
+ */
+public class ListEnumeration extends GiopNamingEnumeration implements
+ NamingEnumeration
+{
+ /**
+ * Create the new enumeration
+ *
+ * @param bh
+ * holder, containing the first portion of the bindings
+ * @param bih
+ * the iterator, containing the remaining bindings
+ * @param batchSize
+ * the number of bindings the the iterator will be requested to
+ * return as a single pack
+ */
+ public ListEnumeration(BindingListHolder bh,
+ BindingIteratorHolder bih, int batchSize)
+ {
+ super(bh, bih, batchSize);
+ }
+
+ /**
+ * Convert from the CORBA binding into the {@link NameClassPair} that this
+ * enumeration should return. This method converts into NameClassPair,
+ * connecting the name components with slashes and setting the class name
+ * to either NamingContext or GIOP Object.
+ *
+ * @param binding
+ * the binding to convert
+ * @return the value, that must be returned by the {@link #next()}.
+ */
+ public Object convert(Binding binding)
+ {
+ StringBuffer name = new StringBuffer();
+
+ for (int i = 0; i < binding.binding_name.length; i++)
+ {
+ name.append(binding.binding_name[i]);
+ if (i < binding.binding_name.length - 1)
+ name.append('/');
+ }
+
+ String className;
+
+ switch (binding.binding_type.value())
+ {
+ case BindingType._ncontext:
+ className = NamingContext.class.getName();
+ break;
+ case BindingType._nobject:
+ className = org.omg.CORBA.Object.class.getName();
+ break;
+ default:
+ className = Object.class.getName();
+ break;
+ }
+
+ NameClassPair pair = new NameClassPair(name.toString(), className);
+ return pair;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java b/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java
new file mode 100644
index 00000000000..b20bfa4ea8b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java
@@ -0,0 +1,467 @@
+/* GnuName.java -- implementation of the javax.naming.Name
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.ictxImpl.trans;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+
+/**
+ * The implementation of the {@link Name}.
+ *
+ * @author Audrius Meskauskas
+ */
+public class GnuName
+ implements Name
+{
+ /**
+ * The enumeration to traverse over name components.
+ */
+ class GnuNameEnum
+ implements Enumeration
+ {
+ /**
+ * Get the new enumeration that enumerates from the given position forward
+ *
+ * @param position the position of the first name component to enumerate (0
+ * means first element)
+ */
+ GnuNameEnum(int position)
+ {
+ nxt = from + position;
+ }
+
+ /**
+ * The position of the next enumeration component to be returned or -1 if
+ * the end has been reached.
+ */
+ int nxt;
+
+ /**
+ * Check if there are more elements in this enumeration.
+ */
+ public boolean hasMoreElements()
+ {
+ return nxt >= 0;
+ }
+
+ /**
+ * Return the next element or throw a NoSuchElementException if there is no
+ * any.
+ */
+ public Object nextElement()
+ {
+ if (nxt < 0)
+ throw new NoSuchElementException();
+ Object r = content[nxt++];
+
+ if (nxt - from == length)
+ nxt = - 1;
+
+ return r;
+ }
+ }
+
+ private static final long serialVersionUID = - 3617482732056931635L;
+
+ /**
+ * The hashcode
+ */
+ int hash;
+
+ /**
+ * The content buffer of the name. This buffer may be shared, so the array
+ * member content should never be modified.
+ */
+ String[] content;
+
+ /**
+ * The place, inclusive, where the name content starts in the content buffer.
+ */
+ int from;
+
+ /**
+ * The length of the name.
+ */
+ int length;
+
+ /**
+ * Creates the unitialised name.
+ */
+ protected GnuName()
+ {
+
+ }
+
+ /**
+ * Creates the name, containing from the given chain of the atomic components.
+ *
+ * @param name the array, containing the name components.
+ */
+ public GnuName(String[] name)
+ {
+ this(name, 0, name.length);
+ }
+
+ /**
+ * Creates the name that uses the given portion of the array for its
+ * components.
+ */
+ public GnuName(String[] buffer, int useFrom, int useLength)
+ {
+ content = buffer;
+ from = useFrom;
+ length = useLength;
+ }
+
+ /**
+ * Inserts the given <code>String</code> component to this <code>Name</code>
+ * at the given index. The method modifies the current <code>Name</code> and
+ * then returns it.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ * @exception InvalidNameException if the given <code>String</code> is not a
+ * valid component for this <code>Name</code>.
+ */
+ public Name add(int posn, String comp) throws InvalidNameException
+ {
+ String[] nc = new String[content.length + 1];
+ System.arraycopy(content, from, nc, 0, posn);
+ nc[posn] = comp;
+ System.arraycopy(content, from + posn, nc, posn + 1, length - posn);
+
+ content = nc;
+ from = 0;
+ length = content.length;
+ hash = 0;
+ return this;
+ }
+
+ /**
+ * Adds the given <code>String</code> component to the end of this
+ * <code>Name</code>. The method modifies the current <code>Name</code>
+ * and then returns it.
+ *
+ * @exception InvalidNameException if the given <code>String</code> is not a
+ * valid component for this <code>Name</code>.
+ */
+ public Name add(String comp) throws InvalidNameException
+ {
+ String[] nc = new String[content.length + 1];
+ System.arraycopy(content, from, nc, 0, length);
+ nc[nc.length - 1] = comp;
+
+ content = nc;
+ from = 0;
+ length = content.length;
+ hash = 0;
+ return this;
+ }
+
+ /**
+ * Inserts all the components of the given <code>Name</code> to this
+ * <code>Name</code> at the given index. Components after this index (if
+ * any) are shifted up. The method modifies the current <code>Name</code>
+ * and then returns it.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ * @exception InvalidNameException if any of the given components is not a
+ * valid component for this <code>Name</code>.
+ */
+ public Name addAll(int posn, Name n) throws InvalidNameException
+ {
+ String[] nc = new String[length + n.size()];
+ System.arraycopy(content, from, nc, 0, posn);
+
+ int i = posn;
+ for (int p = 0; p < n.size(); i++, p++)
+ nc[i] = n.get(p);
+
+ System.arraycopy(content, from + posn, nc, i, length - posn);
+
+ length = length + n.size();
+ hash = 0;
+ content = nc;
+ return this;
+ }
+
+ /**
+ * Adds all the components of the given <code>Name</code> to the end of this
+ * <code>Name</code>. The method modifies the current <code>Name</code>
+ * and then returns it.
+ *
+ * @exception InvalidNameException if any of the given components is not a
+ * valid component for this <code>Name</code>.
+ */
+ public Name addAll(Name suffix) throws InvalidNameException
+ {
+ String[] nc = new String[length + suffix.size()];
+ System.arraycopy(content, from, nc, 0, length);
+
+ for (int i = length, p = 0; i < nc.length; i++, p++)
+ nc[i] = suffix.get(p);
+
+ length = length + suffix.size();
+ hash = 0;
+ content = nc;
+ return this;
+ }
+
+ /**
+ * Compares the given object to this <code>Name</code>. Returns a negative
+ * value if the given <code>Object</code> is smaller then this
+ * <code>Name</code>, a positive value if the <code>Object</code> is
+ * bigger, and zero if the are equal. If the <code>Object</code> is not of a
+ * class that can be compared to the class of this <code>Name</code> then a
+ * <code>ClassCastException</code> is thrown. Note that it is not guaranteed
+ * that <code>Name</code>s implemented in different classes can be
+ * compared. The definition of smaller, bigger and equal is up to the actual
+ * implementing class.
+ */
+ public int compareTo(Object obj)
+ {
+ Name n = (Name) obj;
+
+ int l = Math.min(length, n.size());
+ int c;
+
+ for (int i = 0; i < l; i++)
+ {
+ c = content[from + i].compareTo(n.get(i));
+ if (c != 0)
+ return c;
+ }
+ return length - n.size();
+ }
+
+ /**
+ * Returns <code>true</code> if this <code>Name</code> ends with the
+ * components of the given <code>Name</code>, <code>false</code>
+ * otherwise.
+ */
+ public boolean endsWith(Name n)
+ {
+ if (n.size() > length)
+ return false;
+
+ int ofs = length - n.size() + from;
+
+ for (int i = 0; i < n.size(); i++, ofs++)
+ if (! content[ofs].equals(n.get(i)))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Gets the component at the given index.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ */
+ public String get(int posn)
+ {
+ return content[from + posn];
+ }
+
+ /**
+ * Returns a non-null (but possibly empty) <code>Enumeration</code> of the
+ * components of the <code>Name</code> as <code>String</code>s.
+ */
+ public Enumeration getAll()
+ {
+ return new GnuNameEnum(0);
+ }
+
+ /**
+ * Returns the components till the given index as a <code>Name</code>. The
+ * returned <code>Name</code> can be modified without changing the original.
+ *
+ * @param posn the ending position, exclusive
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ */
+ public Name getPrefix(int posn)
+ {
+ return new GnuName(content, from, posn);
+ }
+
+ /**
+ * Returns the components from the given index till the end as a
+ * <code>Name</code>. The returned <code>Name</code> can be modified
+ * without changing the original.
+ *
+ * @param posn the starting position, inclusive. If it is equal to the size of
+ * the name, the empty name is returned.
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ */
+ public Name getSuffix(int posn)
+ {
+ return new GnuName(content, from + posn, length - posn);
+ }
+
+ /**
+ * Returns <code>true</code> if the number of components of this
+ * <code>Name</code> is zero, <code>false</code> otherwise.
+ */
+ public boolean isEmpty()
+ {
+ return length == 0;
+ }
+
+ /**
+ * Removes the component at the given index from this <code>Name</code>.
+ * The method modifies the current <code>Name</code> and then returns it.
+ *
+ * @exception InvalidNameException if the name size reduces below zero.
+ */
+ public Object remove(int posn) throws InvalidNameException
+ {
+ if (length == 0)
+ throw new InvalidNameException("negative size");
+ else
+ {
+ length--;
+ if (posn == 0)
+ from++;
+ else if (posn < length)
+ {
+ String[] nc = new String[length];
+ System.arraycopy(content, from, nc, 0, posn);
+ System.arraycopy(content, from + posn + 1, nc, posn, length - posn);
+ content = nc;
+ from = 0;
+ }
+ }
+ hash = 0;
+ return this;
+ }
+
+ /**
+ * Returns the number of components of this <code>Name</code>. The returned
+ * number can be zero.
+ */
+ public int size()
+ {
+ return length;
+ }
+
+ /**
+ * Returns <code>true</code> if this <code>Name</code> starts with the
+ * components of the given <code>Name</code>, <code>false</code>
+ * otherwise.
+ */
+ public boolean startsWith(Name n)
+ {
+ if (n.size() > length)
+ return false;
+
+ for (int i = 0; i < n.size(); i++)
+ if (! content[from + i].equals(n.get(i)))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Returns a clone of this <code>Name</code>. It will be a deep copy of all
+ * the components of the <code>Name</code> so that changes to components of
+ * the components does not change the component in this <code>Name</code>.
+ */
+ public Object clone()
+ {
+ return new GnuName(content, from, length);
+ }
+
+ /**
+ * The name is equal to other name if they contents are equal.
+ */
+ public boolean equals(Object arg0)
+ {
+ if (this == arg0)
+ return true;
+ else if (arg0 instanceof Name)
+ {
+ Name n = (Name) arg0;
+ if (length != n.size())
+ return false;
+
+ for (int i = 0; i < length; i++)
+ if (! content[from + i].equals(n.get(i)))
+ return false;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Overridden to make consistent with equals.
+ */
+ public int hashCode()
+ {
+ if (hash == 0 && length > 0)
+ {
+ int s = 0;
+ for (int i = from; i < from + length; i++)
+ s ^= content[i].hashCode();
+ hash = s;
+ }
+ return hash;
+ }
+
+ /**
+ * Get the string representation, separating the name components by slashes
+ */
+ public String toString()
+ {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < length; i++)
+ {
+ b.append(get(i));
+ if (i < length - 1)
+ b.append('/');
+ }
+ return b.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java b/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java
new file mode 100644
index 00000000000..7fe2e5c8cad
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java
@@ -0,0 +1,53 @@
+/* corbanameURLContextFactory.java -- handles corbaname: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.jndi.url.corbaname;
+
+import gnu.javax.naming.giop.GiopNamingServiceFactory;
+
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * The GIOP URL context factory.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+public class corbanameURLContextFactory extends GiopNamingServiceFactory
+ implements ObjectFactory
+{
+ // Nothing to override here.
+}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java
new file mode 100644
index 00000000000..de79b93c3dc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java
@@ -0,0 +1,597 @@
+/* ContextContinuation.java -- RMI naming context
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.jndi.url.rmi;
+
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+
+/**
+ * The implementation of the RMI URL context. This context connects
+ *
+ * @author Audrius Meskauskas
+ */
+public class ContextContinuation implements Context
+{
+ /**
+ * The default registry location.
+ */
+ public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099";
+
+ /**
+ * The local or remote RMI registry, performing the actual work for this
+ * context.
+ */
+ Registry registry;
+
+ /**
+ * The properties.
+ */
+ Properties properties;
+
+ /**
+ * The flag, indicating, that the lookup methods were called before.
+ * If the lookup methods were called before, the existing ORB cannot be
+ * destroyed, as references to the existing objects will become
+ * unfunctional.
+ */
+ boolean lookupCalled;
+
+ /**
+ * Add new environment property to the environment of this context. Both name
+ * and value of the new property must not be null. If the property is already
+ * defined, is current value is replaced by the propVal. This method replaces
+ * the registry. The new registry will be lazily instantiated on the first
+ * call.
+ *
+ * @param propName
+ * the name of the new property
+ * @param propVal
+ * the value of the new property
+ * @return the previous value of this property or null if the property has not
+ * been previously defined
+ */
+ public Object addToEnvironment(String key, Object value)
+ {
+ removeRegistry();
+ if (key == null || value == null)
+ throw new NullPointerException();
+ return properties.put(key, value);
+ }
+
+ /**
+ * Returns the environment, associated with this naming context. The returned
+ * table should never be modified by the caller (the registry would not be updated
+ * in such case). Use {@link #addToEnvironment} and
+ * {@link #removeFromEnvironment} to modify the environement, if needed.
+ *
+ * @return the table, representing the environment of this context
+ * @throws NamingException
+ */
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return properties;
+ }
+
+ /**
+ * Removes the property with the given name from the environment. Returns
+ * without action if this property is not defined. Replaces the ORB,
+ * constructing the new ORB with the changes set of properties (you can
+ * replace the CORBA implementation provider, for instance). The new ORB will
+ * be lazily instantiated on the first call.
+ *
+ * @param propName
+ * the name of the property being removed.
+ * @return the value of the property that has been removed or null if the
+ * property was not defined.
+ * @throws NamingException
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ removeRegistry();
+ return properties.remove(propName);
+ }
+
+ /**
+ * Remove the current registry reference.
+ */
+ public void removeRegistry()
+ {
+ registry = null;
+ }
+
+ /**
+ * Get the cached or new registry reference.
+ *
+ * @return the registry reference, either cached or new.
+ */
+ public Registry getRegistry() throws NamingException
+ {
+ if (registry == null)
+ {
+ String address = properties.getProperty(Context.PROVIDER_URL,
+ DEFAULT_REGISTRY_LOCATION);
+
+ // The format like rmi://localhost:1099 is expected. Parse.
+ if (!address.startsWith("rmi://"))
+ throw new InvalidNameException(address);
+
+ String a = address.substring("rmi://".length());
+
+ // The colon, if present, indicates the start of the port number.
+ int colon = a.lastIndexOf(':');
+ int port;
+
+ try
+ {
+ if (colon >=0)
+ {
+ port = Integer.parseInt(a.substring(colon+1));
+ a = a.substring(0, colon);
+ }
+ else
+ port = Registry.REGISTRY_PORT;
+ }
+ catch (NumberFormatException e1)
+ {
+ throw new InvalidNameException(address);
+ }
+
+ try
+ {
+ registry = LocateRegistry.getRegistry(a, port);
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+ return registry;
+ }
+
+ /**
+ * Create the rmi url context that works, talking with the given RMI registry.
+ *
+ * @param props
+ * the properties for this context
+ * @param initialRegistry
+ * the initial value of the registry
+ */
+ public ContextContinuation(Map props, Registry initialRegistry)
+ {
+ properties = new Properties();
+ if (props != null)
+ properties.putAll(props);
+ registry = initialRegistry;
+ }
+
+ /**
+ * Bind the given name into this context. The .toString() is called to
+ * convert into the string representation, required by RMI registry.
+ *
+ * @throws NamingException if the object is not an instance of Remote
+ */
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ bind(name.toString(), obj);
+ }
+
+ /**
+ * Bind the given name into this context.
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ getRegistry().bind(name, (Remote) obj);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException("access:"+e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (AlreadyBoundException e)
+ {
+ throw new NameAlreadyBoundException(name);
+ }
+ catch (ClassCastException c)
+ {
+ throw new NamingException("Only Remote can be bound:"
+ + obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public String composeName(String name, String prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry. The only supported case is an
+ * empty name (returns the cloned instance of self).
+ */
+ public Context createSubcontext(Name name) throws NamingException
+ {
+ if (name.size() == 0)
+ return new rmiURLContext(properties);
+ else
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry. The only supported case is an
+ * empty name (returns the cloned instance of self).
+ */
+ public Context createSubcontext(String name) throws NamingException
+ {
+ if (name.length() == 0)
+ return new rmiURLContext(properties);
+ else
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry.
+ */
+ public void destroySubcontext(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry.
+ */
+ public void destroySubcontext(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Returns the naming service URL, same that was passed vie
+ * {@link Context#PROVIDER_URL}.
+ */
+ public String getNameInNamespace() throws NamingException
+ {
+ return properties.getProperty(Context.PROVIDER_URL,
+ DEFAULT_REGISTRY_LOCATION);
+ }
+
+ /**
+ * Not supported, this context never parses any names.
+ */
+ public NameParser getNameParser(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported, this context never parses any names.
+ */
+ public NameParser getNameParser(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context). The class name of the returned name class
+ * pairs is "Remote", as this "quick preview" method should probably not call
+ * the naming service again. Use listBindings if more details are required.
+ */
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ if (name.size() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+ return list("");
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty string,
+ * indicating the root context). The class name of the returned name class
+ * pairs is "Remote", as this "quick preview" method should probably not call
+ * the naming service again. Use listBindings if more details are required.
+ */
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ if (name.length() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+
+ try
+ {
+ return new ListEnumeration(getRegistry().list());
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context).
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ if (name.size() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+ return listBindings("");
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context).
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ if (name.length() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+
+ try
+ {
+ Registry r = getRegistry();
+ return new ListBindingsEnumeration(r.list(), r);
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Rebinds this object.
+ *
+ * @param name
+ * the object name (.toString()) is used to convert into string
+ * representation.
+ * @param the
+ * object (must be an instance of Remote).
+ */
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ rebind(name.toString(), obj);
+ }
+
+ /**
+ * Rebinds this object.
+ *
+ * @param name
+ * the object name.
+ * @param the
+ * object (must be an instance of Remote).
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ getRegistry().rebind(name, (Remote) obj);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException("access:"+e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (ClassCastException c)
+ {
+ throw new NamingException("Only Remote can be bound:"
+ + obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Renames the object. If the new name is already bound in the given context,
+ * the {@link AlreadyBoundException} is thrown and the oldName binding is
+ * preserved.
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ rename(oldName.toString(), newName.toString());
+ }
+
+ /**
+ * Renames the object. If the new name is already bound in the given context,
+ * the {@link AlreadyBoundException} is thrown and the oldName binding is
+ * preserved.
+ */
+ public synchronized void rename(String oldName, String newName)
+ throws NamingException
+ {
+ try
+ {
+ Registry r = getRegistry();
+ Remote object = r.lookup(oldName);
+ r.unbind(oldName);
+ try
+ {
+ r.bind(newName, object);
+ }
+ catch (AlreadyBoundException e)
+ {
+ // Bind it back.
+ try
+ {
+ r.bind(oldName, object);
+ }
+ catch (AlreadyBoundException e1)
+ {
+ // We have just removed this name.
+ throw new InternalError();
+ }
+ throw new NameAlreadyBoundException(newName);
+ }
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+
+ /**
+ * Unbind the object.
+ */
+ public void unbind(Name name) throws NamingException
+ {
+ unbind(name.toString());
+ }
+
+ /**
+ * Unbind the object.
+ */
+ public void unbind(String name) throws NamingException
+ {
+ try
+ {
+ getRegistry().unbind(name);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+
+ /**
+ * Release the associated resources.
+ */
+ public void close() throws NamingException
+ {
+ removeRegistry();
+ }
+
+ /**
+ * Resolve the object by name.
+ *
+ * @param name
+ * the object name, .toString() is used to get the string
+ * representation.
+ */
+ public Object lookup(Name name) throws NamingException
+ {
+ return lookup(name.toString());
+ }
+
+ /**
+ * Resolve the object by name
+ *
+ * @param name the object name.
+ */
+ public Object lookup(String name) throws NamingException
+ {
+ try
+ {
+ return getRegistry().lookup(name);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new NameNotFoundException(name);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401Swing.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java
index 9c934f647de..757e8bf59c1 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401Swing.java
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java
@@ -1,4 +1,4 @@
-/* HTML_401Swing.java -- The HTML 4.01 DTD, adapted for HTML rendering in Swing
+/* ListBindingsEnumeration.java -- handles rmi: urls
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -36,56 +36,62 @@ obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-package gnu.javax.swing.text.html.parser;
+package gnu.javax.naming.jndi.url.rmi;
-import javax.swing.text.html.parser.DTD;
+import java.rmi.registry.Registry;
+
+import javax.naming.NamingEnumeration;
/**
- * This class is necessary because the current implementation of the GNU
- * Classpath Swing requires always enclose the text into paragraphs.
+ * Iterates over bindings, obtaining values first from the binding list and then
+ * from the binding iterator.
*
- * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ * @author Audrius Meskauskas
*/
-public class HTML_401Swing extends HTML_401F
+public class ListBindingsEnumeration extends RmiNamingEnumeration implements
+ NamingEnumeration
{
/**
- * The singleton instance;
+ * The naming service, to resolve the objects.
*/
- final static HTML_401Swing singleton = new HTML_401Swing();
+ Registry service;
/**
- * Either takes the document (by name) from DTD table, or
- * creates a new instance and registers it in the tabe.
- * The document is registerd under name "-//W3C//DTD HTML 4.01 Frameset//EN".
- * @return The new or existing DTD for parsing HTML 4.01 Frameset.
+ * Create the new enumeration
+ *
+ * @param bindings
+ * the list of the bound names
+ * @param aService
+ * the RMI naming service, used to get the bound values.
*/
- public static DTD getInstance()
+ public ListBindingsEnumeration(String [] bindings,
+ Registry aService)
{
- return singleton;
- }
+ super(bindings);
+ service = aService;
+ }
/**
- * Get elements that are allowed in the document body, at the zero level.
- * This list disallows the text at this level (the implied P tag will be
- * generated). It also disallows A, B, I, U, CITE and other similar
- * elements that have the plain text inside. They will also be placed
- * inside the generated implied P tags.
+ * Convert from the CORBA binding into the javax.naming binding. As the CORBA
+ * naming service binding does not contain the object itself, this method
+ * makes the additional calls to the naming service.
+ *
+ * @param binding
+ * the binding to convert
+ * @return the value, that must be returned by the {@link #next()}.
*/
- protected String[] getBodyElements()
+ public Object convert(String binding)
{
- return new String[] {
- APPLET, BASEFONT,
- BR, BUTTON,
- IFRAME, IMG,
- INPUT, LABEL, MAP, OBJECT,
- SCRIPT, SELECT,
- TEXTAREA,
- BLOCKQUOTE, CENTER, DEL, DIR,
- DIV, DL, FIELDSET, FORM, H1,
- H2, H3, H4, H5, H6,
- HR, INS, ISINDEX, MENU, NOFRAMES,
- NOSCRIPT, OL, P, PRE, TABLE,
- UL
- };
+ try
+ {
+ Object object = service.lookup(binding);
+ return new javax.naming.Binding(binding, object);
+ }
+ catch (Exception e)
+ {
+ // Probably was removed by the concurent thread.
+ return null;
+ }
}
+
}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java
new file mode 100644
index 00000000000..b4142c5e37d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java
@@ -0,0 +1,80 @@
+/* ListEnumeration.java -- handles rmi: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.jndi.url.rmi;
+
+import java.rmi.Remote;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+
+/**
+ * Iterates over name class pairs, obtaining values first from the binding list
+ * and then from the binding iterator.
+ *
+ * @author Audrius Meskauskas
+ */
+public class ListEnumeration extends RmiNamingEnumeration implements
+ NamingEnumeration
+{
+ /**
+ * Create the new enumeration
+ *
+ * @param bindings
+ * the array of the binding names, returned by the RMI registry.
+ */
+ public ListEnumeration(String [] bindings)
+ {
+ super(bindings);
+ }
+
+ /**
+ * Convert from the binding name into the {@link NameClassPair} that this
+ * enumeration should return.
+ *
+ * @param binding
+ * the binding to convert
+ * @return the value, that must be returned by the {@link #next()}.
+ */
+ public Object convert(String binding)
+ {
+ NameClassPair pair = new NameClassPair(binding, Remote.class.getName());
+ return pair;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java
new file mode 100644
index 00000000000..29eb61b4be5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java
@@ -0,0 +1,594 @@
+/* RmiContinuation.java -- RMI naming context
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.jndi.url.rmi;
+
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+
+/**
+ * The implementation of the RMI URL context. This context connects
+ *
+ * @author Audrius Meskauskas
+ */
+public class RmiContinuation implements Context
+{
+ /**
+ * The default registry location.
+ */
+ public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099";
+
+ /**
+ * The local or remote RMI registry, performing the actual work for this
+ * context.
+ */
+ Registry registry;
+
+ /**
+ * The properties.
+ */
+ Properties properties;
+
+ /**
+ * The flag, indicating, that the lookup methods were called before.
+ * If the lookup methods were called before, the existing ORB cannot be
+ * destroyed, as references to the existing objects will become
+ * unfunctional.
+ */
+ boolean lookupCalled;
+
+ /**
+ * Add new environment property to the environment of this context. Both name
+ * and value of the new property must not be null. If the property is already
+ * defined, is current value is replaced by the propVal. This method replaces
+ * the registry. The new registry will be lazily instantiated on the first
+ * call.
+ *
+ * @param key
+ * the name of the new property
+ * @param value
+ * the value of the new property
+ * @return the previous value of this property or null if the property has not
+ * been previously defined
+ */
+ public Object addToEnvironment(String key, Object value)
+ {
+ removeRegistry();
+ if (key == null || value == null)
+ throw new NullPointerException();
+ return properties.put(key, value);
+ }
+
+ /**
+ * Returns the environment, associated with this naming context. The returned
+ * table should never be modified by the caller (the registry would not be updated
+ * in such case). Use {@link #addToEnvironment} and
+ * {@link #removeFromEnvironment} to modify the environement, if needed.
+ *
+ * @return the table, representing the environment of this context
+ * @throws NamingException
+ */
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return properties;
+ }
+
+ /**
+ * Removes the property with the given name from the environment. Returns
+ * without action if this property is not defined. Replaces the ORB,
+ * constructing the new ORB with the changes set of properties (you can
+ * replace the CORBA implementation provider, for instance). The new ORB will
+ * be lazily instantiated on the first call.
+ *
+ * @param propName
+ * the name of the property being removed.
+ * @return the value of the property that has been removed or null if the
+ * property was not defined.
+ * @throws NamingException
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ removeRegistry();
+ return properties.remove(propName);
+ }
+
+ /**
+ * Remove the current registry reference.
+ */
+ public void removeRegistry()
+ {
+ registry = null;
+ }
+
+ /**
+ * Get the cached or new registry reference.
+ *
+ * @return the registry reference, either cached or new.
+ */
+ public Registry getRegistry() throws NamingException
+ {
+ if (registry == null)
+ {
+ String address = properties.getProperty(Context.PROVIDER_URL,
+ DEFAULT_REGISTRY_LOCATION);
+
+ // The format like rmi://localhost:1099 is expected. Parse.
+ if (!address.startsWith("rmi://"))
+ throw new InvalidNameException(address);
+
+ String a = address.substring("rmi://".length());
+
+ // The colon, if present, indicates the start of the port number.
+ int colon = a.lastIndexOf(':');
+ int port;
+
+ try
+ {
+ if (colon >=0)
+ {
+ port = Integer.parseInt(a.substring(colon+1));
+ a = a.substring(0, colon);
+ }
+ else
+ port = Registry.REGISTRY_PORT;
+ }
+ catch (NumberFormatException e1)
+ {
+ throw new InvalidNameException(address);
+ }
+
+ try
+ {
+ registry = LocateRegistry.getRegistry(a, port);
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+ return registry;
+ }
+
+ /**
+ * Create the rmi url context that works, talking with the given RMI registry.
+ *
+ * @param props
+ * the properties for this context
+ */
+ public RmiContinuation(Map props)
+ {
+ properties = new Properties();
+ if (props != null)
+ properties.putAll(props);
+ }
+
+ /**
+ * Bind the given name into this context. The .toString() is called to
+ * convert into the string representation, required by RMI registry.
+ *
+ * @throws NamingException if the object is not an instance of Remote
+ */
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ bind(name.toString(), obj);
+ }
+
+ /**
+ * Bind the given name into this context.
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ getRegistry().bind(name, (Remote) obj);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException("access:"+e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (AlreadyBoundException e)
+ {
+ throw new NameAlreadyBoundException(name);
+ }
+ catch (ClassCastException c)
+ {
+ throw new NamingException("Only Remote can be bound:"
+ + obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public String composeName(String name, String prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry. The only supported case is an
+ * empty name (returns the cloned instance of self).
+ */
+ public Context createSubcontext(Name name) throws NamingException
+ {
+ if (name.size() == 0)
+ return new RmiContinuation(properties);
+ else
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry. The only supported case is an
+ * empty name (returns the cloned instance of self).
+ */
+ public Context createSubcontext(String name) throws NamingException
+ {
+ if (name.length() == 0)
+ return new RmiContinuation(properties);
+ else
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry.
+ */
+ public void destroySubcontext(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry.
+ */
+ public void destroySubcontext(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Returns the naming service URL, same that was passed vie
+ * {@link Context#PROVIDER_URL}.
+ */
+ public String getNameInNamespace() throws NamingException
+ {
+ return properties.getProperty(Context.PROVIDER_URL,
+ DEFAULT_REGISTRY_LOCATION);
+ }
+
+ /**
+ * Not supported, this context never parses any names.
+ */
+ public NameParser getNameParser(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported, this context never parses any names.
+ */
+ public NameParser getNameParser(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context). The class name of the returned name class
+ * pairs is "Remote", as this "quick preview" method should probably not call
+ * the naming service again. Use listBindings if more details are required.
+ */
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ if (name.size() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+ return list("");
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty string,
+ * indicating the root context). The class name of the returned name class
+ * pairs is "Remote", as this "quick preview" method should probably not call
+ * the naming service again. Use listBindings if more details are required.
+ */
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ if (name.length() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+
+ try
+ {
+ return new ListEnumeration(getRegistry().list());
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context).
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ if (name.size() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+ return listBindings("");
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context).
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ if (name.length() > 0)
+ throw new OperationNotSupportedException("Only empty name is accepted");
+
+ try
+ {
+ Registry r = getRegistry();
+ return new ListBindingsEnumeration(r.list(), r);
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public Object lookupLink(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Rebinds this object.
+ *
+ * @param name
+ * the object name (.toString()) is used to convert into string
+ * representation.
+ * @param obj
+ * object (must be an instance of Remote).
+ */
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ rebind(name.toString(), obj);
+ }
+
+ /**
+ * Rebinds this object.
+ *
+ * @param name
+ * the object name.
+ * @param obj
+ * object (must be an instance of Remote).
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ getRegistry().rebind(name, (Remote) obj);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException("access:"+e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (ClassCastException c)
+ {
+ throw new NamingException("Only Remote can be bound:"
+ + obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Renames the object. If the new name is already bound in the given context,
+ * the {@link AlreadyBoundException} is thrown and the oldName binding is
+ * preserved.
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ rename(oldName.toString(), newName.toString());
+ }
+
+ /**
+ * Renames the object. If the new name is already bound in the given context,
+ * the {@link AlreadyBoundException} is thrown and the oldName binding is
+ * preserved.
+ */
+ public synchronized void rename(String oldName, String newName)
+ throws NamingException
+ {
+ try
+ {
+ Registry r = getRegistry();
+ Remote object = r.lookup(oldName);
+ r.unbind(oldName);
+ try
+ {
+ r.bind(newName, object);
+ }
+ catch (AlreadyBoundException e)
+ {
+ // Bind it back.
+ try
+ {
+ r.bind(oldName, object);
+ }
+ catch (AlreadyBoundException e1)
+ {
+ // We have just removed this name.
+ throw new InternalError();
+ }
+ throw new NameAlreadyBoundException(newName);
+ }
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+
+ /**
+ * Unbind the object.
+ */
+ public void unbind(Name name) throws NamingException
+ {
+ unbind(name.toString());
+ }
+
+ /**
+ * Unbind the object.
+ */
+ public void unbind(String name) throws NamingException
+ {
+ try
+ {
+ getRegistry().unbind(name);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+
+ /**
+ * Release the associated resources.
+ */
+ public void close() throws NamingException
+ {
+ removeRegistry();
+ }
+
+ /**
+ * Resolve the object by name.
+ *
+ * @param name
+ * the object name, .toString() is used to get the string
+ * representation.
+ */
+ public Object lookup(Name name) throws NamingException
+ {
+ return lookup(name.toString());
+ }
+
+ /**
+ * Resolve the object by name
+ *
+ * @param name the object name.
+ */
+ public Object lookup(String name) throws NamingException
+ {
+ try
+ {
+ return getRegistry().lookup(name);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new NameNotFoundException(name);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java
new file mode 100644
index 00000000000..6d88cccefe3
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java
@@ -0,0 +1,130 @@
+/* RmiNamingEnumeration.java -- handles rmi: urls
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.naming.jndi.url.rmi;
+
+import java.util.NoSuchElementException;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+/**
+ * Iterates over name class pairs, obtaining values first from the binding list
+ * and then from the binding iterator.
+ *
+ * @author Audrius Meskauskas
+ */
+public abstract class RmiNamingEnumeration implements NamingEnumeration
+{
+ /**
+ * The array of bindings, returned at once.
+ */
+ String[] list;
+
+ /**
+ * The position of the element in the binding list, that must be returned
+ * during the subsequent call of the next(). If this field is grater or equal
+ * to the lenght of the list, the subsequent values must be requested from the
+ * iterator.
+ */
+ int p;
+
+ RmiNamingEnumeration(String[] bindingList)
+ {
+ list = bindingList;
+ }
+
+ /**
+ * Convert from the CORBA binding into that this enumeration should return.
+ *
+ * @param binding
+ * the binding to convert
+ * @return the value, that must be returned by the {@link #next()}.
+ */
+ public abstract Object convert(String binding);
+
+ /**
+ * Checks if there are more elements to return.
+ *
+ * @throws NamingException
+ * never
+ */
+ public boolean hasMore() throws NamingException
+ {
+ return hasMoreElements();
+ }
+
+ /**
+ * Returns the next element.
+ *
+ * @throws NamingException
+ * never
+ */
+ public Object next() throws NamingException
+ {
+ return nextElement();
+ }
+
+ /**
+ * Checks if there are more elements to return.
+ */
+ public boolean hasMoreElements()
+ {
+ return p < list.length;
+ }
+
+ /**
+ * Returns the next element.
+ */
+ public Object nextElement()
+ {
+ if (p < list.length)
+ return convert(list[p++]);
+ else
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Nothing to do in this method.
+ */
+ public void close()
+ {
+ // Nothing to do here.
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java
new file mode 100644
index 00000000000..a17ce026b16
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java
@@ -0,0 +1,637 @@
+/* rmiURLContext.java -- RMI naming context
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.jndi.url.rmi;
+
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.WeakHashMap;
+
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+
+/**
+ * The implementation of the RMI URL context. This context connects
+ *
+ * @author Audrius Meskauskas
+ */
+public class rmiURLContext implements Context
+{
+ /**
+ * The default registry location.
+ */
+ public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099";
+
+ /**
+ * The registry cache, maps the registry URL's to they instances. The
+ * obtained registries are reused, as newly obtaining them may cause the
+ * resource leak.
+ */
+ static WeakHashMap registryCache = new WeakHashMap();
+
+ /**
+ * The properties.
+ */
+ Properties properties;
+
+ /**
+ * The flag, indicating, that the lookup methods were called before.
+ * If the lookup methods were called before, the existing ORB cannot be
+ * destroyed, as references to the existing objects will become
+ * unfunctional.
+ */
+ boolean lookupCalled;
+
+ /**
+ * Add new environment property to the environment of this context. Both name
+ * and value of the new property must not be null. If the property is already
+ * defined, is current value is replaced by the propVal. This method replaces
+ * the registry. The new registry will be lazily instantiated on the first
+ * call.
+ *
+ * @param key
+ * the name of the new property
+ * @param value
+ * the value of the new property
+ * @return the previous value of this property or null if the property has not
+ * been previously defined
+ */
+ public Object addToEnvironment(String key, Object value)
+ {
+ if (key == null || value == null)
+ throw new NullPointerException();
+ return properties.put(key, value);
+ }
+
+ /**
+ * Returns the environment, associated with this naming context. The returned
+ * table should never be modified by the caller (the registry would not be updated
+ * in such case). Use {@link #addToEnvironment} and
+ * {@link #removeFromEnvironment} to modify the environement, if needed.
+ *
+ * @return the table, representing the environment of this context
+ * @throws NamingException
+ */
+ public Hashtable getEnvironment() throws NamingException
+ {
+ return properties;
+ }
+
+ /**
+ * Removes the property with the given name from the environment. Returns
+ * without action if this property is not defined. Replaces the ORB,
+ * constructing the new ORB with the changes set of properties (you can
+ * replace the CORBA implementation provider, for instance). The new ORB will
+ * be lazily instantiated on the first call.
+ *
+ * @param propName
+ * the name of the property being removed.
+ * @return the value of the property that has been removed or null if the
+ * property was not defined.
+ * @throws NamingException
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ return properties.remove(propName);
+ }
+
+ /**
+ * Get the cached or new registry reference.
+ *
+ * @return the registry reference, either cached or new.
+ */
+ public Registry getRegistry(String netAddress) throws NamingException
+ {
+ Registry registry;
+
+ synchronized (registryCache)
+ {
+ registry = (Registry) registryCache.get(netAddress);
+ }
+
+ if (registry == null)
+ {
+ // The colon, if present, indicates the start of the port number.
+ int colon = netAddress.lastIndexOf(':');
+ int port;
+
+ try
+ {
+ if (colon >= 0)
+ {
+ port = Integer.parseInt(netAddress.substring(colon + 1));
+ netAddress = netAddress.substring(0, colon);
+ }
+ else
+ port = Registry.REGISTRY_PORT;
+ }
+ catch (NumberFormatException e1)
+ {
+ throw new InvalidNameException(netAddress);
+ }
+
+ try
+ {
+ registry = LocateRegistry.getRegistry(netAddress, port);
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+
+ synchronized (registryCache)
+ {
+ registryCache.put(netAddress, registry);
+ }
+ }
+ return registry;
+ }
+
+ /**
+ * Create the rmi url context that works, talking with the given RMI registry.
+ *
+ * @param props
+ * the properties for this context
+ */
+ public rmiURLContext(Map props)
+ {
+ properties = new Properties();
+ if (props != null)
+ properties.putAll(props);
+ }
+
+ /**
+ * Bind the given name into this context. The .toString() is called to
+ * convert into the string representation, required by RMI registry.
+ *
+ * @throws NamingException if the object is not an instance of Remote
+ */
+ public void bind(Name name, Object obj) throws NamingException
+ {
+ bind(name.toString(), obj);
+ }
+
+ /**
+ * Bind the given name into this context.
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ getRegistry(n[0]).bind(n[1], (Remote) obj);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException("access:"+e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (AlreadyBoundException e)
+ {
+ throw new NameAlreadyBoundException(name);
+ }
+ catch (ClassCastException c)
+ {
+ throw new NamingException("Only Remote can be bound:"
+ + obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Not supported.
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported.
+ */
+ public String composeName(String name, String prefix) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry. The only supported case is an
+ * empty name (returns the cloned instance of self).
+ */
+ public Context createSubcontext(Name name) throws NamingException
+ {
+ if (name.size() == 0)
+ return new rmiURLContext(properties);
+ else
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry. The only supported case is an
+ * empty name (returns the cloned instance of self).
+ */
+ public Context createSubcontext(String name) throws NamingException
+ {
+ if (name.length() == 0)
+ return new rmiURLContext(properties);
+ else
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry.
+ */
+ public void destroySubcontext(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Subcontexts are not supporte by RMI registry.
+ */
+ public void destroySubcontext(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Returns the naming service URL, same that was passed vie
+ * {@link Context#PROVIDER_URL}.
+ */
+ public String getNameInNamespace() throws NamingException
+ {
+ return properties.getProperty(Context.PROVIDER_URL,
+ DEFAULT_REGISTRY_LOCATION);
+ }
+
+ /**
+ * Not supported, this context never parses any names.
+ */
+ public NameParser getNameParser(Name name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * Not supported, this context never parses any names.
+ */
+ public NameParser getNameParser(String name) throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context). The class name of the returned name class
+ * pairs is "Remote", as this "quick preview" method should probably not call
+ * the naming service again. Use listBindings if more details are required.
+ */
+ public NamingEnumeration list(Name name) throws NamingException
+ {
+ return list(name);
+ }
+
+ /**
+ * List existing bindings of thie given registry.The class name of the
+ * returned name class pairs is "Remote", as this "quick preview" method
+ * should probably not call the naming service again. Use listBindings if more
+ * details are required.
+ */
+ public NamingEnumeration list(String name) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ if (n[1].length() > 0)
+ throw new InvalidNameException(name+", the name part must be empty");
+ return new ListEnumeration(getRegistry(n[0]).list());
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * List existing bindings of this context (the parameter must be empty name,
+ * indicating the root context).
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException
+ {
+ return listBindings(name.toString());
+ }
+
+ /**
+ * List existing bindings of this context.
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ if (n[1].length() > 0)
+ throw new InvalidNameException(name+", the name part must be empty");
+
+ Registry r = getRegistry(n[0]);
+ return new ListBindingsEnumeration(r.list(), r);
+ }
+ catch (Exception e)
+ {
+ throw new NamingException(e.toString());
+ }
+ }
+
+ /**
+ * Returns the naming service context under the given address, wrapped as
+ * Context.
+ */
+ public Object lookupLink(Name name) throws NamingException
+ {
+ return lookupLink(name.toString());
+ }
+
+ /**
+ * Returns the naming service context under the given address,
+ * wrapped as Context.
+ */
+ public Object lookupLink(String name) throws NamingException
+ {
+ return new ContextContinuation(properties, getRegistry(name));
+ }
+
+ /**
+ * Rebinds this object.
+ *
+ * @param name
+ * the object name (.toString()) is used to convert into string
+ * representation.
+ * @param obj
+ * object (must be an instance of Remote).
+ */
+ public void rebind(Name name, Object obj) throws NamingException
+ {
+ rebind(name.toString(), obj);
+ }
+
+ /**
+ * Rebinds this object.
+ *
+ * @param name
+ * the object name.
+ * @param obj
+ * object (must be an instance of Remote).
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ getRegistry(n[0]).rebind(n[1], (Remote) obj);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException("access:"+e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (ClassCastException c)
+ {
+ throw new NamingException("Only Remote can be bound:"
+ + obj.getClass().getName());
+ }
+ }
+
+ /**
+ * Renames the object. If the new name is already bound in the given context,
+ * the {@link AlreadyBoundException} is thrown and the oldName binding is
+ * preserved.
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ rename(oldName.toString(), newName.toString());
+ }
+
+ /**
+ * Renames the object. If the new name is already bound in the given context,
+ * the {@link AlreadyBoundException} is thrown and the oldName binding is
+ * preserved.
+ */
+ public synchronized void rename(String oldName, String newName)
+ throws NamingException
+ {
+ try
+ {
+ String [] n = split(oldName);
+ Registry r = getRegistry(n[0]);
+ Remote object = r.lookup(n[1]);
+ r.unbind(oldName);
+ try
+ {
+ String [] n2 = split(newName);
+ Registry r2 = getRegistry(n2[0]);
+ r2.bind(n2[1], object);
+ }
+ catch (AlreadyBoundException e)
+ {
+ // Bind it back.
+ try
+ {
+ r.bind(oldName, object);
+ }
+ catch (AlreadyBoundException e1)
+ {
+ // We have just removed this name.
+ throw new InternalError();
+ }
+ throw new NameAlreadyBoundException(newName);
+ }
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+
+ /**
+ * Unbind the object.
+ */
+ public void unbind(Name name) throws NamingException
+ {
+ unbind(name.toString());
+ }
+
+ /**
+ * Unbind the object.
+ */
+ public void unbind(String name) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ getRegistry(n[0]).unbind(n[1]);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ }
+
+ /**
+ * Release the associated resources.
+ */
+ public void close() throws NamingException
+ {
+ }
+
+ /**
+ * Resolve the object by name.
+ *
+ * @param name
+ * the object name, .toString() is used to get the string
+ * representation.
+ */
+ public Object lookup(Name name) throws NamingException
+ {
+ return lookup(name.toString());
+ }
+
+ /**
+ * Resolve the object by name
+ *
+ * @param name the object name.
+ */
+ public Object lookup(String name) throws NamingException
+ {
+ try
+ {
+ String [] n = split(name);
+ return getRegistry(n[0]).lookup(n[1]);
+ }
+ catch (AccessException e)
+ {
+ throw new NamingException(e.toString());
+ }
+ catch (RemoteException e)
+ {
+ throw new CommunicationException(e.toString());
+ }
+ catch (NotBoundException e)
+ {
+ throw new NameNotFoundException(name);
+ }
+ }
+
+ /**
+ * Split the given rmi address into the network address and naming service
+ * name.
+ *
+ * @param address
+ * the address to split
+ * @return the two member array, lower being the network address of the naming
+ * service and upper being the naming service name
+ * @throws NamingException
+ * if the name is invalid
+ */
+ public String[] split(String address) throws NamingException
+ {
+ // The format like rmi://localhost:1099/name is expected. Parse.
+ if (!address.startsWith("rmi://"))
+ throw new InvalidNameException(
+ address
+ + " should be like 'rmi://localhost:1099/name'");
+
+ String a = address.substring("rmi://".length());
+
+ // The suffix starts after the first slash from the rmi://
+ int sfx = a.indexOf('/');
+
+ // Handle the possible escape
+ while (sfx > 0 && a.charAt(sfx - 1) == '\\')
+ sfx = a.indexOf('/', sfx + 1);
+
+ String net;
+ String name;
+ if (sfx >= 0)
+ {
+ net = a.substring(0, sfx);
+ name = a.substring(sfx + 1);
+ }
+ else
+ {
+ net = a;
+ name = "";
+ }
+
+ return new String[] { net, name };
+ }
+}
diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java
new file mode 100644
index 00000000000..59384532736
--- /dev/null
+++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java
@@ -0,0 +1,66 @@
+/* rmiURLContextFactory.java -- handles RMI naming context
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.javax.naming.jndi.url.rmi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * Find the RMI URL context. This factory checks the Context.PROVIDER_URL
+ * property for the address of the RMI naming service and creates the
+ * context that operates talking with this naming service. If such property
+ * is missing, "rmi://localhost:1099" is assumed.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
+ */
+public class rmiURLContextFactory implements ObjectFactory
+{
+
+ /**
+ * Create a new instance of the context.
+ */
+ public Object getObjectInstance(Object refObj, Name name, Context nameCtx,
+ Hashtable environment)
+ {
+ return new rmiURLContext(environment);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java
new file mode 100644
index 00000000000..bdd7f274e06
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java
@@ -0,0 +1,288 @@
+/* AbstractSessionContext -- stores SSL sessions, possibly persistently.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import gnu.java.security.Requires;
+
+import gnu.javax.net.ssl.provider.SimpleSessionContext;
+
+import java.util.Enumeration;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPermission;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A skeletal implementation of {@link SSLSessionContext}. This class may
+ * be subclassed to add extended functionality to session contexts, such
+ * as by storing sessions in files on disk, or by sharing contexts
+ * across different JVM instances.
+ *
+ * <p>In order to securely store sessions, along with private key data,
+ * the abstract methods {@lnk {@link #load(char[])} and {@link #store(char[])}
+ * come into play. When storing sessions, a session context implementation
+ * must pass this password to the {@link Session#prepare(char[])} method,
+ * before either writing the {@link java.io.Serializable} session to the
+ * underlying store, or getting the opaque {@link Session#privateData()}
+ * class from the session, and storing that.
+ *
+ * <p>As a simple example, that writes sessions to some object output
+ * stream:
+ *
+ * <pre>
+ char[] password = ...;
+ ObjectOutputStream out = ...;
+ ...
+ for (Session s : this)
+ {
+ s.prepare(password);
+ out.writeObject(s);
+ }</pre>
+ *
+ * <p>The reverse must be done when deserializing sessions, by using the
+ * {@link Session#repair(char[])} method, possibly by first calling
+ * {@link Session#setPrivateData(java.io.Serializable)} with the read,
+ * opaque private data type. Thus an example of reading may be:
+ *
+ * <pre>
+ char[] password = ...;
+ ObjectInputStream in = ...;
+ ...
+ while (hasMoreSessions(in))
+ {
+ Session s = (Session) in.readObject();
+ s.repair(password);
+ addToThisStore(s);
+ }</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class AbstractSessionContext implements SSLSessionContext
+{
+ protected long timeout;
+ private static Class<? extends AbstractSessionContext>
+ implClass = SimpleSessionContext.class;
+
+ /**
+ * Create a new instance of a session context, according to the configured
+ * implementation class.
+ *
+ * @return The new session context.
+ * @throws SSLException If an error occurs in creating the instance.
+ */
+ public static AbstractSessionContext newInstance () throws SSLException
+ {
+ try
+ {
+ return implClass.newInstance();
+ }
+ catch (IllegalAccessException iae)
+ {
+ throw new SSLException(iae);
+ }
+ catch (InstantiationException ie)
+ {
+ throw new SSLException(ie);
+ }
+ }
+
+ /**
+ * Reconfigure this instance to use a different session context
+ * implementation.
+ *
+ * <p><strong>Note:</strong> this method requires that the caller have
+ * {@link SSLPermission} with target
+ * <code>gnu.javax.net.ssl.AbstractSessionContext</code> and action
+ * <code>setImplClass</code>.
+ *
+ * @param clazz The new implementation class.
+ * @throws SecurityException If the caller does not have permission to
+ * change the session context.
+ */
+ @Requires(permissionClass = SSLPermission.class,
+ target = "gnu.javax.net.ssl.AbstractSessionContext",
+ action = "setImplClass")
+ public static synchronized void setImplClass
+ (Class<? extends AbstractSessionContext> clazz)
+ throws SecurityException
+ {
+ SecurityManager sm = System.getSecurityManager ();
+ if (sm != null)
+ sm.checkPermission(new SSLPermission("gnu.javax.net.ssl.AbstractSessionContext",
+ "setImplClass"));
+ implClass = clazz;
+ }
+
+ /**
+ * @param timeout The initial session timeout.
+ */
+ protected AbstractSessionContext (final int timeout)
+ {
+ setSessionTimeout(timeout);
+ }
+
+ /**
+ * Fetch a saved session by its ID. This method will (possibly)
+ * deserialize and return the SSL session with that ID, or null if
+ * the requested session does not exist, or has expired.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * perform any blocking operations in this method. If any blocking
+ * behavior is required, it must be done in the {@link load(char[])}
+ * method.
+ *
+ * @param sessionId The ID of the session to get.
+ * @return The found session, or null if no such session was found,
+ * or if that session has expired.
+ */
+ public final SSLSession getSession (byte[] sessionId)
+ {
+ Session s = implGet (sessionId);
+ if (s != null
+ && System.currentTimeMillis () - s.getLastAccessedTime () > timeout)
+ {
+ remove (sessionId);
+ return null;
+ }
+ return s;
+ }
+
+ public final SSLSession getSession(String host, int port)
+ {
+ for (Enumeration e = getIds(); e.hasMoreElements(); )
+ {
+ byte[] id = (byte[]) e.nextElement();
+ SSLSession s = getSession(id);
+ if (s == null) // session expired.
+ continue;
+ String host2 = s.getPeerHost();
+ if (host == null)
+ {
+ if (host2 != null)
+ continue;
+ }
+ else if (!host.equals(host2))
+ continue;
+ int port2 = s.getPeerPort();
+ if (port != port2)
+ continue;
+
+ // Else, a match.
+ return s;
+ }
+
+ return null;
+ }
+
+ /**
+ * To be implemented by subclasses. Subclasses do not need to check
+ * timeouts in this method.
+ *
+ * @param sessionId The session ID.
+ * @return The session, or <code>null</code> if the requested session
+ * was not found.
+ */
+ protected abstract Session implGet (byte[] sessionId);
+
+ public int getSessionTimeout()
+ {
+ return (int) (timeout / 1000);
+ }
+
+ /**
+ * Load this session store from the underlying media, if supported
+ * by the implementation.
+ *
+ * @param password The password that protects the sensitive data in
+ * this store.
+ * @throws SessionStoreException If reading this store fails, such
+ * as when an I/O exception occurs, or if the password is incorrect.
+ */
+ public abstract void load (char[] password) throws SessionStoreException;
+
+ /**
+ * Add a new session to the store. The underlying implementation
+ * will add the session to its store, possibly overwriting any
+ * existing session with the same ID.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * perform any blocking operations in this method. If any blocking
+ * behavior is required, it must be done in the {@link
+ * #store(char[])} method.
+ *
+ * @param session The session to add.
+ * @throws NullPointerException If the argument is null.
+ */
+ public abstract void put (Session session);
+
+ /**
+ * Remove a session from this store.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * perform any blocking operations in this method. If any blocking
+ * behavior is required, it must be done in the {@link
+ * #store(char[])} method.
+ *
+ * @param sessionId The ID of the session to remove.
+ */
+ public abstract void remove (byte[] sessionId);
+
+ /**
+ *
+ */
+ public final void setSessionTimeout(int seconds)
+ {
+ if (timeout < 0)
+ throw new IllegalArgumentException("timeout may not be negative");
+ this.timeout = (long) seconds * 1000;
+ }
+
+ /**
+ * Commit this session store to the underlying media. For session
+ * store implementations that support saving sessions across
+ * invocations of the JVM, this method will save any sessions that
+ * have not expired to some persistent media, so they may be loaded
+ * and used again later.
+ *
+ * @param password The password that will protect the sensitive data
+ * in this store.
+ */
+ public abstract void store (char[] password) throws SessionStoreException;
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java
new file mode 100644
index 00000000000..ba6500a27d4
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java
@@ -0,0 +1,54 @@
+/* PreSharedKeyManager.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import java.security.KeyManagementException;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public interface PreSharedKeyManager extends KeyManager
+{
+ SecretKey getKey(String name) throws KeyManagementException;
+
+ String chooseIdentityHint();
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java
new file mode 100644
index 00000000000..1b1d492b1ae
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java
@@ -0,0 +1,83 @@
+/* PreSharedKeyManagerParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class PreSharedKeyManagerParameters
+ implements ManagerFactoryParameters
+{
+ private final LinkedHashMap<String, SecretKey> keys;
+
+ public PreSharedKeyManagerParameters()
+ {
+ keys = new LinkedHashMap<String, SecretKey>();
+ }
+
+ public SecretKey getKey(String name)
+ {
+ name.getClass();
+ return keys.get(name);
+ }
+
+ public void putKey(String name, SecretKey key)
+ {
+ name.getClass();
+ key.getClass();
+ keys.put(name, key);
+ }
+
+ public boolean removeKey(String name)
+ {
+ name.getClass();
+ return keys.remove(name) != null;
+ }
+
+ public Iterator<String> identities()
+ {
+ return keys.keySet().iterator();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java
index f602f98ae22..442629309e7 100644
--- a/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java
+++ b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java
@@ -51,6 +51,7 @@ import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -95,16 +96,16 @@ public class PrivateCredentials implements ManagerFactoryParameters
public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY";
public static final String END_RSA = "-----END RSA PRIVATE KEY";
- private List privateKeys;
- private List certChains;
+ private List<PrivateKey> privateKeys;
+ private List<X509Certificate[]> certChains;
// Constructor.
// -------------------------------------------------------------------------
public PrivateCredentials()
{
- privateKeys = new LinkedList();
- certChains = new LinkedList();
+ privateKeys = new LinkedList<PrivateKey>();
+ certChains = new LinkedList<X509Certificate[]>();
}
// Instance methods.
@@ -115,7 +116,7 @@ public class PrivateCredentials implements ManagerFactoryParameters
IOException, NoSuchAlgorithmException, WrongPaddingException
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
- Collection certs = cf.generateCertificates(certChain);
+ Collection<? extends Certificate> certs = cf.generateCertificates(certChain);
X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]);
String alg = null;
@@ -199,11 +200,12 @@ public class PrivateCredentials implements ManagerFactoryParameters
(BigInteger) der.read().getValue(), // d mod (q-1)
(BigInteger) der.read().getValue()); // coefficient
}
+
privateKeys.add(kf.generatePrivate(spec));
certChains.add(chain);
}
- public List getPrivateKeys()
+ public List<PrivateKey> getPrivateKeys()
{
if (isDestroyed())
{
@@ -212,7 +214,7 @@ public class PrivateCredentials implements ManagerFactoryParameters
return privateKeys;
}
- public List getCertChains()
+ public List<X509Certificate[]> getCertChains()
{
return certChains;
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java
new file mode 100644
index 00000000000..a3ab8771389
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java
@@ -0,0 +1,142 @@
+/* SSLCipherSuite.java -- an SSL cipher suite.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import gnu.java.security.Engine;
+
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * An SSL cipher suite.
+ */
+public abstract class SSLCipherSuite
+{
+ private static final String SERVICE = "SSLCipherSuite";
+ private final String algorithm;
+ private final byte[] id;
+ private final SSLProtocolVersion version;
+ private Provider provider;
+
+ protected SSLCipherSuite (final String algorithm, final byte[] id,
+ final SSLProtocolVersion version)
+ {
+ this.algorithm = algorithm;
+ if (id.length != 2)
+ throw new IllegalArgumentException ("cipher suite ID must be two bytes");
+ this.id = (byte[]) id.clone ();
+ this.version = version;
+ }
+
+ public static final SSLCipherSuite getInstance (SSLProtocolVersion version, byte[] id)
+ throws NoSuchAlgorithmException
+ {
+ return getInstance (version + "-" + ((id[0] & 0xFF) + "/" + (id[1] & 0xFF)));
+ }
+
+ public static final SSLCipherSuite getInstance (SSLProtocolVersion version,
+ byte[] id, Provider provider)
+ throws NoSuchAlgorithmException
+ {
+ return getInstance (version + "-" + (id[0] & 0xFF) + "/" + (id[1] & 0xFF), provider);
+ }
+
+ public static final SSLCipherSuite getInstance (String name)
+ throws NoSuchAlgorithmException
+ {
+ Provider[] providers = Security.getProviders ();
+ for (int i = 0; i < providers.length; i++)
+ {
+ try
+ {
+ return getInstance (name, providers[i]);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ // Ignore.
+ }
+ }
+
+ throw new NoSuchAlgorithmException (SERVICE + ": " + name);
+ }
+
+ public static final SSLCipherSuite getInstance (String name, Provider provider)
+ throws NoSuchAlgorithmException
+ {
+ SSLCipherSuite suite = null;
+ try
+ {
+ suite = (SSLCipherSuite) Engine.getInstance (SERVICE, name, provider);
+ suite.provider = provider;
+ }
+ catch (InvocationTargetException ite)
+ {
+ // XXX
+ NoSuchAlgorithmException nsae = new NoSuchAlgorithmException (name);
+ nsae.initCause (ite);
+ throw nsae;
+ }
+ return suite;
+ }
+
+ public final String getAlgorithm ()
+ {
+ return algorithm;
+ }
+
+ public final byte[] getId ()
+ {
+ return (byte[]) id.clone ();
+ }
+
+ public final Provider getProvider ()
+ {
+ return provider;
+ }
+
+ public final SSLProtocolVersion getProtocolVersion ()
+ {
+ return version;
+ }
+
+ public abstract void encipher (ByteBuffer in, ByteBuffer out);
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java
new file mode 100644
index 00000000000..3998f936abe
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java
@@ -0,0 +1,54 @@
+/* SSLProtocolVersion.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+public enum SSLProtocolVersion
+{
+ SSLv3 (3, 0),
+ TLSv1 (3, 1);
+
+ public final int major;
+ public final int minor;
+
+ private SSLProtocolVersion (int major, int minor)
+ {
+ this.major = major;
+ this.minor = minor;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java b/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java
new file mode 100644
index 00000000000..3147415fe36
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java
@@ -0,0 +1,101 @@
+/* SSLRecordHandler.java -- a class that handles SSL record layer messages.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+
+public abstract class SSLRecordHandler
+{
+ private final byte contentType;
+
+ /**
+ * Create a new record handler for the given content type.
+ */
+ protected SSLRecordHandler (final byte contentType)
+ {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Handle an SSL record layer message, encapsulated in the supplied
+ * input buffer, and writing any output bytes to the output
+ * buffer. The input buffer is always only limited to the bytes that
+ * encapsulate the <em>fragment</em> of the record layer message
+ * &mdash; that is, the content-type, version, and length fields are
+ * not present in the input buffer, and the limit of the input
+ * buffer is always only as large as the fragment. If the message
+ * being read is not contained entirely within the given buffer,
+ * then the implementation should cache the bytes read as input, and
+ * wait until subsequent calls finish the object being read.
+ *
+ * <p>Technically, we expect only APPLICATION messages to ever
+ * produce output, but do suppose that extensions to the SSL
+ * protocol could allow other channels that produce output.
+ *
+ * @param input The input buffer.
+ * @param output The output buffer.
+ */
+ public abstract void handle (final ByteBuffer input,
+ final ByteBuffer output)
+ throws SSLException;
+
+ /**
+ * Returns the record layer content type that this handler is for.
+ *
+ * @return The content type value.
+ */
+ public final byte contentType ()
+ {
+ return contentType;
+ }
+
+ public boolean equals (final Object o)
+ {
+ if (!(o instanceof SSLRecordHandler))
+ return false;
+ return ((SSLRecordHandler) o).contentType == contentType;
+ }
+
+ public int hashCode ()
+ {
+ return contentType & 0xFF;
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/Session.java b/libjava/classpath/gnu/javax/net/ssl/Session.java
new file mode 100644
index 00000000000..e2b21aa1e81
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/Session.java
@@ -0,0 +1,364 @@
+/* SessionImpl.java -- concrete definition of SSLSession.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import java.io.Serializable;
+
+import java.security.Principal;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Set;
+
+import javax.crypto.SealedObject;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
+import javax.security.cert.X509Certificate;
+
+/**
+ * A concrete implementation of the {@link SSLSession} interface. This
+ * class is provided to allow pluggable {@link AbstractSessionContext}
+ * implementations.
+ */
+public abstract class Session implements SSLSession, Serializable
+{
+ protected final long creationTime;
+ protected long lastAccessedTime;
+ protected int applicationBufferSize;
+
+ protected ID sessionId;
+ protected Certificate[] localCerts;
+ protected Certificate[] peerCerts;
+ protected X509Certificate[] peerCertChain;
+ protected String peerHost;
+ protected int peerPort;
+ protected boolean peerVerified;
+ protected HashMap<String,Object> values;
+ protected boolean valid;
+ protected boolean truncatedMac = false;
+ transient protected SecureRandom random;
+ transient protected SSLSessionContext context;
+
+ protected Session()
+ {
+ creationTime = System.currentTimeMillis();
+ values = new HashMap<String, Object>();
+ applicationBufferSize = (1 << 14);
+ }
+
+ public void access()
+ {
+ lastAccessedTime = System.currentTimeMillis ();
+ }
+
+ public int getApplicationBufferSize()
+ {
+ return applicationBufferSize;
+ }
+
+ public String getCipherSuite()
+ {
+ return null;
+ }
+
+ public long getCreationTime()
+ {
+ return creationTime;
+ }
+
+ public byte[] getId()
+ {
+ return sessionId.id();
+ }
+
+ public ID id()
+ {
+ return sessionId;
+ }
+
+ public long getLastAccessedTime()
+ {
+ return lastAccessedTime;
+ }
+
+ public Certificate[] getLocalCertificates()
+ {
+ if (localCerts == null)
+ return null;
+ return (Certificate[]) localCerts.clone();
+ }
+
+ public Principal getLocalPrincipal()
+ {
+ if (localCerts != null)
+ {
+ if (localCerts[0] instanceof java.security.cert.X509Certificate)
+ return ((java.security.cert.X509Certificate) localCerts[0]).getSubjectDN();
+ }
+ return null;
+ }
+
+ public int getPacketBufferSize()
+ {
+ return applicationBufferSize + 2048;
+ }
+
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
+ {
+ if (!peerVerified)
+ throw new SSLPeerUnverifiedException("peer not verified");
+ if (peerCerts == null)
+ return null;
+ return (Certificate[]) peerCerts.clone();
+ }
+
+ public X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException
+ {
+ if (!peerVerified)
+ throw new SSLPeerUnverifiedException("peer not verified");
+ if (peerCertChain == null)
+ return null;
+ return (X509Certificate[]) peerCertChain.clone();
+ }
+
+ public String getPeerHost()
+ {
+ return peerHost;
+ }
+
+ public int getPeerPort()
+ {
+ return peerPort;
+ }
+
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException
+ {
+ if (!peerVerified)
+ throw new SSLPeerUnverifiedException("peer not verified");
+ if (peerCertChain == null)
+ return null;
+ return peerCertChain[0].getSubjectDN();
+ }
+
+ public SSLSessionContext getSessionContext()
+ {
+ return context;
+ }
+
+ public String[] getValueNames()
+ {
+ Set<String> keys = this.values.keySet();
+ return keys.toArray(new String[keys.size()]);
+ }
+
+ public Object getValue(String name)
+ {
+ return values.get(name);
+ }
+
+ public void invalidate()
+ {
+ valid = false;
+ }
+
+ public boolean isValid()
+ {
+ return valid;
+ }
+
+ public void putValue(String name, Object value)
+ {
+ values.put(name, value);
+ try
+ {
+ if (value instanceof SSLSessionBindingListener)
+ ((SSLSessionBindingListener) value).valueBound
+ (new SSLSessionBindingEvent(this, name));
+ }
+ catch (Exception x)
+ {
+ }
+ }
+
+ public void removeValue(String name)
+ {
+ Object value = values.remove(name);
+ try
+ {
+ if (value instanceof SSLSessionBindingListener)
+ ((SSLSessionBindingListener) value).valueUnbound
+ (new SSLSessionBindingEvent(this, name));
+ }
+ catch (Exception x)
+ {
+ }
+ }
+
+ public final boolean isTruncatedMac()
+ {
+ return truncatedMac;
+ }
+
+ /**
+ * Prepare this session for serialization. Private data will be encrypted
+ * with the given password, and this object will then be ready to be
+ * serialized.
+ *
+ * @param password The password to protect this session with.
+ * @throws SSLException If encrypting this session's private data fails.
+ */
+ public abstract void prepare (char[] password) throws SSLException;
+
+ /**
+ * Repair this session's private data after deserialization. This method
+ * will decrypt this session's private data, and prepare the session for
+ * use in new SSL connections.
+ *
+ * @param password The password to decrypt the private data with.
+ * @throws SSLException
+ */
+ public abstract void repair(char[] password) throws SSLException;
+
+ /**
+ * Get the private data of this session. This method may only be called
+ * after first calling {@link #prepare(char[])}.
+ *
+ * @return The sealed private data.
+ * @throws SSLException If the private data have not been sealed.
+ */
+ public abstract SealedObject privateData() throws SSLException;
+
+ /**
+ * Set the private data of this session.
+ * @param data
+ * @throws SSLException
+ */
+ public abstract void setPrivateData(SealedObject data) throws SSLException;
+
+ // Inner classes.
+ // -------------------------------------------------------------------------
+
+ /**
+ * An SSL or TLS session ID.
+ */
+ public static final class ID implements Comparable, Serializable
+ {
+
+ // Fields.
+ // -----------------------------------------------------------------------
+
+ static final long serialVersionUID = 7887036954666565936L;
+ /** The ID itself. */
+ private final byte[] id;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ /**
+ * Creates a new ID.
+ *
+ * @param id The ID. The array is cloned.
+ */
+ public ID (final byte[] id)
+ {
+ if (id.length > 32)
+ throw new IllegalArgumentException ("session ID's are limited to 32 bytes");
+ this.id = (byte[]) id.clone();
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] id()
+ {
+ return (byte[]) id.clone();
+ }
+
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof ID))
+ return false;
+ return Arrays.equals(id, ((ID) other).id);
+ }
+
+ public int hashCode()
+ {
+ int code = 0;
+ for (int i = 0; i < id.length; i++)
+ code |= (id[i] & 0xFF) << ((i & 3) << 3);
+ return code;
+ }
+
+ public int compareTo(Object other)
+ {
+ byte[] id2 = ((ID) other).id;
+ if (id.length != id2.length)
+ return (id.length < id2.length) ? -1 : 1;
+ for (int i = 0; i < id.length; i++)
+ {
+ if ((id[i] & 0xFF) < (id2[i] & 0xFF))
+ return -1;
+ if ((id[i] & 0xFF) > (id2[i] & 0xFF))
+ return 1;
+ }
+ return 0;
+ }
+
+ public String toString()
+ {
+ StringBuffer str = new StringBuffer (3 * id.length + 1);
+ for (int i = 0; i < id.length; i++)
+ {
+ int x = id[i] & 0xFF;
+ str.append (Character.forDigit ((x >>> 4) & 0xF, 16));
+ str.append (Character.forDigit (x & 0xF, 16));
+ if (i != id.length - 1)
+ str.append (':');
+ }
+ return str.toString ();
+ }
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java b/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java
new file mode 100644
index 00000000000..5dcf3d02887
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java
@@ -0,0 +1,59 @@
+/* SessionStoreException.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl;
+
+import javax.net.ssl.SSLException;
+
+public class SessionStoreException extends SSLException
+{
+ public SessionStoreException (final String message)
+ {
+ super (message);
+ }
+
+ public SessionStoreException (final String message, final Throwable cause)
+ {
+ super (message, cause);
+ }
+
+ public SessionStoreException (final Throwable cause)
+ {
+ super (cause);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java
new file mode 100644
index 00000000000..d80a5bb789b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java
@@ -0,0 +1,1205 @@
+/* AbstractHandshake.java -- abstract handshake handler.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.ByteArray;
+import gnu.javax.security.auth.callback.CertificateCallback;
+import gnu.javax.security.auth.callback.DefaultCallbackHandler;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.DigestException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.ConfirmationCallback;
+
+/**
+ * The base interface for handshake implementations. Concrete
+ * subclasses of this class (one for the server, one for the client)
+ * handle the HANDSHAKE content-type in communications.
+ */
+public abstract class AbstractHandshake
+{
+ protected static final SystemLogger logger = SystemLogger.SYSTEM;
+
+ /**
+ * "server finished" -- TLS 1.0 and later
+ */
+ protected static final byte[] SERVER_FINISHED
+ = new byte[] {
+ 115, 101, 114, 118, 101, 114, 32, 102, 105, 110, 105, 115,
+ 104, 101, 100
+ };
+
+ /**
+ * "client finished" -- TLS 1.0 and later
+ */
+ protected static final byte[] CLIENT_FINISHED
+ = new byte[] {
+ 99, 108, 105, 101, 110, 116, 32, 102, 105, 110, 105, 115,
+ 104, 101, 100
+ };
+
+ /**
+ * "key expansion" -- TLS 1.0 and later
+ */
+ private static final byte[] KEY_EXPANSION =
+ new byte[] { 107, 101, 121, 32, 101, 120, 112,
+ 97, 110, 115, 105, 111, 110 };
+
+ /**
+ * "master secret" -- TLS 1.0 and later
+ */
+ private static final byte[] MASTER_SECRET
+ = new byte[] {
+ 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116
+ };
+
+ /**
+ * "client write key" -- TLS 1.0 exportable whitener.
+ */
+ private static final byte[] CLIENT_WRITE_KEY
+ = new byte[] {
+ 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32, 107,
+ 101, 121
+ };
+
+ /**
+ * "server write key" -- TLS 1.0 exportable whitener.
+ */
+ private static final byte[] SERVER_WRITE_KEY
+ = new byte[] {
+ 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32, 107,
+ 101, 121
+ };
+
+ private static final byte[] IV_BLOCK
+ = new byte[] {
+ 73, 86, 32, 98, 108, 111, 99, 107
+ };
+
+ /**
+ * SSL 3.0; the string "CLNT"
+ */
+ private static final byte[] SENDER_CLIENT
+ = new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
+
+ /**
+ * SSL 3.0; the string "SRVR"
+ */
+ private static final byte[] SENDER_SERVER
+ = new byte[] { 0x53, 0x52, 0x56, 0x52 };
+
+ /**
+ * SSL 3.0; the value 0x36 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
+ * times.
+ */
+ protected static final byte[] PAD1 = new byte[48];
+
+ /**
+ * SSL 3.0; the value 0x5c 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
+ * times.
+ */
+ protected static final byte[] PAD2 = new byte[48];
+
+ static
+ {
+ Arrays.fill(PAD1, SSLHMac.PAD1);
+ Arrays.fill(PAD2, SSLHMac.PAD2);
+ }
+
+ /**
+ * The currently-read handshake messages. There may be zero, or
+ * multiple, handshake messages in this buffer.
+ */
+ protected ByteBuffer handshakeBuffer;
+
+ /**
+ * The offset into `handshakeBuffer' where the first unread
+ * handshake message resides.
+ */
+ protected int handshakeOffset;
+
+ protected MessageDigest sha;
+ protected MessageDigest md5;
+
+ protected final SSLEngineImpl engine;
+ protected KeyAgreement keyAgreement;
+ protected byte[] preMasterSecret;
+ protected InputSecurityParameters inParams;
+ protected OutputSecurityParameters outParams;
+ protected LinkedList<DelegatedTask> tasks;
+ protected Random serverRandom;
+ protected Random clientRandom;
+ protected CompressionMethod compression;
+
+ protected AbstractHandshake(SSLEngineImpl engine)
+ throws NoSuchAlgorithmException
+ {
+ this.engine = engine;
+ sha = MessageDigest.getInstance("SHA-1");
+ md5 = MessageDigest.getInstance("MD5");
+ tasks = new LinkedList<DelegatedTask>();
+ }
+
+ /**
+ * Handles the next input message in the handshake. This is called
+ * in response to a call to {@link javax.net.ssl.SSLEngine#unwrap}
+ * for a message with content-type HANDSHAKE.
+ *
+ * @param record The input record. The callee should not assume that
+ * the record's buffer is writable, and should not try to use it for
+ * output or temporary storage.
+ * @return An {@link SSLEngineResult} describing the result.
+ */
+ public final HandshakeStatus handleInput (ByteBuffer fragment)
+ throws SSLException
+ {
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+
+ HandshakeStatus status = status();
+ if (status != HandshakeStatus.NEED_UNWRAP)
+ return status;
+
+ // Try to read another...
+ if (!pollHandshake(fragment))
+ return HandshakeStatus.NEED_UNWRAP;
+
+ while (hasMessage() && status != HandshakeStatus.NEED_WRAP)
+ {
+ int pos = handshakeOffset;
+ status = implHandleInput();
+ int len = handshakeOffset - pos;
+ if (len == 0)
+ {
+ // Don't bother; the impl is just telling us to go around
+ // again.
+ continue;
+ }
+ if (doHash())
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "hashing output\n{0}",
+ Util.hexDump((ByteBuffer) handshakeBuffer
+ .duplicate().position(pos)
+ .limit(pos+len), " >> "));
+ sha.update((ByteBuffer) handshakeBuffer.duplicate()
+ .position(pos).limit(pos+len));
+ md5.update((ByteBuffer) handshakeBuffer.duplicate()
+ .position(pos).limit(pos+len));
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Called to process more handshake data. This method will be called
+ * repeatedly while there is remaining handshake data, and while the
+ * status is
+ * @return
+ * @throws SSLException
+ */
+ protected abstract HandshakeStatus implHandleInput()
+ throws SSLException;
+
+ /**
+ * Produce more handshake output. This is called in response to a
+ * call to {@link javax.net.ssl.SSLEngine#wrap}, when the handshake
+ * is still in progress.
+ *
+ * @param record The output record; the callee should put its output
+ * handshake message (or a part of it) in the argument's
+ * <code>fragment</code>, and should set the record length
+ * appropriately.
+ * @return An {@link SSLEngineResult} describing the result.
+ */
+ public final HandshakeStatus handleOutput (ByteBuffer fragment)
+ throws SSLException
+ {
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+
+ int orig = fragment.position();
+ SSLEngineResult.HandshakeStatus status = implHandleOutput(fragment);
+ if (doHash())
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "hashing output:\n{0}",
+ Util.hexDump((ByteBuffer) fragment.duplicate().flip().position(orig), " >> "));
+ sha.update((ByteBuffer) fragment.duplicate().flip().position(orig));
+ md5.update((ByteBuffer) fragment.duplicate().flip().position(orig));
+ }
+ return status;
+ }
+
+ /**
+ * Called to implement the underlying output handling. The callee should
+ * attempt to fill the given buffer as much as it can; this can include
+ * multiple, and even partial, handshake messages.
+ *
+ * @param fragment The buffer the callee should write handshake messages to.
+ * @return The new status of the handshake.
+ * @throws SSLException If an error occurs processing the output message.
+ */
+ protected abstract SSLEngineResult.HandshakeStatus implHandleOutput (ByteBuffer fragment)
+ throws SSLException;
+
+ /**
+ * Return a new instance of input security parameters, initialized with
+ * the session key. It is, of course, only valid to invoke this method
+ * once the handshake is complete, and the session keys established.
+ *
+ * <p>In the presence of a well-behaving peer, this should be called once
+ * the <code>ChangeCipherSpec</code> message is recieved.
+ *
+ * @return The input parameters for the newly established session.
+ * @throws SSLException If the handshake is not complete.
+ */
+ final InputSecurityParameters getInputParams() throws SSLException
+ {
+ checkKeyExchange();
+ return inParams;
+ }
+
+ /**
+ * Return a new instance of output security parameters, initialized with
+ * the session key. This should be called after the
+ * <code>ChangeCipherSpec</code> message is sent to the peer.
+ *
+ * @return The output parameters for the newly established session.
+ * @throws SSLException If the handshake is not complete.
+ */
+ final OutputSecurityParameters getOutputParams() throws SSLException
+ {
+ checkKeyExchange();
+ return outParams;
+ }
+
+ /**
+ * Fetch a delegated task waiting to run, if any.
+ *
+ * @return The task.
+ */
+ final Runnable getTask()
+ {
+ if (tasks.isEmpty())
+ return null;
+ return tasks.removeFirst();
+ }
+
+ /**
+ * Used by the skeletal code to query the current status of the handshake.
+ * This <em>should</em> be the same value as returned by the previous call
+ * to {@link #implHandleOutput(ByteBuffer)} or {@link
+ * #implHandleInput(ByteBuffer)}.
+ *
+ * @return The current handshake status.
+ */
+ abstract HandshakeStatus status();
+
+ /**
+ * Check if the key exchange completed successfully, throwing an exception
+ * if not.
+ *
+ * <p>Note that we assume that the caller of our SSLEngine is correct, and
+ * that they did run the delegated tasks that encapsulate the key exchange.
+ * What we are primarily checking, therefore, is that no error occurred in the
+ * key exchange operation itself.
+ *
+ * @throws SSLException If the key exchange did not complete successfully.
+ */
+ abstract void checkKeyExchange() throws SSLException;
+
+ /**
+ * Handle an SSLv2 client hello. This is only used by SSL servers.
+ *
+ * @param hello The hello message.
+ */
+ abstract void handleV2Hello(ByteBuffer hello) throws SSLException;
+
+ /**
+ * Attempt to read the next handshake message from the given
+ * record. If only a partial handshake message is available, then
+ * this method saves the incoming bytes and returns false. If a
+ * complete handshake is read, or if there was one buffered in the
+ * handshake buffer, this method returns true, and `handshakeBuffer'
+ * can be used to read the handshake.
+ *
+ * @param record The input record.
+ * @return True if a complete handshake is present in the buffer;
+ * false if only a partial one.
+ */
+ protected boolean pollHandshake (final ByteBuffer fragment)
+ {
+ // Allocate space for the new fragment.
+ if (handshakeBuffer == null
+ || handshakeBuffer.remaining() < fragment.remaining())
+ {
+ // We need space for anything still unread in the handshake
+ // buffer...
+ int len = ((handshakeBuffer == null) ? 0
+ : handshakeBuffer.position() - handshakeOffset);
+
+ // Plus room for the incoming record.
+ len += fragment.remaining();
+ reallocateBuffer(len);
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "inserting {0} into {1}",
+ fragment, handshakeBuffer);
+
+ // Put the fragment into the buffer.
+ handshakeBuffer.put(fragment);
+
+ return hasMessage();
+ }
+
+ protected boolean doHash()
+ {
+ return true;
+ }
+
+ /**
+ * Tell if the handshake buffer currently has a full handshake
+ * message.
+ */
+ protected boolean hasMessage()
+ {
+ if (handshakeBuffer == null)
+ return false;
+ ByteBuffer tmp = handshakeBuffer.duplicate();
+ tmp.flip();
+ tmp.position(handshakeOffset);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "current buffer: {0}; test buffer {1}",
+ handshakeBuffer, tmp);
+ if (tmp.remaining() < 4)
+ return false;
+ Handshake handshake = new Handshake(tmp.slice());
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "handshake len:{0} remaining:{1}",
+ handshake.length(), tmp.remaining());
+ return (handshake.length() <= tmp.remaining() - 4);
+ }
+
+ /**
+ * Reallocate the handshake buffer so it can hold `totalLen'
+ * bytes. The smallest buffer allocated is 1024 bytes, and the size
+ * doubles from there until the buffer is sufficiently large.
+ */
+ private void reallocateBuffer (final int totalLen)
+ {
+ int len = handshakeBuffer == null ? -1
+ : handshakeBuffer.capacity() - (handshakeBuffer.limit() - handshakeOffset);
+ if (len >= totalLen)
+ {
+ // Big enough; no need to reallocate; but maybe shift the contents
+ // down.
+ if (handshakeOffset > 0)
+ {
+ handshakeBuffer.flip().position(handshakeOffset);
+ handshakeBuffer.compact();
+ handshakeOffset = 0;
+ }
+ return;
+ }
+
+ // Start at 1K (probably the system's page size). Double the size
+ // from there.
+ len = 1024;
+ while (len < totalLen)
+ len = len << 1;
+ ByteBuffer newBuf = ByteBuffer.allocate (len);
+
+ // Copy the unread bytes from the old buffer.
+ if (handshakeBuffer != null)
+ {
+ handshakeBuffer.flip ();
+ handshakeBuffer.position(handshakeOffset);
+ newBuf.put(handshakeBuffer);
+ }
+ handshakeBuffer = newBuf;
+
+ // We just put only unread handshake messages in the new buffer;
+ // the offset of the next one is now zero.
+ handshakeOffset = 0;
+ }
+
+ /**
+ * Generate a certificate verify message for SSLv3. In SSLv3, a different
+ * algorithm was used to generate this value was subtly different than
+ * that used in TLSv1.0 and later. In TLSv1.0 and later, this value is
+ * just the digest over the handshake messages.
+ *
+ * <p>SSLv3 uses the algorithm:
+ *
+ * <pre>
+CertificateVerify.signature.md5_hash
+ MD5(master_secret + pad_2 +
+ MD5(handshake_messages + master_secret + pad_1));
+Certificate.signature.sha_hash
+ SHA(master_secret + pad_2 +
+ SHA(handshake_messages + master_secret + pad_1));</pre>
+ *
+ * @param md5 The running MD5 hash of the handshake.
+ * @param sha The running SHA-1 hash of the handshake.
+ * @param session The current session being negotiated.
+ * @return The computed to-be-signed value.
+ */
+ protected byte[] genV3CertificateVerify(MessageDigest md5,
+ MessageDigest sha,
+ SessionImpl session)
+ {
+ byte[] md5value = null;
+ if (session.suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+ {
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD1, 0, 48);
+ byte[] tmp = md5.digest();
+ md5.reset();
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD2, 0, 48);
+ md5.update(tmp);
+ md5value = md5.digest();
+ }
+
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD1, 0, 40);
+ byte[] tmp = sha.digest();
+ sha.reset();
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD2, 0, 40);
+ sha.update(tmp);
+ byte[] shavalue = sha.digest();
+
+ if (md5value != null)
+ return Util.concat(md5value, shavalue);
+
+ return shavalue;
+ }
+
+ /**
+ * Generate the session keys from the computed master secret.
+ *
+ * @param clientRandom The client's nonce.
+ * @param serverRandom The server's nonce.
+ * @param session The session being established.
+ * @return The derived keys.
+ */
+ protected byte[][] generateKeys(Random clientRandom, Random serverRandom,
+ SessionImpl session)
+ {
+ int maclen = 20; // SHA-1.
+ if (session.suite.macAlgorithm() == MacAlgorithm.MD5)
+ maclen = 16;
+ int ivlen = 0;
+ if (session.suite.cipherAlgorithm() == CipherAlgorithm.DES
+ || session.suite.cipherAlgorithm() == CipherAlgorithm.DESede)
+ ivlen = 8;
+ if (session.suite.cipherAlgorithm() == CipherAlgorithm.AES)
+ ivlen = 16;
+ int keylen = session.suite.keyLength();
+
+ byte[][] keys = new byte[6][];
+ keys[0] = new byte[maclen]; // client_write_MAC_secret
+ keys[1] = new byte[maclen]; // server_write_MAC_secret
+ keys[2] = new byte[keylen]; // client_write_key
+ keys[3] = new byte[keylen]; // server_write_key
+ keys[4] = new byte[ivlen]; // client_write_iv
+ keys[5] = new byte[ivlen]; // server_write_iv
+
+ IRandom prf = null;
+ if (session.version == ProtocolVersion.SSL_3)
+ {
+ byte[] seed = new byte[clientRandom.length()
+ + serverRandom.length()];
+ serverRandom.buffer().get(seed, 0, serverRandom.length());
+ clientRandom.buffer().get(seed, serverRandom.length(),
+ clientRandom.length());
+ prf = new SSLRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(SSLRandom.SECRET, session.privateData.masterSecret);
+ attr.put(SSLRandom.SEED, seed);
+ prf.init(attr);
+ }
+ else
+ {
+ byte[] seed = new byte[KEY_EXPANSION.length
+ + clientRandom.length()
+ + serverRandom.length()];
+ System.arraycopy(KEY_EXPANSION, 0, seed, 0, KEY_EXPANSION.length);
+ serverRandom.buffer().get(seed, KEY_EXPANSION.length,
+ serverRandom.length());
+ clientRandom.buffer().get(seed, (KEY_EXPANSION.length
+ + serverRandom.length()),
+ clientRandom.length());
+
+ prf = new TLSRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(TLSRandom.SECRET, session.privateData.masterSecret);
+ attr.put(TLSRandom.SEED, seed);
+ prf.init(attr);
+ }
+
+ try
+ {
+ prf.nextBytes(keys[0], 0, keys[0].length);
+ prf.nextBytes(keys[1], 0, keys[1].length);
+ prf.nextBytes(keys[2], 0, keys[2].length);
+ prf.nextBytes(keys[3], 0, keys[3].length);
+
+ if (session.suite.isExportable())
+ {
+ if (session.version == ProtocolVersion.SSL_3)
+ {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(clientRandom.buffer());
+ md5.update(serverRandom.buffer());
+ byte[] d = md5.digest();
+ System.arraycopy(d, 0, keys[4], 0, keys[4].length);
+
+ md5.reset();
+ md5.update(serverRandom.buffer());
+ md5.update(clientRandom.buffer());
+ d = md5.digest();
+ System.arraycopy(d, 0, keys[5], 0, keys[5].length);
+
+ md5.reset();
+ md5.update(keys[2]);
+ md5.update(clientRandom.buffer());
+ md5.update(serverRandom.buffer());
+ keys[2] = Util.trim(md5.digest(), 8);
+
+ md5.reset();
+ md5.update(keys[3]);
+ md5.update(serverRandom.buffer());
+ md5.update(clientRandom.buffer());
+ keys[3] = Util.trim(md5.digest(), 8);
+ }
+ else
+ {
+ TLSRandom prf2 = new TLSRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(TLSRandom.SECRET, keys[2]);
+ byte[] seed = new byte[CLIENT_WRITE_KEY.length +
+ clientRandom.length() +
+ serverRandom.length()];
+ System.arraycopy(CLIENT_WRITE_KEY, 0, seed, 0,
+ CLIENT_WRITE_KEY.length);
+ clientRandom.buffer().get(seed, CLIENT_WRITE_KEY.length,
+ clientRandom.length());
+ serverRandom.buffer().get(seed, CLIENT_WRITE_KEY.length
+ + clientRandom.length(),
+ serverRandom.length());
+ attr.put(TLSRandom.SEED, seed);
+ prf2.init(attr);
+ keys[2] = new byte[8];
+ prf2.nextBytes(keys[2], 0, keys[2].length);
+
+ attr.put(TLSRandom.SECRET, keys[3]);
+ seed = new byte[SERVER_WRITE_KEY.length +
+ serverRandom.length() +
+ clientRandom.length()];
+ System.arraycopy(SERVER_WRITE_KEY, 0, seed, 0,
+ SERVER_WRITE_KEY.length);
+ serverRandom.buffer().get(seed, SERVER_WRITE_KEY.length,
+ serverRandom.length());
+ clientRandom.buffer().get(seed, SERVER_WRITE_KEY.length
+ + serverRandom.length(),
+ + clientRandom.length());
+ attr.put(TLSRandom.SEED, seed);
+ prf2.init(attr);
+ keys[3] = new byte[8];
+ prf2.nextBytes(keys[3], 0, keys[3].length);
+
+ attr.put(TLSRandom.SECRET, new byte[0]);
+ seed = new byte[IV_BLOCK.length +
+ clientRandom.length() +
+ serverRandom.length()];
+ System.arraycopy(IV_BLOCK, 0, seed, 0, IV_BLOCK.length);
+ clientRandom.buffer().get(seed, IV_BLOCK.length,
+ clientRandom.length());
+ serverRandom.buffer().get(seed, IV_BLOCK.length
+ + clientRandom.length(),
+ serverRandom.length());
+ attr.put(TLSRandom.SEED, seed);
+ prf2.init(attr);
+ prf2.nextBytes(keys[4], 0, keys[4].length);
+ prf2.nextBytes(keys[5], 0, keys[5].length);
+ }
+ }
+ else
+ {
+ prf.nextBytes(keys[4], 0, keys[4].length);
+ prf.nextBytes(keys[5], 0, keys[5].length);
+ }
+ }
+ catch (LimitReachedException lre)
+ {
+ // Won't happen with our implementation.
+ throw new Error(lre);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new Error(nsae);
+ }
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE,
+ "keys generated;\n [0]: {0}\n [1]: {1}\n [2]: {2}\n" +
+ " [3]: {3}\n [4]: {4}\n [5]: {5}",
+ Util.toHexString(keys[0], ':'),
+ Util.toHexString(keys[1], ':'),
+ Util.toHexString(keys[2], ':'),
+ Util.toHexString(keys[3], ':'),
+ Util.toHexString(keys[4], ':'),
+ Util.toHexString(keys[5], ':'));
+ return keys;
+ }
+
+ /**
+ * Generate a "finished" message. The hashes passed in are modified
+ * by this function, so they should be clone copies of the digest if
+ * the hash function needs to be used more.
+ *
+ * @param md5 The MD5 computation.
+ * @param sha The SHA-1 computation.
+ * @param isClient Whether or not the client-side finished message is
+ * being computed.
+ * @param session The current session.
+ * @return A byte buffer containing the computed finished message.
+ */
+ protected ByteBuffer generateFinished(MessageDigest md5,
+ MessageDigest sha,
+ boolean isClient,
+ SessionImpl session)
+ {
+ ByteBuffer finishedBuffer = null;
+ if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ finishedBuffer = ByteBuffer.allocate(12);
+ TLSRandom prf = new TLSRandom();
+ byte[] md5val = md5.digest();
+ byte[] shaval = sha.digest();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "finished md5:{0} sha:{1}",
+ Util.toHexString(md5val, ':'),
+ Util.toHexString(shaval, ':'));
+ byte[] seed = new byte[CLIENT_FINISHED.length
+ + md5val.length
+ + shaval.length];
+ if (isClient)
+ System.arraycopy(CLIENT_FINISHED, 0, seed, 0, CLIENT_FINISHED.length);
+ else
+ System.arraycopy(SERVER_FINISHED, 0, seed, 0, SERVER_FINISHED.length);
+ System.arraycopy(md5val, 0,
+ seed, CLIENT_FINISHED.length,
+ md5val.length);
+ System.arraycopy(shaval, 0,
+ seed, CLIENT_FINISHED.length + md5val.length,
+ shaval.length);
+ HashMap<String, Object> params = new HashMap<String, Object>(2);
+ params.put(TLSRandom.SECRET, session.privateData.masterSecret);
+ params.put(TLSRandom.SEED, seed);
+ prf.init(params);
+ byte[] buf = new byte[12];
+ prf.nextBytes(buf, 0, buf.length);
+ finishedBuffer.put(buf).position(0);
+ }
+ else
+ {
+ // The SSLv3 algorithm is:
+ //
+ // enum { client(0x434C4E54), server(0x53525652) } Sender;
+ //
+ // struct {
+ // opaque md5_hash[16];
+ // opaque sha_hash[20];
+ // } Finished;
+ //
+ // md5_hash MD5(master_secret + pad2 +
+ // MD5(handshake_messages + Sender +
+ // master_secret + pad1));
+ // sha_hash SHA(master_secret + pad2 +
+ // SHA(handshake_messages + Sender +
+ // master_secret + pad1));
+ //
+
+ finishedBuffer = ByteBuffer.allocate(36);
+
+ md5.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD1);
+
+ byte[] tmp = md5.digest();
+ md5.reset();
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD2);
+ md5.update(tmp);
+ finishedBuffer.put(md5.digest());
+
+ sha.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD1, 0, 40);
+
+ tmp = sha.digest();
+ sha.reset();
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD2, 0, 40);
+ sha.update(tmp);
+ finishedBuffer.put(sha.digest()).position(0);
+ }
+ return finishedBuffer;
+ }
+
+ protected void initDiffieHellman(DHPrivateKey dhKey, SecureRandom random)
+ throws SSLException
+ {
+ try
+ {
+ keyAgreement = KeyAgreement.getInstance("DH");
+ keyAgreement.init(dhKey, random);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+
+ protected void generateMasterSecret(Random clientRandom,
+ Random serverRandom,
+ SessionImpl session)
+ throws SSLException
+ {
+ assert(clientRandom != null);
+ assert(serverRandom != null);
+ assert(session != null);
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
+ new ByteArray(preMasterSecret));
+
+ if (session.version == ProtocolVersion.SSL_3)
+ {
+ try
+ {
+ MessageDigest _md5 = MessageDigest.getInstance("MD5");
+ MessageDigest _sha = MessageDigest.getInstance("SHA");
+ session.privateData.masterSecret = new byte[48];
+
+ _sha.update((byte) 'A');
+ _sha.update(preMasterSecret);
+ _sha.update(clientRandom.buffer());
+ _sha.update(serverRandom.buffer());
+ _md5.update(preMasterSecret);
+ _md5.update(_sha.digest());
+ _md5.digest(session.privateData.masterSecret, 0, 16);
+
+ _sha.update((byte) 'B');
+ _sha.update((byte) 'B');
+ _sha.update(preMasterSecret);
+ _sha.update(clientRandom.buffer());
+ _sha.update(serverRandom.buffer());
+ _md5.update(preMasterSecret);
+ _md5.update(_sha.digest());
+ _md5.digest(session.privateData.masterSecret, 16, 16);
+
+ _sha.update((byte) 'C');
+ _sha.update((byte) 'C');
+ _sha.update((byte) 'C');
+ _sha.update(preMasterSecret);
+ _sha.update(clientRandom.buffer());
+ _sha.update(serverRandom.buffer());
+ _md5.update(preMasterSecret);
+ _md5.update(_sha.digest());
+ _md5.digest(session.privateData.masterSecret, 32, 16);
+ }
+ catch (DigestException de)
+ {
+ throw new SSLException(de);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+ else // TLSv1.0 and later
+ {
+ byte[] seed = new byte[clientRandom.length()
+ + serverRandom.length()
+ + MASTER_SECRET.length];
+ System.arraycopy(MASTER_SECRET, 0, seed, 0, MASTER_SECRET.length);
+ clientRandom.buffer().get(seed, MASTER_SECRET.length,
+ clientRandom.length());
+ serverRandom.buffer().get(seed,
+ MASTER_SECRET.length + clientRandom.length(),
+ serverRandom.length());
+ TLSRandom prf = new TLSRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(TLSRandom.SECRET, preMasterSecret);
+ attr.put(TLSRandom.SEED, seed);
+ prf.init(attr);
+
+ session.privateData.masterSecret = new byte[48];
+ prf.nextBytes(session.privateData.masterSecret, 0, 48);
+ }
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.log(Component.SSL_KEY_EXCHANGE, "master_secret: {0}",
+ new ByteArray(session.privateData.masterSecret));
+
+ // Wipe out the preMasterSecret.
+ for (int i = 0; i < preMasterSecret.length; i++)
+ preMasterSecret[i] = 0;
+ }
+
+ protected void setupSecurityParameters(byte[][] keys, boolean isClient,
+ SSLEngineImpl engine,
+ CompressionMethod compression)
+ throws SSLException
+ {
+ assert(keys.length == 6);
+ assert(engine != null);
+ assert(compression != null);
+
+ try
+ {
+ CipherSuite s = engine.session().suite;
+ Cipher inCipher = s.cipher();
+ Mac inMac = s.mac(engine.session().version);
+ Inflater inflater = (compression == CompressionMethod.ZLIB
+ ? new Inflater() : null);
+ inCipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(keys[isClient ? 3 : 2],
+ s.cipherAlgorithm().toString()),
+ new IvParameterSpec(keys[isClient ? 5 : 4]));
+ inMac.init(new SecretKeySpec(keys[isClient ? 1 : 0],
+ inMac.getAlgorithm()));
+ inParams = new InputSecurityParameters(inCipher, inMac,
+ inflater,
+ engine.session(), s);
+
+ Cipher outCipher = s.cipher();
+ Mac outMac = s.mac(engine.session().version);
+ Deflater deflater = (compression == CompressionMethod.ZLIB
+ ? new Deflater() : null);
+ outCipher.init(Cipher.ENCRYPT_MODE,
+ new SecretKeySpec(keys[isClient ? 2 : 3],
+ s.cipherAlgorithm().toString()),
+ new IvParameterSpec(keys[isClient ? 4 : 5]));
+ outMac.init(new SecretKeySpec(keys[isClient ? 0 : 1],
+ outMac.getAlgorithm()));
+ outParams = new OutputSecurityParameters(outCipher, outMac,
+ deflater,
+ engine.session(), s);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new SSLException(iape);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ catch (NoSuchPaddingException nspe)
+ {
+ throw new SSLException(nspe);
+ }
+ }
+
+ protected void generatePSKSecret(String identity, byte[] otherkey,
+ boolean isClient)
+ throws SSLException
+ {
+ SecretKey key = null;
+ try
+ {
+ key = engine.contextImpl.pskManager.getKey(identity);
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ if (key != null)
+ {
+ byte[] keyb = key.getEncoded();
+ if (otherkey == null)
+ {
+ otherkey = new byte[keyb.length];
+ }
+ preMasterSecret = new byte[otherkey.length + keyb.length + 4];
+ preMasterSecret[0] = (byte) (otherkey.length >>> 8);
+ preMasterSecret[1] = (byte) otherkey.length;
+ System.arraycopy(otherkey, 0, preMasterSecret, 2, otherkey.length);
+ preMasterSecret[otherkey.length + 2]
+ = (byte) (keyb.length >>> 8);
+ preMasterSecret[otherkey.length + 3]
+ = (byte) keyb.length;
+ System.arraycopy(keyb, 0, preMasterSecret,
+ otherkey.length + 4, keyb.length);
+ }
+ else
+ {
+ // Generate a random, fake secret.
+ preMasterSecret = new byte[8];
+ preMasterSecret[1] = 2;
+ preMasterSecret[5] = 2;
+ preMasterSecret[6] = (byte) engine.session().random().nextInt();
+ preMasterSecret[7] = (byte) engine.session().random().nextInt();
+ }
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE, "PSK identity {0} key {1}",
+ identity, key);
+
+ generateMasterSecret(clientRandom, serverRandom,
+ engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, isClient, engine, compression);
+ }
+
+ protected class DHPhase extends DelegatedTask
+ {
+ private final DHPublicKey key;
+ private final boolean full;
+
+ protected DHPhase(DHPublicKey key)
+ {
+ this(key, true);
+ }
+
+ protected DHPhase(DHPublicKey key, boolean full)
+ {
+ this.key = key;
+ this.full = full;
+ }
+
+ protected void implRun() throws InvalidKeyException, SSLException
+ {
+ keyAgreement.doPhase(key, true);
+ preMasterSecret = keyAgreement.generateSecret();
+ if (full)
+ {
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression);
+ }
+ }
+ }
+
+ protected class CertVerifier extends DelegatedTask
+ {
+ private final boolean clientSide;
+ private final X509Certificate[] chain;
+ private boolean verified;
+
+ protected CertVerifier(boolean clientSide, X509Certificate[] chain)
+ {
+ this.clientSide = clientSide;
+ this.chain = chain;
+ }
+
+ boolean verified()
+ {
+ return verified;
+ }
+
+ protected void implRun()
+ {
+ X509TrustManager tm = engine.contextImpl.trustManager;
+ if (clientSide)
+ {
+ try
+ {
+ tm.checkServerTrusted(chain, null);
+ verified = true;
+ }
+ catch (CertificateException ce)
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce);
+ // For client connections, ask the user if the certificate is OK.
+ CallbackHandler verify = new DefaultCallbackHandler();
+ GetSecurityPropertyAction gspa
+ = new GetSecurityPropertyAction("jessie.certificate.handler");
+ String clazz = AccessController.doPrivileged(gspa);
+ try
+ {
+ ClassLoader cl =
+ AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()
+ {
+ public ClassLoader run() throws Exception
+ {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
+ verify = (CallbackHandler) cl.loadClass(clazz).newInstance();
+ }
+ catch (Exception x)
+ {
+ // Ignore.
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK,
+ "callback handler loading", x);
+ }
+ // XXX Internationalize
+ CertificateCallback confirm =
+ new CertificateCallback(chain[0],
+ "The server's certificate could not be verified. There is no proof " +
+ "that this server is who it claims to be, or that their certificate " +
+ "is valid. Do you wish to continue connecting? ");
+
+ try
+ {
+ verify.handle(new Callback[] { confirm });
+ verified = confirm.getSelectedIndex() == ConfirmationCallback.YES;
+ }
+ catch (Exception x)
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK,
+ "callback handler exception", x);
+ verified = false;
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ tm.checkClientTrusted(chain, null);
+ }
+ catch (CertificateException ce)
+ {
+ verified = false;
+ }
+ }
+
+ if (verified)
+ engine.session().setPeerVerified(true);
+ }
+ }
+
+ protected class DHE_PSKGen extends DelegatedTask
+ {
+ private final DHPublicKey dhKey;
+ private final SecretKey psKey;
+ private final boolean isClient;
+
+ protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient)
+ {
+ this.dhKey = dhKey;
+ this.psKey = psKey;
+ this.isClient = isClient;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun()
+ */
+ @Override protected void implRun() throws Throwable
+ {
+ keyAgreement.doPhase(dhKey, true);
+ byte[] dhSecret = keyAgreement.generateSecret();
+ byte[] psSecret = null;
+ if (psKey != null)
+ psSecret = psKey.getEncoded();
+ else
+ {
+ psSecret = new byte[8];
+ engine.session().random().nextBytes(psSecret);
+ }
+
+ preMasterSecret = new byte[dhSecret.length + psSecret.length + 4];
+ preMasterSecret[0] = (byte) (dhSecret.length >>> 8);
+ preMasterSecret[1] = (byte) dhSecret.length;
+ System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length);
+ preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8);
+ preMasterSecret[dhSecret.length + 3] = (byte) psSecret.length;
+ System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4,
+ psSecret.length);
+
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, isClient, engine, compression);
+ }
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java
index c31e1bef5ca..12c86b0a402 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java
@@ -38,10 +38,10 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
/**
* An alert message in the SSL protocol. Alerts are sent both as warnings
@@ -52,211 +52,112 @@ import java.io.OutputStream;
*
* <pre>
* struct {
- * AlertLevel level;
+ * AlertLevel level;
* AlertDescription description;
* }
* </pre>
*/
-final class Alert implements Constructed
+public final class Alert implements Constructed
{
// Fields.
// -------------------------------------------------------------------------
- /** The alert level enumerated. */
- private final Level level;
-
- /** The alert description enumerated. */
- private final Description description;
+ /** The underlying byte buffer. */
+ private final ByteBuffer buffer;
// Constructor.
// -------------------------------------------------------------------------
- Alert(Level level, Description description)
+ public Alert (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public Alert (final Level level, final Description description)
{
- this.level = level;
- this.description = description;
+ level.getClass ();
+ description.getClass ();
+ ByteBuffer b = ByteBuffer.allocate (2);
+ b.put (0, (byte) level.getValue ());
+ b.put (1, (byte) description.getValue ());
+ this.buffer = b.asReadOnlyBuffer ();
}
- // Class method.
+ // Instance methods.
// -------------------------------------------------------------------------
- static Alert read(InputStream in) throws IOException
+ public int length ()
{
- Level level = Level.read(in);
- Description desc = Description.read(in);
- return new Alert(level, desc);
+ return 2;
}
- static Alert forName(String name)
+ byte[] getEncoded()
{
- if (name == null)
- {
- return new Alert(Level.FATAL, Description.INTERNAL_ERROR);
- }
- Description desc = Description.INTERNAL_ERROR;
- if (name.equals("close_notify"))
- {
- desc = Description.CLOSE_NOTIFY;
- }
- else if (name.equals("unexpected_message"))
- {
- desc = Description.UNEXPECTED_MESSAGE;
- }
- else if (name.equals("bad_record_mac"))
- {
- desc = Description.BAD_RECORD_MAC;
- }
- else if (name.equals("DECRYPTION_FAILED"))
- {
- desc = Description.DECRYPTION_FAILED;
- }
- else if (name.equals("record_overflow"))
- {
- desc = Description.RECORD_OVERFLOW;
- }
- else if (name.equals("decompression_failure"))
- {
- desc = Description.DECOMPRESSION_FAILURE;
- }
- else if (name.equals("handshake_failure"))
- {
- desc = Description.HANDSHAKE_FAILURE;
- }
- else if (name.equals("no_certificate"))
- {
- desc = Description.NO_CERTIFICATE;
- }
- else if (name.equals("bad_certificate"))
- {
- desc = Description.BAD_CERTIFICATE;
- }
- else if (name.equals("unsupported_certificate"))
- {
- desc = Description.UNSUPPORTED_CERTIFICATE;
- }
- else if (name.equals("certificate_revoked"))
- {
- desc = Description.CERTIFICATE_REVOKED;
- }
- else if (name.equals("certificate_expired"))
- {
- desc = Description.CERTIFICATE_EXPIRED;
- }
- else if (name.equals("certificate_unknown"))
- {
- desc = Description.CERTIFICATE_UNKNOWN;
- }
- else if (name.equals("illegal_parameter"))
- {
- desc = Description.ILLEGAL_PARAMETER;
- }
- else if (name.equals("unknown_ca"))
- {
- desc = Description.UNKNOWN_CA;
- }
- else if (name.equals("access_denied"))
- {
- desc = Description.ACCESS_DENIED;
- }
- else if (name.equals("decode_error"))
- {
- desc = Description.DECODE_ERROR;
- }
- else if (name.equals("decrypt_error"))
- {
- desc = Description.DECRYPT_ERROR;
- }
- else if (name.equals("export_restriction"))
- {
- desc = Description.EXPORT_RESTRICTION;
- }
- else if (name.equals("protocol_version"))
- {
- desc = Description.PROTOCOL_VERSION;
- }
- else if (name.equals("insufficient_security"))
- {
- desc = Description.INSUFFICIENT_SECURITY;
- }
- else if (name.equals("internal_error"))
- {
- desc = Description.INTERNAL_ERROR;
- }
- else if (name.equals("user_canceled"))
- {
- desc = Description.USER_CANCELED;
- }
- else if (name.equals("no_renegotiation"))
- {
- desc = Description.NO_RENEGOTIATION;
- }
- else if (name.equals("unsupported_extension"))
- {
- desc = Description.UNSUPPORTED_EXTENSION;
- }
- else if (name.equals("certificate_unobtainable"))
- {
- desc = Description.CERTIFICATE_UNOBTAINABLE;
- }
- else if (name.equals("unrecognized_name"))
- {
- desc = Description.UNRECOGNIZED_NAME;
- }
- else if (name.equals("bad_certificate_status_response"))
- {
- desc = Description.BAD_CERTIFICATE_STATUS_RESPONSE;
- }
- else if (name.equals("bad_certificate_hash_value"))
- {
- desc = Description.BAD_CERTIFICATE_HASH_VALUE;
- }
- else if (name.equals("unknown_srp_username"))
- {
- desc = Description.UNKNOWN_SRP_USERNAME;
- }
- else if (name.equals("missing_srp_username"))
- {
- desc = Description.MISSING_SRP_USERNAME;
- }
- return new Alert(Level.FATAL, desc);
+ byte[] buf = new byte[2];
+ buffer.position (0);
+ buffer.get (buf);
+ return buf;
}
- // Instance methods.
- // -------------------------------------------------------------------------
+ public Level level()
+ {
+ return Level.forInteger (buffer.get (0) & 0xFF);
+ }
- public void write(OutputStream out) throws IOException
+ public Description description()
{
- out.write((byte) level.getValue());
- out.write((byte) description.getValue());
+ return Description.forInteger (buffer.get (1) & 0xFF);
}
- byte[] getEncoded()
+ public void setLevel (final Level level)
+ {
+ buffer.put (0, (byte) level.getValue ());
+ }
+
+ public void setDescription (final Description description)
{
- return new byte[] { (byte) level.getValue(),
- (byte) description.getValue() };
+ buffer.put (1, (byte) description.getValue ());
}
- Level getLevel()
+ public boolean equals (Object o)
{
- return level;
+ if (!(o instanceof Alert))
+ return false;
+ Alert that = (Alert) o;
+ return that.buffer.position (0).equals (buffer.position (0));
}
- Description getDescription()
+ public int hashCode ()
{
- return description;
+ return buffer.getShort (0) & 0xFFFF;
}
public String toString()
{
- String nl = System.getProperty("line.separator");
- return "struct {" + nl +
- " level = " + level + ";" + nl +
- " description = " + description + ";" + nl +
- "} Alert;" + nl;
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" level: ");
+ out.print (level ());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print (" description: ");
+ out.print (description ());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print ("} Alert;");
+ return str.toString ();
}
- // Inner classes.
+ // Enumerations.
// -------------------------------------------------------------------------
/**
@@ -266,129 +167,88 @@ final class Alert implements Constructed
* enum { warning(1), fatal(2), (255) } AlertLevel;
* </pre>
*/
- static final class Level implements Enumerated
+ public static enum Level
{
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final Level WARNING = new Level(1), FATAL = new Level(2);
-
+ WARNING (1), FATAL (2);
+
private final int value;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Level(int value)
{
this.value = value;
}
- // Class method.
- // -----------------------------------------------------------------------
-
- static Level read(InputStream in) throws IOException
+ public static Level forInteger (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of stream");
- }
- switch (i & 0xFF)
+ switch (value & 0xFF)
{
case 1: return WARNING;
case 2: return FATAL;
- default: return new Level(i);
+ default: throw new IllegalArgumentException ("invalid alert level: " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 1: return "warning";
- case 2: return "fatal";
- default: return "unknown(" + value + ")";
- }
- }
}
/**
* The description enumeration.
*/
- static final class Description implements Enumerated
+ public static enum Description
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final Description
- CLOSE_NOTIFY = new Description( 0),
- UNEXPECTED_MESSAGE = new Description( 10),
- BAD_RECORD_MAC = new Description( 20),
- DECRYPTION_FAILED = new Description( 21),
- RECORD_OVERFLOW = new Description( 22),
- DECOMPRESSION_FAILURE = new Description( 30),
- HANDSHAKE_FAILURE = new Description( 40),
- NO_CERTIFICATE = new Description( 41),
- BAD_CERTIFICATE = new Description( 42),
- UNSUPPORTED_CERTIFICATE = new Description( 43),
- CERTIFICATE_REVOKED = new Description( 44),
- CERTIFICATE_EXPIRED = new Description( 45),
- CERTIFICATE_UNKNOWN = new Description( 46),
- ILLEGAL_PARAMETER = new Description( 47),
- UNKNOWN_CA = new Description( 48),
- ACCESS_DENIED = new Description( 49),
- DECODE_ERROR = new Description( 50),
- DECRYPT_ERROR = new Description( 51),
- EXPORT_RESTRICTION = new Description( 60),
- PROTOCOL_VERSION = new Description( 70),
- INSUFFICIENT_SECURITY = new Description( 71),
- INTERNAL_ERROR = new Description( 80),
- USER_CANCELED = new Description( 90),
- NO_RENEGOTIATION = new Description(100),
- UNSUPPORTED_EXTENSION = new Description(110),
- CERTIFICATE_UNOBTAINABLE = new Description(111),
- UNRECOGNIZED_NAME = new Description(112),
- BAD_CERTIFICATE_STATUS_RESPONSE = new Description(113),
- BAD_CERTIFICATE_HASH_VALUE = new Description(114),
- UNKNOWN_SRP_USERNAME = new Description(120),
- MISSING_SRP_USERNAME = new Description(121);
-
+ CLOSE_NOTIFY ( 0),
+ UNEXPECTED_MESSAGE ( 10),
+ BAD_RECORD_MAC ( 20),
+ DECRYPTION_FAILED ( 21),
+ RECORD_OVERFLOW ( 22),
+ DECOMPRESSION_FAILURE ( 30),
+ HANDSHAKE_FAILURE ( 40),
+ NO_CERTIFICATE ( 41),
+ BAD_CERTIFICATE ( 42),
+ UNSUPPORTED_CERTIFICATE ( 43),
+ CERTIFICATE_REVOKED ( 44),
+ CERTIFICATE_EXPIRED ( 45),
+ CERTIFICATE_UNKNOWN ( 46),
+ ILLEGAL_PARAMETER ( 47),
+ UNKNOWN_CA ( 48),
+ ACCESS_DENIED ( 49),
+ DECODE_ERROR ( 50),
+ DECRYPT_ERROR ( 51),
+ EXPORT_RESTRICTION ( 60),
+ PROTOCOL_VERSION ( 70),
+ INSUFFICIENT_SECURITY ( 71),
+ INTERNAL_ERROR ( 80),
+ USER_CANCELED ( 90),
+ NO_RENEGOTIATION (100),
+ UNSUPPORTED_EXTENSION (110),
+ CERTIFICATE_UNOBTAINABLE (111),
+ UNRECOGNIZED_NAME (112),
+ BAD_CERTIFICATE_STATUS_RESPONSE (113),
+ BAD_CERTIFICATE_HASH_VALUE (114),
+ UNKNOWN_SRP_USERNAME (120),
+ MISSING_SRP_USERNAME (121);
+
private final int value;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Description(int value)
{
this.value = value;
}
- // Class method.
- // -----------------------------------------------------------------------
-
- static Description read(InputStream in) throws IOException
+ /**
+ * Return an alert description object based on the specified integer
+ * value.
+ *
+ * @param value The raw description value.
+ * @return The appropriate description object.
+ */
+ public static Description forInteger (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- switch (i)
+ switch (value & 0xFF)
{
case 0: return CLOSE_NOTIFY;
case 10: return UNEXPECTED_MESSAGE;
@@ -416,59 +276,13 @@ final class Alert implements Constructed
case 100: return NO_RENEGOTIATION;
case 120: return UNKNOWN_SRP_USERNAME;
case 121: return MISSING_SRP_USERNAME;
- default: return new Description(i);
+ default: throw new IllegalArgumentException("unknown alert description: " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 0: return "close_notify";
- case 10: return "unexpected_message";
- case 20: return "bad_record_mac";
- case 21: return "decryption_failed";
- case 22: return "record_overflow";
- case 30: return "decompression_failure";
- case 40: return "handshake_failure";
- case 42: return "bad_certificate";
- case 43: return "unsupported_certificate";
- case 44: return "certificate_revoked";
- case 45: return "certificate_expired";
- case 46: return "certificate_unknown";
- case 47: return "illegal_parameter";
- case 48: return "unknown_ca";
- case 49: return "access_denied";
- case 50: return "decode_error";
- case 51: return "decrypt_error";
- case 60: return "export_restriction";
- case 70: return "protocol_version";
- case 71: return "insufficient_security";
- case 80: return "internal_error";
- case 90: return "user_canceled";
- case 100: return "no_renegotiation";
- case 110: return "unsupported_extension";
- case 111: return "certificate_unobtainable";
- case 112: return "unrecognized_name";
- case 113: return "bad_certificate_status_response";
- case 114: return "bad_certificate_hash_value";
- case 120: return "unknown_srp_username";
- case 121: return "missing_srp_username";
- default: return "unknown(" + value + ")";
- }
- }
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java
index 666efe5ac0d..291de2700c9 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java
@@ -40,7 +40,10 @@ package gnu.javax.net.ssl.provider;
import javax.net.ssl.SSLException;
-class AlertException extends SSLException
+/**
+ * An exception generated by an SSL alert.
+ */
+public class AlertException extends SSLException
{
// Fields.
@@ -52,25 +55,47 @@ class AlertException extends SSLException
// Constructor.
// -------------------------------------------------------------------------
- AlertException(Alert alert, boolean isLocal)
+ public AlertException(Alert alert, boolean isLocal)
{
- super(alert.getDescription().toString());
+ super(alert.description().toString());
this.alert = alert;
this.isLocal = isLocal;
}
+ public AlertException(Alert alert)
+ {
+ this(alert, true);
+ }
+
+ public AlertException(Alert alert, boolean isLocal, Throwable cause)
+ {
+ super(alert.description().toString(), cause);
+ this.alert = alert;
+ this.isLocal = isLocal;
+ }
+
+ public AlertException(Alert alert, Throwable cause)
+ {
+ this(alert, true, cause);
+ }
+
// Instance methods.
// -------------------------------------------------------------------------
public String getMessage()
{
- return alert.getDescription() + ": " +
+ return alert.description() + ": " +
(isLocal ? "locally generated; " : "remotely generated; ") +
- alert.getLevel();
+ alert.level();
}
- public Alert getAlert ()
+ public Alert alert ()
{
return alert;
}
+
+ public boolean isLocal()
+ {
+ return isLocal;
+ }
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java
new file mode 100644
index 00000000000..baaba8aecf6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java
@@ -0,0 +1,66 @@
+/* Builder.java -- builder interface for protocol objects.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The base interface for classes that build SSL protocol objects. The
+ * general contract for Builder implementations is that they maintain a
+ * buffer that grows to fit the object being built; the allocated size of
+ * this buffer may be larger than the built object needs, but the general
+ * effort will be not to allocate too large a buffer.
+ *
+ * <p>Once the object is built, through various <em>setters</em> for
+ * the object's attributes, the final buffer may be retrieved with the
+ * {@link #buffer()} method.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public interface Builder extends Constructed
+{
+ /**
+ * Returns the final buffer, possibly containing the built object. The
+ * returned buffer will be "trimmed" to size: its position will be zero,
+ * and its limit and capacity set to the length of the built object.
+ *
+ * @return The underlying buffer.
+ */
+ ByteBuffer buffer();
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java
index b1d6b2a0143..8ff91e5579e 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java
@@ -1,4 +1,4 @@
-/* Certificate.java -- SSL Certificate message.
+/* Certificate.java -- SSL certificate message.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,157 +38,140 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.io.StringWriter;
-import java.security.cert.CertificateEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.Iterator;
import java.util.LinkedList;
-
-import javax.net.ssl.SSLProtocolException;
-
-final class Certificate implements Handshake.Body
+import java.util.List;
+
+/**
+ * The certificate object. This is used by both the client and the server
+ * to send their certificates (if any) to one another.
+ *
+ * <pre>opaque ASN.1Cert&lt;1..2^24-1&gt;;
+
+struct {
+ ASN.1Cert certificate_list&lt;0..2^24-1&gt;;
+} Certificate;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class Certificate implements Handshake.Body
{
// Fields.
// -------------------------------------------------------------------------
- private final X509Certificate[] certs;
+ protected ByteBuffer buffer;
+ protected final CertificateType type;
// Constructors.
// -------------------------------------------------------------------------
- Certificate(X509Certificate[] certs)
+ public Certificate (final ByteBuffer buffer, final CertificateType type)
{
- if (certs == null)
- {
- throw new NullPointerException();
- }
- this.certs = certs;
+ buffer.getClass ();
+ type.getClass ();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.type = type;
}
- // Class methods.
+ // Instance methods.
// -------------------------------------------------------------------------
- static Certificate read(InputStream in, CertificateType type)
- throws IOException
+ public int length ()
{
- if (type == CertificateType.X509)
- {
- int len = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8
- | (in.read() & 0xFF);
- byte[] buf = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(buf, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of stream");
- }
- count += l;
- }
- try
- {
- LinkedList certs = new LinkedList();
- CertificateFactory fact = CertificateFactory.getInstance("X.509");
- ByteArrayInputStream bin = new ByteArrayInputStream(buf);
- count = 0;
- while (count < len)
- {
- int len2 = (bin.read() & 0xFF) << 16 | (bin.read() & 0xFF) << 8
- | (bin.read() & 0xFF);
- certs.add(fact.generateCertificate(bin));
- count += len2 + 3;
- }
- return new Certificate((X509Certificate[])
- certs.toArray(new X509Certificate[certs.size()]));
- }
- catch (CertificateException ce)
- {
- SSLProtocolException sslpe = new SSLProtocolException(ce.getMessage());
- sslpe.initCause (ce);
- throw sslpe;
- }
- }
- else if (type == CertificateType.OPEN_PGP)
- {
- throw new UnsupportedOperationException("not yet implemented");
- }
- else
- throw new Error("unsupported certificate type "+type);
+ return (((buffer.get (0) & 0xFF) << 24)
+ | buffer.getShort (1)) + 3;
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ public List<java.security.cert.Certificate> certificates ()
+ throws CertificateException, NoSuchAlgorithmException
{
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try
- {
- for (int i = 0; i < certs.length; i++)
- {
- byte[] enc = certs[i].getEncoded();
- bout.write((enc.length >>> 16) & 0xFF);
- bout.write((enc.length >>> 8) & 0xFF);
- bout.write( enc.length & 0xFF);
- bout.write(enc);
- }
- }
- catch (CertificateEncodingException cee)
- {
- throw new Error("cannot encode certificates");
- }
- catch (IOException ignored)
+ LinkedList<java.security.cert.Certificate> list
+ = new LinkedList<java.security.cert.Certificate>();
+ CertificateFactory factory = CertificateFactory.getInstance(type.toString());
+ int length = (((buffer.get(0) & 0xFF) << 16)
+ | (buffer.getShort(1) & 0xFFFF));
+ ByteBuffer b = (ByteBuffer) buffer.duplicate().position(3);
+ for (int i = 3; i < length; )
{
+ int length2 = (((b.get () & 0xFF) << 16)
+ | (b.getShort () & 0xFFFF));
+ byte[] buf = new byte[length2];
+ b.position(i+3);
+ b.get (buf);
+ list.add(factory.generateCertificate (new ByteArrayInputStream (buf)));
+ i += length2 + 3;
+ b.position(i);
}
- out.write(bout.size() >>> 16 & 0xFF);
- out.write(bout.size() >>> 8 & 0xFF);
- out.write(bout.size() & 0xFF);
- bout.writeTo(out);
+ return list;
}
- X509Certificate[] getCertificates()
+ public String toString ()
{
- return certs;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
- out.println("struct {");
- out.println(" certificateList =");
- for (int i = 0; i < certs.length; i++)
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ try
{
- BufferedReader r =
- new BufferedReader(new StringReader(certs[i].toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
+ List certs = certificates ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" certificateList: [");
+ out.print (certs.size ());
+ out.println ("] {");
+ for (Iterator it = certs.iterator (); it.hasNext (); )
{
+ java.security.cert.Certificate cert =
+ (java.security.cert.Certificate) it.next ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ if (cert instanceof X509Certificate)
+ out.print (((X509Certificate) cert).getSubjectDN ());
+ else
+ out.print (cert);
+ out.println (";");
}
+ if (prefix != null)
+ out.print (prefix);
+ out.println (" };");
+ }
+ catch (CertificateException ce)
+ {
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (ce);
+ out.println (";");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (nsae);
+ out.println (";");
}
- out.println("} Certificate;");
+ out.print ("} Certificate;");
return str.toString();
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java
index dd138b436a1..b60ad556ac9 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java
@@ -1,4 +1,4 @@
-/* DigestInputStream.java -- digesting input stream.
+/* CertificateBuilder.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -33,71 +33,62 @@ module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
+exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.FilterInputStream;
-import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
-
-import gnu.java.security.hash.IMessageDigest;
-
-final class DigestInputStream extends FilterInputStream
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.security.cert.CertificateException;
+
+/**
+ * Builder for {@link Certificate} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateBuilder extends Certificate implements Builder
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private IMessageDigest md5, sha;
- private boolean digesting;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha)
+ public CertificateBuilder(final CertificateType certType)
{
- super(in);
- if (md5 == null || sha == null)
- throw new NullPointerException();
- this.md5 = md5;
- this.sha = sha;
- digesting = true;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- void setDigesting(boolean digesting)
- {
- this.digesting = digesting;
- }
-
- public int read() throws IOException
- {
- int i = in.read();
- if (digesting && i != -1)
- {
- md5.update((byte) i);
- sha.update((byte) i);
- }
- return i;
+ super(ByteBuffer.allocate(1024), certType);
}
- public int read(byte[] buf) throws IOException
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
{
- return read(buf, 0, buf.length);
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
}
- public int read(byte[] buf, int off, int len) throws IOException
+ public void setCertificates (final List<? extends java.security.cert.Certificate> certificates)
+ throws CertificateException
{
- int ret = in.read(buf, off, len);
- if (digesting && ret != -1)
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ for (java.security.cert.Certificate cert : certificates)
{
- md5.update(buf, off, ret);
- sha.update(buf, off, ret);
+ byte[] encoded = cert.getEncoded();
+ out.write((encoded.length >>> 16) & 0xFF);
+ out.write((encoded.length >>> 8) & 0xFF);
+ out.write( encoded.length & 0xFF);
+ try
+ {
+ out.write(encoded);
+ }
+ catch (IOException shouldNotHappen)
+ {
+ // ignore; this is a ByteArrayOutputStream.
+ }
}
- return ret;
+ byte[] certs = out.toByteArray();
+ // There is only one field in Certificate; so it is easy to reallocate.
+ if (buffer.capacity() < certs.length + 3)
+ buffer = ByteBuffer.allocate(certs.length + 3);
+ buffer.put(0, (byte) (certs.length >>> 16));
+ buffer.putShort(1, (short) certs.length);
+ ((ByteBuffer) buffer.duplicate().position(3)).put(certs);
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java
index 0f788039b0b..b7a22b20400 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java
@@ -38,201 +38,96 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-import java.util.LinkedList;
-import java.security.Principal;
-
-final class CertificateRequest implements Handshake.Body
+/**
+ * A request by the server for a client certificate.
+ *
+ * <pre>
+struct
+{
+ ClientCertificateType certificate_types&lt;1..2^8-1&gt;;
+ DistinguishedName certificate_authorities&lt;3..2^16-1&gt;;
+} CertificateRequest;
+</pre>
+ */
+public class CertificateRequest implements Handshake.Body
{
// Fields.
// -------------------------------------------------------------------------
- private final ClientType[] types;
- private final Principal[] authorities;
-
+ protected ByteBuffer buffer;
+
// Constructor.
// -------------------------------------------------------------------------
- CertificateRequest(ClientType[] types, Principal[] authorities)
- {
- if (types == null)
- {
- throw new NullPointerException();
- }
- this.types = types;
- if (authorities == null)
- {
- throw new NullPointerException();
- }
- this.authorities = authorities;
- }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- static CertificateRequest read(InputStream in) throws IOException
+ public CertificateRequest(final ByteBuffer buffer)
{
- DataInputStream din = new DataInputStream(in);
- ClientType[] types = new ClientType[din.readUnsignedByte()];
- for (int i = 0; i < types.length; i++)
- {
- types[i] = ClientType.read(din);
- }
-
- LinkedList authorities = new LinkedList();
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- ByteArrayInputStream bin = new ByteArrayInputStream(buf);
- try
- {
- String x500name = Util.getSecurityProperty("jessie.x500.class");
- if (x500name == null)
- {
- x500name = "org.metastatic.jessie.pki.X500Name";
- }
- Class x500class = null;
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- if (cl != null)
- {
- x500class = cl.loadClass(x500name);
- }
- else
- {
- x500class = Class.forName(x500name);
- }
- Constructor c = x500class.getConstructor(new Class[] { new byte[0].getClass() });
- while (bin.available() > 0)
- {
- buf = new byte[(bin.read() & 0xFF) << 8 | (bin.read() & 0xFF)];
- bin.read(buf);
- authorities.add(c.newInstance(new Object[] { buf }));
- }
- }
- catch (IOException ioe)
- {
- throw ioe;
- }
- catch (Exception ex)
- {
- throw new Error(ex.toString());
- }
- return new CertificateRequest(types,
- (Principal[]) authorities.toArray(new Principal[authorities.size()]));
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public int length ()
{
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- out.write(types.length);
- for (int i = 0; i < types.length; i++)
- {
- out.write(types[i].getValue());
- }
-
- try
- {
- Class x500class = authorities[0].getClass();
- Method m = x500class.getMethod("getEncoded", null);
- for (int i = 0; i < authorities.length; i++)
- {
- byte[] buf = (byte[]) m.invoke(authorities[i], null);
- bout.write(buf.length >>> 8 & 0xFF);
- bout.write(buf.length & 0xFF);
- bout.write(buf, 0, buf.length);
- }
- }
- catch (Exception ex)
- {
- throw new Error(ex.toString());
- }
- out.write(bout.size() >>> 8 & 0xFF);
- out.write(bout.size() & 0xFF);
- bout.writeTo(out);
+ int o1 = (buffer.get (0) & 0xFF) + 1;
+ return o1 + (buffer.getShort (o1) & 0xFFFF) + 2;
}
- ClientType[] getTypes()
+ public ClientCertificateTypeList types ()
{
- return types;
+ return new ClientCertificateTypeList(buffer.duplicate());
}
- String[] getTypeStrings()
+ public X500PrincipalList authorities ()
{
- try
- {
- return (String[]) Util.transform(types, String.class, "toString", null);
- }
- catch (Exception x)
- {
- return null;
- }
+ int offset = (buffer.get (0) & 0xFF) + 1;
+ return new X500PrincipalList (((ByteBuffer) buffer.position(offset)).slice());
}
- Principal[] getAuthorities()
+ public String toString()
{
- return authorities;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + " ";
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- out.print(" types = ");
- for (int i = 0; i < types.length; i++)
- {
- out.print(types[i]);
- if (i != types.length - 1)
- out.print(", ");
- }
- out.println(";");
+ if (prefix != null) out.print (prefix);
+ out.println (" types =");
+ out.println (types ().toString (subprefix));
+ if (prefix != null) out.print (prefix);
out.println(" authorities =");
- for (int i = 0; i < authorities.length; i++)
- {
- out.print(" ");
- out.print(authorities[i].getName());
- if (i != types.length - 1)
- out.println(",");
- }
- out.println(";");
- out.println("} CertificateRequest;");
+ out.println (authorities ().toString (subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print ("} CertificateRequest;");
return str.toString();
}
- // Inner class.
- // -------------------------------------------------------------------------
-
- static final class ClientType implements Enumerated
+ public static enum ClientCertificateType
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final ClientType
- RSA_SIGN = new ClientType(1), DSS_SIGN = new ClientType(2),
- RSA_FIXED_DH = new ClientType(3), DSS_FIXED_DH = new ClientType(4);
+ RSA_SIGN (1),
+ DSS_SIGN (2),
+ RSA_FIXED_DH (3),
+ DSS_FIXED_DH (4);
private final int value;
// Constructor.
// -----------------------------------------------------------------------
- private ClientType(int value)
+ private ClientCertificateType (final int value)
{
this.value = value;
}
@@ -240,46 +135,21 @@ final class CertificateRequest implements Handshake.Body
// Class method.
// -----------------------------------------------------------------------
- static ClientType read(InputStream in) throws IOException
+ static ClientCertificateType forValue (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- switch (i & 0xFF)
+ switch (value)
{
case 1: return RSA_SIGN;
case 2: return DSS_SIGN;
case 3: return RSA_FIXED_DH;
case 4: return DSS_FIXED_DH;
- default: return new ClientType(i);
+ default: throw new IllegalArgumentException("unknown client certificate type: " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 1: return "rsa_sign";
- case 2: return "dss_sign";
- case 3: return "rsa_fixed_dh";
- case 4: return "dss_fixed_dh";
- default: return "unknown(" + value + ")";
- }
- }
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java
new file mode 100644
index 00000000000..9beab473ca6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java
@@ -0,0 +1,113 @@
+/* CertificateRequestBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import static gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Builder for {@link CertificateRequest} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateRequestBuilder extends CertificateRequest
+ implements Builder
+{
+ public CertificateRequestBuilder()
+ {
+ super(ByteBuffer.allocate(1024));
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().limit(length())).slice();
+ }
+
+ public void setTypes(List<ClientCertificateType> types)
+ {
+ ensureCapacity(types.size() + 3);
+ buffer.put(0, (byte) types.size());
+ ByteBuffer b = (ByteBuffer) buffer.duplicate().position(1);
+ for (ClientCertificateType type : types)
+ b.put((byte) type.getValue());
+ }
+
+ public void setAuthorities(List<X500Principal> authorities)
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ for (X500Principal auth : authorities)
+ {
+ byte[] encoded = auth.getEncoded();
+ out.write((encoded.length >>> 8) & 0xFF);
+ out.write( encoded.length & 0xFF);
+ try
+ {
+ out.write(encoded);
+ }
+ catch (IOException ignored)
+ {
+ // Ignored; we use a ByteArrayOutputStream.
+ }
+ }
+ byte[] auths = out.toByteArray();
+ int typesLen = 1 + (buffer.get(0) & 0xFF);
+ int len = typesLen + auths.length + 2;
+ ensureCapacity(len);
+ buffer.putShort(typesLen, (short) auths.length);
+ ((ByteBuffer) buffer.duplicate().position(typesLen + 2)).put(auths);
+ }
+
+ public void ensureCapacity(final int capacity)
+ {
+ if (buffer.capacity() >= capacity)
+ return;
+ ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+ newBuffer.duplicate().put(buffer);
+ buffer = newBuffer;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
new file mode 100644
index 00000000000..059c6ec47ba
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
@@ -0,0 +1,272 @@
+/* CertificateStatusRequest.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * <pre>
+struct {
+ CertificateStatusType status_type;
+ select (status_type) {
+ case ocsp: OCSPStatusRequest;
+ } request;
+} CertificateStatusRequest;
+
+enum { ocsp(1), (255) } CertificateStatusType;
+
+struct {
+ ResponderID responder_id_list&lt;0..2^16-1&gt;;
+ Extensions request_extensions;
+} OCSPStatusRequest;
+
+opaque ResponderID&lt;1..2^16-1&gt;;
+opaque Extensions&lt;0..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class CertificateStatusRequest extends Value implements Iterable<byte[]>
+{
+ private ByteBuffer buffer;
+
+ public CertificateStatusRequest(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public CertificateStatusRequest(CertificateStatusType type,
+ List<byte[]> responderIdList,
+ byte[] requestExtensions)
+ {
+ if (type != CertificateStatusType.OCSP)
+ throw new IllegalArgumentException();
+ int length = 3;
+ int idsLength = 0;
+ for (byte[] responderId : responderIdList)
+ {
+ length += 2 + responderId.length;
+ idsLength += 2 + responderId.length;
+ }
+ length += 2 + requestExtensions.length;
+ buffer = ByteBuffer.allocate(length);
+ buffer.put((byte) 1);
+ buffer.putShort((short) idsLength);
+ for (byte[] responderId : responderIdList)
+ buffer.putShort((short) responderId.length).put(responderId);
+ buffer.putShort((short) requestExtensions.length);
+ buffer.put(requestExtensions);
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ int l = 3 + (buffer.getShort(1) & 0xFFFF);
+ return l + (buffer.getShort(l) & 0xFFFF) + 2;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public CertificateStatusType statusType()
+ {
+ int x = buffer.get(0) & 0xFF;
+ if (x == 1)
+ return CertificateStatusType.OCSP;
+ throw new IllegalArgumentException ("invalid type: " + x);
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ for (int i = 3; i < len; )
+ {
+ int l = buffer.getShort(i);
+ i += l + 2;
+ n++;
+ }
+ return n;
+ }
+
+ public byte[] responderId(int index)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i = 3;
+ while (i < len && n <= index)
+ {
+ int l = buffer.getShort(i) & 0xFFFF;
+ if (n == index)
+ {
+ byte[] b = new byte[l];
+ ((ByteBuffer) buffer.duplicate().position(i+2)).get(b);
+ return b;
+ }
+ i += l + 2;
+ n++;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public byte[] requestExtensions()
+ {
+ int l = 2 + (buffer.getShort(0) & 0xFFFF);
+ int ll = buffer.getShort(l) & 0xFFFF;
+ byte[] b = new byte[ll];
+ ((ByteBuffer) buffer.duplicate().position(ll+2)).get(b);
+ return b;
+ }
+
+ public void setStatusType(CertificateStatusType type)
+ {
+ buffer.put(0, (byte) type.value);
+ }
+
+ public void setRequestIdListLength(int newLength)
+ {
+ if (newLength < 0 || newLength > 0xFFFF)
+ throw new IllegalArgumentException("length out of range");
+ buffer.putShort(1, (short) newLength);
+ }
+
+ public void putRequestId(int index, byte[] id)
+ {
+ if (id.length > 0xFFFF)
+ throw new IllegalArgumentException("request ID too large");
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i = 3;
+ while (i < len && n < index)
+ {
+ int l = buffer.getShort(i) & 0xFFFF;
+ i += l + 2;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException();
+ buffer.putShort(i, (short) id.length);
+ ((ByteBuffer) buffer.duplicate().position(i)).put(id);
+ }
+
+ public void setRequestExtensions(int index, byte[] ext)
+ {
+ if (ext.length > 0xFFFF)
+ throw new IllegalArgumentException("exceptions too large");
+ int off = 3 + (buffer.getShort(1) & 0xFFFF);
+ buffer.putShort(off, (short) ext.length);
+ ((ByteBuffer) buffer.duplicate().position(off+2)).put(ext);
+ }
+
+ public Iterator<byte[]> iterator()
+ {
+ return new ResponderIdIterator();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" status_type = ");
+ out.print(statusType());
+ out.println(";");
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ if (prefix != null) out.print(prefix);
+ out.println(" responder_id_list = {");
+ for (byte[] b : this)
+ out.print(Util.hexDump(b, subprefix));
+ if (prefix != null) out.print(prefix);
+ out.println(" };");
+ if (prefix != null) out.print(prefix);
+ out.println(" request_extensions =");
+ out.print(Util.hexDump(requestExtensions(), subprefix));
+ if (prefix != null) out.print(prefix);
+ out.print("} CertificateStatus;");
+ return str.toString();
+ }
+
+ public class ResponderIdIterator implements Iterator<byte[]>
+ {
+ private int index;
+
+ public ResponderIdIterator()
+ {
+ index = 0;
+ }
+
+ public byte[] next() throws NoSuchElementException
+ {
+ try
+ {
+ return responderId(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java
new file mode 100644
index 00000000000..7cddf168f94
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java
@@ -0,0 +1,13 @@
+package gnu.javax.net.ssl.provider;
+
+public enum CertificateStatusType
+{
+ OCSP (1);
+
+ public final int value;
+
+ private CertificateStatusType (final int value)
+ {
+ this.value = value;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java
index c5705939f74..ecba21b6342 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java
@@ -38,67 +38,25 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-
-final class CertificateType implements Enumerated
+public enum CertificateType
{
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- static final CertificateType X509 = new CertificateType(0);
- static final CertificateType OPEN_PGP = new CertificateType(1);
+ X509 (0),
+ OPEN_PGP (1);
private final int value;
- // Constructor.
- // -------------------------------------------------------------------------
-
private CertificateType(int value)
{
this.value = value;
}
- // Class method.
- // -------------------------------------------------------------------------
-
- static CertificateType read(InputStream in) throws IOException
- {
- int value = in.read();
- if (value == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- switch (value & 0xFF)
- {
- case 0: return X509;
- case 1: return OPEN_PGP;
- default: return new CertificateType(value);
- }
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
- public int getValue()
- {
- return value;
- }
-
- public String toString()
+ public static CertificateType forValue (final int value)
{
switch (value)
{
- case 0: return "X.509";
- case 1: return "OpenPGP";
- default: return "unknown(" + value + ")";
+ case 0: return X509;
+ case 1: return OPEN_PGP;
+ default: throw new IllegalArgumentException ("unknown certificate type: " + value);
}
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java
new file mode 100644
index 00000000000..0bc1c428b48
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java
@@ -0,0 +1,388 @@
+/* CertificateURL.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * The CertificateURL extension value.
+ *
+ * <pre>
+enum {
+ individual_certs(0), pkipath(1), (255)
+} CertChainType;
+
+enum {
+ false(0), true(1)
+} Boolean;
+
+struct {
+ CertChainType type;
+ URLAndOptionalHash url_and_hash_list&lt;1..2^16-1&gt;;
+} CertificateURL;
+
+struct {
+ opaque url&lt;1..2^16-1&gt;;
+ Boolean hash_present;
+ select (hash_present) {
+ case false: struct {};
+ case true: SHA1Hash;
+ } hash;
+} URLAndOptionalHash;
+
+opaque SHA1Hash[20];</pre>
+ *
+ * @author csm
+ *
+ */
+public class CertificateURL extends Value implements Iterable<CertificateURL.URLAndOptionalHash>
+{
+ private ByteBuffer buffer;
+
+ public CertificateURL(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public CertificateURL(CertChainType type, List<URLAndOptionalHash> urls)
+ {
+ int length = 3;
+ for (URLAndOptionalHash url : urls)
+ length += url.length();
+ buffer = ByteBuffer.allocate(length);
+ buffer.put((byte) type.getValue());
+ buffer.putShort((short) (length - 1));
+ for (URLAndOptionalHash url : urls)
+ buffer.put(url.buffer());
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return 3 + (buffer.getShort(1) & 0xFFFF);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public CertChainType type()
+ {
+ switch (buffer.get(0))
+ {
+ case 0: return CertChainType.INDIVIDUAL_CERTS;
+ case 1: return CertChainType.PKIPATH;
+ }
+ throw new IllegalArgumentException("unknown certificate URL type");
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ for (int i = 3; i < len; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ int l = u.length();
+ i += l;
+ n++;
+ }
+ return n;
+ }
+
+ public URLAndOptionalHash get(int index)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int l = 0;
+ int i;
+ for (i = 3; i < len && n < index; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ l = u.length();
+ i += l;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException();
+ return new URLAndOptionalHash(((ByteBuffer) buffer.duplicate().position(i).limit(i+l)).slice());
+ }
+
+ public void set(int index, URLAndOptionalHash url)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i;
+ for (i = 3; i < len && n < index-1; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ int l = u.length();
+ i += l;
+ n++;
+ }
+ if (n < index - 1)
+ throw new IndexOutOfBoundsException();
+ int l = url.urlLength();
+ buffer.putShort(i, (short) l);
+ ((ByteBuffer) buffer.duplicate().position(i+2)).put(url.urlBuffer());
+ buffer.put(i+l+2, (byte) (url.hashPresent() ? 1 : 0));
+ if (url.hashPresent())
+ ((ByteBuffer) buffer.duplicate().position(i+l+3)).put (url.sha1Hash());
+ }
+
+ public void setLength(final int length)
+ {
+ if (length < 0 || length > 65535)
+ throw new IllegalArgumentException("length must be between 0 and 65535");
+ buffer.putShort(1, (short) length);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" type = ");
+ out.print(type());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.println(" url_and_hash_list = {");
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ for (URLAndOptionalHash url : this)
+ {
+ out.println(url.toString(subprefix));
+ }
+ if (prefix != null) out.print(prefix);
+ out.println(" };");
+ if (prefix != null) out.print(prefix);
+ out.print("} CertificateURL;");
+ return str.toString();
+ }
+
+ public java.util.Iterator<URLAndOptionalHash> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<URLAndOptionalHash>
+ {
+ private int index;
+
+ public Iterator()
+ {
+ index = 0;
+ }
+
+ public URLAndOptionalHash next() throws NoSuchElementException
+ {
+ try
+ {
+ return get(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static enum CertChainType
+ {
+ INDIVIDUAL_CERTS (0), PKIPATH (1);
+
+ private final int value;
+
+ private CertChainType (final int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+
+ public static class URLAndOptionalHash implements Builder, Constructed
+ {
+ private ByteBuffer buffer;
+
+ public URLAndOptionalHash (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public URLAndOptionalHash(String url)
+ {
+ this(url, null);
+ }
+
+ public URLAndOptionalHash(String url, byte[] hash)
+ {
+ if (hash != null && hash.length < 20)
+ throw new IllegalArgumentException();
+ int length = 3 + url.length();
+ if (hash != null)
+ length += 20;
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) url.length());
+ Charset cs = Charset.forName("US-ASCII");
+ CharsetEncoder ascii = cs.newEncoder();
+ ascii.encode(CharBuffer.wrap(url), buffer, true);
+ buffer.put((byte) (hash != null ? 1 : 0));
+ if (hash != null)
+ buffer.put(hash, 0, 20);
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return ((buffer.getShort(0) & 0xFFFF)
+ + (hashPresent() ? 23 : 3));
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public String url()
+ {
+ Charset cs = Charset.forName("ASCII");
+ return cs.decode(urlBuffer()).toString();
+ }
+
+ public int urlLength()
+ {
+ return buffer.getShort(0) & 0xFFFF;
+ }
+
+ public ByteBuffer urlBuffer()
+ {
+ int len = urlLength();
+ return ((ByteBuffer) buffer.duplicate().position(2).limit(2+len)).slice();
+ }
+
+ public boolean hashPresent()
+ {
+ int i = (buffer.getShort(0) & 0xFFFF) + 2;
+ byte b = buffer.get(i);
+ if (b == 0)
+ return false;
+ if (b == 1)
+ return true;
+ throw new IllegalArgumentException("expecting 0 or 1: " + (b & 0xFF));
+ }
+
+ public byte[] sha1Hash()
+ {
+ int i = (buffer.getShort(0) & 0xFFFF) + 2;
+ byte b = buffer.get(i);
+ if (b == 0)
+ return null;
+ byte[] buf = new byte[20];
+ ((ByteBuffer) buffer.duplicate().position(i+1)).get(buf);
+ return buf;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" url = ");
+ out.print(url());
+ out.println(";");
+ boolean has_hash = hashPresent();
+ if (prefix != null) out.print(prefix);
+ out.print(" hash_present = ");
+ out.print(has_hash);
+ out.println(";");
+ if (has_hash)
+ {
+ if (prefix != null) out.print(prefix);
+ out.print(" sha1Hash = ");
+ out.print(Util.toHexString(sha1Hash(), ':'));
+ out.println(";");
+ }
+ if (prefix != null) out.print(prefix);
+ out.print("} URLAndOptionalHash;");
+ return str.toString();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java
index e0bf130f189..b63f5e4ef0c 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java
@@ -38,34 +38,24 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.io.StringWriter;
-import java.security.PublicKey;
+import java.nio.ByteBuffer;
-final class CertificateVerify extends Signature implements Handshake.Body
+public class CertificateVerify extends Signature implements Handshake.Body
{
// Contstructor.
// -------------------------------------------------------------------------
- CertificateVerify(Object sigValue, String sigAlg)
+ public CertificateVerify(final ByteBuffer buffer, final SignatureAlgorithm sigAlg)
{
- super(sigValue, sigAlg);
+ super(buffer, sigAlg);
}
-
- // Class method.
- // --------------------------------------------------------------------------
-
- static Signature read(InputStream in, CipherSuite suite, PublicKey key)
- throws IOException
+
+ public CertificateVerify(final byte[] sigVal, final SignatureAlgorithm sigAlg)
{
- Signature sig = Signature.read(in, suite, key);
- return new CertificateVerify(sig.getSigValue(), sig.getSigAlg());
+ super(sigVal, sigAlg);
}
// Instance method.
@@ -73,23 +63,21 @@ final class CertificateVerify extends Signature implements Handshake.Body
public String toString()
{
- StringWriter str = new StringWriter();
- PrintWriter out = new PrintWriter(str);
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- BufferedReader r = new BufferedReader(new StringReader(super.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- out.println("} CertificateVerify;");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.println (super.toString (subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print ("} CertificateVerify;");
return str.toString();
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java
index 93bdcaec5ed..98e05af310d 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java
@@ -1,4 +1,4 @@
-/* OverflowException.java -- signals an input overflow.
+/* CipherAlgorithm.java -- Cipher algorithm enumeration.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,20 +38,10 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.IOException;
-
-class OverflowException extends IOException
+/**
+ * The set of cipher algorithms we support.
+ */
+public enum CipherAlgorithm
{
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- OverflowException()
- {
- }
-
- OverflowException(String msg)
- {
- super(msg);
- }
+ NULL, RC4, DES, DESede, CAST5, AES
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java
index de916817b92..af3041e9403 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java
@@ -38,407 +38,521 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.DataInputStream;
-import java.io.InputStream;
+import gnu.java.security.action.GetSecurityPropertyAction;
+
import java.io.IOException;
import java.io.OutputStream;
-import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
-import java.security.Provider;
-import java.security.Security;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
+import javax.crypto.NullCipher;
-import gnu.javax.crypto.cipher.CipherFactory;
-import gnu.javax.crypto.cipher.IBlockCipher;
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mac.MacFactory;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.mode.ModeFactory;
-
-final class CipherSuite implements Constructed
+public final class CipherSuite implements Constructed
{
// Constants and fields.
// -------------------------------------------------------------------------
- private static final List tlsSuiteNames = new LinkedList();
- private static final HashMap namesToSuites = new HashMap();
-
- // SSL CipherSuites.
- static final CipherSuite SSL_NULL_WITH_NULL_NULL =
- new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00,
- "SSL_NULL_WITH_NULL_NULL", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_NULL_MD5 =
- new CipherSuite("null", "RSA", "RSA", "SSLMAC-MD5", 0, 0x00, 0x01,
- "SSL_RSA_WITH_NULL_MD5", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_NULL_SHA =
- new CipherSuite("null", "RSA", "RSA", "SSLMAC-SHA", 0, 0x00, 0x02,
- "SSL_RSA_WITH_NULL_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 5, 0x00, 0x03,
- "SSL_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 16, 0x00, 0x04,
- "SSL_RSA_WITH_RC4_128_MD5", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_RC4_128_SHA =
- new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x05,
- "SSL_RSA_WITH_RC4_128_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 5, 0x00, 0x08,
- "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 8, 0x00, 0x09,
- "SSL_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "RSA", "RSA", "SSLMAC-SHA", 24, 0x00, 0x0A,
- "SSL_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 5, 0x00, 0x0B,
- "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 8, 0x00, 0x0C,
- "SSL_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "DSS", "SSLMAC-SHA", 24, 0x00, 0x0D,
- "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 5, 0x00, 0x0E,
- "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 8, 0x00, 0x0F,
- "SSL_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "RSA", "SSLMAC-SHA", 24, 0x00, 0x10,
- "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 5, 0x00, 0x11,
- "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 8, 0x00, 0x12,
- "SSL_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "DSS", "SSLMAC-SHA", 24, 0x00, 0x13,
- "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 5, 0x00, 0x14,
- "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 8, 0x00, 0x15,
- "SSL_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "RSA", "SSLMAC-SHA", 24, 0x00, 0x16,
- "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+ private static final List<String> tlsSuiteNames = new LinkedList<String>();
+ private static final HashMap<String, CipherSuite> namesToSuites = new HashMap<String, CipherSuite>();
+
+ // Core TLS cipher suites.
+ public static final CipherSuite TLS_NULL_WITH_NULL_NULL =
+ new CipherSuite (CipherAlgorithm.NULL,
+ KeyExchangeAlgorithm.NONE,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.NULL, 0, 0x00, 0x00,
+ "TLS_NULL_WITH_NULL_NULL");
+ public static final CipherSuite TLS_RSA_WITH_NULL_MD5 =
+ new CipherSuite (CipherAlgorithm.NULL,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.MD5, 0, 0x00, 0x01,
+ "TLS_RSA_WITH_NULL_MD5");
+ public static final CipherSuite TLS_RSA_WITH_NULL_SHA =
+ new CipherSuite (CipherAlgorithm.NULL,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 0, 0x00, 0x02,
+ "TLS_RSA_WITH_NULL_SHA");
+ public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
+ new CipherSuite (CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.MD5, 5, 0x00, 0x03,
+ "TLS_RSA_EXPORT_WITH_RC4_40_MD5");
+ public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 =
+ new CipherSuite (CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.MD5, 16, 0x00, 0x04,
+ "TLS_RSA_WITH_RC4_128_MD5");
+ public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA =
+ new CipherSuite (CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x05,
+ "TLS_RSA_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 5, 0x00, 0x08,
+ "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 8, 0x00, 0x09,
+ "TLS_RSA_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x0A,
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 5, 0x00, 0x0B,
+ "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 8, 0x00, 0x0C,
+ "TLS_DH_DSS_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x0D,
+ "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 5, 0x00, 0x0E,
+ "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 8, 0x00, 0x0F,
+ "TLS_DH_RSA_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x10,
+ "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 5, 0x00, 0x11,
+ "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 8, 0x00, 0x12,
+ "TLS_DHE_DSS_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x13,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 5, 0x00, 0x14,
+ "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 8, 0x00, 0x15,
+ "TLS_DHE_RSA_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x16,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
// AES CipherSuites.
- static final CipherSuite SSL_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x2F,
- "SSL_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 16, 0x00, 0x30,
- "SSL_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 16, 0x00, 0x31,
- "SSL_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 16, 0x00, 0x32,
- "SSL_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 16, 0x00, 0x33,
- "SSL_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 32, 0x00, 0x35,
- "SSL_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 32, 0x00, 0x36,
- "SSL_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DH_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 32, 0x00, 0x37,
- "SSL_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 32, 0x00, 0x38,
- "SSL_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 32, 0x00, 0x39,
- "SSL_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
-
- // Ciphersuites from the OpenPGP extension draft.
- static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70,
- "SSL_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71,
- "SSL_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72,
- "SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73,
- "SSL_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74,
- "SSL_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75,
- "SSL_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76,
- "SSL_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77,
- "SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78,
- "SSL_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79,
- "SSL_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A,
- "SSL_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B,
- "SSL_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C,
- "SSL_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D,
- "SSL_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
- static final CipherSuite SSL_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E,
- "SSL_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
-
- static final CipherSuite TLS_NULL_WITH_NULL_NULL =
- new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00,
- "TLS_NULL_WITH_NULL_NULL", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_NULL_MD5 =
- new CipherSuite("null", "RSA", "RSA", "HMAC-MD5", 0, 0x00, 0x01,
- "TLS_RSA_WITH_NULL_MD5", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_NULL_SHA =
- new CipherSuite("null", "RSA", "RSA", "HMAC-SHA", 0, 0x00, 0x02,
- "TLS_RSA_WITH_NULL_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 5, 0x00, 0x03,
- "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 =
- new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 16, 0x00, 0x04,
- "TLS_RSA_WITH_RC4_128_MD5", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_RC4_128_SHA =
- new CipherSuite("RC4", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x05,
- "TLS_RSA_WITH_RC4_128_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 5, 0x00, 0x08,
- "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 8, 0x00, 0x09,
- "TLS_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-SHA", 24, 0x00, 0x0A,
- "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 5, 0x00, 0x0B,
- "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 8, 0x00, 0x0C,
- "TLS_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "DSS", "HMAC-SHA", 24, 0x00, 0x0D,
- "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 5, 0x00, 0x0E,
- "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 8, 0x00, 0x0F,
- "TLS_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DH", "RSA", "HMAC-SHA", 24, 0x00, 0x10,
- "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 5, 0x00, 0x11,
- "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 8, 0x00, 0x12,
- "TLS_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-SHA", 24, 0x00, 0x13,
- "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 5, 0x00, 0x14,
- "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA =
- new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 8, 0x00, 0x15,
- "TLS_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-SHA", 24, 0x00, 0x16,
- "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
-
- // AES CipherSuites.
- static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x2F,
- "TLS_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 16, 0x00, 0x30,
- "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 16, 0x00, 0x31,
- "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x32,
- "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x33,
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 32, 0x00, 0x35,
- "TLS_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 32, 0x00, 0x36,
- "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 32, 0x00, 0x37,
- "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 32, 0x00, 0x38,
- "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 32, 0x00, 0x39,
- "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x2F,
+ "TLS_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x30,
+ "TLS_DH_DSS_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x31,
+ "TLS_DH_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x32,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x33,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x35,
+ "TLS_RSA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x36,
+ "TLS_DH_DSS_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x37,
+ "TLS_DH_RSA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x38,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x39,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
// Secure remote password (SRP) ciphersuites
- static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "SRP", "anon", "HMAC-SHA", 24, 0x00, 0x50,
- "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "SRP", "RSA", "HMAC-SHA", 24, 0x00, 0x51,
- "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA =
- new CipherSuite("TripleDES", "SRP", "DSS", "HMAC-SHA", 24, 0x00, 0x52,
- "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 16, 0x00, 0x53,
- "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 16, 0x00, 0x54,
- "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA =
- new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 16, 0x00, 0x55,
- "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 32, 0x00, 0x56,
- "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 32, 0x00, 0x57,
- "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA =
- new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 32, 0x00, 0x58,
- "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ // Actual ID values are TBD, so these are omitted until they are specified.
+ /*public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x50,
+ "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x51,
+ "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x52,
+ "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x53,
+ "TLS_SRP_SHA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x54,
+ "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x55,
+ "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x56,
+ "TLS_SRP_SHA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x57,
+ "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x58,
+ "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA");*/
+
+ // Pre-shared key suites.
+ public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA =
+ new CipherSuite(CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x8A,
+ "TLS_PSK_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x8B,
+ "TLS_PSK_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x8C,
+ "TLS_PSK_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x8D,
+ "TLS_PSK_WITH_AES_256_CBC_SHA");
+
+ public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA =
+ new CipherSuite(CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x8E,
+ "TLS_DHE_PSK_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x8F,
+ "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x90,
+ "TLS_DHE_PSK_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x91,
+ "TLS_DHE_PSK_WITH_AES_256_CBC_SHA");
+
+ public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA =
+ new CipherSuite(CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x92,
+ "TLS_RSA_PSK_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x93,
+ "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x94,
+ "TLS_RSA_PSK_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x95,
+ "TLS_RSA_PSK_WITH_AES_256_CBC_SHA");
// Ciphersuites from the OpenPGP extension draft.
- static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70,
- "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71,
- "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72,
- "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73,
- "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74,
- "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75,
- "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76,
- "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77,
- "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78,
- "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79,
- "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A,
- "TLS_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD =
- new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B,
- "TLS_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD =
- new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C,
- "TLS_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D,
- "TLS_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
- static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD =
- new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E,
- "TLS_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
-
- private final String cipherName;
- private final String kexName;
- private final String sigName;
- private final String macName;
+ // These disappeared from a more recent draft.
+/* public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x70,
+ "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x71,
+ "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 24, 0x00, 0x72,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x73,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 32, 0x00, 0x74,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x75,
+ "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x76,
+ "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 24, 0x00, 0x77,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x78,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 32, 0x00, 0x79,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x7A,
+ "TLS_RSA_WITH_CAST_128_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7B,
+ "TLS_RSA_WITH_CAST_128_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 24, 0x00, 0x7C,
+ "TLS_RSA_WITH_3DES_EDE_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7D,
+ "TLS_RSA_WITH_AES_128_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 32, 0x00, 0x7E,
+ "TLS_RSA_WITH_AES_256_CBC_RMD"); */
+
+ private final CipherAlgorithm cipherAlgorithm;
+ private final KeyExchangeAlgorithm keyExchangeAlgorithm;
+ private final SignatureAlgorithm signatureAlgorithm;
+ private final MacAlgorithm macAlgorithm;
+ private final boolean ephemeralDH;
private final boolean exportable;
private final boolean isStream;
private final int keyLength;
private final byte[] id;
private final String name;
- private final ProtocolVersion version;
+ private final boolean isResolved;
// Constructors.
// -------------------------------------------------------------------------
- private CipherSuite(String cipherName, String kexName, String sigName,
- String macName, int keyLength, int id1, int id2,
- String name, ProtocolVersion version)
+ private CipherSuite (final CipherAlgorithm cipherAlgorithm,
+ final KeyExchangeAlgorithm keyExchangeAlgorithm,
+ final SignatureAlgorithm signatureAlgorithm,
+ final MacAlgorithm macAlgorithm,
+ final int keyLength,
+ final int id1,
+ final int id2,
+ final String name)
+ {
+ this (cipherAlgorithm, keyExchangeAlgorithm, false, signatureAlgorithm,
+ macAlgorithm, keyLength, id1, id2, name);
+ }
+
+ private CipherSuite (final CipherAlgorithm cipherAlgorithm,
+ final KeyExchangeAlgorithm keyExchangeAlgorithm,
+ final boolean ephemeralDH,
+ final SignatureAlgorithm signatureAlgorithm,
+ final MacAlgorithm macAlgorithm,
+ final int keyLength,
+ final int id1,
+ final int id2,
+ final String name)
{
- this.cipherName = cipherName.intern();
- this.kexName = kexName.intern();
- this.sigName = sigName.intern();
- this.macName = macName.intern();
+ this.cipherAlgorithm = cipherAlgorithm;
+ this.keyExchangeAlgorithm = keyExchangeAlgorithm;
+ this.ephemeralDH = ephemeralDH;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.macAlgorithm = macAlgorithm;
this.exportable = keyLength <= 5;
- this.isStream = cipherName.equals("null") || cipherName.equals("RC4");
+ this.isStream = (cipherAlgorithm == CipherAlgorithm.NULL
+ || cipherAlgorithm == CipherAlgorithm.RC4);
this.keyLength = keyLength;
this.id = new byte[] { (byte) id1, (byte) id2 };
this.name = name.intern();
- this.version = version;
namesToSuites.put(name, this);
if (name.startsWith("TLS"))
{
tlsSuiteNames.add(name);
}
+ isResolved = true;
}
private CipherSuite(byte[] id)
{
- cipherName = null;
- kexName = null;
- sigName = null;
- macName = null;
+ cipherAlgorithm = null;
+ keyExchangeAlgorithm = null;
+ signatureAlgorithm = null;
+ macAlgorithm = null;
+ ephemeralDH = false;
exportable = false;
isStream = false;
keyLength = 0;
this.id = id;
name = null;
- version = null;
+ isResolved = false;
}
// Class methods.
@@ -450,274 +564,243 @@ final class CipherSuite implements Constructed
*
* @return The named cipher suite.
*/
- static CipherSuite forName(String name)
+ public static CipherSuite forName(String name)
{
- return (CipherSuite) namesToSuites.get(name);
+ if (name.startsWith("SSL_"))
+ name = "TLS_" + name.substring(4);
+ return namesToSuites.get(name);
}
- static List availableSuiteNames()
+ public static CipherSuite forValue(final short raw_value)
{
- return tlsSuiteNames;
+ byte[] b = new byte[] { (byte) (raw_value >>> 8), (byte) raw_value };
+ return new CipherSuite(b).resolve();
}
- static CipherSuite read(InputStream in) throws IOException
+ public static List<String> availableSuiteNames()
{
- DataInputStream din = new DataInputStream(in);
- byte[] id = new byte[2];
- din.readFully(id);
- return new CipherSuite(id);
+ return tlsSuiteNames;
}
- static IMode getCipher(String cbcCipherName)
+ // Intance methods.
+ // -------------------------------------------------------------------------
+
+ public CipherAlgorithm cipherAlgorithm ()
{
- IBlockCipher cipher = CipherFactory.getInstance(cbcCipherName);
- if (cipher == null)
- {
- return null;
- }
- return ModeFactory.getInstance("CBC", cipher, cipher.defaultBlockSize());
+ return cipherAlgorithm;
}
- static Cipher getJCECipher (final String name)
- throws NoSuchAlgorithmException, NoSuchPaddingException
+ public Cipher cipher () throws NoSuchAlgorithmException, NoSuchPaddingException
{
- final String provider = Util.getSecurityProperty ("jessie.with.jce.provider");
- if (name.equals ("RC4"))
+ if (cipherAlgorithm == null)
+ throw new NoSuchAlgorithmException (toString () + ": unresolved cipher suite");
+ if (cipherAlgorithm == CipherAlgorithm.NULL)
+ return new NullCipher ();
+
+ String alg = null;
+ if (cipherAlgorithm == CipherAlgorithm.RC4)
+ alg = "RC4";
+ else
+ alg = cipherAlgorithm + "/CBC/NoPadding";
+ GetSecurityPropertyAction gspa =
+ new GetSecurityPropertyAction ("jessie.jce.provider");
+ final String provider = (String) AccessController.doPrivileged (gspa);
+ if (provider != null)
{
- if (provider != null)
+ try
{
- try
- {
- return Cipher.getInstance (name, provider);
- }
- catch (NoSuchProviderException nsae)
- {
- // Fall through. Try any available provider.
- }
+ return Cipher.getInstance (alg, provider);
}
-
- return Cipher.getInstance (name);
- }
- else
- {
- // Oh, hey! Look! Something else Sun doesn't understand: SSLv3 padding
- // is different than TLSv1 in subtle, but important, ways. But they
- // sorta look the same, so why not make them equivalent?
- //
- // There should be a seperate padding "TLS1Padding".
- if (provider != null)
+ catch (NoSuchProviderException nspe)
{
- try
- {
- return Cipher.getInstance (name + "/CBC/SSL3Padding", provider);
- }
- catch (NoSuchProviderException nspe)
- {
- // Fall through. Try any available provider.
- }
}
- return Cipher.getInstance (name + "/CBC/SSL3Padding");
}
+ return Cipher.getInstance (alg);
+ }
+
+ public MacAlgorithm macAlgorithm ()
+ {
+ return macAlgorithm;
}
- static IMac getMac(String macName)
+ public Mac mac(ProtocolVersion version) throws NoSuchAlgorithmException
{
- if (macName.startsWith("SSLMAC-"))
+ if (macAlgorithm == null)
+ throw new NoSuchAlgorithmException(toString() + ": unresolved cipher suite");
+ if (macAlgorithm == MacAlgorithm.NULL)
+ return null;
+
+ String macAlg = null;
+ if (version == ProtocolVersion.SSL_3)
{
- return new SSLHMac(macName.substring(7));
+ macAlg = "SSLv3HMac-" + macAlgorithm;
}
else
{
- return MacFactory.getInstance(macName);
+ if (macAlgorithm == MacAlgorithm.MD5)
+ macAlg = "HMac-MD5";
+ if (macAlgorithm == MacAlgorithm.SHA)
+ macAlg = "HMac-SHA1";
}
- }
-
- static Mac getJCEMac (final String name)
- throws NoSuchAlgorithmException
- {
- final String provider = Util.getSecurityProperty ("jessie.with.jce.provider");
+
+ GetSecurityPropertyAction gspa =
+ new GetSecurityPropertyAction ("jessie.jce.provider");
+ final String provider = AccessController.doPrivileged (gspa);
if (provider != null)
{
try
{
- return Mac.getInstance (name, provider);
+ return Mac.getInstance(macAlg, provider);
}
catch (NoSuchProviderException nspe)
{
- // Fall through. Try any available provider.
+ // Ignore; try any installed provider.
}
}
- return Mac.getInstance (name);
+ return Mac.getInstance(macAlg);
}
- // Intance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ public SignatureAlgorithm signatureAlgorithm ()
{
- out.write(id);
+ return signatureAlgorithm;
}
- CipherSuite resolve(ProtocolVersion version)
+ public KeyExchangeAlgorithm keyExchangeAlgorithm ()
{
- if (version == ProtocolVersion.SSL_3)
- {
- if (id[0] == 0x00) switch (id[1])
- {
- case 0x00: return SSL_NULL_WITH_NULL_NULL;
- case 0x01: return SSL_RSA_WITH_NULL_MD5;
- case 0x02: return SSL_RSA_WITH_NULL_SHA;
- case 0x03: return SSL_RSA_EXPORT_WITH_RC4_40_MD5;
- case 0x04: return SSL_RSA_WITH_RC4_128_MD5;
- case 0x05: return SSL_RSA_WITH_RC4_128_SHA;
- case 0x08: return SSL_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x09: return SSL_RSA_WITH_DES_CBC_SHA;
- case 0x0A: return SSL_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x0B: return SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
- case 0x0C: return SSL_DH_DSS_WITH_DES_CBC_SHA;
- case 0x0D: return SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x0E: return SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x0F: return SSL_DH_RSA_WITH_DES_CBC_SHA;
- case 0x10: return SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x11: return SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
- case 0x12: return SSL_DHE_DSS_WITH_DES_CBC_SHA;
- case 0x13: return SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x14: return SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x15: return SSL_DHE_RSA_WITH_DES_CBC_SHA;
- case 0x16: return SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x2F: return SSL_RSA_WITH_AES_128_CBC_SHA;
- case 0x30: return SSL_DH_DSS_WITH_AES_128_CBC_SHA;
- case 0x31: return SSL_DH_RSA_WITH_AES_128_CBC_SHA;
- case 0x32: return SSL_DHE_DSS_WITH_AES_128_CBC_SHA;
- case 0x33: return SSL_DHE_RSA_WITH_AES_128_CBC_SHA;
- case 0x35: return SSL_RSA_WITH_AES_256_CBC_SHA;
- case 0x36: return SSL_DH_DSS_WITH_AES_256_CBC_SHA;
- case 0x37: return SSL_DH_RSA_WITH_AES_256_CBC_SHA;
- case 0x38: return SSL_DHE_DSS_WITH_AES_256_CBC_SHA;
- case 0x39: return SSL_DHE_RSA_WITH_AES_256_CBC_SHA;
- }
- }
- else if (version == ProtocolVersion.TLS_1 ||
- version == ProtocolVersion.TLS_1_1)
- {
- if (id[0] == 0x00) switch (id[1])
- {
- case 0x00: return TLS_NULL_WITH_NULL_NULL;
- case 0x01: return TLS_RSA_WITH_NULL_MD5;
- case 0x02: return TLS_RSA_WITH_NULL_SHA;
- case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5;
- case 0x04: return TLS_RSA_WITH_RC4_128_MD5;
- case 0x05: return TLS_RSA_WITH_RC4_128_SHA;
- case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x09: return TLS_RSA_WITH_DES_CBC_SHA;
- case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
- case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA;
- case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA;
- case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
- case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA;
- case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
- case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA;
- case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA;
- case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA;
- case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA;
- case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
- case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
- case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA;
- case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA;
- case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA;
- case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
- case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
- case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
- case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
- case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
- case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
- case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
- case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
- case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
- case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
- case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
- case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA;
- case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD;
- case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD;
- case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD;
- case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD;
- case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA;
- case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD;
- case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD;
- case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD;
- case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD;
- case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA;
- case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD;
- case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD;
- case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD;
- case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD;
- }
- }
- return this;
+ return keyExchangeAlgorithm;
}
- String getCipher()
+ public boolean isEphemeralDH ()
{
- return cipherName;
+ return ephemeralDH;
}
- int getKeyLength()
+ public int length ()
{
- return keyLength;
+ return 2;
}
- String getKeyExchange()
+ public void write(OutputStream out) throws IOException
{
- return kexName;
+ out.write(id);
}
- String getSignature()
+ public void put (final ByteBuffer buf)
{
- return sigName;
+ buf.put (id);
}
-
- String getMac()
+
+ public CipherSuite resolve()
{
- return macName;
+ if (id[0] == 0x00) switch (id[1] & 0xFF)
+ {
+ case 0x00: return TLS_NULL_WITH_NULL_NULL;
+ case 0x01: return TLS_RSA_WITH_NULL_MD5;
+ case 0x02: return TLS_RSA_WITH_NULL_SHA;
+ case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5;
+ case 0x04: return TLS_RSA_WITH_RC4_128_MD5;
+ case 0x05: return TLS_RSA_WITH_RC4_128_SHA;
+ case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x09: return TLS_RSA_WITH_DES_CBC_SHA;
+ case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA;
+ case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA;
+ case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA;
+ case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA;
+ case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA;
+ case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA;
+ case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA;
+ case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+ case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+ case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA;
+ case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA;
+ case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA;
+ case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+ case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+ /*case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+ case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+ case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+ case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+ case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+ case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+ case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+ case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA;
+ case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD;
+ case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD;
+ case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD;
+ case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD;
+ case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA;
+ case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD;
+ case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD;
+ case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD;
+ case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD;
+ case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA;
+ case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD;
+ case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD;
+ case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD;
+ case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD;*/
+ case 0x8A: return TLS_PSK_WITH_RC4_128_SHA;
+ case 0x8B: return TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+ case 0x8C: return TLS_PSK_WITH_AES_128_CBC_SHA;
+ case 0x8D: return TLS_PSK_WITH_AES_256_CBC_SHA;
+ case 0x8E: return TLS_DHE_PSK_WITH_RC4_128_SHA;
+ case 0x8F: return TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+ case 0x90: return TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+ case 0x91: return TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+ case 0x92: return TLS_RSA_PSK_WITH_RC4_128_SHA;
+ case 0x93: return TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+ case 0x94: return TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+ case 0x95: return TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+ }
+ return this;
}
-
- boolean isExportable()
+
+ public boolean isResolved()
{
- return exportable;
+ return isResolved;
}
- boolean isStreamCipher()
+ public int keyLength()
{
- return isStream;
+ return keyLength;
}
- String getAuthType()
+ public boolean isExportable()
{
- if (kexName.equals("RSA"))
- {
- if (isExportable())
- {
- return "RSA_EXPORT";
- }
- return "RSA";
- }
- return kexName + "_" + sigName;
+ return exportable;
}
- byte[] getId()
+ public boolean isStreamCipher()
{
- return id;
+ return isStream;
}
- ProtocolVersion getVersion()
+// String getAuthType()
+// {
+// if (keyExchangeAlgorithm == KeyExchangeAlgorithm.RSA)
+// {
+// if (isExportable())
+// {
+// return "RSA_EXPORT";
+// }
+// return "RSA";
+// }
+// return kexName + "_" + sigName;
+// }
+
+ public byte[] id()
{
- return version;
+ return id;
}
public boolean equals(Object o)
@@ -728,26 +811,26 @@ final class CipherSuite implements Constructed
}
if (o == this)
return true;
- byte[] id = ((CipherSuite) o).getId();
- return id[0] == this.id[0] &&
- id[1] == this.id[1];
+ byte[] id = ((CipherSuite) o).id();
+ return (id[0] == this.id[0] &&
+ id[1] == this.id[1]);
}
public int hashCode()
{
- if (version == null)
- {
- return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
- }
- return version.getMajor() << 24 | version.getMinor() << 16
- | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ }
+
+ public String toString (String prefix)
+ {
+ return toString ();
}
public String toString()
{
if (name == null)
{
- return "UNKNOWN { " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
+ return "{ " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
}
return name;
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java
new file mode 100644
index 00000000000..0e96b31443a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java
@@ -0,0 +1,283 @@
+/* CipherSuiteList.java -- A list of cipher suites.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public final class CipherSuiteList implements Iterable<CipherSuite>
+{
+ private final ByteBuffer buffer;
+ private final ProtocolVersion version;
+ private int modCount;
+
+ public CipherSuiteList (final ByteBuffer buffer)
+ {
+ this (buffer, ProtocolVersion.SSL_3);
+ }
+
+ public CipherSuiteList (final ByteBuffer buffer, final ProtocolVersion version)
+ {
+ this.version = version;
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ /**
+ * Return the number of elements in this list.
+ *
+ * @return The size of this list.
+ */
+ public int size ()
+ {
+ return (buffer.getShort (0) & 0xFFFF) >>> 1;
+ }
+
+ /**
+ * Get the cipher suite at the specified index.
+ *
+ * @param index The index of the suite to get.
+ * @return The cipher suite at that index.
+ * @throws IndexOutOfBoundsException If the index is negative or is
+ * not less than {@link size()}.
+ */
+ public CipherSuite get (final int index)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ return CipherSuite.forValue(buffer.getShort(2 + (index << 1))).resolve();
+ }
+
+ /**
+ * Set the CipherSuite at the specified index. The list must have
+ * sufficient size to hold the element (that is, <code>index &lt;=
+ * size ()</code>).
+ *
+ * @param index The index to put the suite.
+ * @param suite The CipherSuite object.
+ * @throws IndexOutOfBoundsException If <code>index</code> is not
+ * less than @{link #size()}, or if it is negative.
+ * @throws NullPointerException If <code>suite</code> is
+ * <code>null</code>.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void put (final int index, final CipherSuite suite)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ buffer.position (2 + (index << 1));
+ buffer.put (suite.id ());
+ modCount++;
+ }
+
+ /**
+ * Sets the size of this list. You must call this if you are adding
+ * elements to the list; calling {@link
+ * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the
+ * list size (the same goes for removing elements, as there is no
+ * <code>remove</code> method).
+ *
+ * @param newSize The new size of this list.
+ * @throws IllegalArgumentException If the new size is negative or
+ * greater than 32767, or if there is insufficient space for that
+ * many elements in the underlying buffer.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void setSize (final int newSize)
+ {
+ if (newSize < 0 || newSize > 32767)
+ throw new IllegalArgumentException ("size must be between 0 and 32767");
+ if ((newSize << 1) + 2 > buffer.capacity ())
+ throw new IllegalArgumentException ("limit: " + buffer.capacity ()
+ + "; requested: " + newSize);
+ buffer.putShort (0, (short) (newSize << 1));
+ modCount++;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("[");
+ out.print (size ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ CipherSuite suite = (CipherSuite) it.next ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (suite);
+ if (it.hasNext ())
+ out.print (",");
+ out.println ();
+ }
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof CipherSuiteList))
+ return false;
+ CipherSuiteList that = (CipherSuiteList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public java.util.Iterator<CipherSuite> iterator ()
+ {
+ return new Iterator ();
+ }
+
+ /**
+ * An iterator for the elements in this list. The iterator supports
+ * only the <code>set</code> method out of the optional methods,
+ * because elements in a CipherSuiteList may not be removed or
+ * added; only the size of the list can be changed, and elements at
+ * a specific index changed.
+ */
+ public class Iterator implements ListIterator<CipherSuite>
+ {
+ private final int modCount;
+ private int index;
+
+ Iterator ()
+ {
+ this.modCount = CipherSuiteList.this.modCount;
+ index = 0;
+ }
+
+ public void add (CipherSuite cs)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < size ());
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public CipherSuite next () throws NoSuchElementException
+ {
+ if (modCount != CipherSuiteList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public CipherSuite previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != CipherSuiteList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe) // on empty list
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final CipherSuite cs)
+ {
+ put (index, cs);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java
new file mode 100644
index 00000000000..1a1886b888c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java
@@ -0,0 +1,227 @@
+/* ClientCertificateTypeList.java -- A list of certificate types.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public class ClientCertificateTypeList implements Iterable<ClientCertificateType>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public ClientCertificateTypeList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ public int size ()
+ {
+ return (buffer.get (0) & 0xFF);
+ }
+
+ public CertificateRequest.ClientCertificateType get (final int index)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ return CertificateRequest.ClientCertificateType.forValue
+ (buffer.get (index + 1) & 0xFF);
+ }
+
+ public java.util.Iterator<ClientCertificateType> iterator()
+ {
+ return new Iterator();
+ }
+
+ public void put (final int index, final CertificateRequest.ClientCertificateType type)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ buffer.put (index + 1, (byte) type.getValue ());
+ modCount++;
+ }
+
+ public void setSize (final int newSize)
+ {
+ if (newSize < 0 || newSize > 255)
+ throw new IllegalArgumentException ("size must be between 0 and 255");
+ if (newSize + 1 > buffer.capacity ())
+ throw new IllegalArgumentException ("limit: " + (buffer.capacity () - 1)
+ + "; requested: " + newSize);
+ buffer.put (0, (byte) newSize);
+ modCount++;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.print ("[");
+ out.print (size ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ if (prefix != null) out.print (prefix);
+ out.print (" ");
+ out.print (it.next ());
+ if (it.hasNext ())
+ out.print (",");
+ out.println ();
+ }
+ if (prefix != null) out.print (prefix);
+ out.println ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof ClientCertificateTypeList))
+ return false;
+ ClientCertificateTypeList that = (ClientCertificateTypeList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public class Iterator implements ListIterator<CertificateRequest.ClientCertificateType>
+ {
+ private int index;
+ private final int modCount;
+
+ Iterator ()
+ {
+ index = 0;
+ modCount = ClientCertificateTypeList.this.modCount;
+ }
+
+ public void add (CertificateRequest.ClientCertificateType type)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < size ());
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public CertificateRequest.ClientCertificateType next () throws NoSuchElementException
+ {
+ if (modCount != ClientCertificateTypeList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public CertificateRequest.ClientCertificateType previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != ClientCertificateTypeList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final CertificateRequest.ClientCertificateType type)
+ {
+ put (index, type);
+ }
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
new file mode 100644
index 00000000000..e63e03c0aa7
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
@@ -0,0 +1,122 @@
+/* ClientDHE_PSKParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case diffie_hellman_psk: /* NEW &#42;/
+ opaque psk_identity<0..2^16-1>;
+ ClientDiffieHellmanPublic public;
+ } exchange_keys;
+ } ClientKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientDHE_PSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+ public ClientDHE_PSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientDHE_PSKParameters(String identity, ClientDiffieHellmanPublic dh)
+ {
+ super(null);
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer idBuf = utf8.encode(identity);
+ buffer = ByteBuffer.allocate(2 + idBuf.remaining() + dh.length());
+ buffer.putShort((short) idBuf.remaining());
+ buffer.put(idBuf);
+ buffer.put(dh.buffer());
+ buffer.rewind();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ private int identityLength()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identity()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+ (identityLength())).toString();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ int length = (buffer.getShort(0) & 0xFFFF) + 2;
+ // XXX always explicit?
+ length += (buffer.getShort(length) & 0xFFFF) + 2;
+ return length;
+ }
+
+ public ClientDiffieHellmanPublic params()
+ {
+ return new ClientDiffieHellmanPublic(((ByteBuffer) buffer.duplicate()
+ .position(identityLength()).limit(length())).slice());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java
new file mode 100644
index 00000000000..8af8b850ba2
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java
@@ -0,0 +1,129 @@
+/* ClientDiffieHellmanPublic.java -- Client Diffie-Hellman value.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The client's explicit Diffie Hellman value.
+ *
+ * <pre>
+struct {
+ select (PublicValueEncoding) {
+ case implicit: struct { };
+ case explicit: opaque dh_Yc&lt;1..2^16-1&gt;;
+ } dh_public;
+} ClientDiffieHellmanPublic;</pre>
+ */
+public class ClientDiffieHellmanPublic extends ExchangeKeys implements Builder
+{
+ public ClientDiffieHellmanPublic(final ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientDiffieHellmanPublic(final BigInteger Yc)
+ {
+ super(wrap(Yc));
+ }
+
+ private static ByteBuffer wrap(BigInteger Yc)
+ {
+ byte[] b = Util.trim(Yc);
+ ByteBuffer ret = ByteBuffer.allocate(b.length + 2);
+ ret.putShort((short) b.length);
+ ret.put(b);
+ return (ByteBuffer) ret.rewind();
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ public BigInteger publicValue()
+ {
+ int len = length() - 2;
+ byte[] b = new byte[len];
+ buffer.position(2);
+ buffer.get(b);
+ buffer.rewind();
+ return new BigInteger(1, b);
+ }
+
+ public void setPublicValue(final BigInteger Yc)
+ {
+ byte[] buf = Util.trim(Yc);
+ if (buffer.capacity() < buf.length + 2)
+ buffer = ByteBuffer.allocate(buf.length + 2);
+ buffer.putShort((short) buf.length);
+ buffer.put(buf);
+ buffer.rewind();
+ }
+
+ public int length ()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_Yc = ");
+ out.print (publicValue ().toString (16));
+ out.println (';');
+ if (prefix != null) out.print (prefix);
+ out.print ("} ClientDiffieHellmanPublic;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java
new file mode 100644
index 00000000000..059b165a67d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java
@@ -0,0 +1,1150 @@
+/* ClientHandshake.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import static gnu.javax.net.ssl.provider.ClientHandshake.State.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+
+import gnu.classpath.debug.Component;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.provider.Alert.Description;
+import gnu.javax.net.ssl.provider.Alert.Level;
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+import gnu.javax.net.ssl.provider.ServerNameList.NameType;
+import gnu.javax.net.ssl.provider.ServerNameList.ServerName;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientHandshake extends AbstractHandshake
+{
+ static enum State
+ {
+ WRITE_CLIENT_HELLO (false, true),
+ READ_SERVER_HELLO (true, false),
+ READ_CERTIFICATE (true, false),
+ READ_SERVER_KEY_EXCHANGE (true, false),
+ READ_CERTIFICATE_REQUEST (true, false),
+ READ_SERVER_HELLO_DONE (true, false),
+ WRITE_CERTIFICATE (false, true),
+ WRITE_CLIENT_KEY_EXCHANGE (false, true),
+ WRITE_CERTIFICATE_VERIFY (false, true),
+ WRITE_FINISHED (false, true),
+ READ_FINISHED (true, false),
+ DONE (false, false);
+
+ private final boolean isWriteState;
+ private final boolean isReadState;
+
+ private State(boolean isReadState, boolean isWriteState)
+ {
+ this.isReadState = isReadState;
+ this.isWriteState = isWriteState;
+ }
+
+ boolean isReadState()
+ {
+ return isReadState;
+ }
+
+ boolean isWriteState()
+ {
+ return isWriteState;
+ }
+ }
+
+ private State state;
+ private ByteBuffer outBuffer;
+ private boolean continuedSession;
+ private SessionImpl continued;
+ private KeyPair dhPair;
+ private String keyAlias;
+ private PrivateKey privateKey;
+ private MaxFragmentLength maxFragmentLengthSent;
+ private boolean truncatedHMacSent;
+ private ProtocolVersion sentVersion;
+
+ // Delegated tasks.
+ private CertVerifier certVerifier;
+ private ParamsVerifier paramsVerifier;
+ private DelegatedTask keyExchange;
+ private CertLoader certLoader;
+ private GenCertVerify genCertVerify;
+
+ public ClientHandshake(SSLEngineImpl engine) throws NoSuchAlgorithmException
+ {
+ super(engine);
+ state = WRITE_CLIENT_HELLO;
+ continuedSession = false;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleInput()
+ */
+ @Override protected HandshakeStatus implHandleInput() throws SSLException
+ {
+ if (state == DONE)
+ return HandshakeStatus.FINISHED;
+
+ if (state.isWriteState()
+ || (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+
+ // Copy the current buffer, and prepare it for reading.
+ ByteBuffer buffer = handshakeBuffer.duplicate ();
+ buffer.flip();
+ buffer.position(handshakeOffset);
+
+ Handshake handshake = new Handshake(buffer.slice(),
+ engine.session().suite,
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
+ state, handshake);
+
+ switch (state)
+ {
+ // Server Hello.
+ case READ_SERVER_HELLO:
+ {
+ if (handshake.type() != Handshake.Type.SERVER_HELLO)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.UNEXPECTED_MESSAGE));
+ ServerHello hello = (ServerHello) handshake.body();
+ serverRandom = hello.random().copy();
+ engine.session().suite = hello.cipherSuite();
+ engine.session().version = hello.version();
+ compression = hello.compressionMethod();
+ Session.ID serverId = new Session.ID(hello.sessionId());
+ if (continued != null
+ && continued.id().equals(serverId))
+ {
+ continuedSession = true;
+ engine.setSession(continued);
+ }
+ else if (engine.getEnableSessionCreation())
+ {
+ ((AbstractSessionContext) engine.contextImpl
+ .engineGetClientSessionContext()).put(engine.session());
+ }
+ ExtensionList extensions = hello.extensions();
+ if (extensions != null)
+ {
+ for (Extension extension : extensions)
+ {
+ Extension.Type type = extension.type();
+ if (type == null)
+ continue;
+ switch (type)
+ {
+ case MAX_FRAGMENT_LENGTH:
+ MaxFragmentLength mfl
+ = (MaxFragmentLength) extension.value();
+ if (maxFragmentLengthSent == mfl)
+ engine.session().setApplicationBufferSize(mfl.maxLength());
+ break;
+
+ case TRUNCATED_HMAC:
+ if (truncatedHMacSent)
+ engine.session().setTruncatedMac(true);
+ break;
+ }
+ }
+ }
+
+ KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+ if (continuedSession)
+ {
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, true, engine, compression);
+ state = READ_FINISHED;
+ }
+ else if (kex == RSA || kex == DH_DSS || kex == DH_RSA
+ || kex == DHE_DSS || kex == DHE_RSA || kex == RSA_PSK)
+ state = READ_CERTIFICATE;
+ else if (kex == DH_anon || kex == PSK || kex == DHE_PSK)
+ state = READ_SERVER_KEY_EXCHANGE;
+ else
+ state = READ_CERTIFICATE_REQUEST;
+ }
+ break;
+
+ // Server Certificate.
+ case READ_CERTIFICATE:
+ {
+ if (handshake.type() != Handshake.Type.CERTIFICATE)
+ {
+ // We need a certificate for non-anonymous suites.
+ if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+ state = READ_SERVER_KEY_EXCHANGE;
+ }
+ Certificate cert = (Certificate) handshake.body();
+ X509Certificate[] chain = null;
+ try
+ {
+ chain = cert.certificates().toArray(new X509Certificate[0]);
+ }
+ catch (CertificateException ce)
+ {
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.BAD_CERTIFICATE),
+ ce);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNSUPPORTED_CERTIFICATE),
+ nsae);
+ }
+ engine.session().setPeerCertificates(chain);
+ certVerifier = new CertVerifier(true, chain);
+ tasks.add(certVerifier);
+
+ // If we are doing an RSA key exchange, generate our parameters.
+ KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
+ if (kea == RSA || kea == RSA_PSK)
+ {
+ keyExchange = new RSAGen(kea == RSA);
+ tasks.add(keyExchange);
+ if (kea == RSA)
+ state = READ_CERTIFICATE_REQUEST;
+ else
+ state = READ_SERVER_KEY_EXCHANGE;
+ }
+ else
+ state = READ_SERVER_KEY_EXCHANGE;
+ }
+ break;
+
+ // Server Key Exchange.
+ case READ_SERVER_KEY_EXCHANGE:
+ {
+ CipherSuite s = engine.session().suite;
+ KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+ // XXX also SRP.
+ if (kexalg != DHE_DSS && kexalg != DHE_RSA && kexalg != DH_anon
+ && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+
+ if (handshake.type() != Handshake.Type.SERVER_KEY_EXCHANGE)
+ {
+ if (kexalg != RSA_PSK && kexalg != PSK)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+ state = READ_CERTIFICATE_REQUEST;
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ ServerKeyExchange skex = (ServerKeyExchange) handshake.body();
+ ByteBuffer paramsBuffer = null;
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
+ {
+ ServerDHParams dhParams = (ServerDHParams) skex.params();
+ ByteBuffer b = dhParams.buffer();
+ paramsBuffer = ByteBuffer.allocate(b.remaining());
+ paramsBuffer.put(b);
+ }
+
+ if (s.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+ {
+ byte[] signature = skex.signature().signature();
+ paramsVerifier = new ParamsVerifier(paramsBuffer, signature);
+ tasks.add(paramsVerifier);
+ }
+
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
+ {
+ ServerDHParams dhParams = (ServerDHParams) skex.params();
+ DHPublicKey serverKey = new GnuDHPublicKey(null,
+ dhParams.p(),
+ dhParams.g(),
+ dhParams.y());
+ DHParameterSpec params = new DHParameterSpec(dhParams.p(),
+ dhParams.g());
+ keyExchange = new ClientDHGen(serverKey, params, true);
+ tasks.add(keyExchange);
+ }
+ if (kexalg == DHE_PSK)
+ {
+ ServerDHE_PSKParameters pskParams = (ServerDHE_PSKParameters)
+ skex.params();
+ ServerDHParams dhParams = pskParams.params();
+ DHPublicKey serverKey = new GnuDHPublicKey(null,
+ dhParams.p(),
+ dhParams.g(),
+ dhParams.y());
+ DHParameterSpec params = new DHParameterSpec(dhParams.p(),
+ dhParams.g());
+ keyExchange = new ClientDHGen(serverKey, params, false);
+ tasks.add(keyExchange);
+ }
+ state = READ_CERTIFICATE_REQUEST;
+ }
+ break;
+
+ // Certificate Request.
+ case READ_CERTIFICATE_REQUEST:
+ {
+ if (handshake.type() != Handshake.Type.CERTIFICATE_REQUEST)
+ {
+ state = READ_SERVER_HELLO_DONE;
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ CertificateRequest req = (CertificateRequest) handshake.body();
+ ClientCertificateTypeList types = req.types();
+ LinkedList<String> typeList = new LinkedList<String>();
+ for (ClientCertificateType t : types)
+ typeList.add(t.name());
+
+ X500PrincipalList issuers = req.authorities();
+ LinkedList<X500Principal> issuerList = new LinkedList<X500Principal>();
+ for (X500Principal p : issuers)
+ issuerList.add(p);
+
+ certLoader = new CertLoader(typeList, issuerList);
+ tasks.add(certLoader);
+ }
+ break;
+
+ // Server Hello Done.
+ case READ_SERVER_HELLO_DONE:
+ {
+ if (handshake.type() != Handshake.Type.SERVER_HELLO_DONE)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+ state = WRITE_CERTIFICATE;
+ }
+ break;
+
+ // Finished.
+ case READ_FINISHED:
+ {
+ if (handshake.type() != Handshake.Type.FINISHED)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+
+ Finished serverFinished = (Finished) handshake.body();
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ Finished clientFinished =
+ new Finished(generateFinished(md5copy, shacopy,
+ false, engine.session()),
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "clientFinished: {0}",
+ clientFinished);
+
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ {
+ if (!Arrays.equals(clientFinished.md5Hash(),
+ serverFinished.md5Hash())
+ || !Arrays.equals(clientFinished.shaHash(),
+ serverFinished.shaHash()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+ else
+ {
+ if (!Arrays.equals(clientFinished.verifyData(),
+ serverFinished.verifyData()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+
+ if (continuedSession)
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ else
+ state = DONE;
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("invalid state: " + state);
+ }
+
+ handshakeOffset += handshake.length() + 4;
+
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isWriteState()
+ || (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleOutput(java.nio.ByteBuffer)
+ */
+ @Override protected HandshakeStatus implHandleOutput(ByteBuffer fragment)
+ throws SSLException
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "output to {0}; state:{1}; outBuffer:{2}",
+ fragment, state, outBuffer);
+
+ // Drain the output buffer, if it needs it.
+ if (outBuffer != null && outBuffer.hasRemaining())
+ {
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+
+ if (!fragment.hasRemaining())
+ {
+ if (state.isWriteState() || outBuffer.hasRemaining())
+ return HandshakeStatus.NEED_WRAP;
+ else
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+outer_loop:
+ while (fragment.remaining() >= 4 && state.isWriteState())
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "loop state={0}", state);
+
+ switch (state)
+ {
+ case WRITE_CLIENT_HELLO:
+ {
+ ClientHelloBuilder hello = new ClientHelloBuilder();
+ AbstractSessionContext ctx = (AbstractSessionContext)
+ engine.contextImpl.engineGetClientSessionContext();
+ continued = (SessionImpl) ctx.getSession(engine.getPeerHost(),
+ engine.getPeerPort());
+ engine.session().setId(new Session.ID(new byte[0]));
+ Session.ID sid = engine.session().id();
+ // If we have a session that we may want to continue, send
+ // that ID.
+ if (continued != null)
+ sid = continued.id();
+
+ hello.setSessionId(sid.id());
+ sentVersion = chooseVersion();
+ hello.setVersion(sentVersion);
+ hello.setCipherSuites(getSuites());
+ hello.setCompressionMethods(getCompressionMethods());
+ Random r = hello.random();
+ r.setGmtUnixTime(Util.unixTime());
+ byte[] nonce = new byte[28];
+ engine.session().random().nextBytes(nonce);
+ r.setRandomBytes(nonce);
+ clientRandom = r.copy();
+ if (enableExtensions())
+ {
+ List<Extension> extensions = new LinkedList<Extension>();
+ MaxFragmentLength fraglen = maxFragmentLength();
+ if (fraglen != null)
+ {
+ extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH,
+ fraglen));
+ maxFragmentLengthSent = fraglen;
+ }
+
+ String host = engine.getPeerHost();
+ if (host != null)
+ {
+ ServerName name
+ = new ServerName(NameType.HOST_NAME, host);
+ ServerNameList names
+ = new ServerNameList(Collections.singletonList(name));
+ extensions.add(new Extension(Extension.Type.SERVER_NAME,
+ names));
+ }
+
+ if (truncatedHMac())
+ {
+ extensions.add(new Extension(Extension.Type.TRUNCATED_HMAC,
+ new TruncatedHMAC()));
+ truncatedHMacSent = true;
+ }
+
+ ExtensionList elist = new ExtensionList(extensions);
+ hello.setExtensions(elist.buffer());
+ }
+ else
+ hello.setDisableExtensions(true);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", hello);
+
+ fragment.putInt((Handshake.Type.CLIENT_HELLO.getValue() << 24)
+ | (hello.length() & 0xFFFFFF));
+ outBuffer = hello.buffer();
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate()
+ .limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ state = READ_SERVER_HELLO;
+ }
+ break;
+
+ case WRITE_CERTIFICATE:
+ {
+ java.security.cert.Certificate[] chain
+ = engine.session().getLocalCertificates();
+ if (chain != null)
+ {
+ CertificateBuilder cert
+ = new CertificateBuilder(CertificateType.X509);
+ try
+ {
+ cert.setCertificates(Arrays.asList(chain));
+ }
+ catch (CertificateException ce)
+ {
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.INTERNAL_ERROR),
+ ce);
+ }
+
+ outBuffer = cert.buffer();
+
+ fragment.putInt((Handshake.Type.CERTIFICATE.getValue() << 24)
+ | (cert.length() & 0xFFFFFF));
+
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate()
+ .limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+ state = WRITE_CLIENT_KEY_EXCHANGE;
+ }
+ break;
+
+ case WRITE_CLIENT_KEY_EXCHANGE:
+ {
+ KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
+ ClientKeyExchangeBuilder ckex
+ = new ClientKeyExchangeBuilder(engine.session().suite,
+ engine.session().version);
+ if (kea == DHE_DSS || kea == DHE_RSA || kea == DH_anon
+ || kea == DH_DSS || kea == DH_RSA)
+ {
+ assert(dhPair != null);
+ DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+ ClientDiffieHellmanPublic pub
+ = new ClientDiffieHellmanPublic(pubkey.getY());
+ ckex.setExchangeKeys(pub.buffer());
+ }
+ if (kea == RSA || kea == RSA_PSK)
+ {
+ assert(keyExchange instanceof RSAGen);
+ assert(keyExchange.hasRun());
+ if (keyExchange.thrown() != null)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.HANDSHAKE_FAILURE),
+ keyExchange.thrown());
+ EncryptedPreMasterSecret epms
+ = new EncryptedPreMasterSecret(((RSAGen) keyExchange).encryptedSecret(),
+ engine.session().version);
+ if (kea == RSA)
+ ckex.setExchangeKeys(epms.buffer());
+ else
+ {
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared-key identity;"
+ + " set the security property"
+ + " \"jessie.client.psk.identity\"");
+ ClientRSA_PSKParameters params =
+ new ClientRSA_PSKParameters(identity, epms.buffer());
+ ckex.setExchangeKeys(params.buffer());
+ generatePSKSecret(identity, preMasterSecret, true);
+ }
+ }
+ if (kea == DHE_PSK)
+ {
+ assert(keyExchange instanceof ClientDHGen);
+ assert(dhPair != null);
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared key identity; set"
+ + " the security property"
+ + " \"jessie.client.psk.identity\"");
+ DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+ ClientDHE_PSKParameters params =
+ new ClientDHE_PSKParameters(identity,
+ new ClientDiffieHellmanPublic(pubkey.getY()));
+ ckex.setExchangeKeys(params.buffer());
+ generatePSKSecret(identity, preMasterSecret, true);
+ }
+ if (kea == PSK)
+ {
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared key identity; set"
+ + " the security property"
+ + " \"jessie.client.psk.identity\"");
+ generatePSKSecret(identity, null, true);
+ ClientPSKParameters params = new ClientPSKParameters(identity);
+ ckex.setExchangeKeys(params.buffer());
+ }
+ if (kea == NONE)
+ {
+ Inflater inflater = null;
+ Deflater deflater = null;
+ if (compression == CompressionMethod.ZLIB)
+ {
+ inflater = new Inflater();
+ deflater = new Deflater();
+ }
+ inParams = new InputSecurityParameters(null, null, inflater,
+ engine.session(),
+ engine.session().suite);
+ outParams = new OutputSecurityParameters(null, null, deflater,
+ engine.session(),
+ engine.session().suite);
+ engine.session().privateData.masterSecret = new byte[0];
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", ckex);
+
+ outBuffer = ckex.buffer();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "client kex buffer {0}", outBuffer);
+ fragment.putInt((Handshake.Type.CLIENT_KEY_EXCHANGE.getValue() << 24)
+ | (ckex.length() & 0xFFFFFF));
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ if (privateKey != null)
+ {
+ genCertVerify = new GenCertVerify(md5, sha);
+ tasks.add(genCertVerify);
+ state = WRITE_CERTIFICATE_VERIFY;
+ }
+ else
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ }
+ // Both states terminate in a NEED_TASK, or a need to change cipher
+ // specs; so we can't write any more messages here.
+ break outer_loop;
+
+ case WRITE_CERTIFICATE_VERIFY:
+ {
+ assert(genCertVerify != null);
+ assert(genCertVerify.hasRun());
+ CertificateVerify verify = new CertificateVerify(genCertVerify.signed(),
+ engine.session().suite.signatureAlgorithm());
+
+ outBuffer = verify.buffer();
+ fragment.putInt((Handshake.Type.CERTIFICATE_VERIFY.getValue() << 24)
+ | (verify.length() & 0xFFFFFF));
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ // XXX This is a potential problem: we may not have drained
+ // outBuffer, but set the changeCipherSpec toggle.
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ break outer_loop;
+
+ case WRITE_FINISHED:
+ {
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ outBuffer
+ = generateFinished(md5copy, shacopy, true,
+ engine.session());
+
+ fragment.putInt((Handshake.Type.FINISHED.getValue() << 24)
+ | outBuffer.remaining() & 0xFFFFFF);
+
+ int l = Math.min(outBuffer.remaining(), fragment.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ if (continuedSession)
+ state = DONE;
+ else
+ state = READ_FINISHED;
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("invalid state: " + state);
+ }
+ }
+
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isWriteState() ||
+ (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#status()
+ */
+ @Override HandshakeStatus status()
+ {
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+ if (state.isWriteState())
+ return HandshakeStatus.NEED_WRAP;
+ return HandshakeStatus.FINISHED;
+ }
+
+ @Override void checkKeyExchange() throws SSLException
+ {
+ // XXX implement.
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#handleV2Hello(java.nio.ByteBuffer)
+ */
+ @Override void handleV2Hello(ByteBuffer hello) throws SSLException
+ {
+ throw new SSLException("this should be impossible");
+ }
+
+ private ProtocolVersion chooseVersion() throws SSLException
+ {
+ // Select the highest enabled version, for our initial key exchange.
+ ProtocolVersion version = null;
+ for (String ver : engine.getEnabledProtocols())
+ {
+ try
+ {
+ ProtocolVersion v = ProtocolVersion.forName(ver);
+ if (version == null || version.compareTo(v) < 0)
+ version = v;
+ }
+ catch (Exception x)
+ {
+ continue;
+ }
+ }
+
+ if (version == null)
+ throw new SSLException("no suitable enabled versions");
+
+ return version;
+ }
+
+ private List<CipherSuite> getSuites() throws SSLException
+ {
+ List<CipherSuite> suites = new LinkedList<CipherSuite>();
+ for (String s : engine.getEnabledCipherSuites())
+ {
+ CipherSuite suite = CipherSuite.forName(s);
+ if (suite != null)
+ suites.add(suite);
+ }
+ if (suites.isEmpty())
+ throw new SSLException("no cipher suites enabled");
+ return suites;
+ }
+
+ private List<CompressionMethod> getCompressionMethods()
+ {
+ List<CompressionMethod> methods = new LinkedList<CompressionMethod>();
+ GetSecurityPropertyAction gspa = new GetSecurityPropertyAction("jessie.enable.compression");
+ if (Boolean.valueOf(AccessController.doPrivileged(gspa)))
+ methods.add(CompressionMethod.ZLIB);
+ methods.add(CompressionMethod.NULL);
+ return methods;
+ }
+
+ private boolean enableExtensions()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.enable.extensions");
+ return Boolean.valueOf(AccessController.doPrivileged(action));
+ }
+
+ private MaxFragmentLength maxFragmentLength()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.maxFragmentLength");
+ String s = AccessController.doPrivileged(action);
+ if (s != null)
+ {
+ try
+ {
+ int len = Integer.parseInt(s);
+ switch (len)
+ {
+ case 9:
+ case (1 << 9): return MaxFragmentLength.LEN_2_9;
+ case 10:
+ case (1 << 10): return MaxFragmentLength.LEN_2_10;
+ case 11:
+ case (1 << 11): return MaxFragmentLength.LEN_2_11;
+ case 12:
+ case (1 << 12): return MaxFragmentLength.LEN_2_12;
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ }
+ }
+ return null;
+ }
+
+ private boolean truncatedHMac()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.truncatedHMac");
+ return Boolean.valueOf(AccessController.doPrivileged(action));
+ }
+
+ private String getPSKIdentity()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.psk.identity");
+ return AccessController.doPrivileged(action);
+ }
+
+ // Delegated tasks.
+
+ class ParamsVerifier extends DelegatedTask
+ {
+ private final ByteBuffer paramsBuffer;
+ private final byte[] signature;
+ private boolean verified;
+
+ ParamsVerifier(ByteBuffer paramsBuffer, byte[] signature)
+ {
+ this.paramsBuffer = paramsBuffer;
+ this.signature = signature;
+ }
+
+ public void implRun()
+ throws InvalidKeyException, NoSuchAlgorithmException,
+ SSLPeerUnverifiedException, SignatureException
+ {
+ java.security.Signature s
+ = java.security.Signature.getInstance(engine.session().suite
+ .signatureAlgorithm().algorithm());
+ s.initVerify(engine.session().getPeerCertificates()[0]);
+ s.update(paramsBuffer);
+ verified = s.verify(signature);
+ synchronized (this)
+ {
+ notifyAll();
+ }
+ }
+
+ boolean verified()
+ {
+ return verified;
+ }
+ }
+
+ class ClientDHGen extends DelegatedTask
+ {
+ private final DHPublicKey serverKey;
+ private final DHParameterSpec params;
+ private final boolean full;
+
+ ClientDHGen(DHPublicKey serverKey, DHParameterSpec params, boolean full)
+ {
+ this.serverKey = serverKey;
+ this.params = params;
+ this.full = full;
+ }
+
+ public void implRun()
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+ SSLException
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK, "running client DH phase");
+ if (paramsVerifier != null)
+ {
+ synchronized (paramsVerifier)
+ {
+ try
+ {
+ while (!paramsVerifier.hasRun())
+ paramsVerifier.wait(500);
+ }
+ catch (InterruptedException ie)
+ {
+ // Ignore.
+ }
+ }
+ }
+ KeyPairGenerator gen = KeyPairGenerator.getInstance("DH");
+ gen.initialize(params, engine.session().random());
+ dhPair = gen.generateKeyPair();
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE,
+ "client keys public:{0} private:{1}", dhPair.getPublic(),
+ dhPair.getPrivate());
+
+ initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), engine.session().random());
+
+ // We have enough info to do the full key exchange; so let's do it.
+ DHPhase phase = new DHPhase(serverKey, full);
+ phase.run();
+ if (phase.thrown() != null)
+ throw new SSLException(phase.thrown());
+ }
+
+ DHPublicKey serverKey()
+ {
+ return serverKey;
+ }
+ }
+
+ class CertLoader extends DelegatedTask
+ {
+ private final List<String> keyTypes;
+ private final List<X500Principal> issuers;
+
+ CertLoader(List<String> keyTypes, List<X500Principal> issuers)
+ {
+ this.keyTypes = keyTypes;
+ this.issuers = issuers;
+ }
+
+ public void implRun()
+ {
+ X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+ if (km == null)
+ return;
+ keyAlias = km.chooseEngineClientAlias(keyTypes.toArray(new String[keyTypes.size()]),
+ issuers.toArray(new X500Principal[issuers.size()]),
+ engine);
+ engine.session().setLocalCertificates(km.getCertificateChain(keyAlias));
+ privateKey = km.getPrivateKey(keyAlias);
+ }
+ }
+
+ class RSAGen extends DelegatedTask
+ {
+ private byte[] encryptedPreMasterSecret;
+ private final boolean full;
+
+ RSAGen()
+ {
+ this(true);
+ }
+
+ RSAGen(boolean full)
+ {
+ this.full = full;
+ }
+
+ public void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException,
+ SSLException
+ {
+ if (certVerifier != null)
+ {
+ synchronized (certVerifier)
+ {
+ try
+ {
+ while (!certVerifier.hasRun())
+ certVerifier.wait(500);
+ }
+ catch (InterruptedException ie)
+ {
+ // Ignore.
+ }
+ }
+ }
+ preMasterSecret = new byte[48];
+ engine.session().random().nextBytes(preMasterSecret);
+ preMasterSecret[0] = (byte) sentVersion.major();
+ preMasterSecret[1] = (byte) sentVersion.minor();
+ Cipher rsa = Cipher.getInstance("RSA");
+ java.security.cert.Certificate cert
+ = engine.session().getPeerCertificates()[0];
+ rsa.init(Cipher.ENCRYPT_MODE, cert);
+ encryptedPreMasterSecret = rsa.doFinal(preMasterSecret);
+
+ // Generate our session keys, because we can.
+ if (full)
+ {
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, true, engine, compression);
+ }
+ }
+
+ byte[] encryptedSecret()
+ {
+ return encryptedPreMasterSecret;
+ }
+ }
+
+ class GenCertVerify extends DelegatedTask
+ {
+ private final MessageDigest md5, sha;
+ private byte[] signed;
+
+ GenCertVerify(MessageDigest md5, MessageDigest sha)
+ {
+ try
+ {
+ this.md5 = (MessageDigest) md5.clone();
+ this.sha = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // Our message digests *should* be cloneable.
+ throw new Error(cnse);
+ }
+ }
+
+ public void implRun()
+ throws InvalidKeyException, NoSuchAlgorithmException, SignatureException
+ {
+ byte[] toSign;
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ {
+ toSign = genV3CertificateVerify(md5, sha, engine.session());
+ }
+ else
+ {
+ if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+ toSign = Util.concat(md5.digest(), sha.digest());
+ else
+ toSign = sha.digest();
+ }
+
+ java.security.Signature sig =
+ java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().name());
+ sig.initSign(privateKey);
+ sig.update(toSign);
+ signed = sig.sign();
+ }
+
+ byte[] signed()
+ {
+ return signed;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java
index 259051df129..54d7f8b4d74 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java
@@ -38,216 +38,203 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-import javax.net.ssl.SSLProtocolException;
-
-final class ClientHello implements Handshake.Body
+/**
+ * A ClientHello handshake message.
+ *
+ * <pre>
+struct
+{
+ ProtocolVersion client_version; // 2
+ Random random; // 32
+ SessionID session_id; // 1 + 0..32
+ CipherSuite cipher_suites&lt;2..2^16-1&gt;
+ CompressionMethod compression_methods&lt;1..2^8-1&gt;
+ Extension client_hello_extension_list&lt;0..2^16-1&gt;
+} ClientHello;
+</pre>
+ */
+public class ClientHello implements Handshake.Body
{
// Fields.
// -------------------------------------------------------------------------
- private ProtocolVersion version;
- private Random random;
- private byte[] sessionId;
- private List suites;
- private List comp;
- private List extensions;
+ // To help track offsets into the message:
+ // The location of the 'random' field.
+ protected static final int RANDOM_OFFSET = 2;
+ // The location of the sesion_id length.
+ protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET;
+ // The location of the session_id bytes (if any).
+ protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1;
+
+ protected ByteBuffer buffer;
+ protected boolean disableExtensions;
// Constructor.
// -------------------------------------------------------------------------
- ClientHello(ProtocolVersion version, Random random,
- byte[] sessionId, List suites, List comp)
+ public ClientHello (final ByteBuffer buffer)
{
- this(version, random, sessionId, suites, comp, null);
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ disableExtensions = false;
}
- ClientHello(ProtocolVersion version, Random random,
- byte[] sessionId, List suites, List comp, List extensions)
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length()
{
- this.version = version;
- this.random = random;
- this.sessionId = sessionId;
- this.suites = suites;
- this.comp = comp;
- this.extensions = extensions;
+ int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET);
+ len += (buffer.getShort(len) & 0xFFFF) + 2;
+ len += (buffer.get(len) & 0xFF) + 1;
+ if (!disableExtensions && len + 1 < buffer.capacity())
+ len += (buffer.getShort(len) & 0xFFFF) + 2;
+ return len;
}
- // Class methods.
- // -------------------------------------------------------------------------
+ /**
+ * Gets the protocol version field.
+ *
+ * @return The protocol version field.
+ */
+ public ProtocolVersion version()
+ {
+ return ProtocolVersion.getInstance (buffer.getShort (0));
+ }
- static ClientHello read(InputStream in) throws IOException
+ /**
+ * Gets the SSL nonce.
+ *
+ * @return The nonce.
+ */
+ public Random random()
{
- ProtocolVersion vers = ProtocolVersion.read(in);
- Random rand = Random.read(in);
- byte[] id = new byte[in.read() & 0xFF];
- in.read(id);
- int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- ArrayList suites = new ArrayList(len / 2);
- for (int i = 0; i < len; i += 2)
- {
- suites.add(CipherSuite.read(in).resolve(vers));
- }
- len = in.read() & 0xFF;
- ArrayList comp = new ArrayList(len);
- for (int i = 0; i < len; i++)
- {
- comp.add(CompressionMethod.read(in));
- }
-
- List ext = null;
- // Since parsing MAY need to continue into the extensions fields, or it
- // may end here, the specified input stream MUST be a ByteArrayInputStream
- // over all the data this hello contains. Otherwise this will mess up
- // the data stream.
- if (in.available() > 0) // then we have extensions.
- {
- ext = new LinkedList();
- len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- int count = 0;
- while (count < len)
- {
- Extension e = Extension.read(in);
- ext.add(e);
- count += e.getValue().length + 4;
- }
- }
- return new ClientHello(vers, rand, id, suites, comp, ext);
+ ByteBuffer randomBuf =
+ ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+ .limit (SESSID_OFFSET)).slice ();
+ return new Random (randomBuf);
}
- // Instance methods.
- // -------------------------------------------------------------------------
+ public byte[] sessionId()
+ {
+ int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+ byte[] sessionId = new byte[idlen];
+ buffer.position (SESSID_OFFSET2);
+ buffer.get (sessionId);
+ return sessionId;
+ }
- public void write(OutputStream out) throws IOException
+ public CipherSuiteList cipherSuites()
{
- version.write(out);
- random.write(out);
- out.write(sessionId.length);
- out.write(sessionId);
- out.write((suites.size() << 1) >>> 8 & 0xFF);
- out.write((suites.size() << 1) & 0xFF);
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- ((CipherSuite) i.next()).write(out);
- }
- out.write(comp.size());
- for (Iterator i = comp.iterator(); i.hasNext(); )
- {
- out.write(((CompressionMethod) i.next()).getValue());
- }
- if (extensions != null)
- {
- ByteArrayOutputStream out2 = new ByteArrayOutputStream();
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- {
- ((Extension) i.next()).write(out2);
- }
- out.write(out2.size() >>> 8 & 0xFF);
- out.write(out2.size() & 0xFF);
- out2.writeTo(out);
- }
+ int offset = getCipherSuitesOffset ();
+
+ // We give the CipherSuiteList all the remaining bytes to play with,
+ // since this might be an in-construction packet that will fill in
+ // the length field itself.
+ ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset)
+ .limit (buffer.capacity ())).slice ();
+ return new CipherSuiteList (listBuf, version ());
}
- ProtocolVersion getVersion()
+ public CompressionMethodList compressionMethods()
{
- return version;
+ int offset = getCompressionMethodsOffset ();
+ ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset)
+ .limit (buffer.capacity ())).slice ();
+ return new CompressionMethodList (listBuf);
+ }
+
+ public boolean hasExtensions()
+ {
+ int offset = getExtensionsOffset();
+ return (offset + 1 < buffer.limit());
}
- Random getRandom()
+ public ExtensionList extensions()
+ {
+ int offset = getExtensionsOffset ();
+ if (offset + 1 >= buffer.limit())
+ return null;
+ int len = buffer.getShort(offset) & 0xFFFF;
+ if (len == 0)
+ len = buffer.limit() - offset - 2;
+ ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset)
+ .limit(offset + len + 2)).slice ();
+ return new ExtensionList(ebuf);
+ }
+
+ public int extensionsLength()
{
- return random;
+ if (hasExtensions())
+ return 0;
+ return buffer.getShort(getExtensionsOffset()) & 0xFFFF;
}
- byte[] getSessionId()
+ protected int getCipherSuitesOffset ()
{
- return sessionId;
+ return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF));
}
- List getCipherSuites()
+ protected int getCompressionMethodsOffset ()
{
- return suites;
+ int csOffset = getCipherSuitesOffset ();
+ int csLen = buffer.getShort (csOffset) & 0xFFFF;
+ return csOffset + csLen + 2;
}
- List getCompressionMethods()
+ protected int getExtensionsOffset ()
{
- return comp;
+ int cmOffset = getCompressionMethodsOffset ();
+ return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1;
}
- List getExtensions()
+ public String toString ()
{
- return extensions;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
- StringWriter str = new StringWriter();
- PrintWriter out = new PrintWriter(str);
- out.println("struct {");
- out.println(" version = " + version + ";");
- BufferedReader r = new BufferedReader(new StringReader(random.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";");
- out.println(" cipherSuites = {");
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- out.print(" ");
- out.println(i.next());
- }
- out.println(" };");
- out.print(" compressionMethods = { ");
- for (Iterator i = comp.iterator(); i.hasNext(); )
- {
- out.print(i.next());
- if (i.hasNext())
- out.print(", ");
- }
- out.println(" };");
- if (extensions != null)
- {
- out.println(" extensions = {");
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- {
- r = new BufferedReader(new StringReader(i.next().toString()));
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println(" };");
- }
- out.println("} ClientHello;");
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix += prefix;
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" version: ");
+ out.print (version ());
+ out.println (";");
+ out.print (subprefix);
+ out.println ("random:");
+ out.print (random ().toString (subprefix));
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" sessionId: ");
+ out.print (Util.toHexString (sessionId (), ':'));
+ out.println (";");
+ out.print (subprefix);
+ out.println ("cipher_suites:");
+ out.println (cipherSuites ().toString (subprefix));
+ out.print (subprefix);
+ out.println ("compression_methods:");
+ out.println (compressionMethods ().toString (subprefix));
+ out.print (subprefix);
+ out.print ("extensions: ");
+ ExtensionList el = extensions();
+ out.println (el != null ? el.toString(subprefix+" ") : "(nil)");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} ClientHello;");
return str.toString();
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java
new file mode 100644
index 00000000000..81e3dd72f71
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java
@@ -0,0 +1,137 @@
+/* ClientHelloBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Builder for {@link ClientHello} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientHelloBuilder extends ClientHello implements Builder
+{
+ public ClientHelloBuilder()
+ {
+ super(ByteBuffer.allocate(256));
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().position(0).limit(length());
+ }
+
+ public void setVersion(final ProtocolVersion version)
+ {
+ ensureCapacity(2);
+ buffer.putShort(0, (short) version.rawValue ());
+ }
+
+ public void setSessionId (final byte[] buffer)
+ {
+ setSessionId(buffer, 0, buffer.length);
+ }
+
+ public void setSessionId (final byte[] buffer, final int offset, final int length)
+ {
+ ensureCapacity(SESSID_OFFSET2 + length);
+ int len = Math.min (32, length);
+ this.buffer.put (SESSID_OFFSET, (byte) len);
+ this.buffer.position (SESSID_OFFSET2);
+ this.buffer.put (buffer, offset, len);
+ }
+
+ public void setCipherSuites(List<CipherSuite> suites)
+ {
+ int off = getCipherSuitesOffset();
+ ensureCapacity(off + (2 * suites.size()) + 2);
+ buffer.putShort(off, (short) (suites.size() * 2));
+ int i = 2;
+ for (CipherSuite suite : suites)
+ {
+ ((ByteBuffer) buffer.duplicate().position(off+i)).put(suite.id());
+ i += 2;
+ }
+ }
+
+ public void setCompressionMethods(List<CompressionMethod> methods)
+ {
+ int off = getCompressionMethodsOffset();
+ ensureCapacity(off + methods.size() + 1);
+ buffer.put(off, (byte) methods.size());
+ for (CompressionMethod method : methods)
+ buffer.put(++off, (byte) method.getValue());
+ }
+
+ public void setExtensionsLength (final int length)
+ {
+ if (length < 0 || length > 16384)
+ throw new IllegalArgumentException("length must be nonnegative and not exceed 16384");
+ int needed = getExtensionsOffset() + 2 + length;
+ if (buffer.capacity() < needed)
+ ensureCapacity(needed);
+ buffer.putShort(getExtensionsOffset(), (short) length);
+ }
+
+ public void setExtensions(ByteBuffer extensions)
+ {
+ int elen = extensions.getShort(0) & 0xFFFF;
+ setExtensionsLength(elen);
+ ((ByteBuffer) buffer.duplicate().position(getExtensionsOffset())).put(extensions);
+ }
+
+ public void setDisableExtensions(boolean disableExtensions)
+ {
+ this.disableExtensions = disableExtensions;
+ }
+
+ public void ensureCapacity(final int length)
+ {
+ if (buffer.capacity() >= length)
+ return;
+ ByteBuffer newBuf = ByteBuffer.allocate(length);
+ newBuf.put((ByteBuffer) buffer.position(0));
+ newBuf.position(0);
+ this.buffer = newBuf;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java
new file mode 100644
index 00000000000..a514d9ad37c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java
@@ -0,0 +1,158 @@
+/* ClientHelloV2.java -- a hello message from SSLv2.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A client hello message from SSLv2. In SSLv3 and later, clients can
+ * send an SSLv2 client hello message, but set the protocol version
+ * for a later version.
+ *
+ * <p>The format of a version 2 client hello is:
+ *
+ * <pre>
+ char MSG-CLIENT-HELLO // equals 1
+ char CLIENT-VERSION-MSB
+ char CLIENT-VERSION-LSB
+ char CIPHER-SPECS-LENGTH-MSB
+ char CIPHER-SPECS-LENGTH-LSB
+ char SESSION-ID-LENGTH-MSB
+ char SESSION-ID-LENGTH-LSB
+ char CHALLENGE-LENGTH-MSB
+ char CHALLENGE-LENGTH-LSB
+ char CIPHER-SPECS-DATA[(MSB&lt;&lt;8)|LSB]
+ char SESSION-ID-DATA[(MSB&lt;&lt;8)|LSB]
+ char CHALLENGE-DATA[(MSB&lt;&lt;8)|LSB]</pre>
+ */
+class ClientHelloV2 implements Constructed
+{
+ private final ByteBuffer buffer;
+
+ ClientHelloV2 (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public int length ()
+ {
+ return 9 + cipherSpecsLength () + sessionIdLength () + challengeLength ();
+ }
+
+ ProtocolVersion version ()
+ {
+ return ProtocolVersion.getInstance (buffer.getShort (1));
+ }
+
+ int cipherSpecsLength ()
+ {
+ return buffer.getShort (3) & 0xFFFF;
+ }
+
+ int sessionIdLength ()
+ {
+ return buffer.getShort (5) & 0xFFFF;
+ }
+
+ int challengeLength ()
+ {
+ return buffer.getShort (7) & 0xFFFF;
+ }
+
+ public List<CipherSuite> cipherSpecs ()
+ {
+ int n = cipherSpecsLength ();
+ List<CipherSuite> l = new ArrayList<CipherSuite>(n / 3);
+ ByteBuffer b = (ByteBuffer) buffer.duplicate ().position (9);
+ for (int i = 0; i < n; i += 3)
+ {
+ if (b.get () == 0)
+ l.add (CipherSuite.forValue(b.getShort()).resolve());
+ else
+ b.getShort ();
+ }
+ return l;
+ }
+
+ byte[] sessionId ()
+ {
+ byte[] id = new byte[sessionIdLength ()];
+ ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength ())).get (id);
+ return id;
+ }
+
+ byte[] challenge ()
+ {
+ byte[] challenge = new byte[challengeLength ()];
+ ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength () + sessionIdLength ())).get (challenge);
+ return challenge;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+
+ if (prefix != null) out.print (prefix);
+ out.println ("CLIENT-HELLO-MSG");
+ if (prefix != null) out.print (prefix);
+ out.print (" version: ");
+ out.println (version ());
+ if (prefix != null) out.print (prefix);
+ out.println (" suites: ");
+ out.println (cipherSpecs ());
+ if (prefix != null) out.print (prefix);
+ out.print (" sessionId: ");
+ out.println (Util.toHexString (sessionId (), ':'));
+ if (prefix != null) out.print (prefix);
+ out.print (" challenge: ");
+ out.println (Util.toHexString (challenge (), ':'));
+ return str.toString ();
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java
index 828aa8d5e93..2006e73850b 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java
@@ -38,143 +38,94 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.io.StringWriter;
-import java.math.BigInteger;
-
-import java.security.PublicKey;
-import java.security.interfaces.RSAKey;
-import javax.crypto.interfaces.DHPublicKey;
-
-final class ClientKeyExchange implements Handshake.Body
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The client key exchange message.
+ *
+ * <pre>
+struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+ } exchange_keys;
+} ClientKeyExchange;</pre>
+ */
+public class ClientKeyExchange implements Handshake.Body
{
// Fields.
// -------------------------------------------------------------------------
- private final Object exObject;
+ protected ByteBuffer buffer;
+ protected final CipherSuite suite;
+ protected final ProtocolVersion version;
// Constructors.
// -------------------------------------------------------------------------
- ClientKeyExchange(byte[] encryptedSecret)
- {
- exObject = encryptedSecret;
- }
-
- ClientKeyExchange(BigInteger bigint)
- {
- exObject = bigint;
- }
-
- // Class method.
- // -------------------------------------------------------------------------
-
- static ClientKeyExchange read(InputStream in, CipherSuite suite,
- PublicKey key)
- throws IOException
+ public ClientKeyExchange (final ByteBuffer buffer, final CipherSuite suite,
+ final ProtocolVersion version)
{
- DataInputStream din = new DataInputStream(in);
- if (suite.getKeyExchange().equals("RSA"))
- {
- int len = 0;
- if (suite.getVersion() == ProtocolVersion.SSL_3)
- {
- len = (((RSAKey) key).getModulus().bitLength()+7) / 8;
- }
- else
- {
- len = din.readUnsignedShort();
- }
- byte[] buf = new byte[len];
- din.readFully(buf);
- return new ClientKeyExchange(buf);
- }
- else if (suite.getKeyExchange().equals("SRP"))
- {
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- return new ClientKeyExchange(new BigInteger(1, buf));
- }
- else if (key == null || !(key instanceof DHPublicKey)) // explicit.
- {
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- return new ClientKeyExchange(new BigInteger(1, buf));
- }
- else
- {
- return new ClientKeyExchange(new byte[0]);
- }
+ suite.getClass();
+ version.getClass ();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.suite = suite;
+ this.version = version;
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public ExchangeKeys exchangeKeys ()
{
- throw new UnsupportedOperationException("use write(java.io.OutputStream,ProtocolVersion) instead");
+ KeyExchangeAlgorithm alg = suite.keyExchangeAlgorithm();
+ if (alg == KeyExchangeAlgorithm.RSA)
+ return new EncryptedPreMasterSecret(buffer, version);
+ else if (alg == KeyExchangeAlgorithm.DH_anon
+ || alg == KeyExchangeAlgorithm.DHE_DSS
+ || alg == KeyExchangeAlgorithm.DHE_RSA)
+ return new ClientDiffieHellmanPublic(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.DHE_PSK)
+ return new ClientDHE_PSKParameters(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.PSK)
+ return new ClientPSKParameters(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.RSA_PSK)
+ return new ClientRSA_PSKParameters(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.NONE)
+ return new EmptyExchangeKeys();
+ throw new IllegalArgumentException("unsupported key exchange: " + alg);
}
- public void write(OutputStream out, ProtocolVersion version) throws IOException
+ public int length()
{
- if (exObject instanceof byte[])
- {
- byte[] b = (byte[]) exObject;
- if (b.length > 0)
- {
- if (version != ProtocolVersion.SSL_3)
- {
- out.write(b.length >>> 8 & 0xFF);
- out.write(b.length & 0xFF);
- }
- out.write(b);
- }
- }
- else
- {
- byte[] bigint = ((BigInteger) exObject).toByteArray();
- if (bigint[0] == 0x00)
- {
- out.write(bigint.length - 1 >>> 8 & 0xFF);
- out.write(bigint.length - 1 & 0xFF);
- out.write(bigint, 1, bigint.length - 1);
- }
- else
- {
- out.write(bigint.length >>> 8 & 0xFF);
- out.write(bigint.length & 0xFF);
- out.write(bigint);
- }
- }
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ return 0;
+ return exchangeKeys().length();
}
- Object getExchangeObject()
+ public String toString ()
{
- return exObject;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
out.println("struct {");
- if (exObject instanceof byte[] && ((byte[]) exObject).length > 0)
- {
- out.println(" encryptedPreMasterSecret =");
- out.print(Util.hexDump((byte[]) exObject, " "));
- }
- else if (exObject instanceof BigInteger)
- {
- out.println(" clientPublic = " + ((BigInteger) exObject).toString(16) + ";");
- }
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.println (exchangeKeys ().toString (subprefix));
+ if (prefix != null)
+ out.print (prefix);
out.println("} ClientKeyExchange;");
return str.toString();
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java
new file mode 100644
index 00000000000..ebebdcc0e03
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java
@@ -0,0 +1,75 @@
+/* ClientKeyExchangeBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Builder for {@link ClientKeyExchange} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientKeyExchangeBuilder extends ClientKeyExchange
+ implements Builder
+{
+ public ClientKeyExchangeBuilder(CipherSuite suite, ProtocolVersion version)
+ {
+ super(ByteBuffer.allocate(512), suite, version);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ public void setExchangeKeys(ByteBuffer exchangeKeys)
+ {
+ // For SSLv3 and RSA key exchange, the message is sent without length.
+ // So we use the precise capacity of the buffer to signal the size of
+ // the message.
+ if (buffer.capacity() < exchangeKeys.remaining()
+ || (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.RSA
+ && version == ProtocolVersion.SSL_3))
+ buffer = ByteBuffer.allocate(exchangeKeys.remaining());
+ ((ByteBuffer) buffer.duplicate().position(0)).put(exchangeKeys);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java
new file mode 100644
index 00000000000..676a872f925
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java
@@ -0,0 +1,125 @@
+/* ClientPSKParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case psk: /* NEW &#42;/
+ opaque psk_identity&lt;0..2^16-1&gt;;
+ } exchange_keys;
+ } ClientKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientPSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+ public ClientPSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientPSKParameters(String identity)
+ {
+ super(null);
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer idBuf = utf8.encode(CharBuffer.wrap(identity));
+ buffer = ByteBuffer.allocate(idBuf.remaining() + 2);
+ buffer.putShort((short) idBuf.remaining());
+ buffer.put(idBuf);
+ buffer.rewind();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identity()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString();
+ }
+
+ public @Override String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity = ");
+ out.print(identity());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.print("} ClientPSKParameters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
new file mode 100644
index 00000000000..f7483a94c30
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
@@ -0,0 +1,126 @@
+/* ClientRSA_PSKParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+ public ClientRSA_PSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientRSA_PSKParameters(String identity, ByteBuffer epms)
+ {
+ super(null);
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer idBuf = utf8.encode(identity);
+ buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.remaining());
+ buffer.putShort((short) idBuf.remaining());
+ buffer.put(idBuf);
+ buffer.put(epms);
+ buffer.rewind();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ public String identity()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+ (identityLength())).toString();
+ }
+
+ private int identityLength()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return identityLength() + secret().length();
+ }
+
+ public EncryptedPreMasterSecret secret()
+ {
+ return new EncryptedPreMasterSecret
+ (((ByteBuffer) buffer.duplicate().position(identityLength())
+ .limit(buffer.capacity())).slice(), ProtocolVersion.TLS_1);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity = ");
+ out.print(identity());
+ if (prefix != null) out.print(prefix);
+ out.println(" encrypted_pre_master_secret =");
+ out.println(secret().toString(prefix != null ? prefix + " " : " "));
+ if (prefix != null) out.print(prefix);
+ out.print("} ClientRSA_PSKParameters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java
index c2fdf05f9a3..6c57e840c65 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java
@@ -1,4 +1,4 @@
-/* CompressionMethod.java -- the compression method enum.
+/* CompressionMethod.java -- The CompressionMethod enum.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,67 +38,32 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-
-final class CompressionMethod implements Enumerated
+public enum CompressionMethod
{
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- static final CompressionMethod NULL = new CompressionMethod(0),
- ZLIB = new CompressionMethod(1);
+ NULL (0), ZLIB(1);
private final int value;
- // Constructor.
- // -------------------------------------------------------------------------
-
private CompressionMethod(int value)
{
this.value = value;
}
- // Class method.
- // -------------------------------------------------------------------------
-
- static CompressionMethod read(InputStream in) throws IOException
+ public static CompressionMethod getInstance (final int value)
{
- int value = in.read();
- if (value == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
switch (value & 0xFF)
{
case 0: return NULL;
case 1: return ZLIB;
- default: return new CompressionMethod(value);
+
+ // Note: we can't throw an exception here, because we get these values
+ // over the wire, and need to just ignore ones we don't recognize.
+ default: return null;
}
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 0: return "null";
- case 1: return "zlib";
- default: return "unknown(" + value + ")";
- }
- }
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java
new file mode 100644
index 00000000000..47ba5484c3f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java
@@ -0,0 +1,281 @@
+/* CompressionMethodList.java -- A list of compression methods.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A basic list interface to a list of compression methods in an SSL
+ * packet.
+ */
+public final class CompressionMethodList implements Iterable<CompressionMethod>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public CompressionMethodList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ /**
+ * Return the number of elements in this list.
+ *
+ * @return The size of this list.
+ */
+ public int size ()
+ {
+ return (buffer.get (0) & 0xFF);
+ }
+
+ /**
+ * Get the cipher suite at the specified index.
+ *
+ * @param index The index of the suite to get.
+ * @return The cipher suite at that index.
+ * @throws IndexOutOfBoundsException If the index is negative or is
+ * not less than {@link #size()}.
+ */
+ public CompressionMethod get (final int index)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ return CompressionMethod.getInstance (buffer.get (1 + index));
+ }
+
+ /**
+ * Set the CompressionMethod at the specified index. The list must
+ * have sufficient size to hold the element (that is, <code>index
+ * &lt;= size ()</code>).
+ *
+ * @param index The index to put the suite.
+ * @param method The CompressionMethod object.
+ * @throws IndexOutOfBoundsException If <code>index</code> is not
+ * less than @{link #size()}, or if it is negative.
+ * @throws NullPointerException If <code>suite</code> is
+ * <code>null</code>.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void put (final int index, final CompressionMethod method)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ buffer.position (1 + index);
+ buffer.put ((byte) method.getValue ());
+ modCount++;
+ }
+
+ /**
+ * Sets the size of this list. You must call this if you are adding
+ * elements to the list; calling {@link
+ * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the
+ * list size (the same goes for removing elements, as there is no
+ * <code>remove</code> method).
+ *
+ * @param newSize The new size of this list.
+ * @throws IllegalArgumentException If the new size is negative or
+ * greater than 32767, or if there is insufficient space for that
+ * many elements in the underlying buffer.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void setSize (final int newSize)
+ {
+ if (newSize < 0 || newSize > 255)
+ throw new IllegalArgumentException ("size must be between 0 and 255");
+ if (newSize + 1 > buffer.capacity ())
+ throw new IllegalArgumentException ("limit: " + buffer.capacity ()
+ + "; requested: " + newSize);
+ buffer.put (0, (byte) newSize);
+ modCount++;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("[");
+ out.print (size ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ CompressionMethod method = (CompressionMethod) it.next ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (method);
+ if (it.hasNext ())
+ out.print (",");
+ out.println ();
+ }
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof CompressionMethodList))
+ return false;
+ CompressionMethodList that = (CompressionMethodList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public java.util.Iterator<CompressionMethod> iterator ()
+ {
+ return new Iterator ();
+ }
+
+ /**
+ * An iterator for the elements in this list. The iterator supports
+ * only the <code>set</code> method out of the optional methods,
+ * because elements in a CipherSuiteList may not be removed or
+ * added; only the size of the list can be changed, and elements at
+ * a specific index changed.
+ */
+ public class Iterator implements ListIterator<CompressionMethod>
+ {
+ private int index;
+ private final int modCount;
+
+ Iterator ()
+ {
+ index = 0;
+ modCount = CompressionMethodList.this.modCount;
+ }
+
+ public void add (CompressionMethod cm)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < size ());
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public CompressionMethod next () throws NoSuchElementException
+ {
+ if (modCount != CompressionMethodList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public CompressionMethod previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != CompressionMethodList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe) // on empty list
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final CompressionMethod cm)
+ {
+ put (index, cm);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java
index ee3f56a7f47..3a3545b226e 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java
@@ -1,4 +1,4 @@
-/* Constructed.java -- constructed type.
+/* Constructed.java -- Constructed type.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,20 +38,49 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.IOException;
-import java.io.OutputStream;
-
/**
* The base interface to SSL constructed types.
+ *
+ * <p><b>Contract for ByteBuffer-based constructed types:</b>
+ *
+ * <p>Most implementations of this interface supported by this library
+ * take a "view" of an underlying ByteBuffer. The general contract of
+ * such classes is that they <em>will not</em> modify the position or
+ * limit of the buffer when doing read operations. That is, the position
+ * of the underlying buffer <em>should</em> remain at 0 throughout the
+ * lifetime of the object, and the limit should be either set to the
+ * capacity of the buffer, or to the size of the object (in most cases,
+ * the length of the protocol object is determined by the contents of
+ * the object, so the limit isn't useful in such cases. Of course, if the
+ * limit is set to something other than the object's length, it must be
+ * larger than the object length).
+ *
+ * <p>Setter methods (usually in a class that implements the {@link Builder}
+ * interface) may modify the limit, but the general contract remains that
+ * the position remain at zero, and that the limit be at least as large as
+ * the object length.
+ *
+ * <p>Thus, very often the code will use <em>absolute</em> getters and setters
+ * for primitive types, or it will use the {@link java.nio.ByteBuffer#duplicate()}
+ * method, and sometimes the {@link java.nio.ByteBuffer#slice()} method, and
+ * will change the position or limit of the duplicate buffer.
*/
-interface Constructed
+public interface Constructed
{
+ /**
+ * Returns the total length, in bytes, of this structure.
+ *
+ * @return The length of this structure.
+ */
+ int length();
/**
- * Writes this structure's encoded form to the given output stream.
+ * Returns a printable representation of this structure, with the
+ * given prefix prepended to each line.
*
- * @param out The output stream.
- * @throws IOException If an I/O error occurs.
+ * @param prefix The prefix to prepend to each line of the
+ * output. This value may be <code>null</code>.
+ * @return A printable representation of this structure.
*/
- void write(OutputStream out) throws IOException;
+ String toString(String prefix);
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java
index 336809467e4..f7165a2d769 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java
@@ -1,4 +1,4 @@
-/* ContentType.java -- record layer content type.
+/* ContentType.java -- SSL record layer content type.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -45,22 +45,23 @@ import java.io.IOException;
/**
* The content type enumeration, which marks packets in the record layer.
*
- * <pre>enum { change_cipher_spec(20), alert(21), handshake(22),
- * application_data(23), (255) } ContentType;</pre>
+ * <pre>
+enum { change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255) } ContentType;</pre>
+ *
+ * <p>There is also a "pseudo" content type, <code>client_hello_v2
+ * (1)</code>, which is used for backwards compatibility with SSLv2.
*
* @author Casey Marshall (rsdio@metastatic.org)
*/
-final class ContentType implements Enumerated
+public enum ContentType
{
- // Constants and fields.
- // ------------------------------------------------------------------------
-
- static final ContentType CLIENT_HELLO_V2 = new ContentType( 1);
- static final ContentType CHANGE_CIPHER_SPEC = new ContentType(20);
- static final ContentType ALERT = new ContentType(21);
- static final ContentType HANDSHAKE = new ContentType(22);
- static final ContentType APPLICATION_DATA = new ContentType(23);
+ CLIENT_HELLO_V2 ( 1),
+ CHANGE_CIPHER_SPEC (20),
+ ALERT (21),
+ HANDSHAKE (22),
+ APPLICATION_DATA (23);
private int value;
@@ -72,16 +73,8 @@ final class ContentType implements Enumerated
this.value = value;
}
- // Class methods.
- // ------------------------------------------------------------------------
-
- static final ContentType read(InputStream in) throws IOException
+ static final ContentType forInteger (final int value)
{
- int value = in.read();
- if (value == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
switch (value & 0xFF)
{
case 1: return CLIENT_HELLO_V2;
@@ -89,47 +82,12 @@ final class ContentType implements Enumerated
case 21: return ALERT;
case 22: return HANDSHAKE;
case 23: return APPLICATION_DATA;
- default: return new ContentType(value);
+ default: return null;
}
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public boolean equals(Object o)
- {
- if (o == null || !(o instanceof ContentType))
- {
- return false;
- }
- return ((ContentType) o).value == value;
- }
-
- public int hashCode()
- {
- return getValue();
- }
-
- public String toString()
- {
- switch (value)
- {
- case 1: return "v2_client_hello";
- case 20: return "change_cipher_spec";
- case 21: return "alert";
- case 22: return "handshake";
- case 23: return "application_data";
- default: return "unknown(" + value + ")";
- }
- }
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Context.java b/libjava/classpath/gnu/javax/net/ssl/provider/Context.java
deleted file mode 100644
index 2bd7193f265..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Context.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/* Context.java -- SSLContext implementation.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.File;
-import java.io.InputStream;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStoreException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.UnrecoverableKeyException;
-import java.sql.SQLException;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContextSpi;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import gnu.javax.net.ssl.NullManagerParameters;
-import gnu.javax.net.ssl.SRPTrustManager;
-import gnu.javax.net.ssl.StaticTrustAnchors;
-
-/**
- * This is Jessie's implementation of a {@link javax.net.ssl.SSLContext}
- * engine, and is available under the algorithm names ``SSLv3'', ``SSL'',
- * ``TLSv1'', and ``TLS''.
- */
-public final class Context extends SSLContextSpi
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private SessionContext clientSessions;
- private SessionContext serverSessions;
- private X509KeyManager keyManager;
- private X509TrustManager trustManager;
- private SRPTrustManager srpTrustManager;
- private SecureRandom random;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- public Context()
- {
- String codec = Util.getSecurityProperty("jessie.clientSessionContext.codec");
- String codecClass = null;
- if (codec == null)
- {
- codec = "null";
- }
- if (codec.equalsIgnoreCase("xml"))
- {
- codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext";
- }
- else if (codec.equalsIgnoreCase("jdbc"))
- {
- codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext";
- }
- else if (codec.equalsIgnoreCase("null"))
- {
- codecClass = "gnu.javax.net.ssl.provider.SessionContext";
- }
- else
- {
- throw new IllegalArgumentException("no such codec: " + codec);
- }
- try
- {
- ClassLoader cl = Context.class.getClassLoader();
- if (cl == null)
- {
- cl = ClassLoader.getSystemClassLoader();
- }
- clientSessions = (SessionContext) cl.loadClass(codecClass).newInstance();
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- throw new IllegalArgumentException(ex.toString());
- }
-
- codec = Util.getSecurityProperty("jessie.serverSessionContext.codec");
- if (codec == null)
- {
- codec = "null";
- }
- if (codec.equalsIgnoreCase("xml"))
- {
- codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext";
- }
- else if (codec.equalsIgnoreCase("jdbc"))
- {
- codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext";
- }
- else if (codec.equalsIgnoreCase("null"))
- {
- codecClass = "gnu.javax.net.ssl.provider.SessionContext";
- }
- else
- {
- throw new IllegalArgumentException("no such codec: " + codec);
- }
- try
- {
- ClassLoader cl = Context.class.getClassLoader();
- if (cl == null)
- {
- cl = ClassLoader.getSystemClassLoader();
- }
- serverSessions = (SessionContext) cl.loadClass(codecClass).newInstance();
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- throw new IllegalArgumentException(ex.toString());
- }
- }
-
- // Engine methods.
- // -------------------------------------------------------------------------
-
- protected SSLSessionContext engineGetClientSessionContext()
- {
- return clientSessions;
- }
-
- protected SSLSessionContext engineGetServerSessionContext()
- {
- return serverSessions;
- }
-
- protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory()
- {
- if (keyManager == null || (trustManager == null && srpTrustManager == null)
- || random == null)
- {
- throw new IllegalStateException();
- }
- return new SSLServerSocketFactory(trustManager, srpTrustManager, keyManager,
- random, serverSessions);
- }
-
- protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory()
- {
- if (keyManager == null || trustManager == null || random == null)
- {
- throw new IllegalStateException();
- }
- return new SSLSocketFactory(trustManager, keyManager, random, clientSessions);
- }
-
- protected void engineInit(KeyManager[] keyManagers,
- TrustManager[] trustManagers, SecureRandom random)
- throws KeyManagementException
- {
- keyManager = null;
- trustManager = null;
- srpTrustManager = null;
- if (keyManagers != null)
- {
- for (int i = 0; i < keyManagers.length; i++)
- {
- if (keyManagers[i] instanceof X509KeyManager)
- {
- keyManager = (X509KeyManager) keyManagers[i];
- break;
- }
- }
- }
- if (keyManager == null)
- {
- keyManager = defaultKeyManager();
- }
- if (trustManagers != null)
- {
- for (int i = 0; i < trustManagers.length; i++)
- {
- if (trustManagers[i] instanceof X509TrustManager)
- {
- if (trustManager == null)
- {
- trustManager = (X509TrustManager) trustManagers[i];
- }
- }
- else if (trustManagers[i] instanceof SRPTrustManager)
- {
- if (srpTrustManager == null)
- {
- srpTrustManager = (SRPTrustManager) trustManagers[i];
- }
- }
- }
- }
- if (trustManager == null && srpTrustManager == null)
- {
- trustManager = defaultTrustManager();
- }
- if (random != null)
- {
- this.random = random;
- }
- else
- {
- this.random = defaultRandom();
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private X509KeyManager defaultKeyManager() throws KeyManagementException
- {
- KeyManagerFactory fact = null;
- try
- {
- fact = KeyManagerFactory.getInstance("JessieX509", "Jessie");
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new KeyManagementException();
- }
- catch (NoSuchProviderException nspe)
- {
- throw new KeyManagementException();
- }
- try
- {
- fact.init(null, null);
- return (X509KeyManager) fact.getKeyManagers()[0];
- }
- catch (NoSuchAlgorithmException nsae) { }
- catch (KeyStoreException kse) { }
- catch (UnrecoverableKeyException uke) { }
- catch (IllegalStateException ise) { }
-
- try
- {
- fact.init(new NullManagerParameters());
- return (X509KeyManager) fact.getKeyManagers()[0];
- }
- catch (Exception shouldNotHappen)
- {
- throw new Error(shouldNotHappen.toString());
- }
- }
-
- private X509TrustManager defaultTrustManager() throws KeyManagementException
- {
- try
- {
- TrustManagerFactory fact =
- TrustManagerFactory.getInstance("JessieX509", "Jessie");
- fact.init(StaticTrustAnchors.CA_CERTS);
- return (X509TrustManager) fact.getTrustManagers()[0];
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new KeyManagementException(nsae.toString());
- }
- catch (NoSuchProviderException nspe)
- {
- throw new KeyManagementException(nspe.toString());
- }
- catch (InvalidAlgorithmParameterException kse)
- {
- throw new KeyManagementException(kse.toString());
- }
- }
-
- private SecureRandom defaultRandom() throws KeyManagementException
- {
- String alg = Util.getSecurityProperty("jessie.secure.random");
- if (alg == null)
- {
- alg = "Fortuna";
- }
- SecureRandom rand = null;
- try
- {
- rand = SecureRandom.getInstance(alg);
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new KeyManagementException(nsae.toString());
- }
-
- return rand;
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java
new file mode 100644
index 00000000000..6d0f7c3a519
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java
@@ -0,0 +1,66 @@
+/* Debug.java -- Jessie debug constants.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * Debug constants for Jessie.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class Debug
+{
+ /**
+ * Set to true to dump out traces of SSL connections to the system
+ * logger.
+ */
+ public static final boolean DEBUG = true;
+
+ /**
+ * Set to true to dump out info about the SSL key exchange. Since this
+ * MAY contain sensitive data, it is a separate value.
+ */
+ public static final boolean DEBUG_KEY_EXCHANGE = true;
+
+ /**
+ * Set to true to turn on dumping of decrypted packets. Since this will
+ * log potentially-sensitive information (i.e., decrypted messages), only
+ * enable this in debug scenarios.
+ */
+ public static final boolean DEBUG_DECRYPTION = false;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java
new file mode 100644
index 00000000000..200d4d457cf
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java
@@ -0,0 +1,93 @@
+/* DelegatedTask.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class DelegatedTask implements Runnable
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private boolean hasRun;
+ protected Throwable thrown;
+
+ protected DelegatedTask()
+ {
+ hasRun = false;
+ }
+
+ public final void run()
+ {
+ if (hasRun)
+ throw new IllegalStateException("task already ran");
+ try
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_DELEGATED_TASK,
+ "running delegated task {0} in {1}", this,
+ Thread.currentThread());
+ implRun();
+ }
+ catch (Throwable t)
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK, "task threw exception", t);
+ thrown = t;
+ }
+ finally
+ {
+ hasRun = true;
+ }
+ }
+
+ public final boolean hasRun()
+ {
+ return hasRun;
+ }
+
+ public final Throwable thrown()
+ {
+ return thrown;
+ }
+
+ protected abstract void implRun() throws Throwable;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java
index ad48c795906..5a5275712a0 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java
@@ -39,6 +39,9 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
import java.math.BigInteger;
+import java.security.AccessController;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
/**
@@ -72,7 +75,8 @@ final class DiffieHellman
static GnuDHPrivateKey getParams()
{
BigInteger p = DiffieHellman.GROUP_5;
- String group = Util.getSecurityProperty("jessie.key.dh.group");
+ String group = AccessController.doPrivileged
+ (new GetSecurityPropertyAction("jessie.key.dh.group"));
if (group != null)
{
group = group.trim();
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java
deleted file mode 100644
index f1548459e8c..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/* DigestOutputStream.java -- digesting output stream.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import gnu.java.security.hash.IMessageDigest;
-
-final class DigestOutputStream extends FilterOutputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private IMessageDigest md5, sha;
- private boolean digesting;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- DigestOutputStream(OutputStream out, IMessageDigest md5, IMessageDigest sha)
- {
- super(out);
- this.md5 = md5;
- this.sha = sha;
- digesting = true;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- void setDigesting(boolean digesting)
- {
- this.digesting = digesting;
- }
-
- public void write(int b) throws IOException
- {
- if (digesting)
- {
- md5.update((byte) b);
- sha.update((byte) b);
- }
- out.write(b);
- }
-
- public void write(byte[] buf) throws IOException
- {
- write(buf, 0, buf.length);
- }
-
- public void write(byte[] buf, int off, int len) throws IOException
- {
- if (buf == null)
- {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off+len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException();
- }
- if (digesting)
- {
- md5.update(buf, off, len);
- sha.update(buf, off, len);
- }
- out.write(buf, off, len);
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java
new file mode 100644
index 00000000000..acf4cfa03a9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java
@@ -0,0 +1,77 @@
+/* EmptyExchangeKeys.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EmptyExchangeKeys
+ extends ExchangeKeys
+{
+
+ public EmptyExchangeKeys()
+ {
+ super(ByteBuffer.allocate(0));
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return 0;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ String ret = "struct { };";
+ if (prefix != null) ret = prefix + ret;
+ return ret;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
new file mode 100644
index 00000000000..ea7439bd2c6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
@@ -0,0 +1,151 @@
+/* EncryptedPreMasterSecret.java -- RSA encrypted secret.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The client's RSA-encrypted pre-master secret.
+ *
+ * <pre>
+struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+} EncryptedPreMasterSecret;</pre>
+ */
+public final class EncryptedPreMasterSecret extends ExchangeKeys implements Builder
+{
+ private final ProtocolVersion version;
+
+ public EncryptedPreMasterSecret(ByteBuffer buffer, ProtocolVersion version)
+ {
+ super(buffer);
+ version.getClass();
+ this.version = version;
+ }
+
+ public EncryptedPreMasterSecret(byte[] encryptedSecret, ProtocolVersion version)
+ {
+ this(ByteBuffer.allocate(version == ProtocolVersion.SSL_3
+ ? encryptedSecret.length
+ : encryptedSecret.length + 2), version);
+ ByteBuffer b = buffer.duplicate();
+ if (version != ProtocolVersion.SSL_3)
+ b.putShort((short) encryptedSecret.length);
+ b.put(encryptedSecret);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind();
+ }
+
+ public byte[] encryptedSecret()
+ {
+ byte[] secret;
+ if (version == ProtocolVersion.SSL_3)
+ {
+ buffer.position (0);
+ secret = new byte[buffer.limit ()];
+ buffer.get(secret);
+ }
+ else
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ secret = new byte[len];
+ buffer.position(2);
+ buffer.get(secret);
+ }
+ return secret;
+ }
+
+ public void setEncryptedSecret(final byte[] secret, final int offset, final int length)
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ buffer.position(0);
+ buffer.put(secret, offset, length);
+ buffer.rewind();
+ }
+ else
+ {
+ buffer.putShort(0, (short) length);
+ buffer.position(2);
+ buffer.put(secret, offset, length);
+ buffer.rewind();
+ }
+ }
+
+ public int length ()
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ return buffer.capacity();
+ }
+ else
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.println(" pre_master_secret = ");
+ out.print(Util.hexDump(encryptedSecret(), prefix != null ? prefix + " "
+ : " "));
+ if (prefix != null) out.print(prefix);
+ out.print("} EncryptedPreMasterSecret;");
+ return str.toString();
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java
new file mode 100644
index 00000000000..f161f484a57
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java
@@ -0,0 +1,54 @@
+/* ExchangeKeys.java -- key exchange values.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public abstract class ExchangeKeys implements Constructed
+{
+
+ protected ByteBuffer buffer;
+
+ public ExchangeKeys (final ByteBuffer buffer)
+ {
+ if (buffer != null)
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java
index 1c79dd5cb26..c79e58832b8 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java
@@ -38,177 +38,209 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-final class Extension implements Constructed
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An SSL hello extension.
+ *
+ * <pre>
+ * struct {
+ * ExtensionType extension_type;
+ * opaque extension_data<0..2^16-1>;
+ * } Extension;</pre>
+ *
+ * @author csm@gnu.org
+ */
+public final class Extension implements Builder, Constructed
{
// Fields.
// -------------------------------------------------------------------------
- private final Type type;
- private final byte[] value;
+ private ByteBuffer buffer;
// Constructor.
// -------------------------------------------------------------------------
- Extension(Type type, byte[] value)
+ public Extension(final ByteBuffer buffer)
{
- if (type == null || value == null)
- {
- throw new NullPointerException();
- }
- this.type = type;
- this.value = value;
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
}
-
- // Class method.
- // -------------------------------------------------------------------------
-
- static Extension read(InputStream in) throws IOException
+
+ public Extension(final Type type, final Value value)
{
- Type t = Type.read(in);
- int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- byte[] v = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(v, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of extension");
- }
- count += l;
- }
- return new Extension(t, v);
+ ByteBuffer valueBuffer = value.buffer();
+ int length = 2 + 2 + valueBuffer.remaining();
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) type.getValue());
+ buffer.putShort((short) valueBuffer.remaining());
+ buffer.put(valueBuffer);
+ buffer.rewind();
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public int length ()
+ {
+ return (buffer.getShort (2) & 0xFFFF) + 4;
+ }
+
+ public ByteBuffer buffer()
{
- out.write(type.getEncoded());
- out.write(value.length >>> 8 & 0xFF);
- out.write(value.length & 0xFF);
- out.write(value);
+ return (ByteBuffer) buffer.duplicate().limit(length());
}
- Type getType()
+ public Type type()
{
- return type;
+ return Type.forValue (buffer.getShort (0) & 0xFFFF);
}
- byte[] getValue()
+ public byte[] valueBytes()
{
+ int len = buffer.getShort (2) & 0xFFFF;
+ byte[] value = new byte[len];
+ ((ByteBuffer) buffer.duplicate ().position (4)).get (value);
return value;
}
+
+ public ByteBuffer valueBuffer()
+ {
+ int len = buffer.getShort(2) & 0xFFFF;
+ return ((ByteBuffer) buffer.duplicate().position(4).limit(len+4)).slice();
+ }
+
+ public Value value()
+ {
+ switch (type ())
+ {
+ case SERVER_NAME:
+ return new ServerNameList(valueBuffer());
+
+ case MAX_FRAGMENT_LENGTH:
+ switch (valueBuffer().get() & 0xFF)
+ {
+ case 1: return MaxFragmentLength.LEN_2_9;
+ case 2: return MaxFragmentLength.LEN_2_10;
+ case 3: return MaxFragmentLength.LEN_2_11;
+ case 4: return MaxFragmentLength.LEN_2_12;
+ default:
+ throw new IllegalArgumentException("invalid max_fragment_len");
+ }
+
+ case TRUNCATED_HMAC:
+ return new TruncatedHMAC();
+
+ case CLIENT_CERTIFICATE_URL:
+ return new CertificateURL(valueBuffer());
+
+ case TRUSTED_CA_KEYS:
+ return new TrustedAuthorities(valueBuffer());
+
+ case STATUS_REQUEST:
+ return new CertificateStatusRequest(valueBuffer());
+
+ case SRP:
+ case CERT_TYPE:
+ }
+ return new UnresolvedExtensionValue(valueBuffer());
+ }
+
+ public void setLength (final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException ("length is out of bounds");
+ buffer.putShort (2, (short) newLength);
+ }
+
+ public void setType (final Type type)
+ {
+ buffer.putShort(0, (short) type.getValue());
+ }
+ public void setValue (byte[] value)
+ {
+ setValue (value, 0, value.length);
+ }
+
+ public void setValue (final byte[] value, final int offset, final int length)
+ {
+ if (length != length ())
+ throw new IllegalArgumentException ("length is different than claimed length");
+ ((ByteBuffer) buffer.duplicate().position(4)).put(value, offset, length);
+ }
+
public String toString()
{
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- out.println(" type = " + type + ";");
+ if (prefix != null) out.print (prefix);
+ out.println(" type = " + type () + ";");
+ if (prefix != null) out.print (prefix);
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
out.println(" value =");
- out.println(Util.hexDump(value, " "));
- out.println("} Extension;");
+ out.println(value().toString(subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print("} Extension;");
return str.toString();
}
- // Inner class.
+ // Inner classes.
// -------------------------------------------------------------------------
- static final class Type implements Enumerated
+ public static enum Type
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- static final Type SERVER_NAME = new Type(0);
- static final Type MAX_FRAGMENT_LENGTH = new Type(1);
- static final Type CLIENT_CERTIFICATE_URL = new Type(2);
- static final Type TRUSTED_CA_KEYS = new Type(3);
- static final Type TRUNCATED_HMAC = new Type(4);
- static final Type STATUS_REQUEST = new Type(5);
- static final Type SRP = new Type(6);
- static final Type CERT_TYPE = new Type(7);
+ SERVER_NAME (0),
+ MAX_FRAGMENT_LENGTH (1),
+ CLIENT_CERTIFICATE_URL (2),
+ TRUSTED_CA_KEYS (3),
+ TRUNCATED_HMAC (4),
+ STATUS_REQUEST (5),
+ SRP (6),
+ CERT_TYPE (7);
private final int value;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Type(int value)
{
this.value = value;
}
- // Class methods.
- // -----------------------------------------------------------------------
-
- static Type read(InputStream in) throws IOException
+ public static Type forValue (final int value)
{
- int i = in.read();
- if (i == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- int value = (i & 0xFF) << 8;
- i = in.read();
- if (i == -1)
+ switch (value & 0xFFFF)
{
- throw new EOFException("unexpected end of input stream");
- }
- value |= i & 0xFF;
- switch (value)
- {
- case 0: return SERVER_NAME;
- case 1: return MAX_FRAGMENT_LENGTH;
- case 2: return CLIENT_CERTIFICATE_URL;
- case 3: return TRUSTED_CA_KEYS;
- case 4: return TRUNCATED_HMAC;
- case 5: return STATUS_REQUEST;
- case 6: return SRP;
- case 7: return CERT_TYPE;
- default: return new Type(value);
+ case 0: return SERVER_NAME;
+ case 1: return MAX_FRAGMENT_LENGTH;
+ case 2: return CLIENT_CERTIFICATE_URL;
+ case 3: return TRUSTED_CA_KEYS;
+ case 4: return TRUNCATED_HMAC;
+ case 5: return STATUS_REQUEST;
+ case 6: return SRP;
+ case 7: return CERT_TYPE;
+ default: return null;
}
}
-
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] {
- (byte) (value >>> 8 & 0xFF), (byte) (value & 0xFF)
- };
- }
-
+
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 0: return "server_name";
- case 1: return "max_fragment_length";
- case 2: return "client_certificate_url";
- case 3: return "trusted_ca_keys";
- case 4: return "truncated_hmac";
- case 5: return "status_request";
- case 6: return "srp";
- case 7: return "cert_type";
- default: return "unknown(" + value + ")";
- }
- }
+ }
+
+ public static abstract class Value implements Builder, Constructed
+ {
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java
new file mode 100644
index 00000000000..d5aaad62155
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java
@@ -0,0 +1,290 @@
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A list of extensions, that may appear in either the {@link ClientHello} or
+ * {@link ServerHello}. The form of the extensions list is:
+ *
+ * <tt> Extension extensions_list&lt;1..2^16-1&gt;</tt>
+ *
+ * @author csm
+ */
+public class ExtensionList implements Builder, Iterable<Extension>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public ExtensionList (ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ modCount = 0;
+ }
+
+ public ExtensionList(List<Extension> extensions)
+ {
+ int length = 2;
+ for (Extension extension : extensions)
+ length += extension.length();
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) (length - 2));
+ for (Extension extension : extensions)
+ buffer.put(extension.buffer());
+ buffer.rewind();
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public Extension get (final int index)
+ {
+ int length = length ();
+ int i;
+ int n = 0;
+ for (i = 2; i < length && n < index; )
+ {
+ int l = buffer.getShort (i+2) & 0xFFFF;
+ i += l + 4;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException ("no elemenet at " + index);
+ int el = buffer.getShort (i+2) & 0xFFFF;
+ ByteBuffer b = (ByteBuffer) buffer.duplicate().position(i).limit(i+el+4);
+ return new Extension(b.slice());
+ }
+
+ /**
+ * Returns the number of extensions this list contains.
+ *
+ * @return The number of extensions.
+ */
+ public int size ()
+ {
+ int length = length ();
+ if (length == 0)
+ return 0;
+ int n = 0;
+ for (int i = 2; i < length; )
+ {
+ int len = buffer.getShort (i+2) & 0xFFFF;
+ i += len + 4;
+ n++;
+ }
+ return n;
+ }
+
+ /**
+ * Returns the length of this extension list, in bytes.
+ *
+ * @return The length of this extension list, in bytes.
+ */
+ public int length ()
+ {
+ return (buffer.getShort (0) & 0xFFFF) + 2;
+ }
+
+ /**
+ * Sets the extension at index <i>i</i> to <i>e</i>. Note that setting an
+ * element at an index <b>may</b> invalidate any other elements that come
+ * after element at index <i>i</i>. In other words, no attempt is made to
+ * move existing elements in this list, and since extensions are variable
+ * length, you can <em>not</em> guarantee that extensions later in the list
+ * will still be valid.
+ *
+ * <p>Thus, elements of this list <b>must</b> be set in order of increasing
+ * index.
+ *
+ * @param index The index to set the extension at.
+ * @param e The extension.
+ * @throws java.nio.BufferOverflowException If setting the extension overflows
+ * the buffer.
+ * @throws IllegalArgumentException If it isn't possible to find the given index
+ * in the current list (say, if no element index - 1 is set), or if setting
+ * the extension will overflow the current list length (given by {@link
+ * #length()}).
+ */
+ public void set (final int index, Extension e)
+ {
+ int length = length();
+ int n = 0;
+ int i;
+ for (i = 2; i < length && n < index; )
+ {
+ int len = buffer.getShort(i+2) & 0xFFFF;
+ i += len + 4;
+ n++;
+ }
+ if (n < index)
+ throw new IllegalArgumentException("nothing set at index " + (index-1)
+ + " or insufficient space");
+ if (i + e.length() + 2 > length)
+ throw new IllegalArgumentException("adding this element will exceed the "
+ + "list length");
+ buffer.putShort(i, (short) e.type().getValue());
+ buffer.putShort(i+2, (short) e.length());
+ ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.valueBuffer());
+ modCount++;
+ }
+
+ /**
+ * Reserve space for an extension at index <i>i</i> in the list. In other
+ * words, this does the job of {@link #set(int, Extension)}, but does not
+ * copy the extension value to the underlying buffer.
+ *
+ * @param index The index of the extension to reserve space for.
+ * @param t The type of the extension.
+ * @param eLength The number of bytes to reserve for this extension. The total
+ * number of bytes used by this method is this length, plus four.
+ */
+ public void set (final int index, Extension.Type t, final int eLength)
+ {
+ int length = length ();
+ int n = 0;
+ int i;
+ for (i = 2; i < length && n < index; )
+ {
+ int len = buffer.getShort (i+2) & 0xFFFF;
+ i += len + 4;
+ n++;
+ }
+ if (n < index)
+ throw new IllegalArgumentException ("nothing set at index " + (index-1)
+ + " or insufficient space");
+ if (i + eLength + 2 > length)
+ throw new IllegalArgumentException ("adding this element will exceed the "
+ + "list length");
+ buffer.putShort(i, (short) t.getValue());
+ buffer.putShort(i+2, (short) eLength);
+ modCount++;
+ }
+
+ /**
+ * Set the total length of this list, in bytes.
+ *
+ * @param newLength The new list length.
+ */
+ public void setLength (final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException ("invalid length");
+ buffer.putShort (0, (short) newLength);
+ modCount++;
+ }
+
+ public Iterator<Extension> iterator()
+ {
+ return new ExtensionsIterator();
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString(final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("ExtensionList {");
+ if (prefix != null) out.print(prefix);
+ out.print(" length = ");
+ out.print(length());
+ out.println(";");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for (Extension e : this)
+ out.println(e.toString(subprefix));
+ if (prefix != null) out.print(prefix);
+ out.print("};");
+ return str.toString();
+ }
+
+ /**
+ * List iterator interface to an extensions list.
+ *
+ * @author csm@gnu.org
+ */
+ public final class ExtensionsIterator implements ListIterator<Extension>
+ {
+ private final int modCount;
+ private int index;
+ private final int size;
+
+ public ExtensionsIterator ()
+ {
+ this.modCount = ExtensionList.this.modCount;
+ index = 0;
+ size = size ();
+ }
+
+ public boolean hasNext()
+ {
+ return index < size;
+ }
+
+ public boolean hasPrevious()
+ {
+ return index > 0;
+ }
+
+ public Extension next() throws NoSuchElementException
+ {
+ if (modCount != ExtensionList.this.modCount)
+ throw new ConcurrentModificationException ();
+ if (!hasNext ())
+ throw new NoSuchElementException ();
+ return get (index++);
+ }
+
+ public Extension previous() throws NoSuchElementException
+ {
+ if (modCount != ExtensionList.this.modCount)
+ throw new ConcurrentModificationException ();
+ if (!hasPrevious ())
+ throw new NoSuchElementException ();
+ return get (--index);
+ }
+
+ public int nextIndex()
+ {
+ if (hasNext ())
+ return index + 1;
+ return index;
+ }
+
+ public int previousIndex()
+ {
+ if (hasPrevious ())
+ return index - 1;
+ return -1;
+ }
+
+ public void add(Extension e)
+ {
+ throw new UnsupportedOperationException ("cannot add items to this iterator");
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException ("cannot remove items from this iterator");
+ }
+
+ public void set(Extension e)
+ {
+ ExtensionList.this.set (index, e);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java
deleted file mode 100644
index 9ed9619f06f..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Extensions.java -- various static extension utilities.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.security.auth.x500.X500Principal;
-
-import gnu.java.security.x509.X500DistinguishedName;
-
-final class Extensions
-{
-
- // Constants.
- // -------------------------------------------------------------------------
-
- private static final Integer _512 = new Integer(512),
- _1024 = new Integer(1024), _2048 = new Integer(2048),
- _4096 = new Integer(4096);
-
- // Class methods only.
- private Extensions() { }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- static List getServerName(Extension ex)
- {
- LinkedList l = new LinkedList();
- byte[] buf = ex.getValue();
- int pos = 0;
- try
- {
- while (pos < buf.length)
- {
- if (buf[pos++] != 0)
- break;
- int len = (buf[pos++] & 0xFF) << 8;
- len |= buf[pos++] & 0xFF;
- l.add(new String(buf, pos, len, "UTF-8"));
- pos += len;
- }
- }
- catch (Exception x)
- {
- }
- return Collections.unmodifiableList(l);
- }
-
- static List getClientCertTypes(Extension ex) throws IOException
- {
- List l = new LinkedList();
- ByteArrayInputStream in = new ByteArrayInputStream(ex.getValue());
- final int len = in.read() & 0xFF;
- for (int i = 0; i < len; i++)
- {
- l.add(CertificateType.read(in));
- }
- return Collections.unmodifiableList(l);
- }
-
- static CertificateType getServerCertType(Extension ex) throws IOException
- {
- return CertificateType.read(new ByteArrayInputStream(ex.getValue()));
- }
-
- static Integer getMaxFragmentLength(Extension ex)
- {
- switch (ex.getValue()[0] & 0xFF)
- {
- case 1: return _512;
- case 2: return _1024;
- case 3: return _2048;
- case 4: return _4096;
- }
- throw new IllegalArgumentException();
- }
-
- static Object[] getTrustedCA(Extension ex)
- {
- byte[] buf = ex.getValue();
- int type = buf[0] & 0xFF;
- try
- {
- switch (type)
- {
- case 0:
- return new Object[] { new Integer(type), null };
- case 1:
- case 3:
- return new Object[] { new Integer(type),
- Util.trim(buf, 1, 20) };
- case 2:
- return new Object[] { new Integer(type),
- new X500Principal(Util.trim(buf, 1, 20)) };
- }
- }
- catch (Exception x)
- {
- }
- throw new IllegalArgumentException();
- }
-
- static String getSRPUsername(Extension ex)
- {
- int len = ex.getValue()[0] & 0xFF;
- if (len > ex.getValue().length - 1)
- throw new IllegalArgumentException();
- try
- {
- return new String(ex.getValue(), 1, len, "UTF-8");
- }
- catch (UnsupportedEncodingException uee)
- {
- throw new Error(uee.toString());
- }
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java
index 8b9c220a527..9a2a4707aa0 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java
@@ -38,10 +38,10 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
final class Finished implements Handshake.Body
{
@@ -49,95 +49,125 @@ final class Finished implements Handshake.Body
// Fields.
// -------------------------------------------------------------------------
- /** TLSv1.x verify data. */
- private final byte[] verifyData;
-
- /** SSLv3 message digest pair. */
- private final byte[] md5, sha;
+ private final ByteBuffer buffer;
+ private final ProtocolVersion version;
// Constructor.
// -------------------------------------------------------------------------
- Finished(byte[] verifyData)
+ Finished (final ByteBuffer buffer, final ProtocolVersion version)
{
- this.verifyData = verifyData;
- md5 = sha = null;
+ buffer.getClass ();
+ version.getClass ();
+ this.buffer = buffer;
+ this.version = version;
}
- Finished(byte[] md5, byte[] sha)
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
{
- this.md5 = md5;
- this.sha = sha;
- verifyData = null;
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ return 12;
+ if (version == ProtocolVersion.SSL_3)
+ return 36;
+ throw new IllegalArgumentException ("length for this version unknown");
}
- // Class methods.
- // -------------------------------------------------------------------------
-
- static Finished read(InputStream in, CipherSuite suite)
- throws IOException
+ byte[] verifyData()
{
- DataInputStream din = new DataInputStream(in);
- if (suite.getVersion().equals(ProtocolVersion.SSL_3))
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
{
- byte[] md5 = new byte[16];
- byte[] sha = new byte[20];
- din.readFully(md5);
- din.readFully(sha);
- return new Finished(md5, sha);
+ byte[] verify = new byte[12];
+ buffer.position (0);
+ buffer.get (verify);
+ return verify;
}
- else
+ throw new IllegalArgumentException ("not TLSv1.0 or later");
+ }
+
+ byte[] md5Hash()
+ {
+ if (version == ProtocolVersion.SSL_3)
{
- byte[] buf = new byte[12];
- din.readFully(buf);
- return new Finished(buf);
+ byte[] md5 = new byte[16];
+ buffer.position (0);
+ buffer.get (md5);
+ return md5;
}
+ throw new IllegalArgumentException ("not SSLv3");
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ byte[] shaHash()
{
- if (verifyData != null)
- out.write(verifyData);
- else
+ if (version == ProtocolVersion.SSL_3)
{
- out.write(md5);
- out.write(sha);
+ byte[] sha = new byte[20];
+ buffer.position (16);
+ buffer.get (sha);
+ return sha;
}
+ throw new IllegalArgumentException ("not SSLv3");
+ }
+
+ void setVerifyData (final byte[] verifyData, final int offset)
+ {
+ if (version == ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not TLSv1");
+ buffer.position (0);
+ buffer.put (verifyData, offset, 12);
}
- byte[] getVerifyData()
+ void setMD5Hash (final byte[] md5, final int offset)
{
- return verifyData;
+ if (version != ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not SSLv3");
+ buffer.position (0);
+ buffer.put (md5, offset, 16);
}
- byte[] getMD5Hash()
+ void setShaHash (final byte[] sha, final int offset)
{
- return md5;
+ if (version != ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not SSLv3");
+ buffer.position (16);
+ buffer.put (sha, offset, 20);
}
- byte[] getSHAHash()
+ public String toString ()
{
- return sha;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
- String nl = System.getProperty("line.separator");
- if (verifyData != null)
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null)
+ out.print (prefix);
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
{
- return "struct {" + nl +
- " verifyData = " + Util.toHexString(verifyData, ':') + ";" + nl +
- "} Finished;" + nl;
+ out.print (" verifyData = ");
+ out.print (Util.toHexString (verifyData (), ':'));
}
- else
+ else if (version == ProtocolVersion.SSL_3)
{
- return "struct {" + nl +
- " md5Hash = " + Util.toHexString(md5, ':') + ";" + nl +
- " shaHash = " + Util.toHexString(sha, ':') + ";" + nl +
- "} Finished;" + nl;
+ out.print (" md5 = ");
+ out.print (Util.toHexString (md5Hash (), ':'));
+ out.println (';');
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" sha = ");
+ out.print (Util.toHexString (shaHash (), ':'));
}
+ out.println (';');
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Finished;");
+ return str.toString ();
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java
deleted file mode 100644
index a04c3fd5c15..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java
+++ /dev/null
@@ -1,490 +0,0 @@
-/* GNUSecurityParameters.java -- SSL security parameters.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import java.security.SecureRandom;
-import java.security.Security;
-import java.util.Arrays;
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-import javax.net.ssl.SSLException;
-
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mode.IMode;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-
-/**
- * This class implements the {@link SecurityParameters} interface, using the
- * GNU Crypto interface for ciphers and macs, and the JZlib package for
- * record compression.
- */
-class GNUSecurityParameters implements SecurityParameters
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final boolean DEBUG_RECORD_LAYER = false;
- private static final PrintWriter debug = new PrintWriter (System.err, true);
-
- /**
- * The CBC block cipher, if any.
- */
- IMode inCipher, outCipher;
-
- /**
- * The RC4 PRNG, if any.
- */
- IRandom inRandom, outRandom;
-
- /**
- * The MAC algorithm.
- */
- IMac inMac, outMac;
-
- long inSequence, outSequence;
- Session session;
- ProtocolVersion version;
- int fragmentLength;
- private Inflater inflater;
- private Deflater deflater;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- GNUSecurityParameters (Session session)
- {
- inSequence = 0;
- outSequence = 0;
- this.session = session;
- fragmentLength = 16384;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void reset()
- {
- inSequence = 0L;
- outSequence = 0L;
- inCipher = null;
- outCipher = null;
- inMac = null;
- outMac = null;
- inRandom = null;
- outRandom = null;
- deflater = null;
- inflater = null;
- }
-
- public ProtocolVersion getVersion()
- {
- return version;
- }
-
- public void setVersion(ProtocolVersion version)
- {
- this.version = version;
- }
-
- public void setInCipher(Object inCipher)
- {
- if (inCipher instanceof IMode)
- {
- this.inCipher = (IMode) inCipher;
- inRandom = null;
- }
- else
- {
- inRandom = (IRandom) inCipher;
- this.inCipher = null;
- }
- }
-
- public void setOutCipher(Object outCipher)
- {
- if (outCipher instanceof IMode)
- {
- this.outCipher = (IMode) outCipher;
- outRandom = null;
- }
- else
- {
- outRandom = (IRandom) outCipher;
- this.outCipher = null;
- }
- }
-
- public void setInMac(Object inMac)
- {
- this.inMac = (IMac) inMac;
- inSequence = 0L;
- }
-
- public void setOutMac(Object outMac)
- {
- this.outMac = (IMac) outMac;
- outSequence = 0L;
- }
-
- public void setDeflating (boolean deflate)
- {
- if (deflate)
- {
- if (deflater == null)
- deflater = new Deflater();
- }
- else
- deflater = null;
- }
-
- public void setInflating (boolean inflate)
- {
- if (inflate)
- {
- if (inflater == null)
- inflater = new Inflater();
- }
- else
- inflater = null;
- }
-
- public int getFragmentLength()
- {
- return fragmentLength;
- }
-
- public void setFragmentLength (int fragmentLength)
- {
- this.fragmentLength = fragmentLength;
- }
-
- /**
- * Decrypt, verify, and decompress a fragment, returning the transformed
- * fragment.
- *
- * @param fragment The fragment to decrypt.
- * @param version The protocol version of the fragment's record.
- * @param type The content type of the record.
- * @return The decrypted fragment.
- * @throws MacException If the MAC could not be verified.
- * @throws OverflowException If the inflated data is too large.
- * @throws SSLException If decompressing fails.
- */
- public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version,
- ContentType type)
- throws MacException, OverflowException, SSLException
- {
- boolean badPadding = false;
-
- // Decrypt the ciphertext, if it is encrypted.
- if (inCipher != null)
- {
- int bs = inCipher.currentBlockSize ();
- for (int i = 0; i < fragment.length; i += bs)
- {
- inCipher.update (fragment, i, fragment, i);
- }
- int padLen = fragment[fragment.length-1] & 0xFF;
- int len = fragment.length - padLen - 1;
- if (version == ProtocolVersion.SSL_3)
- {
- // SSLv3 requires that the padding length not exceed the
- // cipher's block size.
- if (padLen >= bs)
- {
- badPadding = true;
- }
- }
- else
- {
- for (int i = len; i < fragment.length; i++)
- {
- // If the TLS padding is wrong, throw a MAC exception below.
- if ((fragment[i] & 0xFF) != padLen)
- {
- badPadding = true;
- }
- }
- }
- fragment = Util.trim (fragment, len);
- }
- else if (inRandom != null)
- {
- transformRC4 (fragment, 0, fragment.length, fragment, 0, inRandom);
- }
-
- // Check the MAC.
- if (inMac != null)
- {
- inMac.update ((byte) (inSequence >>> 56));
- inMac.update ((byte) (inSequence >>> 48));
- inMac.update ((byte) (inSequence >>> 40));
- inMac.update ((byte) (inSequence >>> 32));
- inMac.update ((byte) (inSequence >>> 24));
- inMac.update ((byte) (inSequence >>> 16));
- inMac.update ((byte) (inSequence >>> 8));
- inMac.update ((byte) inSequence);
- inMac.update ((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- inMac.update ((byte) version.getMajor());
- inMac.update ((byte) version.getMinor());
- }
- int macLen = inMac.macSize ();
- int fragLen = fragment.length - macLen;
- inMac.update ((byte) (fragLen >>> 8));
- inMac.update ((byte) fragLen);
- inMac.update (fragment, 0, fragLen);
- byte[] mac = inMac.digest ();
- inMac.reset ();
- for (int i = 0; i < macLen; i++)
- {
- if (fragment[i + fragLen] != mac[i])
- {
- throw new MacException();
- }
- }
- if (badPadding)
- {
- throw new MacException();
- }
- fragment = Util.trim (fragment, fragLen);
- }
-
- if (inflater != null)
- {
- byte[] buf = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1);
- inflater.setInput (fragment);
- int len;
- try
- {
- while ((len = inflater.inflate (buf)) > 0)
- {
- bout.write (buf, 0, len);
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("inflated data too large");
- }
- }
- catch (DataFormatException dfe)
- {
- throw new SSLException (String.valueOf (dfe));
- }
- fragment = bout.toByteArray();
- inflater.reset();
- }
-
- inSequence++;
- return fragment;
- }
-
- /**
- * Compress, MAC, encrypt, and write a record. The fragment of the
- * record is taken from <i>buf</i> as <i>len</i> bytes starting at
- * <i>offset</i>. <i>len</i> <b>must</b> be smaller than or equal to
- * the configured fragment length.
- *
- * @param buf The fragment bytes.
- * @param off The offset from whence to read.
- * @param len The size of the fragment.
- * @param type The content-type for this record.
- * @param out The output stream to write the record to.
- * @throws IOException If an I/O error occurs.
- * @throws SSLException If compression fails.
- * @throws OverflowException If compression inflates the data beyond
- * the fragment length plus 1024 bytes.
- */
- public synchronized byte[] encrypt (byte[] buf, int off, int len,
- ContentType type)
- throws SSLException, OverflowException
- {
- // If we are compressing, do it.
- if (deflater != null)
- {
- byte[] buf2 = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1);
- deflater.setInput (buf, off, len);
- deflater.finish();
- len = 0;
- while ((len = deflater.deflate (buf2)) > 0)
- bout.write (buf2, 0, len);
- // This should technically never happen for zlib.
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("deflated data too large");
- buf = bout.toByteArray();
- off = 0;
- len = buf.length;
- deflater.reset();
- }
-
- // If there is a MAC, compute it.
- byte[] mac = new byte[0];
- if (outMac != null)
- {
- outMac.update((byte) (outSequence >>> 56));
- outMac.update((byte) (outSequence >>> 48));
- outMac.update((byte) (outSequence >>> 40));
- outMac.update((byte) (outSequence >>> 32));
- outMac.update((byte) (outSequence >>> 24));
- outMac.update((byte) (outSequence >>> 16));
- outMac.update((byte) (outSequence >>> 8));
- outMac.update((byte) outSequence);
- outMac.update((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- outMac.update((byte) version.getMajor());
- outMac.update((byte) version.getMinor());
- }
- outMac.update((byte) (len >>> 8));
- outMac.update((byte) len);
- outMac.update(buf, off, len);
- mac = outMac.digest();
- outMac.reset();
- }
- outSequence++;
-
- // Compute padding if needed.
- byte[] pad = new byte[0];
- if (outCipher != null)
- {
- int padLen = outCipher.currentBlockSize() -
- ((len + mac.length + 1) % outCipher.currentBlockSize());
- // Use a random amount of padding if the protocol is TLS.
- if (version != ProtocolVersion.SSL_3 && session.random != null)
- {
- padLen += (Math.abs(session.random.nextInt ()) & 7) *
- outCipher.currentBlockSize();
- while (padLen > 255)
- {
- padLen -= outCipher.currentBlockSize();
- }
- }
- pad = new byte[padLen+1];
- Arrays.fill (pad, (byte) padLen);
- }
-
- // Write the record header.
- final int fraglen = len + mac.length + pad.length;
-
- // Encrypt and write the fragment.
- if (outCipher != null)
- {
- byte[] buf2 = new byte[fraglen];
- System.arraycopy (buf, off, buf2, 0, len);
- System.arraycopy (mac, 0, buf2, len, mac.length);
- System.arraycopy (pad, 0, buf2, len + mac.length, pad.length);
- int bs = outCipher.currentBlockSize ();
- for (int i = 0; i < fraglen; i += bs)
- {
- outCipher.update (buf2, i, buf2, i);
- }
- return buf2;
- }
- else if (outRandom != null)
- {
- byte[] buf2 = new byte[fraglen];
- transformRC4 (buf, off, len, buf2, 0, outRandom);
- transformRC4 (mac, 0, mac.length, buf2, len, outRandom);
- return buf2;
- }
- else
- {
- if (mac.length == 0)
- {
- return Util.trim (buf, off, len);
- }
- else
- {
- return Util.concat (Util.trim (buf, off, len), mac);
- }
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- /**
- * Encrypt/decrypt a byte array with the RC4 stream cipher.
- *
- * @param in The input data.
- * @param off The input offset.
- * @param len The number of bytes to transform.
- * @param out The output buffer.
- * @param outOffset The offest into the output buffer.
- * @param random The ARCFOUR PRNG.
- */
- private static void transformRC4(byte[] in, int off, int len,
- byte[] out, int outOffset, IRandom random)
- {
- if (random == null)
- {
- throw new IllegalStateException();
- }
- if (in == null || out == null)
- {
- throw new NullPointerException();
- }
- if (off < 0 || off + len > in.length ||
- outOffset < 0 || outOffset + len > out.length)
- {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- try
- {
- for (int i = 0; i < len; i++)
- {
- out[outOffset+i] = (byte) (in[off+i] ^ random.nextByte());
- }
- }
- catch (LimitReachedException cannotHappen)
- {
- throw new Error(cannotHappen.toString());
- }
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java
index ef9e72381c1..52f61424e4c 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java
@@ -1,4 +1,4 @@
-/* Handshake.java -- SSL handshake message.
+/* Handshake.java -- SSL Handshake message.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -49,6 +49,8 @@ import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
import java.security.PublicKey;
import java.util.ArrayList;
@@ -56,306 +58,219 @@ import java.util.Collections;
import javax.net.ssl.SSLProtocolException;
-final class Handshake implements Constructed
+/**
+ * An SSL handshake message. SSL handshake messages have the following
+ * form:
+ *
+ * <pre>
+struct
+{
+ HandshakeType msg_type;
+ uint24 length;
+ select (msg_type)
+ {
+ case hello_request: HelloRequest;
+ case client_hello: ClientHello;
+ case server_hello: ServerHello;
+ case certificate: Certificate;
+ case server_key_exchange: ServerKeyExchange;
+ case certificate_request: CertificateRequest;
+ case server_hello_done: ServerHelloDone;
+ case certificate_verify: CertificateVerify;
+ case client_key_exchange: ClientKeyExchange;
+ case finished: Finished;
+ } body;
+};</pre>
+ */
+public final class Handshake implements Constructed
{
// Fields.
// -------------------------------------------------------------------------
- private static final buffer BUF = new buffer();
-
- private final Type type;
- private final Body body;
+ private final ByteBuffer buffer;
+ private final CipherSuite suite;
+ private final ProtocolVersion version;
// Constructors.
// -------------------------------------------------------------------------
- Handshake(Type type, Body body)
+ public Handshake (final ByteBuffer buffer)
{
- this.type = type;
- this.body = body;
+ this (buffer, null, ProtocolVersion.TLS_1_1);
}
- // Class methods.
- // -------------------------------------------------------------------------
-
- static Handshake read(byte[] buffer) throws IOException
+ public Handshake (final ByteBuffer buffer, final CipherSuite suite,
+ final ProtocolVersion version)
{
- return read(new ByteArrayInputStream(buffer));
+ this.buffer = buffer;
+ this.suite = suite;
+ this.version = version;
}
- static Handshake read(byte[] buffer, CipherSuite suite, PublicKey key)
- throws IOException
- {
- return read(new ByteArrayInputStream(buffer), suite, key);
- }
-
- static Handshake read(InputStream in) throws IOException
- {
- return read(in, null, null);
- }
+ // Instance methods.
+ // -------------------------------------------------------------------------
- static Handshake read(InputStream in, CipherSuite suite, PublicKey key)
- throws IOException
+ /**
+ * Returns the handshake type.
+ *
+ * @return The handshake type.
+ */
+ public Type type()
{
- return read(in, suite, key, null);
+ return Type.forInteger (buffer.get (0) & 0xFF);
}
- static Handshake read(InputStream in, CertificateType certType)
- throws IOException
+ /**
+ * Returns the message length.
+ *
+ * @return The message length.
+ */
+ public int length ()
{
- return read(in, null, null, certType);
+ // Length is a uint24.
+ return buffer.getInt (0) & 0xFFFFFF;
}
- static Handshake read(InputStream in, CipherSuite suite, PublicKey key,
- CertificateType certType)
- throws IOException
+ /**
+ * Returns the handshake message body. Depending on the handshake
+ * type, some implementation of the Body interface is returned.
+ *
+ * @return The handshake body.
+ */
+ public Body body()
{
- Type type = Type.read(in);
- byte[] lenbuf = new byte[3];
- in.read(lenbuf);
- int len = (lenbuf[0] & 0xFF) << 16 | (lenbuf[1] & 0xFF) << 8
- | (lenbuf[2] & 0xFF);
- Body body = null;
- if (type == Type.HELLO_REQUEST)
- {
- body = null;
- }
- else if (type == Type.CLIENT_HELLO)
- {
- // Most likely a V2 hello. If the first byte is 0x30, and if this
- // is not a V2 client hello, then it is a V3 client hello with
- // at least 1.5 million cipher specs, which is unlikely.
- if (lenbuf[0] == 3 && (lenbuf[1] >= 0 && lenbuf[1] <= 2))
- {
- ProtocolVersion vers = null;
- switch (lenbuf[1])
- {
- case 0:
- vers = ProtocolVersion.SSL_3;
- break;
- case 1:
- vers = ProtocolVersion.TLS_1;
- break;
- case 2:
- vers = ProtocolVersion.TLS_1_1;
- break;
- }
- int specLen = (lenbuf[2] & 0xFF) << 8 | (in.read() & 0xFF);
- int idLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- int chalLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
-
- ArrayList suites = new ArrayList(specLen / 3);
- for (int i = 0; i < specLen; i += 3)
- {
- if (in.read() == 0)
- {
- suites.add(CipherSuite.read(in).resolve(vers));
- }
- else
- {
- in.read();
- in.read();
- }
- }
- byte[] id = new byte[idLen];
- in.read(id);
- byte[] challenge = new byte[chalLen];
- in.read(challenge);
- if (challenge.length > 32)
- challenge = Util.trim(challenge, 32);
- else if (challenge.length < 32)
- {
- byte[] b = new byte[32];
- System.arraycopy(challenge, 0, b, b.length - challenge.length,
- challenge.length);
- challenge = b;
- }
- int time = (challenge[0] & 0xFF) << 24 | (challenge[1] & 0xFF) << 16
- | (challenge[2] & 0xFF) << 8 | (challenge[3] & 0xFF);
- Random rand = new Random(time, Util.trim(challenge, 4, 28));
- return new Handshake(Handshake.Type.CLIENT_HELLO,
- new ClientHello(vers, rand, id, suites,
- Collections.singletonList(CompressionMethod.NULL)));
- }
- // Since hello messages may contain extensions, we read the whole
- // thing here.
- byte[] buf = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(buf, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- count += l;
- }
- body = ClientHello.read(new ByteArrayInputStream(buf));
- }
- else if (type == Type.SERVER_HELLO)
- {
- byte[] buf = new byte[len];
- int count = 0;
- while (count < len)
- {
- int l = in.read(buf, count, len - count);
- if (l == -1)
- {
- throw new EOFException("unexpected end of input stream");
- }
- count += l;
- }
- body = ServerHello.read(new ByteArrayInputStream(buf));
- }
- else if (type == Type.CERTIFICATE)
- {
- body = Certificate.read(in, certType);
- }
- else if (type == Type.SERVER_KEY_EXCHANGE)
+ Type type = type ();
+ ByteBuffer bodyBuffer = bodyBuffer ();
+ switch (type)
{
- body = ServerKeyExchange.read(in, suite, key);
- }
- else if (type == Type.CERTIFICATE_REQUEST)
- {
- body = CertificateRequest.read(in);
- }
- else if (type == Type.CERTIFICATE_VERIFY)
- {
- body = (CertificateVerify) CertificateVerify.read(in, suite, key);
- }
- else if (type == Type.CLIENT_KEY_EXCHANGE)
- {
- body = ClientKeyExchange.read(in, suite, key);
- }
- else if (type == Type.SERVER_HELLO_DONE)
- {
- body = null;
- }
- else if (type == Type.FINISHED)
- {
- body = Finished.read(in, suite);
- }
- else
- {
- throw new SSLProtocolException("unknown HandshakeType: " +
- type.getValue());
- }
+ case HELLO_REQUEST:
+ return new HelloRequest ();
- return new Handshake(type, body);
- }
+ case CLIENT_HELLO:
+ return new ClientHello (bodyBuffer);
- // Instance methods.
- // -------------------------------------------------------------------------
+ case SERVER_HELLO:
+ return new ServerHello (bodyBuffer);
- public void write(OutputStream out)
- {
- throw new UnsupportedOperationException();
+ case CERTIFICATE:
+ return new Certificate (bodyBuffer, CertificateType.X509);
+
+ case SERVER_KEY_EXCHANGE:
+ return new ServerKeyExchange (bodyBuffer, suite);
+
+ case CERTIFICATE_REQUEST:
+ return new CertificateRequest (bodyBuffer);
+
+ case SERVER_HELLO_DONE:
+ return new ServerHelloDone ();
+
+ case CERTIFICATE_VERIFY:
+ return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ());
+
+ case CLIENT_KEY_EXCHANGE:
+ return new ClientKeyExchange (bodyBuffer, suite, version);
+
+ case FINISHED:
+ return new Finished (bodyBuffer, version);
+
+ case CERTIFICATE_URL:
+ case CERTIFICATE_STATUS:
+ throw new UnsupportedOperationException ("FIXME");
+ }
+ throw new IllegalArgumentException ("unknown handshake type " + type);
}
- public int write(OutputStream out, ProtocolVersion version)
- throws IOException
+ /**
+ * Returns a subsequence of the underlying buffer, containing only
+ * the bytes that compose the handshake body.
+ *
+ * @return The body's byte buffer.
+ */
+ public ByteBuffer bodyBuffer ()
{
- out.write(type.getValue());
- if (body == null)
- {
- out.write(0);
- out.write(0);
- out.write(0);
- return 4;
- }
- else
- {
- ByteArrayOutputStream bout = BUF.getBuffer();
- bout.reset();
- if (body instanceof ServerKeyExchange)
- {
- ((ServerKeyExchange) body).write(bout, version);
- }
- else if (body instanceof ClientKeyExchange)
- {
- ((ClientKeyExchange) body).write(bout, version);
- }
- else if (body instanceof CertificateVerify)
- {
- ((CertificateVerify) body).write(bout, version);
- }
- else
- {
- body.write(bout);
- }
- out.write(bout.size() >>> 16 & 0xFF);
- out.write(bout.size() >>> 8 & 0xFF);
- out.write(bout.size() & 0xFF);
- bout.writeTo(out);
- return 4 + bout.size();
- }
+ int length = length ();
+ return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice ();
}
- Type getType()
+ /**
+ * Sets the handshake body type.
+ *
+ * @param type The handshake type.
+ */
+ public void setType (final Type type)
{
- return type;
+ buffer.put (0, (byte) type.getValue ());
}
- Body getBody()
+ /**
+ * Sets the length of the handshake body.
+ *
+ * @param length The handshake body length.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ * @throws IllegalArgumentException of <code>length</code> is not
+ * between 0 and 16777215, inclusive.
+ */
+ public void setLength (final int length)
{
- return body;
+ if (length < 0 || length > 0xFFFFFF)
+ throw new IllegalArgumentException ("length " + length + " out of range;"
+ + " must be between 0 and 16777215");
+ buffer.put (1, (byte) (length >>> 16));
+ buffer.put (2, (byte) (length >>> 8));
+ buffer.put (3, (byte) length);
}
public String toString()
{
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
- String nl = System.getProperty("line.separator");
- StringBuffer buf = new StringBuffer();
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- out.println(" type = " + type + ";");
- if (body != null)
- {
- BufferedReader r = new BufferedReader(new StringReader(body.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println("} Handshake;");
+ if (prefix != null) out.print (prefix);
+ out.print (" type: ");
+ out.print (type ());
+ out.println (";");
+ Body body = body ();
+ out.println (body.toString (prefix != null ? (prefix + " ") : " "));
+ if (prefix != null) out.print (prefix);
+ out.print ("} Handshake;");
return str.toString();
}
// Inner class.
// -------------------------------------------------------------------------
- static interface Body extends Constructed
+ public static interface Body extends Constructed
{
+ int length ();
+
+ String toString (String prefix);
}
- static class Type implements Enumerated
+ public static enum Type
{
-
- // Constants and fields.
- // -----------------------------------------------------------------------
-
- public static final Type
- HELLO_REQUEST = new Type( 0), CLIENT_HELLO = new Type( 1),
- SERVER_HELLO = new Type( 2), CERTIFICATE = new Type(11),
- SERVER_KEY_EXCHANGE = new Type(12), CERTIFICATE_REQUEST = new Type(13),
- SERVER_HELLO_DONE = new Type(14), CERTIFICATE_VERIFY = new Type(15),
- CLIENT_KEY_EXCHANGE = new Type(16), FINISHED = new Type(20),
- CERTIFICATE_URL = new Type(21), CERTIFICATE_STATUS = new Type(22);
+ HELLO_REQUEST ( 0),
+ CLIENT_HELLO ( 1),
+ SERVER_HELLO ( 2),
+ CERTIFICATE (11),
+ SERVER_KEY_EXCHANGE (12),
+ CERTIFICATE_REQUEST (13),
+ SERVER_HELLO_DONE (14),
+ CERTIFICATE_VERIFY (15),
+ CLIENT_KEY_EXCHANGE (16),
+ FINISHED (20),
+ CERTIFICATE_URL (21),
+ CERTIFICATE_STATUS (22);
private final int value;
- // Constructor.
- // -----------------------------------------------------------------------
-
private Type(int value)
{
this.value = value;
@@ -364,18 +279,20 @@ final class Handshake implements Constructed
// Class methods.
// -----------------------------------------------------------------------
- public static Type read(InputStream in) throws IOException
+ /**
+ * Convert a raw handshake type value to a type enum value.
+ *
+ * @return The corresponding enum value for the raw integer value.
+ * @throws IllegalArgumentException If the value is not a known handshake
+ * type.
+ */
+ public static Type forInteger (final int value)
{
- int i = in.read();
- if (i == -1)
+ switch (value & 0xFF)
{
- throw new EOFException("unexpected end of input stream");
- }
- switch (i & 0xFF)
- {
- case 0: return HELLO_REQUEST;
- case 1: return CLIENT_HELLO;
- case 2: return SERVER_HELLO;
+ case 0: return HELLO_REQUEST;
+ case 1: return CLIENT_HELLO;
+ case 2: return SERVER_HELLO;
case 11: return CERTIFICATE;
case 12: return SERVER_KEY_EXCHANGE;
case 13: return CERTIFICATE_REQUEST;
@@ -385,56 +302,13 @@ final class Handshake implements Constructed
case 20: return FINISHED;
case 21: return CERTIFICATE_URL;
case 22: return CERTIFICATE_STATUS;
- default: return new Type(i);
+ default: throw new IllegalArgumentException ("unsupported value type " + value);
}
}
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getEncoded()
- {
- return new byte[] { (byte) value };
- }
-
public int getValue()
{
return value;
}
-
- public String toString()
- {
- switch (value)
- {
- case 0: return "hello_request";
- case 1: return "client_hello";
- case 2: return "server_hello";
- case 11: return "certificate";
- case 12: return "server_key_exchange";
- case 13: return "certificate_request";
- case 14: return "server_hello_done";
- case 15: return "certificate_verify";
- case 16: return "client_key_exchange";
- case 20: return "finished";
- case 21: return "certificate_url";
- case 22: return "certificate_status";
- default: return "unknown(" + value + ")";
- }
- }
- }
-
- private static class buffer extends ThreadLocal
- {
- static final int SIZE = 2048;
-
- protected Object initialValue()
- {
- return new ByteArrayOutputStream(SIZE);
- }
-
- ByteArrayOutputStream getBuffer()
- {
- return (ByteArrayOutputStream) get();
- }
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java
index 8875addab3f..0ffc26c2b5d 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java
@@ -1,4 +1,4 @@
-/* Enumerated.java -- Interface to enumerated types.
+/* HelloRequest.java -- SSL HelloRequest handshake message.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -39,41 +39,32 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
/**
- * An enumerated type in the SSL protocols. Enumerated values take on
- * one of a set of possible numeric values, which are not specifically
- * ordered, and may be extensible to a maximum value.
+ * The handshake body for a HelloRequest handshake message.
*
- * <pre>enum { e1(v1), e2(v2), ... [[, (n) ]] }</pre>
- *
- * <p>Enumerated types are encoded as big-endian multibyte integers,
- * which take up the least possible number of bytes. Thus, an
- * enumeration with up to 255 values will be encoded in a single byte,
- * and so on.
- *
- * @author Casey Marshall (rsdio@metastatic.org)
+ * <pre>struct { } HelloRequest;</pre>
*/
-interface Enumerated
+public final class HelloRequest implements Handshake.Body
{
+ public HelloRequest ()
+ {
+ }
- /**
- * Returns the encoded value of this enumerated value, which is
- * appropriate to send over-the-wire.
- *
- * @return The encoded value.
- */
- byte[] getEncoded();
+ public String toString (final String prefix)
+ {
+ StringBuffer str = new StringBuffer ();
+ if (prefix != null)
+ str.append (prefix);
+ str.append ("HelloRequest { };");
+ return str.toString ();
+ }
- /**
- * Returns the numeric value of this enumerated value.
- *
- * @return The numeric value.
- */
- int getValue();
+ public int length ()
+ {
+ return 0;
+ }
- /**
- * Returns a string representation of this enumerated value.
- *
- * @return The string.
- */
- String toString();
+ public String toString ()
+ {
+ return toString (null);
+ }
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java
new file mode 100644
index 00000000000..13a3ef814de
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java
@@ -0,0 +1,336 @@
+/* SecurityParameters.java -- SSL security parameters.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.util.ByteArray;
+import gnu.java.security.util.ByteBufferOutputStream;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+import javax.net.ssl.SSLException;
+
+public class InputSecurityParameters
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private final Cipher cipher;
+ private final Mac mac;
+ private final Inflater inflater;
+ private SessionImpl session;
+ private final CipherSuite suite;
+ private long sequence;
+
+ public InputSecurityParameters (final Cipher cipher, final Mac mac,
+ final Inflater inflater,
+ final SessionImpl session,
+ final CipherSuite suite)
+ {
+ this.cipher = cipher;
+ this.mac = mac;
+ this.inflater = inflater;
+ this.session = session;
+ this.suite = suite;
+ sequence = 0;
+ }
+
+ /**
+ * Decrypt a record, storing the decrypted fragment into the given array
+ * of byte buffers.
+ *
+ * @param record The input record.
+ * @param output The output buffers.
+ * @param offset The offset of the first buffer to use.
+ * @param length The number of buffers to use.
+ * @return The number of bytes put in the output buffers.
+ * @throws DataFormatException If decompression fails.
+ * @throws IllegalBlockSizeException If the current cipher is a block cipher,
+ * and the input fragment is not a multiple of the block size.
+ * @throws MacException If verifying the MAC fails.
+ * @throws SSLException ???
+ * @throws ShortBufferException
+ */
+ public int decrypt(Record record, ByteBuffer[] output, int offset, int length)
+ throws DataFormatException, IllegalBlockSizeException,
+ MacException, SSLException, ShortBufferException
+ {
+ return decrypt(record, output, offset, length, null);
+ }
+
+ /**
+ * Decrypt a record, storing the decrypted fragment into the given growable
+ * buffer.
+ *
+ * @param record The input record.
+ * @param outputStream The output buffer.
+ * @return The number of bytes put into the output buffer.
+ * @throws DataFormatException
+ * @throws IllegalBlockSizeException
+ * @throws MacException
+ * @throws SSLException
+ * @throws ShortBufferException
+ */
+ public int decrypt(Record record, ByteBufferOutputStream outputStream)
+ throws DataFormatException, IllegalBlockSizeException,
+ MacException, SSLException, ShortBufferException
+ {
+ return decrypt(record, null, 0, 0, outputStream);
+ }
+
+ private int decrypt(Record record, ByteBuffer[] output, int offset, int length,
+ ByteBufferOutputStream outputStream)
+ throws DataFormatException, IllegalBlockSizeException,
+ MacException, SSLException, ShortBufferException
+ {
+ boolean badPadding = false;
+ ByteBuffer fragment;
+ if (cipher != null)
+ {
+ ByteBuffer input = record.fragment();
+ fragment = ByteBuffer.allocate(input.remaining());
+ cipher.update(input, fragment);
+ }
+ else
+ fragment = record.fragment();
+
+ if (Debug.DEBUG_DECRYPTION)
+ logger.logv(Component.SSL_RECORD_LAYER, "decrypted fragment:\n{0}",
+ Util.hexDump((ByteBuffer) fragment.duplicate().position(0), " >> "));
+
+ int fragmentLength = record.length();
+ int maclen = 0;
+ if (mac != null)
+ maclen = mac.getMacLength();
+ fragmentLength -= maclen;
+
+ int padlen = 0;
+ int padRemoveLen = 0;
+ if (!suite.isStreamCipher ())
+ {
+ padlen = fragment.get(record.length() - 1) & 0xFF;
+ padRemoveLen = padlen + 1;
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "padlen:{0}", padlen);
+
+ if (record.version() == ProtocolVersion.SSL_3)
+ {
+ // In SSLv3, the padding length must not be larger than
+ // the cipher's block size.
+ if (padlen > cipher.getBlockSize ())
+ badPadding = true;
+ }
+ else if (record.version().compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ // In TLSv1 and later, the padding must be `padlen' copies of the
+ // value `padlen'.
+ byte[] pad = new byte[padlen];
+ ((ByteBuffer) fragment.duplicate().position(record.length() - padlen - 1)).get(pad);
+ for (int i = 0; i < pad.length; i++)
+ if ((pad[i] & 0xFF) != padlen)
+ badPadding = true;
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "TLSv1.x padding\n{0}",
+ new ByteArray(pad));
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "padding bad? {0}",
+ badPadding);
+ if (!badPadding)
+ fragmentLength = fragmentLength - padRemoveLen;
+ }
+
+ int ivlen = 0;
+ if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ ivlen = cipher.getBlockSize();
+
+ // Compute and check the MAC.
+ if (mac != null)
+ {
+ mac.update((byte) (sequence >>> 56));
+ mac.update((byte) (sequence >>> 48));
+ mac.update((byte) (sequence >>> 40));
+ mac.update((byte) (sequence >>> 32));
+ mac.update((byte) (sequence >>> 24));
+ mac.update((byte) (sequence >>> 16));
+ mac.update((byte) (sequence >>> 8));
+ mac.update((byte) sequence);
+ mac.update((byte) record.getContentType().getValue());
+ ProtocolVersion version = record.version();
+ if (version != ProtocolVersion.SSL_3)
+ {
+ mac.update((byte) version.major());
+ mac.update((byte) version.minor());
+ }
+ mac.update((byte) ((fragmentLength - ivlen) >>> 8));
+ mac.update((byte) (fragmentLength - ivlen));
+ ByteBuffer content =
+ (ByteBuffer) fragment.duplicate().position(ivlen).limit(fragmentLength);
+ mac.update(content);
+ byte[] mac1 = mac.doFinal ();
+ byte[] mac2 = new byte[maclen];
+ mac.reset();
+ ((ByteBuffer) fragment.duplicate().position(fragmentLength)).get(mac2);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "mac1:{0} mac2:{1}",
+ Util.toHexString(mac1, ':'), Util.toHexString(mac2, ':'));
+ if (!Arrays.equals (mac1, mac2))
+ badPadding = true;
+ }
+
+ // We always say "bad MAC" and not "bad padding," because saying
+ // the latter will leak information to an attacker.
+ if (badPadding)
+ throw new MacException ();
+
+ // Inflate the compressed bytes.
+ int produced = 0;
+ if (inflater != null)
+ {
+ ByteBufferOutputStream out = new ByteBufferOutputStream(fragmentLength);
+ byte[] inbuffer = new byte[1024];
+ byte[] outbuffer = new byte[1024];
+ boolean done = false;
+ if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ fragment.position (cipher.getBlockSize());
+ else
+ fragment.position(0);
+ fragment.limit(fragmentLength);
+
+ while (!done)
+ {
+ int l;
+ if (inflater.needsInput())
+ {
+ l = Math.min(inbuffer.length, fragment.remaining());
+ fragment.get(inbuffer, 0, l);
+ inflater.setInput(inbuffer);
+ }
+
+ l = inflater.inflate(outbuffer);
+ out.write(outbuffer, 0, l);
+ done = !fragment.hasRemaining() && inflater.finished();
+ }
+
+ ByteBuffer outbuf = out.buffer();
+ if (outputStream != null)
+ {
+ byte[] buf = new byte[1024];
+ while (outbuf.hasRemaining())
+ {
+ int l = Math.min(outbuf.remaining(), buf.length);
+ outbuf.get(buf, 0, l);
+ outputStream.write(buf, 0, l);
+ produced += l;
+ }
+ }
+ else
+ {
+ int i = offset;
+ while (outbuf.hasRemaining() && i < offset + length)
+ {
+ int l = Math.min(output[i].remaining(), outbuf.remaining());
+ ByteBuffer b = (ByteBuffer)
+ outbuf.duplicate().limit(outbuf.position() + l);
+ output[i++].put(b);
+ outbuf.position(outbuf.position() + l);
+ produced += l;
+ }
+ if (outbuf.hasRemaining())
+ throw new BufferOverflowException();
+ }
+ }
+ else
+ {
+ ByteBuffer outbuf = (ByteBuffer)
+ fragment.duplicate().position(0).limit(record.length() - maclen - padRemoveLen);
+ if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ outbuf.position(cipher.getBlockSize());
+ if (outputStream != null)
+ {
+ byte[] buf = new byte[1024];
+ while (outbuf.hasRemaining())
+ {
+ int l = Math.min(outbuf.remaining(), buf.length);
+ outbuf.get(buf, 0, l);
+ outputStream.write(buf, 0, l);
+ produced += l;
+ }
+ }
+ else
+ {
+ int i = offset;
+ while (outbuf.hasRemaining() && i < offset + length)
+ {
+ int l = Math.min(output[i].remaining(), outbuf.remaining());
+ ByteBuffer b = (ByteBuffer) outbuf.duplicate().limit(outbuf.position() + l);
+ output[i++].put(b);
+ outbuf.position(outbuf.position() + l);
+ produced += l;
+ }
+ if (outbuf.hasRemaining())
+ throw new BufferOverflowException();
+ }
+ }
+
+ sequence++;
+
+ return produced;
+ }
+
+ CipherSuite cipherSuite ()
+ {
+ return suite;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java
deleted file mode 100644
index 6663c97b59d..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/* JCESecurityParameters.java -- JCE-based security parameters.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.ByteArrayOutputStream;
-
-import java.util.Arrays;
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.Mac;
-
-import javax.net.ssl.SSLException;
-
-class JCESecurityParameters implements SecurityParameters
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private Cipher inCipher, outCipher;
- private Mac inMac, outMac;
- private Inflater inflater;
- private Deflater deflater;
- private int fragmentLength;
- private long inSequence, outSequence;
- private ProtocolVersion version;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- JCESecurityParameters ()
- {
- fragmentLength = 16384;
- inSequence = 0L;
- outSequence = 0L;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void reset()
- {
- inCipher = null;
- outCipher = null;
- inMac = null;
- outMac = null;
- deflater = null;
- inflater = null;
- }
-
- public void setInCipher (Object inCipher)
- {
- this.inCipher = (Cipher) inCipher;
- }
-
- public void setOutCipher (Object outCipher)
- {
- this.outCipher = (Cipher) outCipher;
- }
-
- public void setInMac (Object inMac)
- {
- this.inMac = (Mac) inMac;
- inSequence = 0L;
- }
-
- public void setOutMac (Object outMac)
- {
- this.outMac = (Mac) outMac;
- outSequence = 0L;
- }
-
- public void setDeflating (boolean deflate)
- {
- if (deflate)
- {
- if (deflater == null)
- deflater = new Deflater();
- }
- else
- deflater = null;
- }
-
- public void setInflating (boolean inflate)
- {
- if (inflate)
- {
- if (inflater == null)
- inflater = new Inflater();
- }
- else
- inflater = null;
- }
-
- public int getFragmentLength()
- {
- return fragmentLength;
- }
-
- public void setFragmentLength (int fragmentLength)
- {
- this.fragmentLength = fragmentLength;
- }
-
- public ProtocolVersion getVersion()
- {
- return version;
- }
-
- public void setVersion (ProtocolVersion version)
- {
- this.version = version;
- }
-
- public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version,
- ContentType type)
- throws MacException, OverflowException, SSLException
- {
- boolean badpad = false;
- if (inCipher != null)
- {
- // We imagine that the JCE would be used in cases where hardware
- // acceleration is available, since it isn't really that useful for
- // pure Java crypto. We decrypt (and encrypt, below) in one go
- // to minimize (potential) calls to native methods.
- try
- {
- fragment = inCipher.doFinal (fragment);
- }
- catch (BadPaddingException bpe)
- {
- badpad = true;
- }
- catch (IllegalBlockSizeException ibse)
- {
- badpad = true;
- }
- }
-
- if (inMac != null)
- {
- int macLen = inMac.getMacLength();
- int fragLen = fragment.length - macLen;
- byte[] mac = Util.trim (fragment, fragLen, macLen);
- fragment = Util.trim (fragment, fragLen);
- inMac.update ((byte) (inSequence >>> 56));
- inMac.update ((byte) (inSequence >>> 48));
- inMac.update ((byte) (inSequence >>> 40));
- inMac.update ((byte) (inSequence >>> 32));
- inMac.update ((byte) (inSequence >>> 24));
- inMac.update ((byte) (inSequence >>> 16));
- inMac.update ((byte) (inSequence >>> 8));
- inMac.update ((byte) inSequence);
- inMac.update ((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- inMac.update ((byte) version.getMajor());
- inMac.update ((byte) version.getMinor());
- }
- inMac.update ((byte) (fragLen >>> 8));
- inMac.update ((byte) fragLen);
- inMac.update (fragment);
- if (!Arrays.equals (mac, inMac.doFinal()) || badpad)
- throw new MacException();
- }
-
- if (inflater != null)
- {
- byte[] buf = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1);
- inflater.setInput (fragment);
- int len;
- try
- {
- while ((len = inflater.inflate (buf)) > 0)
- {
- bout.write (buf, 0, len);
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("inflated data too large");
- }
- }
- catch (DataFormatException dfe)
- {
- throw new SSLException (String.valueOf (dfe));
- }
- fragment = bout.toByteArray();
- inflater.reset();
- }
-
- inSequence++;
- return fragment;
- }
-
- public synchronized byte[] encrypt (byte[] fragment, int off, int len,
- ContentType type)
- throws OverflowException, SSLException
- {
- if (deflater != null)
- {
- byte[] buf = new byte[1024];
- ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1);
- deflater.setInput (fragment, off, len);
- deflater.finish();
- len = 0;
- while ((len = deflater.deflate (buf)) > 0)
- bout.write (buf, 0, len);
- // This should technically never happen for zlib.
- if (bout.size() > fragmentLength + 1024)
- throw new OverflowException ("deflated data too large");
- fragment = bout.toByteArray();
- off = 0;
- len = fragment.length;
- deflater.reset();
- }
-
- if (outMac != null)
- {
- outMac.update ((byte) (inSequence >>> 56));
- outMac.update ((byte) (inSequence >>> 48));
- outMac.update ((byte) (inSequence >>> 40));
- outMac.update ((byte) (inSequence >>> 32));
- outMac.update ((byte) (inSequence >>> 24));
- outMac.update ((byte) (inSequence >>> 16));
- outMac.update ((byte) (inSequence >>> 8));
- outMac.update ((byte) inSequence);
- outMac.update ((byte) type.getValue());
- if (version != ProtocolVersion.SSL_3)
- {
- outMac.update ((byte) version.getMajor());
- outMac.update ((byte) version.getMinor());
- }
- outMac.update ((byte) (len >>> 8));
- outMac.update ((byte) len);
- outMac.update (fragment, off, len);
- fragment = Util.concat (fragment, outMac.doFinal());
- off = 0;
- len = fragment.length;
- }
-
- if (outCipher != null)
- {
- try
- {
- fragment = outCipher.doFinal (fragment, off, len);
- }
- catch (BadPaddingException shouldNeverHappen)
- {
- // This is nonsensical. Don't even pretend that we can handle this.
- throw new RuntimeException ("bad padding thrown while encrypting");
- }
- catch (IllegalBlockSizeException ibse)
- {
- // Ditto.
- throw new RuntimeException ("illegal block size thrown while encrypting");
- }
- off = 0;
- len = fragment.length;
- }
-
- outSequence++;
- if (off == 0 && len == fragment.length)
- return fragment;
- else
- return Util.trim (fragment, off, len);
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java
deleted file mode 100644
index 2b9b1403425..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/* JDBCSessionContext.java -- database persistent sessions.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-
-import java.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Timestamp;
-import java.sql.Types;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Enumeration;
-import java.util.TreeSet;
-import java.util.Vector;
-
-import javax.net.ssl.SSLSession;
-
-/**
- * The SQL table this class stores sessions in, called <tt>SESSIONS</tt>,
- * looks like this:
- *
- * <blockquote><pre>
- * TABLE SESSIONS (
- * ID VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL,
- * CREATED TIMESTAMP NOT NULL,
- * LAST_ACCESSED TIMESTAMP NOT NULL,
- * PROTOCOL VARCHAR(7) NOT NULL,
- * SUITE VARCHAR(255) NOT NULL,
- * PEER_HOST TEXT NOT NULL,
- * PEER_CERT_TYPE VARCHAR(32),
- * PEER_CERTS BLOB,
- * CERT_TYPE VARCHAR(32),
- * CERTS BLOB,
- * SECRET VARBINARY(48) NOT NULL
- * )
- * </pre></blockquote>
- *
- * <p>Note that the master secret for sessions is not protected before
- * being inserted into the database; it is up to the system to protect
- * the stored data from unauthorized access.
- */
-class JDBCSessionContext extends SessionContext
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- protected Connection connection;
- protected PreparedStatement selectById;
- protected PreparedStatement insert;
- protected PreparedStatement selectTimestamp;
- protected PreparedStatement updateTimestamp;
- protected PreparedStatement deleteSession;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JDBCSessionContext() throws SQLException
- {
- String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url");
- String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user");
- String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password");
- if (url == null)
- {
- throw new IllegalArgumentException("no JDBC URL");
- }
- if (user == null || passwd == null)
- {
- connection = DriverManager.getConnection(url);
- }
- else
- {
- connection = DriverManager.getConnection(url, user, passwd);
- }
- selectById =
- connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?");
- insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
- selectTimestamp =
- connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?");
- updateTimestamp =
- connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?");
- deleteSession =
- connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?");
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public synchronized Enumeration getIds()
- {
- Vector ids = new Vector();
- try
- {
- Statement stmt = connection.createStatement();
- ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS");
- while (rs.next())
- {
- byte[] id = rs.getBytes("ID");
- ids.add(id);
- }
- }
- catch (SQLException sqle)
- {
- }
- return ids.elements();
- }
-
- public synchronized SSLSession getSession(byte[] sessionId)
- {
- Session session = (Session) super.getSession(sessionId);
- if (session == null)
- {
- try
- {
- selectById.setBytes(1, sessionId);
- ResultSet rs = selectById.executeQuery();
- if (rs.next())
- {
- session = new Session(rs.getTimestamp("CREATED").getTime());
- session.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
- session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
- session.random = new SecureRandom();
- session.context = this;
- session.sessionId = new Session.ID(rs.getBytes("ID"));
- session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime());
- long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
- if ((int) (elapsed / 1000L) > timeout)
- {
- removeSession(session.sessionId);
- return null;
- }
- session.peerHost = rs.getString("PEER_HOST");
- String protocol = rs.getString("PROTOCOL");
- if (protocol.equals("SSLv3"))
- {
- session.protocol = ProtocolVersion.SSL_3;
- }
- else if (protocol.equals("TLSv1"))
- {
- session.protocol = ProtocolVersion.TLS_1;
- }
- else if (protocol.equals("TLSv1.1"))
- {
- session.protocol = ProtocolVersion.TLS_1_1;
- }
- else
- {
- return null;
- }
- session.cipherSuite = CipherSuite.forName(rs.getString("SUITE"));
- String type = rs.getString("PEER_CERT_TYPE");
- boolean wasNull = rs.wasNull();
- InputStream certs = null;
- if (!wasNull)
- {
- certs = rs.getBinaryStream("PEER_CERTS");
- wasNull = rs.wasNull();
- }
- if (!wasNull)
- {
- CertificateFactory cf = CertificateFactory.getInstance(type);
- session.peerCerts = (Certificate[])
- cf.generateCertificates(certs).toArray(new Certificate[0]);
- session.peerVerified = true;
- }
- type = rs.getString("CERT_TYPE");
- wasNull = rs.wasNull();
- if (!wasNull)
- {
- certs = rs.getBinaryStream("CERTS");
- wasNull = rs.wasNull();
- }
- if (!wasNull)
- {
- CertificateFactory cf = CertificateFactory.getInstance(type);
- session.localCerts = (Certificate[])
- cf.generateCertificates(certs).toArray(new Certificate[0]);
- }
- session.masterSecret = rs.getBytes("SECRET");
- if (cacheSize == 0 || sessions.size() < cacheSize)
- {
- sessions.put(session.sessionId, session);
- }
- }
- }
- catch (Exception ex)
- {
- }
- }
- return session;
- }
-
- synchronized boolean addSession(Session.ID id, Session s)
- {
- if (containsSessionID(id))
- {
- return false;
- }
- try
- {
- insert.setBytes(1, id.getId());
- insert.setTimestamp(2, new Timestamp(s.getCreationTime()));
- insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime()));
- insert.setString(4, s.getProtocol());
- insert.setString(5, s.getCipherSuite());
- insert.setString(6, s.peerHost);
- if (s.peerCerts != null && s.peerCerts.length > 0)
- {
- insert.setString(7, s.peerCerts[0].getType());
- insert.setBytes(8, certs(s.peerCerts));
- }
- else
- {
- insert.setNull(7, Types.VARCHAR);
- insert.setNull(8, Types.LONGVARBINARY);
- }
- if (s.localCerts != null && s.localCerts.length > 0)
- {
- insert.setString(9, s.localCerts[0].getType());
- insert.setBytes(10, certs(s.localCerts));
- }
- else
- {
- insert.setNull(9, Types.VARCHAR);
- insert.setNull(10, Types.LONGVARBINARY);
- }
- insert.setBytes(11, s.masterSecret);
- insert.executeUpdate();
- super.addSession(id, s);
- }
- catch (SQLException sqle)
- {
- return false;
- }
- return true;
- }
-
- synchronized boolean containsSessionID(Session.ID sessionId)
- {
- try
- {
- selectTimestamp.setBytes(1, sessionId.getId());
- ResultSet rs = selectTimestamp.executeQuery();
- if (!rs.next())
- {
- return false;
- }
- Timestamp ts = rs.getTimestamp("CREATED");
- if (rs.wasNull())
- {
- return false;
- }
- long elapsed = System.currentTimeMillis() - ts.getTime();
- if ((int) (elapsed / 1000) > timeout)
- {
- removeSession(sessionId);
- return false;
- }
- return true;
- }
- catch (SQLException sqle)
- {
- return false;
- }
- }
-
- protected boolean removeSession(Session.ID sessionId)
- {
- super.removeSession(sessionId);
- try
- {
- deleteSession.setBytes(1, sessionId.getId());
- return deleteSession.executeUpdate() > 0;
- }
- catch (SQLException sqle)
- {
- }
- return false;
- }
-
- synchronized void notifyAccess(Session session)
- {
- try
- {
- updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime()));
- updateTimestamp.setBytes(2, session.getId());
- updateTimestamp.executeUpdate();
- }
- catch (SQLException sqle)
- {
- }
- }
-
- private byte[] certs(Certificate[] certs)
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
- for (int i = 0; i < certs.length; i++)
- {
- try
- {
- out.write(certs[i].getEncoded());
- }
- catch (Exception x)
- {
- }
- }
- return out.toByteArray();
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java
index 14b671d0230..6bd68b3850f 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java
@@ -59,31 +59,42 @@ import java.security.Provider;
*/
public class Jessie extends Provider
{
+ private static final long serialVersionUID = -1;
- public static final String VERSION = "1.0.0";
- public static final double VERSION_DOUBLE = 1.0;
+ public static final String VERSION = "2.0.0";
+ public static final double VERSION_DOUBLE = 2.0;
public Jessie()
{
super("Jessie", VERSION_DOUBLE,
- "Implementing SSLv3, TLSv1 SSL Contexts; X.509 Key Manager Factories;" +
- System.getProperty("line.separator") +
- "X.509 and SRP Trust Manager Factories, continuously-seeded secure random." );
+ "Implementing TLSv1.1, with SSLv3, TLSv1.0 compatibility modes; "
+ + "X.509 Key Manager Factory; "
+ + "X.509 Trust Manager Factory; "
+ + "SSLv3 MD5 and SHA Mac.");
- AccessController.doPrivileged(new PrivilegedAction()
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
{
public Object run()
{
- put("SSLContext.SSLv3", Context.class.getName());
- put("Alg.Alias.SSLContext.SSL", "SSLv3");
- put("Alg.Alias.SSLContext.TLSv1", "SSLv3");
- put("Alg.Alias.SSLContext.TLS", "SSLv3");
- //put("Alg.Alias.SSLContext.TLSv1.1", "SSLv3");
+ put("SSLContext.TLSv1.1", SSLContextImpl.class.getName());
+ put("Alg.Alias.SSLContext.SSLv3", "TLSv1.1");
+ put("Alg.Alias.SSLContext.TLSv1", "TLSv1.1");
+ put("Alg.Alias.SSLContext.TLSv1.0", "TLSv1.1");
+ put("Alg.Alias.SSLContext.TLS", "TLSv1.1");
+ put("Alg.Alias.SSLContext.SSL", "TLSv1.1");
put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName());
put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName());
- put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName());
+ put("KeyManagerFactory.JessiePSK", PreSharedKeyManagerFactoryImpl.class.getName());
+ //put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName());
+ put("Mac.SSLv3HMac-MD5", SSLv3HMacMD5Impl.class.getName());
+ put("Mac.SSLv3HMac-SHA", SSLv3HMacSHAImpl.class.getName());
+
+ put("Signature.TLSv1.1-RSA", SSLRSASignatureImpl.class.getName());
+ put("Alg.Alias.Signature.TLSv1-RSA", "TLSv1.1-RSA");
+ put("Alg.Alias.Signature.SSLv3-RSA", "TLSv1.1-RSA");
+
return null;
}
});
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java
deleted file mode 100644
index 4ec71a7aad3..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/* JessieRSAPrivateKey.java -- simple RSA private key.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.math.BigInteger;
-import java.security.interfaces.RSAPrivateKey;
-
-class JessieRSAPrivateKey implements RSAPrivateKey
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final BigInteger modulus;
- private final BigInteger exponent;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieRSAPrivateKey(BigInteger modulus, BigInteger exponent)
- {
- this.modulus = modulus;
- this.exponent = exponent;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
- {
- return "RSA";
- }
-
- public String getFormat()
- {
- return "NONE";
- }
-
- public byte[] getEncoded()
- {
- return null;
- }
-
- public BigInteger getModulus()
- {
- return modulus;
- }
-
- public BigInteger getPrivateExponent()
- {
- return exponent;
- }
-
- public String toString()
- {
- String nl = System.getProperty("line.separator");
- return "RSAPrivateKey {" + nl +
- " modulus = " + modulus.toString(16) + ";" + nl +
- " exponent = " + exponent.toString(16) + ";" + nl +
- "};";
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
new file mode 100644
index 00000000000..04416c5a5cc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
@@ -0,0 +1,57 @@
+/* KeyExchangeAlgorithm.java -- Key exchange algorithm enumeration.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * The enumeration of supported key exchange algorithms.
+ */
+public enum KeyExchangeAlgorithm
+{
+ NONE,
+ RSA,
+ DH_DSS,
+ DH_RSA,
+ DH_anon,
+ DHE_DSS,
+ DHE_RSA,
+// SRP,
+ PSK,
+ DHE_PSK,
+ RSA_PSK;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java
deleted file mode 100644
index 18d9dc281ab..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/* KeyPool.java -- A set of ephemeral key pairs.
- Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.SecureRandom;
-
-final class KeyPool
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final BigInteger ONE = BigInteger.ONE;
- private static final BigInteger TWO = BigInteger.valueOf(2L);
- private static final BigInteger E = BigInteger.valueOf(65537L);
- private static final SecureRandom RANDOM = new SecureRandom ();
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- private KeyPool()
- {
- }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- /**
- * Generate an export-class (512 bit) RSA key pair.
- *
- * @return The new key pair.
- */
- static KeyPair generateRSAKeyPair()
- {
- BigInteger p, q, n, d;
-
- // Simplified version of GNU Crypto's RSAKeyPairGenerator.
-
- int M = 256;
- BigInteger lower = TWO.pow(255);
- BigInteger upper = TWO.pow(256).subtract(ONE);
- byte[] kb = new byte[32];
- while (true)
- {
- nextBytes(kb);
- p = new BigInteger(1, kb).setBit(0);
- if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 &&
- p.isProbablePrime(80) && p.gcd(E).equals(ONE))
- break;
- }
-
- while (true)
- {
- nextBytes(kb);
- q = new BigInteger(1, kb).setBit(0);
- n = q.multiply(p);
- if (n.bitLength() == 512 && q.isProbablePrime(80) &&
- q.gcd(E).equals(ONE))
- break;
- }
-
- d = E.modInverse(p.subtract(ONE).multiply(q.subtract(ONE)));
-
- return new KeyPair(new JessieRSAPublicKey(n, E),
- new JessieRSAPrivateKey(n, d));
- }
-
- private static void nextBytes(byte[] buf)
- {
- RANDOM.nextBytes (buf);
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java
new file mode 100644
index 00000000000..cae0efbfa80
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java
@@ -0,0 +1,47 @@
+/* MacAlgorithm.java -- MAC algorithm enumeration.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * An enumeration of MAC algorithms we support.
+ */
+public enum MacAlgorithm
+{
+ NULL, MD5, SHA;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java
new file mode 100644
index 00000000000..eb63958b839
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java
@@ -0,0 +1,59 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Extension value
+ * @author csm
+ */
+public class MaxFragmentLength extends Value
+{
+ public static final MaxFragmentLength LEN_2_9 = new MaxFragmentLength(1, 1 << 9);
+ public static final MaxFragmentLength LEN_2_10 = new MaxFragmentLength(2, 1 << 10);
+ public static final MaxFragmentLength LEN_2_11 = new MaxFragmentLength(3, 1 << 11);
+ public static final MaxFragmentLength LEN_2_12 = new MaxFragmentLength(4, 1 << 12);
+
+ private final int value;
+ private final int length;
+
+ private MaxFragmentLength(int value, int length)
+ {
+ this.value = value;
+ this.length = length;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ByteBuffer.allocate(1).put(0, (byte) value);
+ }
+
+ public int length()
+ {
+ return 1;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public int maxLength()
+ {
+ return length;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ String s = "max_fragment_length = ";
+ if (prefix != null)
+ s = prefix + s;
+ return s + maxLength() + ";";
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java
new file mode 100644
index 00000000000..6da0d066741
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java
@@ -0,0 +1,297 @@
+/* OutputSecurityParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.util.ByteArray;
+import gnu.java.security.util.ByteBufferOutputStream;
+
+import java.nio.ByteBuffer;
+
+import java.util.logging.Level;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+public class OutputSecurityParameters
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private final Cipher cipher;
+ private final Mac mac;
+ private final Deflater deflater;
+ private final SessionImpl session;
+ private final CipherSuite suite;
+ private long sequence;
+
+ public OutputSecurityParameters (final Cipher cipher, final Mac mac,
+ final Deflater deflater, SessionImpl session,
+ CipherSuite suite)
+ {
+ this.cipher = cipher;
+ this.mac = mac;
+ this.deflater = deflater;
+ this.session = session;
+ this.suite = suite;
+ sequence = 0;
+ }
+
+ /**
+ * Encrypt a record, storing the result in the given output buffer.
+ *
+ * @return The number of bytes taken from the input, and the number stored
+ * into `output;' that is, the size of the encrypted fragment, plus the
+ * encoding for the record.
+ */
+ public int[] encrypt (final ByteBuffer[] input, int offset, int length,
+ final ContentType contentType, final ByteBuffer output)
+ throws DataFormatException, IllegalBlockSizeException, ShortBufferException
+ {
+ if (offset < 0 || offset >= input.length
+ || length <= 0 || offset + length > input.length)
+ throw new IndexOutOfBoundsException();
+
+ if (Debug.DEBUG)
+ for (int i = offset; i < offset+length; i++)
+ logger.logv(Component.SSL_RECORD_LAYER, "encrypting record [{0}]: {1}",
+ i-offset, input[i]);
+
+ int maclen = 0;
+ if (mac != null)
+ maclen = session.isTruncatedMac() ? 10 : mac.getMacLength ();
+
+ int ivlen = 0;
+ byte[] iv = null;
+ if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ {
+ ivlen = cipher.getBlockSize();
+ iv = new byte[ivlen];
+ session.random().nextBytes(iv);
+ }
+
+ int padaddlen = 0;
+ if (!suite.isStreamCipher()
+ && session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ padaddlen = (session.random().nextInt(255 / cipher.getBlockSize())
+ * cipher.getBlockSize());
+ }
+
+ int fragmentLength = 0;
+ ByteBuffer[] fragments = null;
+ // Compress the content, if needed.
+ if (deflater != null)
+ {
+ ByteBufferOutputStream deflated = new ByteBufferOutputStream();
+
+ byte[] inbuf = new byte[1024];
+ byte[] outbuf = new byte[1024];
+ int written = 0;
+
+ // Here we use the guarantee that the deflater won't increase the
+ // output size by more than 1K -- we resign ourselves to only deflate
+ // as much data as we have space for *uncompressed*,
+ int limit = output.remaining() - (maclen + ivlen + padaddlen) - 1024;
+
+ for (int i = offset; i < length && written < limit; i++)
+ {
+ ByteBuffer in = input[i];
+ while (in.hasRemaining() && written < limit)
+ {
+ int l = Math.min(in.remaining(), inbuf.length);
+ l = Math.min(limit - written, l);
+ in.get(inbuf, 0, l);
+ deflater.setInput(inbuf, 0, l);
+ l = deflater.deflate(outbuf);
+ deflated.write(outbuf, 0, l);
+ written += l;
+ }
+ }
+ deflater.finish();
+ while (!deflater.finished())
+ {
+ int l = deflater.deflate(outbuf);
+ deflated.write(outbuf, 0, l);
+ written += l;
+ }
+ fragments = new ByteBuffer[] { deflated.buffer() };
+ fragmentLength = ((int) deflater.getBytesWritten()) + maclen + ivlen;
+ deflater.reset();
+ offset = 0;
+ length = 1;
+ }
+ else
+ {
+ int limit = output.remaining() - (maclen + ivlen + padaddlen);
+ fragments = input;
+ for (int i = offset; i < length && fragmentLength < limit; i++)
+ {
+ int l = Math.min(limit - fragmentLength, fragments[i].remaining());
+ fragmentLength += l;
+ }
+ fragmentLength += maclen + ivlen;
+ }
+
+ // Compute padding...
+ int padlen = 0;
+ byte[] pad = null;
+ if (!suite.isStreamCipher())
+ {
+ int bs = cipher.getBlockSize();
+ padlen = bs - (fragmentLength % bs);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER,
+ "framentLen:{0} padlen:{1} blocksize:{2}",
+ fragmentLength, padlen, bs);
+ if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ // TLS 1.0 and later uses a random amount of padding, up to
+ // 255 bytes. Each byte of the pad is equal to the padding
+ // length, minus one.
+ padlen += padaddlen;
+ while (padlen > 255)
+ padlen -= bs;
+ pad = new byte[padlen];
+ for (int i = 0; i < padlen; i++)
+ pad[i] = (byte) (padlen - 1);
+ }
+ else
+ {
+ // SSL 3 uses a pad only as large as the block size, but the
+ // pad may contain any values.
+ pad = new byte[padlen];
+ session.random().nextBytes(pad);
+ pad[padlen - 1] = (byte) (padlen - 1);
+ }
+ fragmentLength += pad.length;
+ }
+
+ // If there is a MAC, compute it.
+ byte[] macValue = null;
+ if (mac != null)
+ {
+ mac.update((byte) (sequence >>> 56));
+ mac.update((byte) (sequence >>> 48));
+ mac.update((byte) (sequence >>> 40));
+ mac.update((byte) (sequence >>> 32));
+ mac.update((byte) (sequence >>> 24));
+ mac.update((byte) (sequence >>> 16));
+ mac.update((byte) (sequence >>> 8));
+ mac.update((byte) sequence);
+ mac.update((byte) contentType.getValue());
+ if (session.version != ProtocolVersion.SSL_3)
+ {
+ mac.update((byte) session.version.major ());
+ mac.update((byte) session.version.minor ());
+ }
+ int toWrite = fragmentLength - maclen - ivlen - padlen;
+ mac.update((byte) (toWrite >>> 8));
+ mac.update((byte) toWrite);
+ int written = 0;
+ for (int i = offset; i < length && written < toWrite; i++)
+ {
+ ByteBuffer fragment = fragments[i].duplicate();
+ int l = Math.min(fragment.remaining(), toWrite - written);
+ fragment.limit(fragment.position() + l);
+ mac.update(fragment);
+ }
+ macValue = mac.doFinal();
+ }
+
+ Record outrecord = new Record(output);
+ outrecord.setContentType(contentType);
+ outrecord.setVersion(session.version);
+ outrecord.setLength(fragmentLength);
+
+ int consumed = 0;
+ ByteBuffer outfragment = outrecord.fragment();
+
+ if (cipher != null)
+ {
+ if (iv != null)
+ cipher.update(ByteBuffer.wrap(iv), outfragment);
+ int toWrite = fragmentLength - maclen - ivlen - padlen;
+ for (int i = offset; i < offset + length && consumed < toWrite; i++)
+ {
+ ByteBuffer fragment = fragments[i].slice();
+ int l = Math.min(fragment.remaining(), toWrite - consumed);
+ fragment.limit(fragment.position() + l);
+ cipher.update(fragment, outfragment);
+ fragments[i].position(fragments[i].position() + l);
+ consumed += l;
+ }
+ if (macValue != null)
+ cipher.update(ByteBuffer.wrap(macValue), outfragment);
+ if (pad != null)
+ cipher.update(ByteBuffer.wrap(pad), outfragment);
+ }
+ else
+ {
+ // iv and pad are only used if we have a block cipher.
+ int toWrite = fragmentLength - maclen;
+ for (int i = offset; i < offset + length && consumed < toWrite; i++)
+ {
+ ByteBuffer fragment = fragments[i];
+ int l = Math.min(fragment.remaining(), toWrite - consumed);
+ fragment.limit(fragment.position() + l);
+ outfragment.put(fragment);
+ consumed += l;
+ }
+ if (macValue != null)
+ outfragment.put(macValue);
+ }
+
+ // Advance the output buffer's position.
+ output.position(output.position() + outrecord.length() + 5);
+ sequence++;
+
+ return new int[] { consumed, fragmentLength + 5 };
+ }
+
+ CipherSuite suite()
+ {
+ return suite;
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java
new file mode 100644
index 00000000000..aa1f97853cf
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java
@@ -0,0 +1,118 @@
+/* PreSharedKeyManagerFactory.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.PreSharedKeyManager;
+import gnu.javax.net.ssl.PreSharedKeyManagerParameters;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class PreSharedKeyManagerFactoryImpl
+ extends KeyManagerFactorySpi
+{
+ PreSharedKeyManagerParameters params;
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.KeyManagerFactorySpi#engineGetKeyManagers()
+ */
+ @Override protected KeyManager[] engineGetKeyManagers()
+ {
+ if (params == null)
+ throw new IllegalStateException("not initialized");
+ return new KeyManager[] { new Manager() };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(javax.net.ssl.ManagerFactoryParameters)
+ */
+ @Override protected void engineInit(ManagerFactoryParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PreSharedKeyManagerParameters))
+ throw new InvalidAlgorithmParameterException("only supports gnu.javax.net.ssl.PreSharedKeyManagerParameters");
+ params = (PreSharedKeyManagerParameters) params;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(java.security.KeyStore, char[])
+ */
+ @Override protected void engineInit(KeyStore store, char[] passwd)
+ throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException
+ {
+ // XXX Could implement this.
+ }
+
+ class Manager implements PreSharedKeyManager
+ {
+ Manager()
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.PreSharedKeyManager#getKey(java.lang.String)
+ */
+ public SecretKey getKey(String name) throws KeyManagementException
+ {
+ return params.getKey(name);
+ }
+
+ public String chooseIdentityHint()
+ {
+ Iterator<String> it = params.identities();
+ if (it.hasNext())
+ return it.next();
+ return null;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java
index 5f5d1d979aa..ca62054a89c 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java
@@ -42,15 +42,16 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
-final class ProtocolVersion implements Comparable, Constructed
+public final class ProtocolVersion
+ implements Comparable<ProtocolVersion>, Constructed
{
// Constants and fields.
// -------------------------------------------------------------------------
- static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0);
- static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1);
- static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2);
+ public static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0);
+ public static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1);
+ public static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2);
private final int major;
private final int minor;
@@ -67,14 +68,25 @@ final class ProtocolVersion implements Comparable, Constructed
// Class methods.
// -------------------------------------------------------------------------
- static ProtocolVersion read(InputStream in) throws IOException
+ public static ProtocolVersion read(InputStream in) throws IOException
{
int major = in.read() & 0xFF;
int minor = in.read() & 0xFF;
return getInstance(major, minor);
}
- static ProtocolVersion getInstance(int major, int minor)
+ public static ProtocolVersion forName (final String name)
+ {
+ if (name.equalsIgnoreCase ("SSLv3"))
+ return SSL_3;
+ if (name.equalsIgnoreCase ("TLSv1"))
+ return TLS_1;
+ if (name.equalsIgnoreCase("TLSv1.1"))
+ return TLS_1_1;
+ throw new IllegalArgumentException ("unknown protocol name: " + name);
+ }
+
+ public static ProtocolVersion getInstance(final int major, final int minor)
{
if (major == 3)
{
@@ -88,35 +100,46 @@ final class ProtocolVersion implements Comparable, Constructed
return new ProtocolVersion(major, minor);
}
+ public static ProtocolVersion getInstance (final short raw_value)
+ {
+ int major = raw_value >>> 8 & 0xFF;
+ int minor = raw_value & 0xFF;
+ return getInstance (major, minor);
+ }
+
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public int length ()
{
- out.write(major);
- out.write(minor);
+ return 2;
}
- byte[] getEncoded()
+ public byte[] getEncoded()
{
return new byte[] {
(byte) major, (byte) minor
};
}
- int getMajor()
+ public int major()
{
return major;
}
- int getMinor()
+ public int minor()
{
return minor;
}
+ public int rawValue ()
+ {
+ return (major << 8) | minor;
+ }
+
public boolean equals(Object o)
{
- if (o == null || !(o instanceof ProtocolVersion))
+ if (!(o instanceof ProtocolVersion))
{
return false;
}
@@ -129,35 +152,33 @@ final class ProtocolVersion implements Comparable, Constructed
return major << 8 | minor;
}
- public int compareTo(Object o)
+ public int compareTo(ProtocolVersion that)
{
- if (o == null || !(o instanceof ProtocolVersion))
+ if (major > that.major)
{
return 1;
}
- if (this.equals(o))
- {
- return 0;
- }
- if (major > ((ProtocolVersion) o).major)
- {
- return 1;
- }
- else if (major < ((ProtocolVersion) o).major)
+ else if (major < that.major)
{
return -1;
}
- if (minor > ((ProtocolVersion) o).minor)
+
+ if (minor > that.minor)
{
return 1;
}
- else if (minor < ((ProtocolVersion) o).minor)
+ else if (minor < that.minor)
{
return -1;
}
return 0;
}
+ public String toString (String prefix)
+ {
+ return toString ();
+ }
+
public String toString()
{
if (this == SSL_3)
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Random.java b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java
index c42592b147b..e6815930934 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Random.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java
@@ -45,80 +45,110 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-class Random implements Constructed
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An SSL nonce.
+ *
+ * <pre>
+struct
+{
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+} Random;
+ */
+public class Random implements Builder, Constructed
{
// Fields.
// -------------------------------------------------------------------------
- private final int gmtUnixTime;
- private final byte[] randomBytes;
+ static final int RANDOM_LENGTH = 28;
+
+ private final ByteBuffer buffer;
// Constructors.
// -------------------------------------------------------------------------
- Random(int gmtUnixTime, byte[] randomBytes)
+ public Random (final ByteBuffer buffer)
{
- this.gmtUnixTime = gmtUnixTime;
- this.randomBytes = (byte[]) randomBytes.clone();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
}
- // Class methods.
- // -------------------------------------------------------------------------
+ public Random copy()
+ {
+ ByteBuffer buffer = ByteBuffer.allocate(32);
+ buffer.put((ByteBuffer) this.buffer.duplicate().position(0));
+ return new Random(buffer);
+ }
- static Random read(InputStream in) throws IOException
+ public int length()
{
- int time = (in.read() & 0xFF) << 24 | (in.read() & 0xFF) << 16
- | (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
- byte[] buf = new byte[28];
- in.read(buf);
- return new Random(time, buf);
+ return RANDOM_LENGTH + 4;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
}
- // Instance methods.
- // -------------------------------------------------------------------------
+ public int gmtUnixTime ()
+ {
+ return buffer.getInt(0);
+ }
- public void write(OutputStream out) throws IOException
+ public byte[] randomBytes()
{
- out.write((gmtUnixTime >>> 24) & 0xFF);
- out.write((gmtUnixTime >>> 16) & 0xFF);
- out.write((gmtUnixTime >>> 8) & 0xFF);
- out.write(gmtUnixTime & 0xFF);
- out.write(randomBytes);
+ byte[] buf = new byte[28];
+ buffer.position (4);
+ buffer.get (buf);
+ return buf;
}
- byte[] getEncoded()
+ public void setGmtUnixTime (final int gmtUnixTime)
{
- ByteArrayOutputStream bout = new ByteArrayOutputStream(32);
- try
- {
- write(bout);
- }
- catch (IOException cantHappen)
- {
- throw new Error(cantHappen.toString());
- }
- return bout.toByteArray();
+ buffer.putInt (0, gmtUnixTime);
}
- int getTime()
+ public void setRandomBytes (final byte[] randomBytes)
{
- return gmtUnixTime;
+ setRandomBytes (randomBytes, 0);
}
- byte[] getRandomBytes()
+ public void setRandomBytes (final byte[] randomBytes, final int offset)
{
- return randomBytes;
+ if (randomBytes.length - offset < RANDOM_LENGTH)
+ throw new IllegalArgumentException ("random value too short");
+ buffer.position (4);
+ buffer.put (randomBytes, offset, RANDOM_LENGTH);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
out.println("struct {");
- out.println(" gmt_unix_time = " + gmtUnixTime + ";");
- out.println(" random_bytes = " + Util.toHexString(randomBytes, ':') + ";");
- out.println("} Random;");
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" gmt_unix_time: ");
+ out.print (gmtUnixTime ());
+ out.println (";");
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" random_bytes: ");
+ out.print (Util.toHexString (randomBytes (), ':'));
+ out.println (";");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Random;");
return str.toString();
}
+
+ public String toString ()
+ {
+ return toString (null);
+ }
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Record.java b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
new file mode 100644
index 00000000000..6f5a23ef4dc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
@@ -0,0 +1,198 @@
+/* Record.java -- A single SSL Record.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A SSL/TLS record structure. An SSL record is defined to be:
+ *
+ * <pre>
+struct
+{
+ {@link ContentType} type;
+ {@link ProtocolVersion} version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+} TLSPlaintext;
+</pre>
+ */
+public class Record
+{
+ private final ByteBuffer buffer;
+
+ public Record (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ // XXX remove
+ public ContentType getContentType ()
+ {
+ return contentType ();
+ }
+
+ /**
+ * Gets the content type field.
+ *
+ * @return The content type field.
+ */
+ public ContentType contentType ()
+ {
+ return ContentType.forInteger (buffer.get (0) & 0xFF);
+ }
+
+ /**
+ * Get the fragment content, storing it into <code>sink</code>.
+ *
+ * @param sink The sink for the fragment bytes.
+ * @return The number of bytes put into <code>sink</code>
+ */
+ public int fragment (final ByteBuffer sink)
+ {
+ int length = length ();
+ sink.put (((ByteBuffer) buffer.limit (5 + length).position (5)).slice ());
+ return length;
+ }
+
+ /**
+ * Returns the fragment field as a ByteBuffer. The returned buffer
+ * is shared with this object's underlying buffer, so it will share
+ * its attributes. For example, if the underlying buffer is
+ * read-only, the returned buffer will be read-only.
+ *
+ * @return The fragment buffer.
+ */
+ public ByteBuffer fragment ()
+ {
+ int length = length ();
+ return ((ByteBuffer) buffer.limit (5 + length).position (5)).slice ();
+ }
+
+ /**
+ * Gets the fragment length.
+ *
+ * @return The fragment length.
+ */
+ public int length ()
+ {
+ // XXX this is different behavior than we usually want: we return the
+ // length field, not the total length. We should consider changing this.
+ return buffer.getShort (3) & 0xFFFF;
+ }
+
+ /**
+ * Gets the protocol version field.
+ *
+ * @return The protocol version field.
+ */
+ public ProtocolVersion version ()
+ {
+ int major = buffer.get (1) & 0xFF;
+ int minor = buffer.get (2) & 0xFF;
+ return ProtocolVersion.getInstance (major, minor);
+ }
+
+ /**
+ * Sets the content type field.
+ *
+ * @param type The content type.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ * @throws NullPointerException If <i>type</i> is <code>null</code>.
+ */
+ public void setContentType (final ContentType type)
+ {
+ buffer.put (0, (byte) type.getValue ());
+ }
+
+ /**
+ * Sets the fragment length.
+ *
+ * @param length The fragment length.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ * @throws IllegalArgumentException If the length is not between 0
+ * and 16384, inclusive.
+ */
+ public void setLength (final int length)
+ {
+ if (length < 0 || length > 16384)
+ throw new IllegalArgumentException ("length " + length + " out of range; "
+ + "must be between 0 and 16384");
+ buffer.putShort (3, (short) length);
+ }
+
+ /**
+ * Sets the protocol version field.
+ *
+ * @param version The protocol version.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ * @throws NullPointerException If <i>version</i> is <code>null</code>.
+ */
+ public void setVersion (final ProtocolVersion version)
+ {
+ buffer.put (1, (byte) version.major ()).put (2, (byte) version.minor ());
+ }
+
+ public String toString ()
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ out.println ("struct {");
+ out.print (" type: ");
+ out.print (contentType ());
+ out.println (";");
+ out.print (" version: ");
+ out.print (version ());
+ out.println (";");
+ out.print(" length: ");
+ out.print(length());
+ out.println(";");
+ out.println (" fragment {");
+ out.print (Util.hexDump (fragment (), " "));
+ out.println (" };");
+ out.print ("} Record;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java
deleted file mode 100644
index d4ba5b596d6..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/* RecordInput.java -- record layer input.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import gnu.classpath.SystemProperties;
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import java.util.logging.Logger;
-
-import javax.net.ssl.SSLProtocolException;
-
-class RecordInput
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final boolean DEBUG_RECORD_LAYER = true;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- private byte[] fragment;
- private int index;
- private ContentType type;
-
- private final DataInputStream in;
- private Session session;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- RecordInput (final InputStream in, final Session session)
- {
- this.in = new DataInputStream (in);
- this.session = session;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- synchronized int available (ContentType type) throws IOException
- {
- if (fragment == null)
- {
- readRecord ();
- }
- if (type != this.type)
- {
- return 0;
- }
- return fragment.length - index;
- }
-
- void setSession (Session session)
- {
- this.session = session;
- }
-
- synchronized int read (byte[] buf, int off, int len, ContentType type)
- throws IOException
- {
- if (off < 0 || len < 0 || off + len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException ("size=" + buf.length +
- " off=" + off + " len=" + len);
- }
- if (fragment == null || index >= fragment.length)
- {
- readRecord ();
- }
- if (type != this.type)
- {
- return 0;
- }
- len = Math.min (len, fragment.length - index);
- System.arraycopy (fragment, index, buf, off, len);
- index += len;
- return len;
- }
-
- boolean pollClose () throws IOException
- {
- if (fragment == null || index >= fragment.length)
- {
- try
- {
- readRecord();
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert();
- if (alert.getDescription() == Alert.Description.CLOSE_NOTIFY)
- {
- return true;
- }
- throw ae;
- }
- }
- return false;
- }
-
- private void readRecord() throws IOException
- {
- type = ContentType.read (in);
- if ((type.getValue() & 0x80) != 0 || (type.getValue() & 0x40) != 0)
- {
- in.read();
- if ((type.getValue() & 0x40) != 0)
- {
- in.read();
- }
- type = ContentType.read(in);
- if (type != ContentType.CLIENT_HELLO_V2)
- {
- throw new SSLProtocolException("unsupported V2 message");
- }
- type = ContentType.HANDSHAKE;
- // Record this message, and re-present it as a normal handshake
- // layer message. ClientHello will handle the real parsing.
- ByteArrayOutputStream buffer = new ByteArrayOutputStream (256);
- buffer.write(1); // The type we just read.
- RecordingInputStream in2 = new RecordingInputStream (in, buffer);
- ProtocolVersion version = ProtocolVersion.read (in2);
- if (version.compareTo (ProtocolVersion.SSL_3) < 0)
- {
- throw new SSLProtocolException("unsupported client version");
- }
- int len = (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
- len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
- len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
- int count = 0;
- while (count < len)
- {
- int l = (int) in2.skip(len - count);
- if (l > 0)
- {
- count += l;
- }
- }
- fragment = buffer.toByteArray ();
- index = 0;
-
- // We can't be encrypted/MACed/compressed here, since a V2 message
- // will only be sent as the first message, and only by the client.
- return;
- }
- ProtocolVersion v = ProtocolVersion.read (in);
- int len = in.readUnsignedShort ();
- if (len > session.params.getFragmentLength() + 2048)
- {
- throw new OverflowException();
- }
- fragment = new byte [len];
- in.readFully (fragment);
-
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- ">> READ RECORD <<{4}" +
- "struct {{4}" +
- " type = {0};{4}" +
- " version = {1};{4}" +
- " length = {2};{4}" +
- "{3}{4}" +
- "} TLSCiphertext;", new Object[]
- {
- type, v, new Integer (len),
- Util.hexDump (fragment, " "),
- SystemProperties.getProperty ("line.separator")
- });
- }
-
- fragment = session.params.decrypt (fragment, v, type);
- index = 0;
-
- if (session.random != null)
- session.random.setSeed (fragment);
-
- if (type == ContentType.ALERT)
- {
- Alert alert = Alert.read (new ByteArrayInputStream (fragment));
- session.currentAlert = alert;
- }
- if (session.currentAlert != null)
- {
- throw new AlertException (session.currentAlert, false);
- }
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java
deleted file mode 100644
index 3bf228f2d69..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/* RecordOutputStream.java -- record layer output.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import gnu.classpath.SystemProperties;
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import java.util.logging.Logger;
-
-/**
- * An output stream for writing data to the record layer. All data written
- * to this stream (through any of the write methods) is immediately sent
- * as a full record, so it is advisable to write large arrays to the stream
- * instead of one byte at a time (alternatively, a {@link
- * java.io.BufferedOutputStream} can be used).
- */
-class RecordOutputStream extends FilterOutputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private static final boolean DEBUG_RECORD_LAYER = true;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- /**
- * The content type of this output stream.
- */
- private final ContentType type;
-
- /**
- * The security parameters.
- */
- private final SecurityParameters params;
-
- private final boolean emitEmpty;
-
- private static final byte[] ZERO = new byte[0];
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- RecordOutputStream (final OutputStream out, final ContentType type,
- final SecurityParameters params)
- {
- super (out);
- this.type = type;
- this.params = params;
- String empty = Util.getSecurityProperty ("jessie.emit.empty.records");
- if (empty == null)
- {
- // IE panics if it gets an empty record; so, leave this false
- // for the default.
- empty = "false";
- }
- emitEmpty = Boolean.valueOf (empty).booleanValue () &&
- type == ContentType.APPLICATION_DATA;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write (int b) throws IOException
- {
- write (new byte[] { (byte) b });
- }
-
- public void write (byte[] buf) throws IOException
- {
- write (buf, 0, buf.length);
- }
-
- public void write (byte[] buf, int off, int len) throws IOException
- {
- if (off < 0 || len < 0 || off + len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException ("size=" + buf.length +
- " off=" + off + " len=" + len);
- }
-
- int count = 0;
- int len2 = 0;
- do
- {
- if (emitEmpty)
- {
- byte[] fragment = params.encrypt (ZERO, 0, 0, type);
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- ">> WRITING RECORD <<{4}" +
- "struct {{4}" +
- " type = {0};{4}" +
- " version = {1};{4}" +
- " length = {2};{4}" +
- "{3}{4}" +
- "} TLSCiphertext;", new Object[]
- {
- type, params.getVersion (), new Integer (fragment.length),
- Util.hexDump (fragment, " "),
- SystemProperties.getProperty ("line.separator")
- });
- }
- out.write (type.getValue());
- params.getVersion().write (out);
- out.write ((fragment.length >>> 8) & 0xFF);
- out.write ( fragment.length & 0xFF);
- out.write (fragment);
- out.flush ();
- }
- len2 = Math.min (len - count, params.getFragmentLength());
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- "writing chunk size={0}", new Integer (len2));
- }
- synchronized (out)
- {
- byte[] fragment = params.encrypt (buf, off + count, len2, type);
- if (DEBUG_RECORD_LAYER)
- {
- logger.log (Component.SSL_RECORD_LAYER,
- ">> WRITING RECORD <<{4}" +
- "struct {{4}" +
- " type = {0};{4}" +
- " version = {1};{4}" +
- " length = {2};{4}" +
- "{3}{4}" +
- "} TLSCiphertext;", new Object[]
- {
- type, params.getVersion (), new Integer (fragment.length),
- Util.hexDump (fragment, " "),
- SystemProperties.getProperty ("line.separator")
- });
- }
- out.write (type.getValue());
- params.getVersion().write (out);
- out.write ((fragment.length >>> 8) & 0xFF);
- out.write ( fragment.length & 0xFF);
- out.write (fragment);
- out.flush ();
- }
- count += len2;
- }
- while (count < len);
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java
deleted file mode 100644
index d81b652d516..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/* RecordingInputStream.java -- Input stream that records data.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FilterInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * A filter input stream that records every byte read from the underlying
- * input stream. This class is useful for protocols that require portions
- * of the communication to be saved, such as the handshake and key
- * derivation in SSL.
- *
- * @author Casey Marshall (rsdio@metastatic.org)
- */
-class RecordingInputStream extends FilterInputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- protected ByteArrayOutputStream sink;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- RecordingInputStream(InputStream in)
- {
- this(in, new ByteArrayOutputStream());
- }
-
- RecordingInputStream(InputStream in, ByteArrayOutputStream sink)
- {
- super(in);
- this.sink = sink;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public synchronized int read() throws IOException
- {
- int i = in.read();
- sink.write(i);
- return i;
- }
-
- public synchronized int read(byte[] buf, int off, int len) throws IOException
- {
- int l = in.read(buf, off, len);
- sink.write(buf, off, l);
- return l;
- }
-
- public synchronized int read(byte[] buf) throws IOException
- {
- return read(buf, 0, buf.length);
- }
-
- public synchronized long skip(long len) throws IOException
- {
- long l = 0;
- int i = 0;
- byte[] buf = new byte[1024];
- while (l < len)
- {
- i = read(buf, 0, (int) Math.min((long) buf.length, len - l));
- if (i == -1)
- break;
- l += i;
- }
- return l;
- }
-
- /**
- * Returns all bytes recorded after this instance was created, or the last
- * call to {@link resetSink()}.
- *
- * @return The recorded bytes.
- */
- byte[] getBytes()
- {
- return sink.toByteArray();
- }
-
- /**
- * Clears the recording buffer off all previously-recorded bytes.
- */
- void resetSink()
- {
- sink.reset();
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java
new file mode 100644
index 00000000000..cf7c8e4e3d6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java
@@ -0,0 +1,315 @@
+/* SSLContextImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.PreSharedKeyManager;
+import gnu.javax.net.ssl.SRPTrustManager;
+
+import java.security.AccessController;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Our implementation of {@link SSLContextSpi}.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class SSLContextImpl extends SSLContextSpi
+{
+ AbstractSessionContext serverContext;
+ AbstractSessionContext clientContext;
+
+ PreSharedKeyManager pskManager;
+ X509ExtendedKeyManager keyManager;
+ X509TrustManager trustManager;
+ SRPTrustManager srpTrustManager;
+ SecureRandom random;
+
+ public SSLContextImpl()
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine()
+ */
+ protected @Override SSLEngine engineCreateSSLEngine()
+ {
+ return engineCreateSSLEngine(null, -1);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine(java.lang.String, int)
+ */
+ protected @Override SSLEngine engineCreateSSLEngine(String host, int port)
+ {
+ return new SSLEngineImpl(this, host, port);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetClientSessionContext()
+ */
+ protected @Override synchronized SSLSessionContext engineGetClientSessionContext()
+ {
+ if (clientContext == null)
+ {
+ try
+ {
+ clientContext = AbstractSessionContext.newInstance();
+ }
+ catch (SSLException ssle)
+ {
+ // XXX Ignore?
+ }
+ }
+ return clientContext;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetServerSessionContext()
+ */
+ protected @Override synchronized SSLSessionContext engineGetServerSessionContext()
+ {
+ if (serverContext == null)
+ {
+ try
+ {
+ serverContext = AbstractSessionContext.newInstance();
+ }
+ catch (SSLException ssle)
+ {
+ // XXX Ignore?
+ }
+ }
+ return serverContext;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetServerSocketFactory()
+ */
+ protected @Override SSLServerSocketFactory engineGetServerSocketFactory()
+ {
+ return new SSLServerSocketFactoryImpl(this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetSocketFactory()
+ */
+ protected @Override SSLSocketFactory engineGetSocketFactory()
+ {
+ return new SSLSocketFactoryImpl(this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineInit(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom)
+ */
+ protected @Override void engineInit(KeyManager[] keyManagers,
+ TrustManager[] trustManagers,
+ SecureRandom random)
+ throws KeyManagementException
+ {
+ keyManager = null;
+ trustManager = null;
+ srpTrustManager = null;
+ if (keyManagers != null)
+ {
+ for (int i = 0; i < keyManagers.length; i++)
+ {
+ if ((keyManagers[i] instanceof X509ExtendedKeyManager)
+ && keyManager == null)
+ keyManager = (X509ExtendedKeyManager) keyManagers[i];
+ if (keyManagers[i] instanceof PreSharedKeyManager
+ && pskManager == null)
+ pskManager = (PreSharedKeyManager) keyManagers[i];
+ }
+ }
+ if (keyManager == null)
+ keyManager = defaultKeyManager();
+ if (trustManagers != null)
+ {
+ for (int i = 0; i < trustManagers.length; i++)
+ {
+ if (trustManagers[i] instanceof X509TrustManager)
+ {
+ if (trustManager == null)
+ trustManager = (X509TrustManager) trustManagers[i];
+ }
+ else if (trustManagers[i] instanceof SRPTrustManager)
+ {
+ if (srpTrustManager == null)
+ srpTrustManager = (SRPTrustManager) trustManagers[i];
+ }
+ }
+ }
+ if (trustManager == null && srpTrustManager == null)
+ {
+ trustManager = defaultTrustManager();
+ }
+ if (random != null)
+ {
+ this.random = random;
+ }
+ else
+ {
+ this.random = defaultRandom();
+ }
+ }
+
+ /**
+ * Create and return a default key manager. The default is the JessieX509
+ * algorithm, loaded from either the jssecerts file, or the cacerts file.
+ *
+ * @return The default key manager instance.
+ * @throws KeyManagementException If the instance cannot be created.
+ */
+ private X509ExtendedKeyManager defaultKeyManager() throws KeyManagementException
+ {
+ KeyManagerFactory fact = null;
+ try
+ {
+ fact = KeyManagerFactory.getInstance("JessieX509", "Jessie");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException(nsae);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new KeyManagementException(nspe);
+ }
+ try
+ {
+ fact.init(null, null);
+ return (X509ExtendedKeyManager) fact.getKeyManagers()[0];
+ }
+ catch (NoSuchAlgorithmException nsae) { }
+ catch (KeyStoreException kse) { }
+ catch (UnrecoverableKeyException uke) { }
+ catch (IllegalStateException ise) { }
+
+ try
+ {
+ fact.init(new NullManagerParameters());
+ return (X509ExtendedKeyManager) fact.getKeyManagers()[0];
+ }
+ catch (Exception shouldNotHappen)
+ {
+ throw new Error(shouldNotHappen.toString());
+ }
+ }
+
+ /**
+ * Create and return a default trust manager. The default is the JessieX509
+ * algorithm, loaded from either the jssecerts file, or the cacerts file.
+ *
+ * @return The default trust manager instance.
+ * @throws KeyManagementException If the instance cannot be created.
+ */
+ private X509TrustManager defaultTrustManager() throws KeyManagementException
+ {
+ try
+ {
+ TrustManagerFactory fact =
+ TrustManagerFactory.getInstance("JessieX509", "Jessie");
+ fact.init((KeyStore) null);
+ return (X509TrustManager) fact.getTrustManagers()[0];
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException(nsae);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new KeyManagementException(nspe);
+ }
+ catch (KeyStoreException kse)
+ {
+ throw new KeyManagementException(kse);
+ }
+ }
+
+ /**
+ * Create a default secure PRNG. This is defined as either the algorithm
+ * given in the <code>gnu.javax.net.ssl.secureRandom</code> security
+ * property, or Fortuna if that property is not set. If none of these
+ * algorithms can be found, and instance created with the SecureRandom
+ * constructor is returned.
+ *
+ * @return The default secure PRNG instance.
+ */
+ private SecureRandom defaultRandom()
+ {
+ GetSecurityPropertyAction gspa
+ = new GetSecurityPropertyAction("gnu.javax.net.ssl.secureRandom");
+ String alg = AccessController.doPrivileged(gspa);
+ if (alg == null)
+ alg = "Fortuna";
+ SecureRandom rand = null;
+ try
+ {
+ rand = SecureRandom.getInstance(alg);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ rand = new SecureRandom();
+ }
+
+ return rand;
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java
new file mode 100644
index 00000000000..22c488d68c0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java
@@ -0,0 +1,842 @@
+/* SSLEngineImpl.java -- implementation of SSLEngine.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import gnu.java.security.util.ByteBufferOutputStream;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.SSLRecordHandler;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.DataFormatException;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+public final class SSLEngineImpl extends SSLEngine
+{
+ final SSLContextImpl contextImpl;
+ private SSLRecordHandler[] handlers;
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private SessionImpl session;
+ private InputSecurityParameters insec;
+ private OutputSecurityParameters outsec;
+ private boolean inClosed;
+ private boolean outClosed;
+ private boolean createSessions;
+ private boolean needClientAuth;
+ private boolean wantClientAuth;
+ private boolean initialHandshakeDone;
+ private AbstractHandshake handshake;
+ private Alert lastAlert;
+ private SSLEngineResult.HandshakeStatus handshakeStatus;
+ private boolean changeCipherSpec;
+
+ private String[] enabledSuites;
+ private String[] enabledProtocols;
+
+ /**
+ * We can receive any message chunked across multiple records,
+ * including alerts, even though all alert messages are only two
+ * bytes long. Handshake messages are de-chunked in the handshake
+ * handler, change-cipher-spec messages are always empty, and we
+ * don't care about chunking of application messages.
+ *
+ * This buffer will hold the incomplete alert that we receive, if
+ * any.
+ */
+ private final ByteBuffer alertBuffer;
+
+ private Mode mode;
+
+ private enum Mode { SERVER, CLIENT };
+
+ SSLEngineImpl (SSLContextImpl contextImpl, String host, int port)
+ {
+ super(host, port);
+ this.contextImpl = contextImpl;
+ handlers = new SSLRecordHandler[256];
+ session = new SessionImpl();
+ session.suite = CipherSuite.TLS_NULL_WITH_NULL_NULL;
+ session.version = ProtocolVersion.TLS_1_1;
+ byte[] sid = new byte[32];
+ contextImpl.random.nextBytes(sid);
+ session.setId(new Session.ID(sid));
+ session.setRandom(contextImpl.random);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "generated session ID {0} with random {1}",
+ session.id(), contextImpl.random);
+
+ // Begin with no encryption.
+ insec = new InputSecurityParameters (null, null, null, session,
+ CipherSuite.TLS_NULL_WITH_NULL_NULL);
+ outsec = new OutputSecurityParameters (null, null, null, session,
+ CipherSuite.TLS_NULL_WITH_NULL_NULL);
+ inClosed = false;
+ outClosed = false;
+ needClientAuth = false;
+ wantClientAuth = false;
+ createSessions = true;
+ initialHandshakeDone = false;
+ alertBuffer = ByteBuffer.wrap (new byte[2]);
+ mode = null;
+ lastAlert = null;
+ handshakeStatus = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+ changeCipherSpec = false;
+
+ // Set up default protocols and suites.
+ enabledProtocols = new String[] {
+ ProtocolVersion.TLS_1_1.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.SSL_3.toString()
+ };
+ enabledSuites = defaultSuites();
+ }
+
+ static String[] defaultSuites()
+ {
+ return new String[] {
+ CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_RC4_128_MD5.toString(),
+ CipherSuite.TLS_RSA_WITH_RC4_128_SHA.toString(),
+ CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5.toString(),
+ CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_NULL_MD5.toString(),
+ CipherSuite.TLS_RSA_WITH_NULL_SHA.toString()
+ };
+ }
+
+ // XXX implement?
+ /*public void registerHandler (final int contentType,
+ SSLRecordHandler handler)
+ throws SSLException
+ {
+ if (type.equals (ContentType.CHANGE_CIPHER_SPEC)
+ || type.equals (ContentType.ALERT)
+ || type.equals (ContentType.HANDSHAKE)
+ || type.equals (ContentType.APPLICATION_DATA))
+ throw new SSLException ("can't override handler for content type " + type);
+ int i = type.getValue ();
+ if (i < 0 || i > 255)
+ throw new SSLException ("illegal content type: " + type);
+ handlers[i] = handler;
+ }*/
+
+ @Override
+ public void beginHandshake () throws SSLException
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0} handshake begins", mode);
+
+ if (mode == null)
+ throw new IllegalStateException("setUseClientMode was never used");
+
+ switch (mode)
+ {
+ case SERVER:
+ if (getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
+ throw new SSLException("handshake already in progress");
+ try
+ {
+ handshake = new ServerHandshake(initialHandshakeDone, this);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ break;
+
+ case CLIENT:
+ try
+ {
+ handshake = new ClientHandshake(this);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void closeInbound()
+ {
+ inClosed = true;
+ }
+
+ @Override
+ public void closeOutbound()
+ {
+ lastAlert = new Alert(Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
+ }
+
+ @Override
+ public Runnable getDelegatedTask()
+ {
+ if (handshake == null)
+ return null;
+ return handshake.getTask();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites()
+ {
+ return (String[]) enabledSuites.clone();
+ }
+
+ @Override
+ public String[] getEnabledProtocols()
+ {
+ return (String[]) enabledProtocols.clone();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation()
+ {
+ return createSessions;
+ }
+
+ @Override
+ public HandshakeStatus getHandshakeStatus()
+ {
+ if (handshake == null)
+ return HandshakeStatus.NOT_HANDSHAKING;
+ return handshake.status();
+ }
+
+ @Override
+ public boolean getNeedClientAuth()
+ {
+ return needClientAuth;
+ }
+
+ @Override
+ public SSLSession getSession()
+ {
+ return session;
+ }
+
+ @Override
+ public boolean getUseClientMode ()
+ {
+ return (mode == Mode.CLIENT);
+ }
+
+ @Override
+ public boolean getWantClientAuth()
+ {
+ return wantClientAuth;
+ }
+
+ @Override
+ public boolean isInboundDone()
+ {
+ return inClosed;
+ }
+
+ @Override
+ public boolean isOutboundDone()
+ {
+ return outClosed;
+ }
+
+ @Override
+ public void setEnableSessionCreation(final boolean createSessions)
+ {
+ this.createSessions = createSessions;
+ }
+
+ @Override
+ public void setEnabledCipherSuites(final String[] suites)
+ {
+ if (suites.length == 0)
+ throw new IllegalArgumentException("need at least one suite");
+ enabledSuites = (String[]) suites.clone();
+ }
+
+ @Override
+ public void setEnabledProtocols(final String[] protocols)
+ {
+ if (protocols.length == 0)
+ throw new IllegalArgumentException("need at least one protocol");
+ enabledProtocols = (String[]) protocols.clone();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites()
+ {
+ // XXX if we ever want to support "pluggable" cipher suites, we'll need
+ // to figure this out.
+
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ @Override
+ public String[] getSupportedProtocols()
+ {
+ return new String[] { ProtocolVersion.SSL_3.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.TLS_1_1.toString() };
+ }
+
+ @Override
+ public void setNeedClientAuth(final boolean needClientAuth)
+ {
+ this.needClientAuth = needClientAuth;
+ }
+
+ @Override
+ public void setUseClientMode (final boolean clientMode)
+ {
+ if (clientMode)
+ mode = Mode.CLIENT;
+ else
+ mode = Mode.SERVER;
+ }
+
+ public @Override void setWantClientAuth(final boolean wantClientAuth)
+ {
+ this.wantClientAuth = wantClientAuth;
+ }
+
+ public @Override SSLEngineResult unwrap (final ByteBuffer source,
+ final ByteBuffer[] sinks,
+ final int offset, final int length)
+ throws SSLException
+ {
+ if (mode == null)
+ throw new IllegalStateException ("setUseClientMode was never called");
+
+ if (inClosed)
+ return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+ handshakeStatus, 0, 0);
+
+ if (source.remaining() < 5)
+ {
+ return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW,
+ handshakeStatus, 0, 0);
+ }
+
+ Record record = null;
+ boolean helloV2 = false;
+
+ // XXX: messages may be chunked across multiple records; does this
+ // include the SSLv2 message? I don't think it does, but we should
+ // make sure.
+ if (!getUseClientMode() && (source.get(source.position()) & 0x80) == 0x80)
+ {
+ if (handshake == null)
+ beginHandshake();
+ int hellolen = source.getShort(source.position()) & 0x7FFF;
+ this.handshake.handleV2Hello(source.slice());
+ if (!insec.cipherSuite().equals (CipherSuite.TLS_NULL_WITH_NULL_NULL))
+ throw new SSLException ("received SSLv2 client hello in encrypted "
+ + "session; this is invalid.");
+ if (Debug.DEBUG)
+ logger.log (Component.SSL_RECORD_LAYER,
+ "converting SSLv2 client hello to version 3 hello");
+
+ source.getShort(); // skip length
+ ClientHelloV2 v2 = new ClientHelloV2(source.slice());
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_RECORD_LAYER, "v2 hello: {0}", v2);
+
+ List<CipherSuite> suites = v2.cipherSpecs();
+
+ ClientHelloBuilder hello = new ClientHelloBuilder();
+ hello.setVersion(v2.version ());
+
+ Random random = hello.random();
+ byte[] challenge = v2.challenge();
+ if (challenge.length < 32)
+ {
+ byte[] b = new byte[32];
+ System.arraycopy(challenge, 0, b, b.length - challenge.length,
+ challenge.length);
+ challenge = b;
+ }
+ random.setGmtUnixTime((challenge[0] & 0xFF) << 24
+ | (challenge[1] & 0xFF) << 16
+ | (challenge[2] & 0xFF) << 8
+ | (challenge[3] & 0xFF));
+ random.setRandomBytes(challenge, 4);
+
+ byte[] sessionId = v2.sessionId();
+ hello.setSessionId(sessionId, 0, sessionId.length);
+ hello.setCipherSuites(suites);
+ ArrayList<CompressionMethod> comps = new ArrayList<CompressionMethod>(1);
+ comps.add(CompressionMethod.NULL);
+ hello.setCompressionMethods(comps);
+
+ record = new Record(ByteBuffer.allocate(hello.length() + 9));
+ record.setContentType(ContentType.HANDSHAKE);
+ record.setVersion(v2.version());
+ record.setLength(hello.length() + 4);
+
+ Handshake handshake = new Handshake(record.fragment());
+ handshake.setLength(hello.length());
+ handshake.setType(Handshake.Type.CLIENT_HELLO);
+
+ handshake.bodyBuffer().put(hello.buffer());
+ source.position(source.position() + hellolen);
+ helloV2 = true;
+ }
+ else
+ record = new Record(source);
+
+ ContentType type = record.contentType ();
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_RECORD_LAYER, "input record:\n{0}", record);
+
+ if (record.length() > session.getPacketBufferSize() - 5)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.RECORD_OVERFLOW);
+ throw new AlertException(lastAlert);
+ }
+
+ ByteBufferOutputStream sysMsg = null;
+ ByteBuffer msg = null;
+
+ int produced = 0;
+ try
+ {
+ // Application data will get decrypted directly into the user's
+ // output buffers.
+ if (record.contentType() == ContentType.APPLICATION_DATA)
+ produced = insec.decrypt(record, sinks, offset, length);
+ else
+ {
+ if (insec.cipherSuite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
+ msg = record.fragment();
+ else
+ {
+ sysMsg = new ByteBufferOutputStream();
+ insec.decrypt(record, sysMsg);
+ }
+ }
+
+ // Advance the input buffer past the record we just read.
+ if (!helloV2)
+ source.position(source.position() + record.length() + 5);
+ }
+ catch (BufferOverflowException boe)
+ {
+ // We throw this if the output buffers are not large enough; signal
+ // the caller about this.
+ logger.log(Component.SSL_RECORD_LAYER, "buffer overflow when decrypting", boe);
+ return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
+ handshakeStatus, 0, 0);
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.BAD_RECORD_MAC);
+ throw new AlertException(lastAlert, ibse);
+ }
+ catch (DataFormatException dfe)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.DECOMPRESSION_FAILURE);
+ throw new AlertException(lastAlert, dfe);
+ }
+ catch (MacException me)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.BAD_RECORD_MAC);
+ throw new AlertException(lastAlert, me);
+ }
+ catch (ShortBufferException sbe)
+ {
+ // We've messed up if this happens.
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR);
+ throw new AlertException(lastAlert, sbe);
+ }
+
+ SSLEngineResult result = null;
+
+ // If we need to handle the output here, do it. Otherwise, the output
+ // has been stored in the supplied output buffers.
+ if (sysMsg != null)
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "sysmessage {0}", sysMsg);
+ msg = sysMsg.buffer();
+ }
+
+ if (type == ContentType.CHANGE_CIPHER_SPEC)
+ {
+ // We *may* get a partial message, even though the message is only
+ // one byte long.
+ if (msg.remaining() == 0)
+ {
+ result = new SSLEngineResult (SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5, 0);
+ }
+ else
+ {
+ byte b = msg.get();
+ if (b != 1)
+ throw new SSLException ("unknown ChangeCipherSpec value: " + (b & 0xFF));
+ InputSecurityParameters params = handshake.getInputParams();
+ logger.log (Component.SSL_RECORD_LAYER,
+ "switching to input security parameters {0}",
+ params.cipherSuite());
+ insec = params;
+ result = new SSLEngineResult (SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5, 0);
+ }
+ }
+ else if (type == ContentType.ALERT)
+ {
+ int len = 0;
+ if (alertBuffer.position() > 0)
+ {
+ alertBuffer.put(msg.get());
+ len = 1;
+ }
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "processing alerts {0}",
+ Util.wrapBuffer(msg));
+ len += msg.remaining() / 2;
+ Alert[] alerts = new Alert[len];
+ int i = 0;
+ if (alertBuffer.position() > 0)
+ {
+ alertBuffer.flip();
+ alerts[0] = new Alert(alertBuffer);
+ i++;
+ }
+ while (i < alerts.length)
+ {
+ alerts[i++] = new Alert(msg.duplicate());
+ msg.position(msg.position() + 2);
+ }
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "alerts: {0}", alerts.length);
+
+ for (i = 0; i < alerts.length; i++)
+ {
+ if (alerts[i].level() == Alert.Level.FATAL)
+ throw new AlertException(alerts[i], false);
+ if (alerts[i].description() != Alert.Description.CLOSE_NOTIFY)
+ logger.log(java.util.logging.Level.WARNING,
+ "received alert: {0}", alerts[i]);
+ if (alerts[i].description() == Alert.Description.CLOSE_NOTIFY)
+ inClosed = true;
+ }
+
+ if (msg.hasRemaining())
+ alertBuffer.position(0).limit(2);
+
+ result = new SSLEngineResult (SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5, 0);
+ }
+ else if (type == ContentType.HANDSHAKE)
+ {
+ if (handshake == null)
+ beginHandshake();
+ try
+ {
+ handshakeStatus = handshake.handleInput(msg);
+ }
+ catch (AlertException ae)
+ {
+ lastAlert = ae.alert();
+ return new SSLEngineResult(SSLEngineResult.Status.OK,
+ SSLEngineResult.HandshakeStatus.NEED_WRAP,
+ 0, 0);
+ }
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}", handshakeStatus);
+ result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5,
+ 0);
+ if (handshakeStatus == HandshakeStatus.FINISHED)
+ {
+ handshake = null;
+ handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ }
+ }
+ else if (type == ContentType.APPLICATION_DATA)
+ {
+ // Do nothing more; the application data has been put into
+ // the output buffers.
+ result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5,
+ produced);
+ }
+ else
+ {
+ SSLRecordHandler handler = handlers[type.getValue()];
+ if (handler != null)
+ {
+ result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5,
+ 0);
+ }
+ else
+ throw new SSLException ("unknown content type: " + type);
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "return result: {0}", result);
+
+ return result;
+ }
+
+ public @Override SSLEngineResult wrap (ByteBuffer[] sources, int offset, int length,
+ ByteBuffer sink)
+ throws SSLException
+ {
+ if (mode == null)
+ throw new IllegalStateException ("setUseClientMode was never called");
+
+ if (outClosed)
+ return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+ handshakeStatus, 0, 0);
+
+ ContentType type = null;
+ ByteBuffer sysMessage = null;
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "wrap {0} {1} {2} {3} / {4}",
+ sources, offset, length, sink, getHandshakeStatus());
+ if (lastAlert != null)
+ {
+ type = ContentType.ALERT;
+ sysMessage = ByteBuffer.allocate(2);
+ Alert alert = new Alert(sysMessage);
+ alert.setDescription(lastAlert.description());
+ alert.setLevel(lastAlert.level());
+ if (lastAlert.description() == Alert.Description.CLOSE_NOTIFY)
+ outClosed = true;
+ }
+ else if (changeCipherSpec)
+ {
+ type = ContentType.CHANGE_CIPHER_SPEC;
+ sysMessage = ByteBuffer.allocate(1);
+ sysMessage.put(0, (byte) 1);
+ }
+ else if (getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)
+ {
+ // If we are not encrypting, optimize the handshake to fill
+ // the buffer directly.
+ if (outsec.suite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
+ {
+ int orig = sink.position();
+ sink.order(ByteOrder.BIG_ENDIAN);
+ sink.put((byte) ContentType.HANDSHAKE.getValue());
+ sink.putShort((short) session.version.rawValue());
+ sink.putShort((short) 0);
+ handshakeStatus = handshake.handleOutput(sink);
+ int produced = sink.position() - orig;
+ sink.putShort(orig + 3, (short) (produced - 5));
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
+ new Record((ByteBuffer) sink.duplicate().position(orig)));
+ SSLEngineResult result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus, 0, produced);
+
+ // Note, this will only happen if we transition from
+ // TLS_NULL_WITH_NULL_NULL *to* TLS_NULL_WITH_NULL_NULL, which
+ // doesn't make a lot of sense, but we support it anyway.
+ if (handshakeStatus == HandshakeStatus.FINISHED)
+ {
+ handshake = null; // finished with it.
+ handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ }
+ return result;
+ }
+
+ // Rough guideline; XXX.
+ sysMessage = ByteBuffer.allocate(sink.remaining() - 2048);
+ type = ContentType.HANDSHAKE;
+ try
+ {
+ handshakeStatus = handshake.handleOutput(sysMessage);
+ }
+ catch (AlertException ae)
+ {
+ lastAlert = ae.alert();
+ return new SSLEngineResult(Status.OK,
+ HandshakeStatus.NEED_WRAP, 0, 0);
+ }
+ sysMessage.flip();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}",
+ handshakeStatus);
+ }
+
+ int produced = 0;
+ int consumed = 0;
+
+ try
+ {
+ int orig = sink.position();
+ int[] inout = null;
+ if (sysMessage != null)
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "encrypt system message {0} to {1}", sysMessage, sink);
+ inout = outsec.encrypt(new ByteBuffer[] { sysMessage }, 0, 1,
+ type, sink);
+ produced = inout[1];
+ }
+ else
+ {
+ inout = outsec.encrypt(sources, offset, length,
+ ContentType.APPLICATION_DATA, sink);
+ consumed = inout[0];
+ produced = inout[1];
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
+ new Record((ByteBuffer) sink.duplicate().position(orig).limit(produced)));
+ }
+ catch (ShortBufferException sbe)
+ {
+ // We don't expect this to happen, except for bugs; signal an
+ // internal error.
+ lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+ return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ // We don't expect this to happen, except for bugs; signal an
+ // internal error.
+ lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+ return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+ }
+ catch (DataFormatException dfe)
+ {
+ // We don't expect this to happen; signal an internal error.
+ lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+ return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+ }
+
+ if (lastAlert != null && lastAlert.level() == Alert.Level.FATAL)
+ {
+ AlertException ae = new AlertException(lastAlert);
+ lastAlert = null;
+ throw ae;
+ }
+
+ if (changeCipherSpec)
+ {
+ outsec = handshake.getOutputParams();
+ changeCipherSpec = false;
+ }
+ SSLEngineResult result
+ = new SSLEngineResult(outClosed ? SSLEngineResult.Status.CLOSED
+ : SSLEngineResult.Status.OK,
+ handshakeStatus, consumed, produced);
+ if (handshakeStatus == HandshakeStatus.FINISHED)
+ {
+ handshake = null; // done with it.
+ handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ }
+ return result;
+ }
+
+ // Package-private methods.
+
+ SessionImpl session ()
+ {
+ return session;
+ }
+
+ void setSession(SessionImpl session)
+ {
+ this.session = session;
+ }
+
+ void changeCipherSpec()
+ {
+ changeCipherSpec = true;
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java
deleted file mode 100644
index 2f8c6cfe665..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/* SSLRSASignature.java -- SSL's RSA signature algorithm.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.math.BigInteger;
-
-import java.security.InvalidKeyException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import gnu.java.security.hash.HashFactory;
-import gnu.java.security.hash.IMessageDigest;
-import gnu.java.security.sig.ISignature;
-import gnu.java.security.sig.rsa.RSA;
-
-/**
- * The RSA signature algorithm as used in the SSL protocol. Note that this
- * is different from the RSA signature used to verify certificates.
- *
- * <p>This signature scheme works as follows:</p>
- *
- * <blockquote><p><pre>digitally-signed struct {
- * opaque md5_hash[16];
- * opaque sha_hash[20];
- * }</pre></p></blockquote>
- *
- * <p>Where a <code>digitally-signed struct</code> is RSA-encrypted with
- * block type 0 or 1 according to PKCS #1, version 1.5.</p>
- */
-final class SSLRSASignature implements ISignature
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private RSAPublicKey pubkey;
- private RSAPrivateKey privkey;
- private final IMessageDigest md5, sha;
- private boolean initVerify = false, initSign = false;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLRSASignature()
- {
- this(HashFactory.getInstance("MD5"), HashFactory.getInstance("SHA-1"));
- }
-
- SSLRSASignature(IMessageDigest md5, IMessageDigest sha)
- {
- this.md5 = md5;
- this.sha = sha;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String name()
- {
- return "RSA/SSL";
- }
-
- public void setupVerify(Map attrib)
- {
- PublicKey key = (PublicKey) attrib.get(VERIFIER_KEY);
- if (key == null)
- {
- if (initSign)
- {
- return; // re-use.
- }
- throw new IllegalArgumentException("no key supplied");
- }
- if (!(key instanceof RSAPublicKey))
- {
- throw new IllegalArgumentException("not an RSA key");
- }
- pubkey = (RSAPublicKey) key;
- privkey = null;
- initSign = false;
- initVerify = true;
- }
-
- public void setupSign(Map attrib)
- {
- PrivateKey key = (PrivateKey) attrib.get(SIGNER_KEY);
- if (key == null)
- {
- if (initVerify)
- {
- return; // re-use.
- }
- throw new IllegalArgumentException("no key supplied");
- }
- if (!(key instanceof RSAPrivateKey))
- {
- throw new IllegalArgumentException("not an RSA key");
- }
- privkey = (RSAPrivateKey) key;
- pubkey = null;
- initVerify = false;
- initSign = true;
- }
-
- public void update(byte b)
- {
- if (!initVerify && !initSign)
- {
- throw new IllegalStateException();
- }
- md5.update(b);
- sha.update(b);
- }
-
- public void update(byte[] buf, int off, int len)
- {
- if (!initVerify && !initSign)
- {
- throw new IllegalStateException();
- }
- md5.update(buf, off, len);
- sha.update(buf, off, len);
- }
-
- public Object sign()
- {
- if (!initSign)
- {
- throw new IllegalStateException();
- }
- // Pad the hash results with RSA block type 1.
- final int k = (privkey.getModulus().bitLength() + 7) >>> 3;
- final byte[] d = Util.concat(md5.digest(), sha.digest());
- if (k - 11 < d.length)
- {
- throw new IllegalArgumentException("message too long");
- }
- final byte[] eb = new byte[k];
- eb[0] = 0x00;
- eb[1] = 0x01;
- for (int i = 2; i < k - d.length - 1; i++)
- {
- eb[i] = (byte) 0xFF;
- }
- System.arraycopy(d, 0, eb, k - d.length, d.length);
- BigInteger EB = new BigInteger(eb);
-
- // Private-key encrypt the padded hashes.
- BigInteger EM = RSA.sign(privkey, EB);
- return Util.trim(EM);
- }
-
- public boolean verify(Object signature)
- {
- if (!initVerify)
- {
- throw new IllegalStateException();
- }
- // Public-key decrypt the signature representative.
- BigInteger EM = new BigInteger(1, (byte[]) signature);
- BigInteger EB = RSA.verify(pubkey, EM);
-
- // Unpad the decrypted message.
- int i = 0;
- final byte[] eb = EB.toByteArray();
- if (eb[0] == 0x00)
- {
- for (i = 0; i < eb.length && eb[i] == 0x00; i++);
- }
- else if (eb[0] == 0x01)
- {
- for (i = 1; i < eb.length && eb[i] != 0x00; i++)
- {
- if (eb[i] != (byte) 0xFF)
- {
- throw new IllegalArgumentException("bad padding");
- }
- }
- i++;
- }
- else
- {
- throw new IllegalArgumentException("decryption failed");
- }
- byte[] d1 = Util.trim(eb, i, eb.length - i);
- byte[] d2 = Util.concat(md5.digest(), sha.digest());
- return Arrays.equals(d1, d2);
- }
-
- public Object clone()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java
new file mode 100644
index 00000000000..415efc6f58d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java
@@ -0,0 +1,233 @@
+/* SSLRSASignatureImpl.java -- SSL/TLS RSA implementation.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.sig.rsa.RSA;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+/**
+ * An implementation of of the RSA signature algorithm; this is an RSA
+ * encrypted MD5 hash followed by a SHA-1 hash.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLRSASignatureImpl extends SignatureSpi
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private RSAPublicKey pubkey;
+ private RSAPrivateKey privkey;
+ private final MessageDigest md5, sha;
+ private boolean initSign = false;
+ private boolean initVerify = false;
+
+ public SSLRSASignatureImpl() throws NoSuchAlgorithmException
+ {
+ md5 = MessageDigest.getInstance("MD5");
+ sha = MessageDigest.getInstance("SHA-1");
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineInitVerify(java.security.PublicKey)
+ */
+ @Override protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ pubkey = (RSAPublicKey) publicKey;
+ initVerify = true;
+ initSign = false;
+ privkey = null;
+ }
+ catch (ClassCastException cce)
+ {
+ throw new InvalidKeyException(cce);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineInitSign(java.security.PrivateKey)
+ */
+ @Override protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ privkey = (RSAPrivateKey) privateKey;
+ initSign = true;
+ initVerify = false;
+ pubkey = null;
+ }
+ catch (ClassCastException cce)
+ {
+ throw new InvalidKeyException(cce);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineUpdate(byte)
+ */
+ @Override protected void engineUpdate(byte b) throws SignatureException
+ {
+ if (!initSign && !initVerify)
+ throw new IllegalStateException("not initialized");
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update 0x{0}",
+ Util.formatInt(b & 0xFF, 16, 2));
+ md5.update(b);
+ sha.update(b);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineUpdate(byte[], int, int)
+ */
+ @Override protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException
+ {
+ if (!initSign && !initVerify)
+ throw new IllegalStateException("not initialized");
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update\n{0}",
+ Util.hexDump(b, off, len, ">> "));
+ md5.update(b, off, len);
+ sha.update(b, off, len);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineSign()
+ */
+ @Override protected byte[] engineSign() throws SignatureException
+ {
+ // FIXME we need to add RSA blinding to this, somehow.
+
+ if (!initSign)
+ throw new SignatureException("not initialized for signing");
+ // Pad the hash results with RSA block type 1.
+ final int k = (privkey.getModulus().bitLength() + 7) >>> 3;
+ final byte[] d = Util.concat(md5.digest(), sha.digest());
+ if (k - 11 < d.length)
+ throw new SignatureException("message too long");
+ final byte[] eb = new byte[k];
+ eb[0] = 0x00;
+ eb[1] = 0x01;
+ for (int i = 2; i < k - d.length - 1; i++)
+ eb[i] = (byte) 0xFF;
+ System.arraycopy(d, 0, eb, k - d.length, d.length);
+ BigInteger EB = new BigInteger(eb);
+
+ // Private-key encrypt the padded hashes.
+ BigInteger EM = RSA.sign(privkey, EB);
+ return Util.trim(EM);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineVerify(byte[])
+ */
+ @Override protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException
+ {
+ if (!initVerify)
+ throw new SignatureException("not initialized for verifying");
+
+ // Public-key decrypt the signature representative.
+ BigInteger EM = new BigInteger(1, (byte[]) sigBytes);
+ BigInteger EB = RSA.verify(pubkey, EM);
+
+ // Unpad the decrypted message.
+ int i = 0;
+ final byte[] eb = EB.toByteArray();
+ if (eb[0] == 0x00)
+ {
+ for (i = 0; i < eb.length && eb[i] == 0x00; i++);
+ }
+ else if (eb[0] == 0x01)
+ {
+ for (i = 1; i < eb.length && eb[i] != 0x00; i++)
+ {
+ if (eb[i] != (byte) 0xFF)
+ {
+ throw new SignatureException("bad padding");
+ }
+ }
+ i++;
+ }
+ else
+ {
+ throw new SignatureException("decryption failed");
+ }
+ byte[] d1 = Util.trim(eb, i, eb.length - i);
+ byte[] d2 = Util.concat(md5.digest(), sha.digest());
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "SSL/RSA d1:{0} d2:{1}",
+ Util.toHexString(d1, ':'), Util.toHexString(d2, ':'));
+ return Arrays.equals(d1, d2);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineSetParameter(java.lang.String, java.lang.Object)
+ */
+ @Override protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException
+ {
+ throw new InvalidParameterException("parameters not supported");
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineGetParameter(java.lang.String)
+ */
+ @Override protected Object engineGetParameter(String param)
+ throws InvalidParameterException
+ {
+ throw new InvalidParameterException("parameters not supported");
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java
deleted file mode 100644
index ee96b8d1bdf..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/* SSLServerSocket.java -- SSL server socket.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.IOException;
-
-import java.net.InetAddress;
-import java.net.Socket;
-
-import java.security.SecureRandom;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-class SSLServerSocket extends javax.net.ssl.SSLServerSocket
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private SessionContext sessions;
- private SortedSet enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
- private List enabledSuites = new ArrayList(SSLSocket.supportedSuites);
- private boolean clientMode = false;
- private boolean needClientAuth = false;
- private boolean wantClientAuth = false;
- private boolean createSessions = true;
- private SRPTrustManager srpTrustManager;
- private X509TrustManager trustManager;
- private X509KeyManager keyManager;
- private SecureRandom random;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLServerSocket() throws IOException
- {
- super();
- }
-
- SSLServerSocket(int port) throws IOException
- {
- super(port);
- }
-
- SSLServerSocket(int port, int backlog) throws IOException
- {
- super(port, backlog);
- }
-
- SSLServerSocket(int port, int backlog, InetAddress address)
- throws IOException
- {
- super(port, backlog, address);
- }
-
- // SSL methods.
- // -------------------------------------------------------------------------
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
- }
-
- public String[] getEnabledCipherSuites()
- {
- synchronized (enabledSuites)
- {
- String[] s = new String[enabledSuites.size()];
- int i = 0;
- for (Iterator it = enabledSuites.iterator(); it.hasNext(); )
- s[i++] = it.next().toString();
- return s;
- }
- }
-
- public void setEnabledCipherSuites(String[] suites)
- {
- if (suites == null || suites.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < suites.length; i++)
- if (CipherSuite.forName(suites[i]) == null)
- throw new IllegalArgumentException("unsupported suite: " +
- suites[i]);
- synchronized (enabledSuites)
- {
- enabledSuites.clear();
- for (int i = 0; i < suites.length; i++)
- {
- CipherSuite suite = CipherSuite.forName(suites[i]);
- if (!enabledSuites.contains(suite))
- enabledSuites.add(suite);
- }
- }
- }
-
- public String[] getSupportedProtocols()
- {
- return new String[] { "SSLv3", "TLSv1", "TLSv1.1" };
- }
-
- public String[] getEnabledProtocols()
- {
- synchronized (enabledProtocols)
- {
- String[] s = new String[enabledProtocols.size()];
- int i = 0;
- for (Iterator it = enabledProtocols.iterator(); it.hasNext(); )
- s[i++] = it.next().toString();
- return s;
- }
- }
-
- public void setEnabledProtocols(String[] protocols)
- {
- if (protocols == null || protocols.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < protocols.length; i++)
- {
- if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
- protocols[i].equalsIgnoreCase("TLSv1") ||
- protocols[i].equalsIgnoreCase("TLSv1.1")))
- {
- throw new
- IllegalArgumentException("unsupported protocol: " +
- protocols[i]);
- }
- }
- synchronized (enabledProtocols)
- {
- enabledProtocols.clear();
- for (int i = 0; i < protocols.length; i++)
- {
- if (protocols[i].equalsIgnoreCase("SSLv3"))
- enabledProtocols.add(ProtocolVersion.SSL_3);
- else if (protocols[i].equalsIgnoreCase("TLSv1"))
- enabledProtocols.add(ProtocolVersion.TLS_1);
- else
- enabledProtocols.add(ProtocolVersion.TLS_1_1);
- }
- }
- }
-
- public void setUseClientMode(boolean clientMode)
- {
- this.clientMode = clientMode;
- }
-
- public boolean getUseClientMode()
- {
- return clientMode;
- }
-
- public void setNeedClientAuth(boolean needClientAuth)
- {
- this.needClientAuth = needClientAuth;
- }
-
- public boolean getNeedClientAuth()
- {
- return needClientAuth;
- }
-
- public void setWantClientAuth(boolean wantClientAuth)
- {
- this.wantClientAuth = wantClientAuth;
- }
-
- public boolean getWantClientAuth()
- {
- return wantClientAuth;
- }
-
- // I misspelled this method in javax.net.SSLServerSocket, and that version
- // made it into kaffe 1.1.4.
- public void setEnabledSessionCreation(boolean createSessions)
- {
- setEnableSessionCreation(createSessions);
- }
-
- public void setEnableSessionCreation(boolean createSessions)
- {
- this.createSessions = createSessions;
- }
-
- public boolean getEnableSessionCreation()
- {
- return createSessions;
- }
-
- // Socket methods.
- // -------------------------------------------------------------------------
-
- public Socket accept() throws IOException
- {
- SSLSocket socket = new SSLSocket();
- implAccept(socket);
- socket.setUseClientMode(clientMode);
- socket.setNeedClientAuth(needClientAuth);
- socket.setWantClientAuth(wantClientAuth);
- socket.setEnableSessionCreation(createSessions);
- socket.setSessionContext(sessions);
- socket.setEnabledCipherSuites(new ArrayList(enabledSuites));
- socket.setEnabledProtocols(new TreeSet(enabledProtocols));
- socket.setSRPTrustManager(srpTrustManager);
- socket.setTrustManager(trustManager);
- socket.setKeyManager(keyManager);
- socket.setRandom(random);
- return socket;
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- void setSessionContext(SessionContext sessions)
- {
- this.sessions = sessions;
- }
-
- void setKeyManager(X509KeyManager keyManager)
- {
- this.keyManager = keyManager;
- }
-
- void setTrustManager(X509TrustManager trustManager)
- {
- this.trustManager = trustManager;
- }
-
- void setSRPTrustManager(SRPTrustManager srpTrustManager)
- {
- this.srpTrustManager = srpTrustManager;
- }
-
- void setRandom(SecureRandom random)
- {
- this.random = random;
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
deleted file mode 100644
index 72fb512c582..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/* SSLServerSocketFactory.java -- factory for SSL server sockets.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.IOException;
-
-import java.net.InetAddress;
-import java.net.ServerSocket;
-
-import java.security.SecureRandom;
-
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-class SSLServerSocketFactory extends javax.net.ssl.SSLServerSocketFactory
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final SessionContext sessions;
- private final X509KeyManager keyManager;
- private final X509TrustManager trustManager;
- private final SRPTrustManager srpTrustManager;
- private final SecureRandom random;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLServerSocketFactory(X509TrustManager trustManager,
- SRPTrustManager srpTrustManager,
- X509KeyManager keyManager,
- SecureRandom random,
- SessionContext sessions)
- {
- super();
- this.trustManager = trustManager;
- this.srpTrustManager = srpTrustManager;
- this.keyManager = keyManager;
- this.random = random;
- this.sessions = sessions;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String[] getDefaultCipherSuites()
- {
- return getSupportedCipherSuites();
- }
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
- }
-
- public ServerSocket createServerSocket() throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket();
- setup(socket);
- return socket;
- }
-
- public ServerSocket createServerSocket(int port) throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket(port);
- setup(socket);
- return socket;
- }
-
- public ServerSocket createServerSocket(int port, int backlog)
- throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket(port, backlog);
- setup(socket);
- return socket;
- }
-
- public ServerSocket createServerSocket(int port, int backlog, InetAddress addr)
- throws IOException
- {
- SSLServerSocket socket = new SSLServerSocket(port, backlog, addr);
- setup(socket);
- return socket;
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private void setup(SSLServerSocket socket)
- {
- socket.setSessionContext(sessions);
- socket.setKeyManager(keyManager);
- socket.setTrustManager(trustManager);
- socket.setSRPTrustManager(srpTrustManager);
- socket.setRandom(random);
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java
new file mode 100644
index 00000000000..dc80dc78248
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java
@@ -0,0 +1,108 @@
+/* SSLServerSocketFactoryImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import javax.net.ssl.SSLServerSocketFactory;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory
+{
+ private final SSLContextImpl contextImpl;
+
+ public SSLServerSocketFactoryImpl(SSLContextImpl contextImpl)
+ {
+ this.contextImpl = contextImpl;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocketFactory#getDefaultCipherSuites()
+ */
+ @Override public String[] getDefaultCipherSuites()
+ {
+ return SSLEngineImpl.defaultSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocketFactory#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ServerSocketFactory#createServerSocket(int)
+ */
+ @Override public SSLServerSocketImpl createServerSocket(int port)
+ throws IOException
+ {
+ SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+ socket.bind(new InetSocketAddress(port));
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ServerSocketFactory#createServerSocket(int, int)
+ */
+ @Override public SSLServerSocketImpl createServerSocket(int port, int backlog)
+ throws IOException
+ {
+ SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+ socket.bind(new InetSocketAddress(port), backlog);
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ServerSocketFactory#createServerSocket(int, int, java.net.InetAddress)
+ */
+ @Override public SSLServerSocketImpl createServerSocket(int port, int backlog,
+ InetAddress bindAddress)
+ throws IOException
+ {
+ SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+ socket.bind(new InetSocketAddress(bindAddress, port), backlog);
+ return socket;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java
new file mode 100644
index 00000000000..41ef5f1cf46
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java
@@ -0,0 +1,199 @@
+/* SSLServerSocketImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+
+import javax.net.ssl.SSLServerSocket;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLServerSocketImpl extends SSLServerSocket
+{
+ private final SSLContextImpl contextImpl;
+
+ private boolean enableSessionCreation;
+ private String[] enabledCipherSuites;
+ private String[] enabledProtocols;
+ private boolean needClientAuth;
+ private boolean wantClientAuth;
+ private boolean clientMode;
+
+ public SSLServerSocketImpl(SSLContextImpl contextImpl) throws IOException
+ {
+ super();
+ this.contextImpl = contextImpl;
+ enableSessionCreation = true;
+ enabledCipherSuites = SSLEngineImpl.defaultSuites();
+ enabledProtocols = new String[] { ProtocolVersion.SSL_3.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.TLS_1_1.toString() };
+ needClientAuth = false;
+ wantClientAuth = false;
+ clientMode = false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getEnableSessionCreation()
+ */
+ @Override public boolean getEnableSessionCreation()
+ {
+ return enableSessionCreation;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getEnabledCipherSuites()
+ */
+ @Override public String[] getEnabledCipherSuites()
+ {
+ return (String[]) enabledCipherSuites.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getEnabledProtocols()
+ */
+ @Override public String[] getEnabledProtocols()
+ {
+ return (String[]) enabledProtocols.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getNeedClientAuth()
+ */
+ @Override public boolean getNeedClientAuth()
+ {
+ return needClientAuth;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getSupportedProtocols()
+ */
+ @Override public String[] getSupportedProtocols()
+ {
+ return new String[] { ProtocolVersion.SSL_3.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.TLS_1_1.toString() };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getUseClientMode()
+ */
+ @Override public boolean getUseClientMode()
+ {
+ return clientMode;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getWantClientAuth()
+ */
+ @Override public boolean getWantClientAuth()
+ {
+ return wantClientAuth;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setEnableSessionCreation(boolean)
+ */
+ @Override public void setEnableSessionCreation(final boolean enabled)
+ {
+ enableSessionCreation = enabled;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setEnabledCipherSuites(java.lang.String[])
+ */
+ @Override public void setEnabledCipherSuites(final String[] suites)
+ {
+ enabledCipherSuites = (String[]) suites.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setEnabledProtocols(java.lang.String[])
+ */
+ @Override public void setEnabledProtocols(final String[] protocols)
+ {
+ enabledProtocols = (String[]) protocols.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setNeedClientAuth(boolean)
+ */
+ @Override public void setNeedClientAuth(final boolean needAuth)
+ {
+ needClientAuth = needAuth;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setUseClientMode(boolean)
+ */
+ @Override public void setUseClientMode(final boolean clientMode)
+ {
+ this.clientMode = clientMode;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setWantClientAuth(boolean)
+ */
+ @Override public void setWantClientAuth(final boolean wantAuth)
+ {
+ wantClientAuth = wantAuth;
+ }
+
+ @Override public SSLSocketImpl accept() throws IOException
+ {
+ SSLSocketImpl socketImpl = new SSLSocketImpl(contextImpl, null, -1);
+ implAccept(socketImpl);
+ socketImpl.setEnableSessionCreation(enableSessionCreation);
+ socketImpl.setEnabledCipherSuites(enabledCipherSuites);
+ socketImpl.setEnabledProtocols(enabledProtocols);
+ socketImpl.setNeedClientAuth(needClientAuth);
+ socketImpl.setUseClientMode(clientMode);
+ socketImpl.setWantClientAuth(wantClientAuth);
+ return socketImpl;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java
deleted file mode 100644
index d08bc50f1c9..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java
+++ /dev/null
@@ -1,3515 +0,0 @@
-/* SSLSocket.java -- the SSL socket class.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.BufferedOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import java.math.BigInteger;
-
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-
-import java.nio.channels.SocketChannel;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.DSAPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import java.util.logging.Logger;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import javax.net.ssl.HandshakeCompletedEvent;
-import javax.net.ssl.HandshakeCompletedListener;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLProtocolException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.ConfirmationCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.TextInputCallback;
-
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import gnu.java.security.Registry;
-import gnu.javax.security.auth.callback.DefaultCallbackHandler;
-import gnu.java.security.hash.HashFactory;
-import gnu.java.security.hash.IMessageDigest;
-import gnu.javax.crypto.key.IKeyAgreementParty;
-import gnu.javax.crypto.key.KeyAgreementFactory;
-import gnu.javax.crypto.key.KeyAgreementException;
-import gnu.javax.crypto.key.OutgoingMessage;
-import gnu.javax.crypto.key.IncomingMessage;
-import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement;
-import gnu.javax.crypto.key.dh.ElGamalKeyAgreement;
-import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
-import gnu.javax.crypto.key.dh.GnuDHPublicKey;
-import gnu.javax.crypto.key.srp6.SRPPrivateKey;
-import gnu.javax.crypto.key.srp6.SRPPublicKey;
-import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.prng.ARCFour;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
-import gnu.javax.crypto.sasl.srp.SRPRegistry;
-import gnu.java.security.sig.ISignature;
-import gnu.java.security.sig.SignatureFactory;
-import gnu.java.security.sig.dss.DSSSignature;
-import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
-import gnu.java.security.sig.rsa.RSA;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-/**
- * This is the core of the Jessie SSL implementation; it implements the {@link
- * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all
- * protocols implemented by this library.
- */
-final class SSLSocket extends javax.net.ssl.SSLSocket
-{
-
- // This class is almost unbearably large and complex, but is laid out
- // as follows:
- //
- // 1. Fields.
- // 2. Constructors.
- // 3. SSLSocket methods. These are the public methods defined in
- // javax.net.ssl.SSLSocket.
- // 4. Socket methods. These override the public methods of java.net.Socket,
- // and delegate the method call to either the underlying socket if this is
- // a wrapped socket, or to the superclass.
- // 5. Package-private methods that various pieces of Jessie use.
- // 6. Private methods. These compose the SSL handshake.
- //
- // Each part is preceeded by a form feed.
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- // Debuggery.
- private static final boolean DEBUG_HANDSHAKE_LAYER = true;
- private static final boolean DEBUG_KEY_EXCHANGE = false;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- // Fields for using this class as a wrapped socket.
- private Socket underlyingSocket;
- private int underlyingPort;
- private boolean autoClose;
-
- // Cryptography fields.
- SessionContext sessionContext;
- Session session;
- LinkedList handshakeListeners;
- private boolean clientMode, wantClientAuth, needClientAuth, createSessions;
- private boolean handshakeDone;
-
- // I/O fields.
- private String remoteHost;
- private InputStream socketIn;
- private OutputStream socketOut;
- private InputStream applicationIn;
- private OutputStream applicationOut;
- private InputStream handshakeIn;
- private OutputStream handshakeOut;
-// private ThreadGroup recordLayer;
- RecordInput recordInput;
-// RecordOutput recordOutput;
- private long handshakeTime;
-
- private SocketChannel channel;
-
- static SortedSet supportedProtocols = new TreeSet();
- static List supportedSuites = new ArrayList(30);
-
- // Static initializer.
- // -------------------------------------------------------------------------
-
- static
- {
- //supportedProtocols.add(ProtocolVersion.TLS_1_1);
- supportedProtocols.add(ProtocolVersion.TLS_1);
- supportedProtocols.add(ProtocolVersion.SSL_3);
-
- // These are in preference order. It's my preference order, but I'm not
- // a total idiot.
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA);
- }
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLSocket(Socket socket, String host, int port, boolean autoClose)
- throws IOException
- {
- underlyingSocket = socket;
- remoteHost = host;
- underlyingPort = port;
- this.autoClose = autoClose;
- initialize();
- }
-
- SSLSocket (Socket socket, SocketChannel channel) throws IOException
- {
- underlyingSocket = socket;
- this.channel = channel;
- initialize ();
- }
-
- SSLSocket() throws IOException
- {
- super();
- initialize();
- }
-
- SSLSocket(InetAddress addr, int port) throws IOException
- {
- super(addr, port);
- initialize();
- remoteHost = addr.getHostName();
- if (remoteHost == null)
- {
- remoteHost = addr.getHostAddress();
- }
- }
-
- SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport)
- throws IOException
- {
- super(addr, port, laddr, lport);
- initialize();
- remoteHost = addr.getHostName();
- if (remoteHost == null)
- remoteHost = addr.getHostAddress();
- }
-
- SSLSocket(String host, int port) throws IOException
- {
- super(host, port);
- initialize();
- remoteHost = host;
- }
-
- SSLSocket(String host, int port, InetAddress laddr, int lport)
- throws IOException
- {
- super(host, port, laddr, lport);
- initialize();
- remoteHost = host;
- }
-
- private void initialize()
- {
- session = new Session();
- session.enabledSuites = new ArrayList(supportedSuites);
- session.enabledProtocols = new TreeSet(supportedProtocols);
- session.protocol = ProtocolVersion.TLS_1;
- session.params.setVersion (ProtocolVersion.TLS_1);
- handshakeListeners = new LinkedList();
- handshakeDone = false;
- }
-
- // SSL methods.
- // -------------------------------------------------------------------------
-
- public void addHandshakeCompletedListener(HandshakeCompletedListener l)
- {
- synchronized (handshakeListeners)
- {
- if (l == null)
- throw new NullPointerException();
- if (!handshakeListeners.contains(l))
- handshakeListeners.add(l);
- }
- }
-
- public void removeHandshakeCompletedListener(HandshakeCompletedListener l)
- {
- synchronized (handshakeListeners)
- {
- handshakeListeners.remove(l);
- }
- }
-
- public String[] getEnabledProtocols()
- {
- synchronized (session.enabledProtocols)
- {
- try
- {
- return (String[]) Util.transform(session.enabledProtocols.toArray(),
- String.class, "toString", null);
- }
- catch (Exception x)
- {
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- }
- }
-
- public void setEnabledProtocols(String[] protocols)
- {
- if (protocols == null || protocols.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < protocols.length; i++)
- {
- if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
- protocols[i].equalsIgnoreCase("TLSv1") ||
- protocols[i].equalsIgnoreCase("TLSv1.1")))
- {
- throw new
- IllegalArgumentException("unsupported protocol: " +
- protocols[i]);
- }
- }
- synchronized (session.enabledProtocols)
- {
- session.enabledProtocols.clear();
- for (int i = 0; i < protocols.length; i++)
- {
- if (protocols[i].equalsIgnoreCase("SSLv3"))
- {
- session.enabledProtocols.add(ProtocolVersion.SSL_3);
- }
- else if (protocols[i].equalsIgnoreCase("TLSv1"))
- {
- session.enabledProtocols.add(ProtocolVersion.TLS_1);
- }
- else
- {
- session.enabledProtocols.add(ProtocolVersion.TLS_1_1);
- }
- }
- }
- }
-
- public String[] getSupportedProtocols()
- {
- return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" };
- }
-
- public String[] getEnabledCipherSuites()
- {
- synchronized (session.enabledSuites)
- {
- try
- {
- return (String[]) Util.transform(session.enabledSuites.toArray(),
- String.class, "toString", null);
- }
- catch (Exception x)
- {
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- }
- }
-
- public void setEnabledCipherSuites(String[] suites)
- {
- if (suites == null || suites.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < suites.length; i++)
- if (CipherSuite.forName(suites[i]) == null)
- throw new IllegalArgumentException("unsupported suite: " +
- suites[i]);
- synchronized (session.enabledSuites)
- {
- session.enabledSuites.clear();
- for (int i = 0; i < suites.length; i++)
- {
- CipherSuite suite = CipherSuite.forName(suites[i]);
- if (!session.enabledSuites.contains(suite))
- {
- session.enabledSuites.add(suite);
- }
- }
- }
- }
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]);
- }
-
- public SSLSession getSession()
- {
- return session;
- }
-
- public boolean getEnableSessionCreation()
- {
- return createSessions;
- }
-
- public void setEnableSessionCreation(boolean flag)
- {
- createSessions = flag;
- }
-
- public boolean getNeedClientAuth()
- {
- return needClientAuth;
- }
-
- public void setNeedClientAuth(boolean flag)
- {
- needClientAuth = flag;
- }
-
- public boolean getWantClientAuth()
- {
- return wantClientAuth;
- }
-
- public void setWantClientAuth(boolean flag)
- {
- wantClientAuth = flag;
- }
-
- public boolean getUseClientMode()
- {
- return clientMode;
- }
-
- public void setUseClientMode(boolean flag)
- {
- this.clientMode = flag;
- }
-
- public synchronized void startHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}",
- Thread.currentThread());
- handshakeTime = System.currentTimeMillis();
- }
- if (handshakeDone)
- {
- if (clientMode)
- {
- handshakeDone = false;
- doClientHandshake();
- }
- else
- {
- Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null);
- req.write (handshakeOut, session.protocol);
- handshakeOut.flush();
-// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol));
- }
- return;
- }
- if (recordInput == null)
- {
- setupIO();
- }
- if (clientMode)
- {
- doClientHandshake();
- }
- else
- {
- doServerHandshake();
- }
- }
-
- // Socket methods.
- // -------------------------------------------------------------------------
-
- public InetAddress getInetAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getInetAddress();
- }
- else
- {
- return super.getInetAddress();
- }
- }
-
- public InetAddress getLocalAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalAddress();
- }
- else
- {
- return super.getLocalAddress();
- }
- }
-
- public int getPort()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getPort();
- }
- else
- {
- return super.getPort();
- }
- }
-
- public int getLocalPort()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalPort();
- }
- else
- {
- return super.getLocalPort();
- }
- }
-
- public InputStream getInputStream() throws IOException
- {
- if (applicationIn == null)
- {
- setupIO();
- }
- return applicationIn;
- }
-
- public OutputStream getOutputStream() throws IOException
- {
- if (applicationOut == null)
- {
- setupIO();
- }
- return applicationOut;
- }
-
- public void setTcpNoDelay(boolean flag) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setTcpNoDelay(flag);
- }
- else
- {
- super.setTcpNoDelay(flag);
- }
- }
-
- public boolean getTcpNoDelay() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getTcpNoDelay();
- }
- else
- {
- return super.getTcpNoDelay();
- }
- }
-
- public void setSoLinger(boolean flag, int linger) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSoLinger(flag, linger);
- }
- else
- {
- super.setSoLinger(flag, linger);
- }
- }
-
- public int getSoLinger() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSoLinger();
- }
- else
- {
- return super.getSoLinger();
- }
- }
-
- public void sendUrgentData(int data) throws IOException
- {
- throw new UnsupportedOperationException("not implemented");
- }
-
- public void setSoTimeout(int timeout) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSoTimeout(timeout);
- }
- else
- {
- super.setSoTimeout(timeout);
- }
- }
-
- public int getSoTimeout() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSoTimeout();
- }
- else
- {
- return super.getSoTimeout();
- }
- }
-
- public void setSendBufferSize(int size) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSendBufferSize(size);
- }
- else
- {
- super.setSendBufferSize(size);
- }
- }
-
- public int getSendBufferSize() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSendBufferSize();
- }
- else
- {
- return super.getSendBufferSize();
- }
- }
-
- public void setReceiveBufferSize(int size) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setReceiveBufferSize(size);
- }
- else
- {
- super.setReceiveBufferSize(size);
- }
- }
-
- public int getReceiveBufferSize() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getReceiveBufferSize();
- }
- else
- {
- return super.getReceiveBufferSize();
- }
- }
-
- public synchronized void close() throws IOException
- {
- if (recordInput == null)
- {
- if (underlyingSocket != null)
- {
- if (autoClose)
- underlyingSocket.close();
- }
- else
- super.close();
- return;
- }
-// while (recordOutput.applicationDataPending()) Thread.yield();
- Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
- sendAlert (close);
- long wait = System.currentTimeMillis() + 60000L;
- while (session.currentAlert == null && !recordInput.pollClose())
- {
-
- Thread.yield();
- if (wait <= System.currentTimeMillis())
- {
- break;
- }
- }
- boolean gotClose = session.currentAlert != null &&
- session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY;
-// recordInput.setRunning(false);
-// recordOutput.setRunning(false);
-// recordLayer.interrupt();
- recordInput = null;
-// recordOutput = null;
-// recordLayer = null;
- if (underlyingSocket != null)
- {
- if (autoClose)
- underlyingSocket.close();
- }
- else
- super.close();
- if (!gotClose)
- {
- session.invalidate();
- throw new SSLException("did not receive close notify");
- }
- }
-
- public String toString()
- {
- if (underlyingSocket != null)
- {
- return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]";
- }
- else
- {
- return SSLSocket.class.getName() + " [ " + super.toString() + " ]";
- }
- }
-
- // Configuration insanity begins here.
-
- public void connect(SocketAddress saddr) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.connect(saddr);
- }
- else
- {
- super.connect(saddr);
- }
- }
-
- public void connect(SocketAddress saddr, int timeout) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.connect(saddr, timeout);
- }
- else
- {
- super.connect(saddr, timeout);
- }
- }
-
- public void bind(SocketAddress saddr) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.bind(saddr);
- }
- else
- {
- super.bind(saddr);
- }
- }
-
- public SocketAddress getLocalSocketAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalSocketAddress();
- }
- else
- {
- return super.getLocalSocketAddress();
- }
- }
-
- public SocketChannel getChannel()
- {
- return channel;
- }
-
- public boolean isBound()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isBound();
- }
- else
- {
- return super.isBound();
- }
- }
-
- public boolean isClosed()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isClosed();
- }
- else
- {
- return super.isClosed();
- }
- }
-
- public SocketAddress getRemoteSocketAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getRemoteSocketAddress();
- }
- else
- {
- return super.getRemoteSocketAddress();
- }
- }
-
- public void setOOBInline(boolean flag) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setOOBInline(flag);
- }
- else
- {
- super.setOOBInline(flag);
- }
- }
-
- public boolean getOOBInline() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getOOBInline();
- }
- else
- {
- return super.getOOBInline();
- }
- }
-
- public void setKeepAlive(boolean flag) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setKeepAlive(flag);
- }
- else
- {
- super.setKeepAlive(flag);
- }
- }
-
- public boolean getKeepAlive() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getKeepAlive();
- }
- else
- {
- return super.getKeepAlive();
- }
- }
-
- public void setTrafficClass(int clazz) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setTrafficClass(clazz);
- }
- else
- {
- super.setTrafficClass(clazz);
- }
- }
-
- public int getTrafficClass() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getTrafficClass();
- }
- else
- {
- return super.getTrafficClass();
- }
- }
-
- public void setReuseAddress(boolean flag) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setReuseAddress(flag);
- }
- else
- {
- super.setReuseAddress(flag);
- }
- }
-
- public boolean getReuseAddress() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getReuseAddress();
- }
- else
- {
- return super.getReuseAddress();
- }
- }
-
- public void shutdownInput() throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.shutdownInput();
- }
- else
- {
- super.shutdownInput();
- }
- }
-
- public void shutdownOutput() throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.shutdownOutput();
- }
- else
- {
- super.shutdownOutput();
- }
- }
-
- public boolean isConnected()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isConnected();
- }
- else
- {
- return super.isConnected();
- }
- }
-
- public boolean isInputShutdown()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isInputShutdown();
- }
- else
- {
- return super.isInputShutdown();
- }
- }
-
- public boolean isOutputShutdown()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isOutputShutdown();
- }
- else
- {
- return super.isOutputShutdown();
- }
- }
-
- protected void finalize()
- {
- if (session.currentAlert == null)
- {
- try
- {
- close();
- }
- catch (Exception ignore) { }
- }
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- void setSessionContext(SessionContext sessionContext)
- {
- this.sessionContext = sessionContext;
- }
-
- void setEnabledCipherSuites(List suites)
- {
- session.enabledSuites = suites;
- }
-
- void setEnabledProtocols(SortedSet protocols)
- {
- session.enabledProtocols = protocols;
- }
-
- void setSRPTrustManager(SRPTrustManager srpTrustManager)
- {
- session.srpTrustManager = srpTrustManager;
- }
-
- void setTrustManager(X509TrustManager trustManager)
- {
- session.trustManager = trustManager;
- }
-
- void setKeyManager(X509KeyManager keyManager)
- {
- session.keyManager = keyManager;
- }
-
- void setRandom(SecureRandom random)
- {
- session.random = random;
- }
-
- void sendAlert (Alert alert) throws IOException
- {
- RecordOutputStream out =
- new RecordOutputStream (socketOut, ContentType.ALERT, session.params);
- out.write (alert.getEncoded ());
- }
-
- /**
- * Gets the most-recently-received alert message.
- *
- * @return The alert message.
- */
- Alert checkAlert()
- {
- return session.currentAlert;
- }
-
- synchronized void checkHandshakeDone() throws IOException
- {
- if (!handshakeDone)
- {
- startHandshake();
- }
- Alert alert = session.currentAlert;
- if (alert != null && alert.getLevel() == Alert.Level.FATAL)
- {
- throw new AlertException(alert, false);
- }
- if (handshakeIn.available() > 0 && !clientMode)
- {
- handshakeDone = false;
- startHandshake();
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private static final byte[] SENDER_CLIENT =
- new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
- private static final byte[] SENDER_SERVER =
- new byte[] { 0x53, 0x52, 0x56, 0x52 };
-
- private void changeCipherSpec () throws IOException
- {
- RecordOutputStream out =
- new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params);
- out.write (1);
- }
-
- private void readChangeCipherSpec () throws IOException
- {
- RecordInputStream in =
- new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC);
- if (in.read() != 1)
- {
- throw new SSLProtocolException ("bad change cipher spec message");
- }
- }
-
- /**
- * Initializes the application data streams and starts the record layer
- * threads.
- */
- private synchronized void setupIO() throws IOException
- {
- if (recordInput != null)
- {
- return;
- }
- if (underlyingSocket != null)
- {
- socketIn = underlyingSocket.getInputStream();
- socketOut = underlyingSocket.getOutputStream();
- }
- else
- {
- socketIn = super.getInputStream();
- socketOut = super.getOutputStream();
- }
-// recordLayer = new ThreadGroup("record_layer");
-// recordInput = new RecordInput(in, session, recordLayer);
-// recordOutput = new RecordOutput(out, session, recordLayer);
-// recordInput.setRecordOutput(recordOutput);
-// recordLayer.setDaemon(true);
-// recordInput.start();
-// recordOutput.start();
- recordInput = new RecordInput (socketIn, session);
- applicationIn = new SSLSocketInputStream(
- new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this);
- applicationOut = new SSLSocketOutputStream(
- new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this);
- handshakeIn = new SSLSocketInputStream(
- new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false);
- handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream(
- new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096);
- }
-
- private void handshakeCompleted ()
- {
- handshakeDone = true;
- HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session);
- for (Iterator it = handshakeListeners.iterator (); it.hasNext (); )
- {
- try
- {
- ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event);
- }
- catch (Throwable t) { }
- }
- if (createSessions)
- {
- synchronized (session)
- {
- sessionContext.addSession (session.sessionId, session);
- session.access ();
- }
- }
-
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}",
- Thread.currentThread());
- handshakeTime = System.currentTimeMillis() - handshakeTime;
- logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s",
- new Long (handshakeTime / 1000));
- }
- }
-
- /*
- * Perform the client handshake. The process looks like this:
- *
- * ClientHello -->
- * ServerHello <--
- * Certificate* <--
- * ServerKeyExchange* <--
- * CertificateRequest* <--
- * ServerHelloDone* <--
- * Certificate* -->
- * ClientKeyExchange -->
- * CertificateVerify* -->
- * [ChangeCipherSpec] -->
- * Finished -->
- * [ChangeCipherSpec] <--
- * Finished <--
- *
- * With --> denoting output and <-- denoting input. * denotes optional
- * messages.
- *
- * Alternatively, this may be an abbreviated handshake if we are resuming
- * a session:
- *
- * ClientHello -->
- * ServerHello <--
- * [ChangeCipherSpec] <--
- * Finished <--
- * [ChangeCipherSpec] -->
- * Finished -->
- */
- private void doClientHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}",
- Thread.currentThread());
- }
-
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
- DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
- DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
- Session continuedSession = null;
- byte[] sessionId = new byte[0];
- List extensions = null;
- String user = null;
- CertificateType certType = CertificateType.X509;
-
- // Look through the available sessions to see if an appropriate one is
- // available.
- for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); )
- {
- byte[] id = (byte[]) e.nextElement();
- continuedSession = (Session) sessionContext.getSession(id);
- if (continuedSession == null)
- {
- continue;
- }
- if (!session.enabledProtocols.contains(continuedSession.protocol))
- {
- continue;
- }
- if (continuedSession.getPeerHost().equals(remoteHost))
- {
- sessionId = id;
- break;
- }
- }
-
- // If a SRP suite is enabled, ask for a username so we can include it
- // with our extensions list.
- for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); )
- {
- CipherSuite s = (CipherSuite) i.next();
- if (s.getKeyExchange() == "SRP")
- {
- extensions = new LinkedList();
- user = askUserName(remoteHost);
- byte[] b = user.getBytes("UTF-8");
- if (b.length > 255)
- {
- handshakeFailure();
- throw new SSLException("SRP username too long");
- }
- extensions.add(new Extension(Extension.Type.SRP,
- Util.concat(new byte[] { (byte) b.length }, b)));
-
- break;
- }
- }
-
- // If the jessie.fragment.length property is set, add the appropriate
- // extension to the list. The fragment length is only actually set if
- // the server responds with the same extension.
- try
- {
- int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length"));
- byte[] ext = new byte[1];
- if (flen == 512)
- ext[0] = 1;
- else if (flen == 1024)
- ext[0] = 2;
- else if (flen == 2048)
- ext[0] = 3;
- else if (flen == 4096)
- ext[0] = 4;
- else
- throw new NumberFormatException();
- if (extensions == null)
- extensions = new LinkedList();
- extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext));
- }
- catch (NumberFormatException nfe) { }
-
- // FIXME: set certificate types.
-
- // Send the client hello.
- ProtocolVersion version = session.protocol;
- Random clientRandom =
- new Random(Util.unixTime(), session.random.generateSeed(28));
- session.protocol = (ProtocolVersion) session.enabledProtocols.last();
- List comp = new ArrayList(2);
- comp.add(CompressionMethod.ZLIB);
- comp.add(CompressionMethod.NULL);
- ClientHello clientHello =
- new ClientHello(session.protocol, clientRandom, sessionId,
- session.enabledSuites, comp, extensions);
- Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write (dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));
- dout.flush();
-// try
-// {
-// Thread.sleep(150);
-// }
-// catch (InterruptedException ie)
-// {
-// }
-
- // Receive the server hello.
- msg = Handshake.read(din);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.SERVER_HELLO)
- {
- throwUnexpectedMessage();
- }
- ServerHello serverHello = (ServerHello) msg.getBody();
- Random serverRandom = serverHello.getRandom();
- version = serverHello.getVersion();
-
- // If we don't directly support the server's protocol version, choose
- // the highest one we support that is less than the server's version.
- if (!session.enabledProtocols.contains(version))
- {
- ProtocolVersion v1 = null, v2 = null;
- for (Iterator it = session.enabledProtocols.iterator();
- it.hasNext(); )
- {
- v1 = (ProtocolVersion) it.next();
- if (v1.compareTo(version) > 0)
- break;
- v2 = v1;
- }
- version = v1;
- }
-
- // The server's version is either unsupported by us (unlikely) or the user
- // has only enabled incompatible versions.
- if (version == null)
- {
- Alert.Description desc = null;
- if (serverHello.getVersion() == ProtocolVersion.SSL_3)
- {
- desc = Alert.Description.HANDSHAKE_FAILURE;
- }
- else
- {
- desc = Alert.Description.PROTOCOL_VERSION;
- }
- Alert alert = new Alert(Alert.Level.FATAL, desc);
- sendAlert(alert);
- session.currentAlert = alert;
- fatal();
- throw new AlertException(alert, true);
- }
-
- if (serverHello.getExtensions() != null)
- {
- for (Iterator it = serverHello.getExtensions().iterator();
- it.hasNext(); )
- {
- Extension e = (Extension) it.next();
- if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
- {
- int len = Extensions.getMaxFragmentLength(e).intValue();
- session.params.setFragmentLength(len);
-// recordOutput.setFragmentLength(len);
-// recordInput.setFragmentLength(len);
- }
- else if (e.getType() == Extension.Type.CERT_TYPE)
- {
- certType = Extensions.getServerCertType(e);
- }
- }
- }
-
- CipherSuite suite = serverHello.getCipherSuite().resolve(version);
- boolean newSession = true;
- if (sessionId.length > 0 &&
- Arrays.equals(sessionId, serverHello.getSessionId()))
- {
- SecurityParameters params = session.params;
- SecureRandom random = session.random;
- session = (Session) continuedSession.clone();
- session.params = params;
- session.random = random;
- recordInput.setSession(session);
-// recordOutput.setSession(session);
- suite = session.cipherSuite;
- newSession = false;
- }
- else
- {
- sessionContext.removeSession(new Session.ID(sessionId));
- }
- if (newSession)
- {
- session.peerHost = remoteHost;
- session.sessionId = new Session.ID(serverHello.getSessionId());
- session.cipherSuite = suite;
- }
- session.params.reset();
-// session.params.setInMac(null);
-// session.params.setOutMac(null);
-// session.params.setInRandom(null);
-// session.params.setOutRandom(null);
-// session.params.setInCipher(null);
-// session.params.setOutCipher(null);
- session.currentAlert = null;
- session.valid = true;
- session.protocol = version;
-
- // If the server responded with the same session id that we sent, we
- // assume that the session will be continued, and skip the bulk of the
- // handshake.
- if (newSession)
- {
- PublicKey serverKey = null, serverKex = null;
- KeyPair clientKeys = null, clientKex = null;
- CertificateRequest certReq;
- boolean sendKeyExchange = false;
- BigInteger srp_x = null;
- IKeyAgreementParty clientKA = null;
- IncomingMessage in; // used for key agreement protocol exchange
- OutgoingMessage out = null;
-
- if (suite.getKeyExchange() == "SRP")
- {
- String password = askPassword(user);
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE,
- "SRP: password read is ''{0}''", password);
- }
- byte[] userSrpPassword = password.getBytes("UTF-8");
-
- // instantiate and setup client-side key agreement party
- clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA);
- Map clientAttributes = new HashMap();
- clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
- Registry.SHA160_HASH);
- clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user);
- clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword);
- try
- {
- clientKA.init(clientAttributes);
- // initiate the exchange
- out = clientKA.processMessage(null);
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- }
-
- if (suite.getSignature() != "anon")
- {
- msg = Handshake.read(din, certType);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.CERTIFICATE)
- {
- throwUnexpectedMessage();
- }
- Certificate serverCertificate = (Certificate) msg.getBody();
- X509Certificate[] peerCerts = serverCertificate.getCertificates();
- try
- {
- session.trustManager.checkServerTrusted(peerCerts,
- suite.getAuthType());
- if (suite.getSignature() == "RSA" &&
- !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getKeyExchange() == "DH" &&
- !(peerCerts[0].getPublicKey() instanceof DHPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getKeyExchange() == "DHE")
- {
- if (suite.getSignature() == "RSA" &&
- !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getSignature() == "DSS" &&
- !(peerCerts[0].getPublicKey() instanceof DSAPublicKey))
- throw new InvalidKeyException("improper public key");
- }
- session.peerCerts = peerCerts;
- session.peerVerified = true;
- }
- catch (InvalidKeyException ike)
- {
- throwHandshakeFailure();
- }
- catch (Exception x)
- {
- if (!checkCertificates(peerCerts))
- {
- peerUnverified(peerCerts);
- SSLPeerUnverifiedException e =
- new SSLPeerUnverifiedException ("could not verify peer certificate: "+
- peerCerts[0].getSubjectDN());
- e.initCause (x);
- throw e;
- }
- session.peerCerts = peerCerts;
- session.peerVerified = true;
- }
- serverKey = peerCerts[0].getPublicKey();
- serverKex = serverKey;
- }
-
- msg = Handshake.read(din, suite, serverKey);
-
- // Receive the server's key exchange.
- if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- ServerKeyExchange skex = (ServerKeyExchange) msg.getBody();
- serverKex = skex.getPublicKey();
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else if (suite.getSignature() == "DSS")
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupVerify(Collections.singletonMap(
- ISignature.VERIFIER_KEY, serverKey));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- if (suite.getKeyExchange() == "RSA")
- {
- updateSig(sig, ((RSAPublicKey) serverKex).getModulus());
- updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent());
- }
- else if (suite.getKeyExchange() == "DHE")
- {
- updateSig(sig, ((DHPublicKey) serverKex).getParams().getP());
- updateSig(sig, ((DHPublicKey) serverKex).getParams().getG());
- updateSig(sig, ((DHPublicKey) serverKex).getY());
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- updateSig(sig, ((SRPPublicKey) serverKex).getN());
- updateSig(sig, ((SRPPublicKey) serverKex).getG());
- byte[] srpSalt = skex.getSRPSalt();
- sig.update((byte) srpSalt.length);
- sig.update(srpSalt, 0, srpSalt.length);
- updateSig(sig, ((SRPPublicKey) serverKex).getY());
- }
- if (!sig.verify(skex.getSignature().getSigValue()))
- {
- throwHandshakeFailure();
- }
- }
-
- if (suite.getKeyExchange() == "SRP")
- {
- // use server's key exchange data to continue
- // agreement protocol by faking a received incoming
- // message. again the following code can be broken
- // into multiple blocks for more accurate exception
- // handling
- try
- {
- out = new OutgoingMessage();
- out.writeMPI(((SRPPublicKey) serverKex).getN());
- out.writeMPI(((SRPPublicKey) serverKex).getG());
- out.writeMPI(new BigInteger(1, skex.getSRPSalt()));
- out.writeMPI(((SRPPublicKey) serverKex).getY());
-
- in = new IncomingMessage(out.toByteArray());
-
- out = clientKA.processMessage(in);
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}",
- Boolean.valueOf (clientKA.isComplete()));
- }
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- }
- msg = Handshake.read(din, suite, serverKey);
- }
-
- // See if the server wants us to send our certificates.
- certReq = null;
- if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST)
- {
- if (suite.getSignature() == "anon")
- {
- throwHandshakeFailure();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- certReq = (CertificateRequest) msg.getBody();
- msg = Handshake.read(din);
- }
-
- // Read ServerHelloDone.
- if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
-
- // Send our certificate chain if the server asked for it.
- if (certReq != null)
- {
- String alias = session.keyManager.chooseClientAlias(
- certReq.getTypeStrings(), certReq.getAuthorities(), null);
- if (alias == null && version == ProtocolVersion.SSL_3)
- {
- Alert alert =
- new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE);
- sendAlert(alert);
- }
- else
- {
- X509Certificate[] chain =
- session.keyManager.getCertificateChain(alias);
- PrivateKey key = session.keyManager.getPrivateKey(alias);
- if (chain == null)
- {
- chain = new X509Certificate[0];
- }
- Certificate cert = new Certificate(chain);
- msg = new Handshake(Handshake.Type.CERTIFICATE, cert);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- if (chain.length > 0)
- {
- session.localCerts = chain;
- clientKeys = new KeyPair(chain[0].getPublicKey(), key);
- }
- }
- }
-
- // Send our key exchange.
- byte[] preMasterSecret = null;
- ClientKeyExchange ckex = null;
- if (suite.getKeyExchange() == "RSA")
- {
- ProtocolVersion v =
- (ProtocolVersion) session.enabledProtocols.last();
- byte[] b = new byte[46];
- session.random.nextBytes (b);
- preMasterSecret = Util.concat(v.getEncoded(), b);
- EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex);
- BigInteger bi = new BigInteger(1,
- pkcs1.encode(preMasterSecret, session.random));
- bi = RSA.encrypt((RSAPublicKey) serverKex, bi);
- ckex = new ClientKeyExchange(Util.trim(bi));
- }
- else if (suite.getKeyExchange().startsWith("DH"))
- {
- if (clientKeys == null ||
- !(clientKeys.getPublic() instanceof DHPublicKey))
- {
- GnuDHPrivateKey tmpKey =
- new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(),
- ((DHPublicKey) serverKex).getParams().getG(), null);
- clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA);
- Map attr = new HashMap();
- attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
- tmpKey);
- attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
- session.random);
- try
- {
- clientKA.init(attr);
- out = new OutgoingMessage();
- out.writeMPI(((DHPublicKey) serverKex).getY());
- in = new IncomingMessage(out.toByteArray());
- out = clientKA.processMessage(in);
- in = new IncomingMessage(out.toByteArray());
- ckex = new ClientKeyExchange(in.readMPI());
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else
- {
- clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
- Map attr = new HashMap();
- attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
- clientKeys.getPrivate());
- try
- {
- // The key exchange is already complete here; our public
- // value was sent with our certificate.
- clientKA.init(attr);
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- ckex = new ClientKeyExchange(new byte[0]);
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- // at this point, out --the outgoing message-- already contains
- // what we want. so...
- BigInteger A = null;
- try
- {
- in = new IncomingMessage(out.toByteArray());
- A = in.readMPI();
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A);
- }
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- ckex = new ClientKeyExchange(A);
- }
- msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write (dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
-
- // Generate the master secret.
- if (suite.getKeyExchange().startsWith("DH"))
- {
- try
- {
- preMasterSecret = clientKA.getSharedSecret();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- try
- {
- preMasterSecret = clientKA.getSharedSecret();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- finally
- {
- clientKA = null;
- }
- }
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
- Util.toHexString (preMasterSecret, ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
- Util.toHexString(clientRandom.getEncoded(), ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
- Util.toHexString(serverRandom.getEncoded(), ':'));
- }
- IRandom genSecret = null;
- if (version == ProtocolVersion.SSL_3)
- {
- genSecret = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, preMasterSecret);
- attr.put(SSLRandom.SEED,
- Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()));
- genSecret.init(attr);
- }
- else
- {
- genSecret = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, preMasterSecret);
- attr.put(TLSRandom.SEED,
- Util.concat(("master secret").getBytes("UTF-8"),
- Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())));
- genSecret.init(attr);
- }
- session.masterSecret = new byte[48];
- try
- {
- genSecret.nextBytes(session.masterSecret, 0, 48);
- for (int i = 0; i < preMasterSecret.length; i++)
- {
- preMasterSecret[i] = 0;
- }
- }
- catch (LimitReachedException shouldNotHappen)
- {
- internalError();
- RuntimeException re = new RuntimeException (shouldNotHappen.getMessage());
- re.initCause (shouldNotHappen);
- throw re;
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
- Util.toHexString(session.masterSecret, ':'));
- }
-
- // Send our certificate verify message.
- if (certReq != null && clientKeys != null)
- {
- IMessageDigest vMD5 = (IMessageDigest) md5.clone();
- IMessageDigest vSHA = (IMessageDigest) sha.clone();
- PrivateKey key = clientKeys.getPrivate();
- Object sig = null;
- String sigAlg = null;
- try
- {
- if (key instanceof DSAPrivateKey)
- {
- sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(),
- session.random);
- sigAlg = "DSS";
- }
- else if (key instanceof RSAPrivateKey)
- {
- SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA);
- rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key));
- sig = rsa.sign();
- sigAlg = "RSA";
- }
- else
- {
- throw new InvalidKeyException("no appropriate key");
- }
- }
- catch (Exception x)
- {
- throwHandshakeFailure();
- }
- CertificateVerify verify = new CertificateVerify(sig, sigAlg);
- msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- }
- dout.flush();
- }
-
- byte[][] keys = null;
- try
- {
- keys = generateKeys(serverRandom.getEncoded(),
- clientRandom.getEncoded(), version);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
-
- session.params.setVersion (version);
-
- // Initialize the algorithms with the derived keys.
- Object readMac = null, writeMac = null;
- Object readCipher = null, writeCipher = null;
- try
- {
- if (session.params instanceof GNUSecurityParameters)
- {
- HashMap attr = new HashMap();
- writeMac = CipherSuite.getMac(suite.getMac());
- readMac = CipherSuite.getMac(suite.getMac());
- attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
- ((IMac) writeMac).init(attr);
- attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
- ((IMac) readMac).init(attr);
- if (suite.getCipher() == "RC4")
- {
- writeCipher = new ARCFour();
- readCipher = new ARCFour();
- attr.clear();
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
- ((ARCFour) writeCipher).init(attr);
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
- ((ARCFour) readCipher).init(attr);
- }
- else if (!suite.isStreamCipher())
- {
- writeCipher = CipherSuite.getCipher(suite.getCipher());
- readCipher = CipherSuite.getCipher(suite.getCipher());
- attr.clear();
- attr.put(IMode.KEY_MATERIAL, keys[2]);
- attr.put(IMode.IV, keys[4]);
- attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- ((IMode) writeCipher).init(attr);
- attr.put(IMode.KEY_MATERIAL, keys[3]);
- attr.put(IMode.IV, keys[5]);
- attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- ((IMode) readCipher).init(attr);
- }
- }
- else // JCESecurityParameters
- {
- writeMac = CipherSuite.getJCEMac (suite.getMac());
- readMac = CipherSuite.getJCEMac (suite.getMac());
- writeCipher = CipherSuite.getJCECipher (suite.getCipher());
- readCipher = CipherSuite.getJCECipher (suite.getCipher());
- ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac()));
- ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac()));
- if (!suite.isStreamCipher())
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()),
- new IvParameterSpec (keys[4]));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()),
- new IvParameterSpec (keys[5]));
- }
- else
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()));
- }
- }
- }
- // These should technically never happen, if our key generation is not
- // broken.
- catch (InvalidKeyException ike)
- {
- internalError();
- RuntimeException re = new RuntimeException (ike.getMessage());
- re.initCause(ike);
- throw re;
- }
- catch (InvalidAlgorithmParameterException iape)
- {
- internalError();
- RuntimeException re = new RuntimeException (iape.getMessage());
- re.initCause (iape);
- throw re;
- }
- // These indicate a configuration error with the JCA.
- catch (NoSuchAlgorithmException nsae)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
- x.initCause (nsae);
- throw x;
- }
- catch (NoSuchPaddingException nspe)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
- x.initCause (nspe);
- throw x;
- }
-
- Finished finis = null;
-
- if (newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), true);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- if (session.currentAlert != null &&
- session.currentAlert.getLevel() == Alert.Level.FATAL)
- {
- fatal();
- throw new AlertException(session.currentAlert, false);
- }
-
- synchronized (session.params)
- {
- readChangeCipherSpec ();
- session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setInMac(readMac);
- session.params.setInCipher(readCipher);
- session.params.notifyAll();
- }
-
- Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), false);
-
- msg = Handshake.read(din, suite, null);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.FINISHED)
- {
- throwUnexpectedMessage();
- }
- finis = (Finished) msg.getBody();
- if (version == ProtocolVersion.SSL_3)
- {
- if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
- !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
- {
- throwHandshakeFailure();
- }
- }
- else
- {
- if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
- {
- throwHandshakeFailure();
- }
- }
-
- if (!newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, md5, sha, true);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- handshakeCompleted();
- }
-
- /**
- * Perform the server handshake.
- */
- private void doServerHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}",
- Thread.currentThread());
- }
-
- if (remoteHost == null)
- {
- remoteHost = getInetAddress().getHostName();
- }
- if (remoteHost == null)
- {
- remoteHost = getInetAddress().getHostAddress();
- }
-
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
- DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
- DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
-
- // Read the client hello.
- Handshake msg = Handshake.read(din);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.CLIENT_HELLO)
- {
- throwUnexpectedMessage();
- }
- ClientHello clientHello = (ClientHello) msg.getBody();
- Random clientRandom = clientHello.getRandom();
- ProtocolVersion version = clientHello.getVersion();
- ProtocolVersion server =
- (ProtocolVersion) session.enabledProtocols.last();
- CompressionMethod comp;
- if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB))
- comp = CompressionMethod.ZLIB;
- else
- comp = CompressionMethod.NULL;
- if (!session.enabledProtocols.contains(version)
- && version.compareTo(server) < 0)
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.PROTOCOL_VERSION);
- sendAlert(alert);
- session.currentAlert = alert;
- throw new AlertException(alert, true);
- }
-
- // Look through the extensions sent by the client (if any), and react to
- // them appropriately.
- List extensions = null;
- String remoteUser = null;
- if (clientHello.getExtensions() != null)
- {
- for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();)
- {
- Extension ex = (Extension) it.next();
- if (ex.getType() == Extension.Type.SERVER_NAME)
- {
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- extensions.add(ex);
- }
- else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
- {
- int maxLen = Extensions.getMaxFragmentLength(ex).intValue();
-// recordInput.setFragmentLength(maxLen);
-// recordOutput.setFragmentLength(maxLen);
- session.params.setFragmentLength(maxLen);
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- extensions.add(ex);
- }
- else if (ex.getType() == Extension.Type.SRP)
- {
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- byte[] b = ex.getValue();
- remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8");
- session.putValue("srp-username", remoteUser);
- }
- }
- }
-
- CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version);
- if (suite == null)
- {
- return;
- }
-
- // If the selected suite turns out to be SRP, set up the key exchange
- // objects.
- IKeyAgreementParty serverKA = null;
- IncomingMessage in;
- OutgoingMessage out = null;
- if (suite.getKeyExchange() == "SRP")
- {
- // FIXME
- // Uhm, I don't think this can happen, because if remoteUser is null
- // we cannot choose an SRP ciphersuite...
- if (remoteUser == null)
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.MISSING_SRP_USERNAME);
- sendAlert(alert);
- throw new AlertException(alert, true);
- }
-
- SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider();
- Map dbAttributes = new HashMap();
- dbAttributes.put(SRPRegistry.PASSWORD_DB,
- session.srpTrustManager.getPasswordFile());
- srpDB.activate(dbAttributes);
-
- // FIXME
- // We can also fake that the user exists, and generate a dummy (and
- // invalid) master secret, and let the handshake fail at the Finished
- // message. This is better than letting the connecting side know that
- // the username they sent isn't valid.
- //
- // But how to implement this?
- if (!srpDB.contains(remoteUser))
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.UNKNOWN_SRP_USERNAME);
- sendAlert(alert);
- throw new AlertException(alert, true);
- }
-
- serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA);
- Map serverAttributes = new HashMap();
- serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
- Registry.SHA160_HASH);
- serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB);
-
- try
- {
- serverKA.init(serverAttributes);
- out = new OutgoingMessage();
- out.writeString(remoteUser);
- in = new IncomingMessage(out.toByteArray());
- out = serverKA.processMessage(in);
- }
- catch (KeyAgreementException x)
- {
- throwHandshakeFailure();
- }
- }
-
- // Check if the session specified by the client's ID corresponds
- // to a saved session, and if so, continue it.
- boolean newSession = true;
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext);
- }
- if (sessionContext.containsSessionID(
- new Session.ID(clientHello.getSessionId())))
- {
- Session old = session;
- session = (Session) sessionContext.getSession(clientHello.getSessionId());
- if (!clientHello.getCipherSuites().contains(session.cipherSuite))
- {
- throwHandshakeFailure();
- }
- if (session.getPeerHost().equals(remoteHost) &&
- old.enabledProtocols.contains(session.protocol))
- {
- session = (Session) session.clone();
- suite = session.cipherSuite;
- newSession = false;
- recordInput.setSession(session);
- session.currentAlert = null;
- session.params = old.params;
- session.random = old.random;
- }
- else
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}",
- new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)),
- Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) });
- }
- session = old;
- session.peerHost = remoteHost;
- newSession = true;
- }
- }
- else if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}",
- new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))),
- sessionContext });
- }
- if (newSession)
- {
- byte[] buf = new byte[32];
- Session.ID sid = null;
- do
- {
- session.random.nextBytes(buf);
- sid = new Session.ID(buf);
- }
- while (sessionContext.containsSessionID(sid));
- session.sessionId = sid;
- }
- session.valid = true;
- session.peerHost = remoteHost;
- session.cipherSuite = suite;
- session.protocol = version;
- session.params.setVersion (version);
-
- // Send the server hello.
- Random serverRandom = new Random(Util.unixTime(),
- session.random.generateSeed(28));
- ServerHello serverHello = new ServerHello(version, serverRandom,
- session.getId(), suite,
- comp, extensions);
- msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));
- dout.flush();
-
- if (newSession)
- {
- X509Certificate[] certs = null;
- PrivateKey serverKey = null;
- if (suite.getSignature() != "anon")
- {
- // Send our CA-issued certificate to the client.
- String alias = session.keyManager.chooseServerAlias(suite.getAuthType(),
- null, null);
- certs = session.keyManager.getCertificateChain(alias);
- serverKey = session.keyManager.getPrivateKey(alias);
- if (certs == null || serverKey == null)
- {
- throwHandshakeFailure();
- }
- session.localCerts = certs;
- Certificate serverCert = new Certificate(certs);
- msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- }
-
- // If the certificate we sent does not contain enough information to
- // do the key exchange (in the case of ephemeral Diffie-Hellman,
- // export RSA, and SRP) we send a signed public key to be used for the
- // key exchange.
- KeyPair signPair = null;
- if (certs != null)
- {
- signPair = new KeyPair(certs[0].getPublicKey(), serverKey);
- }
- KeyPair kexPair = signPair;
- ServerKeyExchange skex = null;
-
- // Set up our key exchange, and/or prepare our ServerKeyExchange
- // message.
- if ((suite.getKeyExchange() == "RSA" && suite.isExportable() &&
- ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512))
- {
- kexPair = KeyPool.generateRSAKeyPair();
- RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic();
- Signature s = null;
- if (suite.getSignature() != "anon")
- {
- SSLRSASignature sig = new SSLRSASignature();
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, pubkey.getModulus());
- updateSig(sig, pubkey.getPublicExponent());
- s = new Signature(sig.sign(), "RSA");
- }
- skex = new ServerKeyExchange(pubkey, s);
- }
- else if (suite.getKeyExchange() == "DH")
- {
- serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
- Map attr = new HashMap();
- attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
- serverKey);
- try
- {
- serverKA.init(attr);
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- // We don't send a ServerKeyExchange for this suite.
- }
- else if (suite.getKeyExchange() == "DHE")
- {
- serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA);
- Map attr = new HashMap();
- GnuDHPrivateKey servParams = DiffieHellman.getParams();
- attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
- servParams);
- attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
- session.random);
- BigInteger serv_y = null;
- try
- {
- serverKA.init(attr);
- out = serverKA.processMessage(null);
- in = new IncomingMessage(out.toByteArray());
- serv_y = in.readMPI();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- GnuDHPublicKey pubkey =
- new GnuDHPublicKey(null, servParams.getParams().getP(),
- servParams.getParams().getG(), serv_y);
- Signature s = null;
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, pubkey.getParams().getP());
- updateSig(sig, pubkey.getParams().getG());
- updateSig(sig, pubkey.getY());
- s = new Signature(sig.sign(), suite.getSignature());
- }
- skex = new ServerKeyExchange(pubkey, s);
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- BigInteger N = null;
- BigInteger g = null;
- BigInteger salt = null;
- BigInteger B = null;
- try
- {
- in = new IncomingMessage(out.toByteArray());
- N = in.readMPI();
- g = in.readMPI();
- salt = in.readMPI();
- B = in.readMPI();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- Signature s = null;
- final byte[] srpSalt = Util.trim(salt);
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, N);
- updateSig(sig, g);
- sig.update((byte) srpSalt.length);
- sig.update(srpSalt, 0, srpSalt.length);
- updateSig(sig, B);
- s = new Signature(sig.sign(), suite.getSignature());
- }
- final SRPPublicKey pubkey = new SRPPublicKey(N, g, B);
- skex = new ServerKeyExchange(pubkey, s, srpSalt);
- }
- if (skex != null)
- {
- msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- }
-
- // If we are configured to want or need client authentication, then
- // ask for it.
- if (wantClientAuth || needClientAuth)
- {
- Principal[] auths = null;
- CertificateRequest.ClientType[] types =
- new CertificateRequest.ClientType[] {
- CertificateRequest.ClientType.RSA_SIGN,
- CertificateRequest.ClientType.DSS_SIGN,
- CertificateRequest.ClientType.RSA_FIXED_DH,
- CertificateRequest.ClientType.DSS_FIXED_DH
- };
- try
- {
- auths = (Principal[])
- Util.transform(session.trustManager.getAcceptedIssuers(),
- Principal.class, "getSubjectDN", null);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- CertificateRequest req = new CertificateRequest(types, auths);
- msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req);
- msg.write(dout, version);
- dout.flush();
- }
-
- // Send our server hello done.
- msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
-
- if (suite.getKeyExchange() == "RSA")
- {
- msg = Handshake.read(din, suite, kexPair.getPublic());
- }
- else
- {
- msg = Handshake.read(din, suite, null);
- }
- boolean clientCertOk = false;
- boolean clientCanSign = false;
- X509Certificate[] clientChain = null;
- PublicKey clientKey = null;
-
- // Read the client's certificate, if sent.
- if (msg.getType() == Handshake.Type.CERTIFICATE)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- Certificate cliCert = (Certificate) msg.getBody();
- clientChain = cliCert.getCertificates();
- try
- {
- session.trustManager.checkClientTrusted(clientChain,
- suite.getAuthType());
- session.peerCerts = clientChain;
- session.peerVerified = true;
- clientKey = clientChain[0].getPublicKey();
- }
- catch (Exception x)
- {
- }
- clientCanSign = ((clientKey instanceof DSAPublicKey) ||
- (clientKey instanceof RSAPublicKey));
- if (suite.getKeyExchange().startsWith("DH"))
- {
- msg = Handshake.read(din, suite, clientKey);
- }
- else
- {
- msg = Handshake.read(din, suite, kexPair.getPublic());
- }
- }
-
- // If we require client authentication, and the client sent an
- // unverifiable certificate or no certificate at all, drop the
- // connection.
- if (!session.peerVerified && needClientAuth)
- {
- throwHandshakeFailure();
- }
-
- // Read the client key exchange.
- if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody();
- byte[] preMasterSecret = null;
- if (suite.getKeyExchange() == "RSA")
- {
- byte[] enc = (byte[]) ckex.getExchangeObject();
- BigInteger bi = new BigInteger(1, enc);
- try
- {
- bi = RSA.decrypt(kexPair.getPrivate(), bi);
- EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance(
- (RSAPrivateKey) kexPair.getPrivate());
- preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray()));
- //rsa.init(kexPair);
- //preMasterSecret = rsa.decrypt(enc);
- }
- catch (Exception x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x);
- }
- // Generate a fake pre-master secret if the RSA decryption
- // fails.
- byte[] b = new byte[46];
- session.random.nextBytes (b);
- preMasterSecret = Util.concat(version.getEncoded(), b);
- }
- }
- else if (suite.getKeyExchange().startsWith("DH"))
- {
- try
- {
- out = new OutgoingMessage();
- if (clientKey == null)
- out.writeMPI((BigInteger) ckex.getExchangeObject());
- else
- out.writeMPI(((DHPublicKey) clientKey).getY());
- in = new IncomingMessage(out.toByteArray());
- serverKA.processMessage(in);
- preMasterSecret = serverKA.getSharedSecret();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- BigInteger A = (BigInteger) ckex.getExchangeObject();
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A);
- }
- try
- {
- out = new OutgoingMessage();
- out.writeMPI(A);
- in = new IncomingMessage(out.toByteArray());
- out = serverKA.processMessage(in);
- preMasterSecret = serverKA.getSharedSecret();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- finally
- {
- serverKA = null;
- }
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
- Util.toHexString(preMasterSecret, ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
- Util.toHexString(clientRandom.getEncoded(), ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
- Util.toHexString(serverRandom.getEncoded(), ':'));
- }
-
- // Generate the master secret.
- IRandom genSecret = null;
- if (version == ProtocolVersion.SSL_3)
- {
- genSecret = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, preMasterSecret);
- attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(),
- serverRandom.getEncoded()));
- genSecret.init(attr);
- }
- else
- {
- genSecret = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, preMasterSecret);
- attr.put(TLSRandom.SEED,
- Util.concat(("master secret").getBytes("UTF-8"),
- Util.concat(clientRandom.getEncoded(),
- serverRandom.getEncoded())));
- genSecret.init(attr);
- }
- session.masterSecret = new byte[48];
- try
- {
- genSecret.nextBytes(session.masterSecret, 0, 48);
- for (int i = 0; i < preMasterSecret.length; i++)
- {
- preMasterSecret[i] = 0;
- }
- }
- catch (LimitReachedException shouldNotHappen)
- {
- internalError();
- RuntimeException re = new RuntimeException();
- re.initCause (shouldNotHappen);
- throw re;
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
- Util.toHexString(session.masterSecret, ':'));
- }
-
- // Read the client's certificate verify message, if needed.
- if (clientCanSign && (wantClientAuth || needClientAuth))
- {
- msg = Handshake.read(din);
- if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY)
- {
- throwUnexpectedMessage();
- }
- CertificateVerify verify = (CertificateVerify) msg.getBody();
- if (clientChain != null && clientChain.length > 0)
- {
- IMessageDigest cvMD5 = (IMessageDigest) md5.clone();
- IMessageDigest cvSHA = (IMessageDigest) sha.clone();
- clientKey = clientChain[0].getPublicKey();
- if (clientKey instanceof RSAPublicKey)
- {
- SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA);
- sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey));
- if (!sig.verify(verify.getSigValue()))
- {
- handshakeFailure();
- throw new SSLHandshakeException("client certificate verify failed");
- }
- }
- else if (clientKey instanceof DSAPublicKey)
- {
- try
- {
- if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(),
- (BigInteger[]) verify.getSigValue()))
- {
- throw new Exception("client's certificate could not be verified");
- }
- }
- catch (Exception x)
- {
- handshakeFailure();
- SSLHandshakeException e = new SSLHandshakeException (x.getMessage());
- e.initCause (x);
- throw e;
- }
- }
- }
- }
- }
-
- // Generate the session keys.
- byte[][] keys = null;
- try
- {
- keys = generateKeys(serverRandom.getEncoded(),
- clientRandom.getEncoded(), version);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
-
- // Initialize the algorithms with the derived keys.
- Object readMac = null, writeMac = null;
- Object readCipher = null, writeCipher = null;
- try
- {
- if (session.params instanceof GNUSecurityParameters)
- {
- HashMap attr = new HashMap();
- writeMac = CipherSuite.getMac(suite.getMac());
- readMac = CipherSuite.getMac(suite.getMac());
- attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
- ((IMac) writeMac).init(attr);
- attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
- ((IMac) readMac).init(attr);
- if (suite.getCipher() == "RC4")
- {
- writeCipher = new ARCFour();
- readCipher = new ARCFour();
- attr.clear();
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
- ((ARCFour) writeCipher).init(attr);
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
- ((ARCFour) readCipher).init(attr);
- }
- else if (!suite.isStreamCipher())
- {
- writeCipher = CipherSuite.getCipher(suite.getCipher());
- readCipher = CipherSuite.getCipher(suite.getCipher());
- attr.clear();
- attr.put(IMode.KEY_MATERIAL, keys[3]);
- attr.put(IMode.IV, keys[5]);
- attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- ((IMode) writeCipher).init(attr);
- attr.put(IMode.KEY_MATERIAL, keys[2]);
- attr.put(IMode.IV, keys[4]);
- attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- ((IMode) readCipher).init(attr);
- }
- }
- else // JCESecurityParameters
- {
- writeMac = CipherSuite.getJCEMac (suite.getMac());
- readMac = CipherSuite.getJCEMac (suite.getMac());
- writeCipher = CipherSuite.getJCECipher (suite.getCipher());
- readCipher = CipherSuite.getJCECipher (suite.getCipher());
- ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac()));
- ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac()));
- if (!suite.isStreamCipher())
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()),
- new IvParameterSpec (keys[5]));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()),
- new IvParameterSpec (keys[4]));
- }
- else
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()));
- }
- }
- }
- // These should technically never happen, if our key generation is not
- // broken.
- catch (InvalidKeyException ike)
- {
- internalError();
- RuntimeException re = new RuntimeException (ike.getMessage());
- re.initCause (ike);
- throw new RuntimeException (String.valueOf (ike));
- }
- catch (InvalidAlgorithmParameterException iape)
- {
- internalError();
- RuntimeException re = new RuntimeException (iape.getMessage());
- re.initCause (iape);
- throw re;
- }
- // These indicate a configuration error with the JCA.
- catch (NoSuchAlgorithmException nsae)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
- e.initCause (nsae);
- throw e;
- }
- catch (NoSuchPaddingException nspe)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
- e.initCause (nspe);
- throw e;
- }
-
- Finished finis = null;
- // If we are continuing a session, we send our Finished message first.
- if (!newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(comp == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), false);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- if (session.currentAlert != null &&
- session.currentAlert.getLevel() == Alert.Level.FATAL)
- {
- fatal();
- throw new AlertException(session.currentAlert, false);
- }
-
- // Wait until we receive a ChangeCipherSpec, then change the crypto
- // algorithms for the incoming side.
- synchronized (session.params)
- {
- readChangeCipherSpec ();
- session.params.setInflating(comp == CompressionMethod.ZLIB);
- session.params.setInMac(readMac);
- session.params.setInCipher(readCipher);
- session.params.notifyAll();
- }
-
- // Receive and verify the client's finished message.
- Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), true);
- msg = Handshake.read(din, suite, null);
- if (msg.getType() != Handshake.Type.FINISHED)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- finis = (Finished) msg.getBody();
- if (version == ProtocolVersion.SSL_3)
- {
- if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
- !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
- {
- throwHandshakeFailure();
- }
- }
- else
- {
- if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
- {
- throwHandshakeFailure();
- }
- }
-
- // Send our Finished message last for new sessions.
- if (newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(comp == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, md5, sha, false);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- handshakeCompleted();
- }
-
- /**
- * Generate the keys from the master secret.
- *
- * @param server The server's random value.
- * @param client The client's random value.
- * @param activeVersion The negotiated protocol version.
- * @return The generated keys.
- */
- private byte[][] generateKeys(byte[] server, byte[] client,
- ProtocolVersion activeVersion)
- throws LimitReachedException, IOException
- {
- CipherSuite suite = session.cipherSuite;
- int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20;
- int keyLen = suite.getKeyLength();
- int ivLen = 0;
- if (suite.getCipher().indexOf("DES") >= 0)
- {
- ivLen = 8;
- }
- else if (suite.getCipher() == "AES")
- {
- ivLen = 16;
- }
- byte[][] keyMaterial = new byte[6][];
- keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret
- keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret
- keyMaterial[2] = new byte[keyLen]; // client_write_key
- keyMaterial[3] = new byte[keyLen]; // server_write_key
- keyMaterial[4] = new byte[ivLen]; // client_write_IV
- keyMaterial[5] = new byte[ivLen]; // server_write_IV
- IRandom prf = null;
- if (activeVersion == ProtocolVersion.SSL_3)
- {
- prf = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, session.masterSecret);
- attr.put(SSLRandom.SEED, Util.concat(server, client));
- prf.init(attr);
- }
- else
- {
- prf = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, session.masterSecret);
- attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"),
- Util.concat(server, client)));
- prf.init(attr);
- }
- for (int i = 0; i < keyMaterial.length; i++)
- {
- prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length);
- }
-
- // Exportable ciphers transform their keys once more, and use a
- // nonsecret IV for block ciphers.
- if (suite.isExportable())
- {
- int finalLen = suite.getCipher() == "DES" ? 8 : 16;
- if (activeVersion == ProtocolVersion.SSL_3)
- {
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- md5.update(keyMaterial[2], 0, keyMaterial[2].length);
- md5.update(client, 0, client.length);
- md5.update(server, 0, server.length);
- keyMaterial[2] = Util.trim(md5.digest(), finalLen);
- md5.update(keyMaterial[3], 0, keyMaterial[3].length);
- md5.update(server, 0, server.length);
- md5.update(client, 0, client.length);
- keyMaterial[3] = Util.trim(md5.digest(), finalLen);
- if (!suite.isStreamCipher())
- {
- md5.update(client, 0, client.length);
- md5.update(server, 0, server.length);
- keyMaterial[4] = Util.trim(md5.digest(), ivLen);
- md5.update(server, 0, server.length);
- md5.update(client, 0, client.length);
- keyMaterial[5] = Util.trim(md5.digest(), ivLen);
- }
- }
- else
- {
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, keyMaterial[2]);
- attr.put(TLSRandom.SEED,
- Util.concat("client write key".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- keyMaterial[2] = new byte[finalLen];
- prf.nextBytes(keyMaterial[2], 0, finalLen);
- attr.put(TLSRandom.SECRET, keyMaterial[3]);
- attr.put(TLSRandom.SEED,
- Util.concat("server write key".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- keyMaterial[3] = new byte[finalLen];
- prf.nextBytes(keyMaterial[3], 0, finalLen);
- if (!suite.isStreamCipher())
- {
- attr.put(TLSRandom.SECRET, new byte[0]);
- attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length);
- prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length);
- }
- }
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:");
- for (int i = 0; i < keyMaterial.length; i++)
- logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}",
- new Object[] { new Integer (i),
- Util.toHexString(keyMaterial[i], ':') });
- }
-
- return keyMaterial;
- }
-
- /**
- * Generate a "finished" message, based on the hashes of the handshake
- * messages, the agreed version, and a label.
- *
- * @param version The agreed version.
- * @param md5 The current state of the handshake MD5 hash.
- * @param sha The current state of the handshake SHA hash.
- * @param client Should be true if the message is generated by the client.
- */
- private Finished generateFinished(ProtocolVersion version, IMessageDigest md5,
- IMessageDigest sha, boolean client)
- {
- if (version == ProtocolVersion.SSL_3)
- {
- if (client)
- {
- md5.update(SENDER_CLIENT, 0, 4);
- }
- else
- {
- md5.update(SENDER_SERVER, 0, 4);
- }
- byte[] ms = session.masterSecret;
- md5.update(ms, 0, ms.length);
- for (int i = 0; i < 48; i++)
- {
- md5.update(SSLHMac.PAD1);
- }
- byte[] b = md5.digest();
- md5.update(ms, 0, ms.length);
- for (int i = 0; i < 48; i++)
- {
- md5.update(SSLHMac.PAD2);
- }
- md5.update(b, 0, b.length);
-
- if (client)
- {
- sha.update(SENDER_CLIENT, 0, 4);
- }
- else
- {
- sha.update(SENDER_SERVER, 0, 4);
- }
- sha.update(ms, 0, ms.length);
- for (int i = 0; i < 40; i++)
- {
- sha.update(SSLHMac.PAD1);
- }
- b = sha.digest();
- sha.update(ms, 0, ms.length);
- for (int i = 0; i < 40; i++)
- {
- sha.update(SSLHMac.PAD2);
- }
- sha.update(b, 0, b.length);
- return new Finished(md5.digest(), sha.digest());
- }
- else
- {
- byte[] h1 = md5.digest();
- byte[] h2 = sha.digest();
- String label = client ? "client finished" : "server finished";
- byte[] seed = null;
- try
- {
- seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2));
- }
- catch (java.io.UnsupportedEncodingException uee)
- {
- RuntimeException re = new RuntimeException (uee.getMessage());
- re.initCause (uee);
- throw re;
- }
- IRandom prf = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, session.masterSecret);
- attr.put(TLSRandom.SEED, seed);
- prf.init(attr);
- byte[] finishedValue = new byte[12];
- try
- {
- prf.nextBytes(finishedValue, 0, 12);
- }
- catch (LimitReachedException lre)
- {
- RuntimeException re = new RuntimeException (lre.getMessage());
- re.initCause (lre);
- throw re;
- }
- return new Finished(finishedValue);
- }
- }
-
- /**
- * Send a fatal unexpected_message alert.
- */
- private Alert unexpectedMessage() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.UNEXPECTED_MESSAGE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwUnexpectedMessage() throws IOException
- {
- throw new AlertException(unexpectedMessage(), true);
- }
-
- /**
- * Send a fatal handshake_failure alert.
- */
- private Alert handshakeFailure() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.HANDSHAKE_FAILURE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwHandshakeFailure() throws IOException
- {
- throw new AlertException(handshakeFailure(), true);
- }
-
- /**
- * Send an internal_error alert.
- */
- private Alert internalError() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.INTERNAL_ERROR);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwInternalError() throws IOException
- {
- throw new AlertException(internalError(), true);
- }
-
- private Alert peerUnverified(X509Certificate[] chain) throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.HANDSHAKE_FAILURE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwPeerUnverified(X509Certificate[] chain) throws IOException
- {
- peerUnverified (chain);
- throw new SSLPeerUnverifiedException("could not verify: "+
- chain[0].getSubjectDN());
- }
-
- /**
- * Grab the first suite that is both in the client's requested suites
- * and in our enabled suites, and for which we have the proper
- * credentials.
- *
- * @param suites The client's requested suites.
- * @param version The version being negotiated.
- * @return The selected cipher suite.
- * @throws SSLException If no appropriate suite can be selected.
- */
- private CipherSuite selectSuite(List suites, ProtocolVersion version)
- throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}",
- new Object[] { suites, session.enabledSuites });
- boolean srpSuiteNoUser = false;
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- CipherSuite herSuite = (CipherSuite) i.next();
- for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); )
- {
- CipherSuite mySuite = (CipherSuite) j.next();
- if (!mySuite.equals(herSuite))
- {
- continue;
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0} == {1}",
- new Object[] { mySuite, herSuite });
- if (mySuite.getSignature() != "anon" && session.keyManager != null &&
- session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key",
- mySuite);
- continue;
- }
- if (mySuite.getKeyExchange() == "SRP")
- {
- if (session.getValue("srp-username") == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "no SRP username");
- srpSuiteNoUser = true;
- continue;
- }
- if (session.srpTrustManager == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "no SRP password file");
- continue;
- }
- }
- return mySuite.resolve(version);
- }
- }
- Alert alert = null;
- if (srpSuiteNoUser)
- {
- alert = new Alert(Alert.Level.WARNING,
- Alert.Description.MISSING_SRP_USERNAME);
- sendAlert(alert);
- return null;
- }
- else
- alert = new Alert(Alert.Level.FATAL,
- Alert.Description.INSUFFICIENT_SECURITY);
- sendAlert(alert);
- fatal();
- throw new AlertException(alert, true);
- }
-
- /**
- * Ask the user for their user name.
- *
- * @param remoteHost The remote host being connected to.
- * @return The user name.
- */
- private String askUserName(String remoteHost)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x) { }
- TextInputCallback user =
- new TextInputCallback("User name for " + remoteHost + ": ",
- Util.getProperty("user.name"));
- try
- {
- handler.handle(new Callback[] { user });
- }
- catch (Exception x) { }
- return user.getText();
- }
-
- /**
- * Ask the user for a password.
- *
- * @param user The user name.
- * @return The password.
- */
- private String askPassword(String user)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x) { }
- PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false);
- try
- {
- handler.handle(new Callback[] { passwd });
- }
- catch (Exception x) { }
- return new String(passwd.getPassword());
- }
-
- /**
- * Ask the user (via a callback) if they will accept a certificate that
- * could not be verified.
- *
- * @param chain The certificate chain in question.
- * @return true if the user accepts the certificate chain.
- */
- private boolean checkCertificates(X509Certificate[] chain)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x)
- {
- }
- String nl = Util.getProperty("line.separator");
- ConfirmationCallback confirm = new ConfirmationCallback(
- "The server's certificate could not be verified. There is no proof" + nl +
- "that this server is who it claims to be, or that their certificate" + nl +
- "is valid. Do you wish to continue connecting?",
- ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION,
- ConfirmationCallback.NO);
- try
- {
- handler.handle(new Callback[] { confirm });
- }
- catch (Exception x)
- {
- return false;
- }
- return confirm.getSelectedIndex() == ConfirmationCallback.YES;
- }
-
- /**
- * Update a signature object with a BigInteger, trimming the leading
- * "00" octet if present.
- *
- * @param sig The signature being updated.
- * @param bi The integer to feed into the signature.
- */
- private void updateSig(ISignature sig, BigInteger bi)
- {
- byte[] buf = Util.trim(bi);
- sig.update((byte) (buf.length >>> 8));
- sig.update((byte) buf.length);
- sig.update(buf, 0, buf.length);
- }
-
- /**
- * Teardown everything on fatal errors.
- */
- private void fatal() throws IOException
- {
- if (session != null)
- {
- session.invalidate();
- }
-// recordInput.setRunning(false);
-// recordOutput.setRunning(false);
- if (underlyingSocket != null)
- {
- underlyingSocket.close();
- }
- else
- {
- super.close();
- }
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java
deleted file mode 100644
index 24a8389c117..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/* SSLSocketFactory.java -- factory for SSL sockets.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.security.SecureRandom;
-
-import javax.net.ssl.X509TrustManager;
-import javax.net.ssl.X509KeyManager;
-
-class SSLSocketFactory extends javax.net.ssl.SSLSocketFactory
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final X509TrustManager trustManager;
- private final X509KeyManager keyManager;
- private final SecureRandom random;
- private final SessionContext sessionContext;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLSocketFactory(X509TrustManager trustManager, X509KeyManager keyManager,
- SecureRandom random, SessionContext sessionContext)
- {
- this.trustManager = trustManager;
- this.keyManager = keyManager;
- this.random = random;
- this.sessionContext = sessionContext;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String[] getDefaultCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
- }
-
- public String[] getSupportedCipherSuites()
- {
- return getDefaultCipherSuites();
- }
-
- public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
- throws IOException
- {
- return setup(new SSLSocket(socket, host, port, autoClose));
- }
-
- public Socket createSocket() throws IOException
- {
- return setup(new SSLSocket());
- }
-
- public Socket createSocket(String host, int port)
- throws IOException, UnknownHostException
- {
- return setup(new SSLSocket(host, port));
- }
-
- public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
- throws IOException, UnknownHostException
- {
- return setup(new SSLSocket(host, port, localAddr, localPort));
- }
-
- public Socket createSocket(InetAddress address, int port) throws IOException
- {
- return setup(new SSLSocket(address, port));
- }
-
- public Socket createSocket(InetAddress address, int port,
- InetAddress localAddr, int localPort)
- throws IOException
- {
- return setup(new SSLSocket(address, port, localAddr, localPort));
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private SSLSocket setup(SSLSocket s)
- {
- s.setTrustManager(trustManager);
- s.setKeyManager(keyManager);
- s.setRandom(random);
- s.setSessionContext(sessionContext);
- s.setUseClientMode(true);
- return s;
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java
new file mode 100644
index 00000000000..6c804f9c629
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java
@@ -0,0 +1,137 @@
+/* SSLSocketFactoryImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLSocketFactoryImpl extends SSLSocketFactory
+{
+ /**
+ * The SSLContextImpl that created us.
+ */
+ private final SSLContextImpl contextImpl;
+
+ public SSLSocketFactoryImpl(SSLContextImpl contextImpl)
+ {
+ this.contextImpl = contextImpl;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean)
+ */
+ @Override public Socket createSocket(Socket socket, String host, int port,
+ boolean autoClose)
+ throws IOException
+ {
+ return new SSLSocketImpl(contextImpl, host, port, socket, autoClose);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites()
+ */
+ @Override public String[] getDefaultCipherSuites()
+ {
+ return SSLEngineImpl.defaultSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.lang.String, int)
+ */
+ @Override public SSLSocketImpl createSocket(String host, int port)
+ throws IOException, UnknownHostException
+ {
+ SSLSocketImpl socket = new SSLSocketImpl(contextImpl, host, port);
+ InetSocketAddress endpoint = new InetSocketAddress(host, port);
+ socket.connect(endpoint);
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(String host, int port,
+ InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException
+ {
+ SSLSocketImpl socket = createSocket(host, port);
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(InetAddress host, int port)
+ throws IOException
+ {
+ SSLSocketImpl socket = new SSLSocketImpl(contextImpl,
+ host.getCanonicalHostName(), port);
+ socket.connect(new InetSocketAddress(host, port));
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int, java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(InetAddress host, int port,
+ InetAddress localHost, int localPort)
+ throws IOException
+ {
+ SSLSocketImpl socket = createSocket(host, port);
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ return socket;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java
new file mode 100644
index 00000000000..0181b66d854
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java
@@ -0,0 +1,833 @@
+/* SSLSocketImpl.java -- implementation of an SSL client socket.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLSocketImpl extends SSLSocket
+{
+ private class SocketOutputStream extends OutputStream
+ {
+ private final ByteBuffer buffer;
+ private final OutputStream out;
+
+ SocketOutputStream() throws IOException
+ {
+ buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ if (underlyingSocket != null)
+ out = underlyingSocket.getOutputStream();
+ else
+ out = SSLSocketImpl.super.getOutputStream();
+ }
+
+ @Override public void write(byte[] buf, int off, int len) throws IOException
+ {
+ if (!initialHandshakeDone
+ || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
+ {
+ doHandshake();
+ if (handshakeException != null)
+ throw handshakeException;
+ }
+
+ int k = 0;
+ while (k < len)
+ {
+ synchronized (engine)
+ {
+ int l = Math.min(len-k, getSession().getApplicationBufferSize());
+ ByteBuffer in = ByteBuffer.wrap(buf, off+k, l);
+ SSLEngineResult result = engine.wrap(in, buffer);
+ if (result.getStatus() == Status.CLOSED)
+ return;
+ if (result.getStatus() != Status.OK)
+ throw new SSLException("unexpected SSL state " + result.getStatus());
+ buffer.flip();
+ out.write(buffer.array(), 0, buffer.limit());
+ k += result.bytesConsumed();
+ buffer.clear();
+ }
+ }
+ }
+
+ @Override public void write(int b) throws IOException
+ {
+ write(new byte[] { (byte) b });
+ }
+
+ @Override public void close() throws IOException
+ {
+ SSLSocketImpl.this.close();
+ }
+ }
+
+ private class SocketInputStream extends InputStream
+ {
+ private final ByteBuffer inBuffer;
+ private final ByteBuffer appBuffer;
+ private final DataInputStream in;
+
+ SocketInputStream() throws IOException
+ {
+ inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ inBuffer.limit(0);
+ appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize());
+ appBuffer.flip();
+ if (underlyingSocket != null)
+ in = new DataInputStream(underlyingSocket.getInputStream());
+ else
+ in = new DataInputStream(SSLSocketImpl.super.getInputStream());
+ }
+
+ @Override public int read(byte[] buf, int off, int len) throws IOException
+ {
+ if (!initialHandshakeDone ||
+ engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
+ {
+ doHandshake();
+ if (handshakeException != null)
+ throw handshakeException;
+ }
+
+ if (!appBuffer.hasRemaining())
+ {
+ int x = in.read();
+ if (x == -1)
+ return -1;
+ inBuffer.clear();
+ inBuffer.put((byte) x);
+ inBuffer.putInt(in.readInt());
+ int reclen = inBuffer.getShort(3) & 0xFFFF;
+ in.readFully(inBuffer.array(), 5, reclen);
+ inBuffer.position(0).limit(reclen + 5);
+ synchronized (engine)
+ {
+ appBuffer.clear();
+ SSLEngineResult result = engine.unwrap(inBuffer, appBuffer);
+ Status status = result.getStatus();
+ if (status == Status.CLOSED && result.bytesProduced() == 0)
+ return -1;
+ }
+ inBuffer.compact();
+ appBuffer.flip();
+ }
+ int l = Math.min(len, appBuffer.remaining());
+ appBuffer.get(buf, off, l);
+ return l;
+ }
+
+ @Override public int read() throws IOException
+ {
+ byte[] b = new byte[1];
+ if (read(b) == -1)
+ return -1;
+ return b[0] & 0xFF;
+ }
+ }
+
+ private static final SystemLogger logger = SystemLogger.getSystemLogger();
+
+ private SSLEngineImpl engine;
+ private Set<HandshakeCompletedListener> listeners;
+ private Socket underlyingSocket;
+ private boolean isHandshaking;
+ private IOException handshakeException;
+ private boolean initialHandshakeDone = false;
+ private final boolean autoClose;
+
+ public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port)
+ {
+ this(contextImpl, host, port, null, false);
+ }
+
+ public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port,
+ Socket underlyingSocket, boolean autoClose)
+ {
+ engine = new SSLEngineImpl(contextImpl, host, port);
+ engine.setUseClientMode(true); // default to client mode
+ listeners = new HashSet<HandshakeCompletedListener>();
+ this.underlyingSocket = underlyingSocket;
+ this.autoClose = autoClose;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
+ */
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener)
+ {
+ listeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
+ */
+ @Override public boolean getEnableSessionCreation()
+ {
+ return engine.getEnableSessionCreation();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
+ */
+ @Override public String[] getEnabledCipherSuites()
+ {
+ return engine.getEnabledCipherSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
+ */
+ @Override public String[] getEnabledProtocols()
+ {
+ return engine.getEnabledProtocols();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
+ */
+ @Override public boolean getNeedClientAuth()
+ {
+ return engine.getNeedClientAuth();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getSession()
+ */
+ @Override public SSLSession getSession()
+ {
+ return engine.getSession();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return engine.getSupportedCipherSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
+ */
+ @Override public String[] getSupportedProtocols()
+ {
+ return engine.getSupportedProtocols();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getUseClientMode()
+ */
+ @Override public boolean getUseClientMode()
+ {
+ return engine.getUseClientMode();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getWantClientAuth()
+ */
+ @Override public boolean getWantClientAuth()
+ {
+ return engine.getWantClientAuth();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
+ */
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener)
+ {
+ listeners.remove(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
+ */
+ @Override public void setEnableSessionCreation(boolean enable)
+ {
+ engine.setEnableSessionCreation(enable);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[])
+ */
+ @Override public void setEnabledCipherSuites(String[] suites)
+ {
+ engine.setEnabledCipherSuites(suites);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[])
+ */
+ @Override public void setEnabledProtocols(String[] protocols)
+ {
+ engine.setEnabledProtocols(protocols);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
+ */
+ @Override public void setNeedClientAuth(boolean needAuth)
+ {
+ engine.setNeedClientAuth(needAuth);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
+ */
+ @Override public void setUseClientMode(boolean clientMode)
+ {
+ engine.setUseClientMode(clientMode);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
+ */
+ @Override public void setWantClientAuth(boolean wantAuth)
+ {
+ engine.setWantClientAuth(wantAuth);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#startHandshake()
+ */
+ @Override public void startHandshake() throws IOException
+ {
+ if (isHandshaking)
+ return;
+
+ if (handshakeException != null)
+ throw handshakeException;
+
+ Thread t = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ doHandshake();
+ }
+ catch (IOException ioe)
+ {
+ handshakeException = ioe;
+ }
+ }
+ }, "HandshakeThread@" + System.identityHashCode(this));
+ t.start();
+ }
+
+ void doHandshake() throws IOException
+ {
+ synchronized (engine)
+ {
+ if (isHandshaking)
+ {
+ try
+ {
+ engine.wait();
+ }
+ catch (InterruptedException ie)
+ {
+ }
+ return;
+ }
+ isHandshaking = true;
+ }
+
+ if (initialHandshakeDone)
+ throw new SSLException("rehandshaking not yet implemented");
+
+ long now = -System.currentTimeMillis();
+ engine.beginHandshake();
+
+ HandshakeStatus status = engine.getHandshakeStatus();
+ assert(status != HandshakeStatus.NOT_HANDSHAKING);
+
+ ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ inBuffer.position(inBuffer.limit());
+ ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
+ SSLEngineResult result = null;
+
+ DataInputStream sockIn = null;
+ if (underlyingSocket != null)
+ sockIn = new DataInputStream(underlyingSocket.getInputStream());
+ else
+ sockIn = new DataInputStream(super.getInputStream());
+
+ OutputStream sockOut = null;
+ if (underlyingSocket != null)
+ sockOut = underlyingSocket.getOutputStream();
+ else
+ sockOut = super.getOutputStream();
+
+ try
+ {
+ while (status != HandshakeStatus.NOT_HANDSHAKING
+ && status != HandshakeStatus.FINISHED)
+ {
+ logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}",
+ status);
+
+ if (inBuffer.capacity() != getSession().getPacketBufferSize())
+ {
+ ByteBuffer b
+ = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ if (inBuffer.hasRemaining())
+ b.put(inBuffer).flip();
+ inBuffer = b;
+ }
+ if (outBuffer.capacity() != getSession().getPacketBufferSize())
+ outBuffer
+ = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+
+ switch (status)
+ {
+ case NEED_UNWRAP:
+ // Read in a single SSL record.
+ inBuffer.clear();
+ int i = sockIn.read();
+ if (i == -1)
+ throw new EOFException();
+ if ((i & 0x80) == 0x80) // SSLv2 client hello.
+ {
+ inBuffer.put((byte) i);
+ int v2len = (i & 0x7f) << 8;
+ i = sockIn.read();
+ v2len = v2len | (i & 0xff);
+ inBuffer.put((byte) i);
+ sockIn.readFully(inBuffer.array(), 2, v2len);
+ inBuffer.position(0).limit(v2len + 2);
+ }
+ else
+ {
+ inBuffer.put((byte) i);
+ inBuffer.putInt(sockIn.readInt());
+ int reclen = inBuffer.getShort(3) & 0xFFFF;
+ sockIn.readFully(inBuffer.array(), 5, reclen);
+ inBuffer.position(0).limit(reclen + 5);
+ }
+ result = engine.unwrap(inBuffer, emptyBuffer);
+ status = result.getHandshakeStatus();
+ if (result.getStatus() != Status.OK)
+ throw new SSLException("unexpected SSL status "
+ + result.getStatus());
+ break;
+
+ case NEED_WRAP:
+ {
+ outBuffer.clear();
+ result = engine.wrap(emptyBuffer, outBuffer);
+ status = result.getHandshakeStatus();
+ if (result.getStatus() != Status.OK)
+ throw new SSLException("unexpected SSL status "
+ + result.getStatus());
+ outBuffer.flip();
+ sockOut.write(outBuffer.array(), outBuffer.position(),
+ outBuffer.limit());
+ }
+ break;
+
+ case NEED_TASK:
+ {
+ Runnable task;
+ while ((task = engine.getDelegatedTask()) != null)
+ task.run();
+ status = engine.getHandshakeStatus();
+ }
+ break;
+
+ case FINISHED:
+ break;
+ }
+ }
+
+ initialHandshakeDone = true;
+
+ HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession());
+ for (HandshakeCompletedListener l : listeners)
+ {
+ try
+ {
+ l.handshakeCompleted(hce);
+ }
+ catch (ThreadDeath td)
+ {
+ throw td;
+ }
+ catch (Throwable x)
+ {
+ logger.log(Component.WARNING,
+ "HandshakeCompletedListener threw exception", x);
+ }
+ }
+
+ now += System.currentTimeMillis();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "handshake completed in {0}ms in thread {1}", now,
+ Thread.currentThread().getName());
+ }
+ catch (SSLException ssle)
+ {
+ handshakeException = ssle;
+ throw ssle;
+ }
+ finally
+ {
+ synchronized (engine)
+ {
+ isHandshaking = false;
+ engine.notifyAll();
+ }
+ }
+ }
+
+ // Methods overriding Socket.
+
+ @Override public void bind(SocketAddress bindpoint) throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.bind(bindpoint);
+ else
+ super.bind(bindpoint);
+ }
+
+ @Override public void connect(SocketAddress endpoint) throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.connect(endpoint);
+ else
+ super.connect(endpoint);
+ }
+
+ @Override public void connect(SocketAddress endpoint, int timeout)
+ throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.connect(endpoint, timeout);
+ else
+ super.connect(endpoint, timeout);
+ }
+
+ @Override public InetAddress getInetAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getInetAddress();
+ return super.getInetAddress();
+ }
+
+ @Override public InetAddress getLocalAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getLocalAddress();
+ return super.getLocalAddress();
+ }
+
+ @Override public int getPort()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getPort();
+ return super.getPort();
+ }
+
+ @Override public int getLocalPort()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getLocalPort();
+ return super.getLocalPort();
+ }
+
+ @Override public SocketAddress getRemoteSocketAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getRemoteSocketAddress();
+ return super.getRemoteSocketAddress();
+ }
+
+ public SocketAddress getLocalSocketAddress()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getLocalSocketAddress();
+ return super.getLocalSocketAddress();
+ }
+
+ @Override public SocketChannel getChannel()
+ {
+ throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO");
+ }
+
+ @Override public InputStream getInputStream() throws IOException
+ {
+ return new SocketInputStream();
+ }
+
+ @Override public OutputStream getOutputStream() throws IOException
+ {
+ return new SocketOutputStream();
+ }
+
+ @Override public void setTcpNoDelay(boolean on) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setTcpNoDelay(on);
+ else
+ super.setTcpNoDelay(on);
+ }
+
+ @Override public boolean getTcpNoDelay() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getTcpNoDelay();
+ return super.getTcpNoDelay();
+ }
+
+ @Override public void setSoLinger(boolean on, int linger) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setSoLinger(on, linger);
+ else
+ super.setSoLinger(on, linger);
+ }
+
+ public int getSoLinger() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getSoLinger();
+ return super.getSoLinger();
+ }
+
+ @Override public void sendUrgentData(int x) throws IOException
+ {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ @Override public void setOOBInline(boolean on) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setOOBInline(on);
+ else
+ super.setOOBInline(on);
+ }
+
+ @Override public boolean getOOBInline() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getOOBInline();
+ return super.getOOBInline();
+ }
+
+ @Override public void setSoTimeout(int timeout) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setSoTimeout(timeout);
+ else
+ super.setSoTimeout(timeout);
+ }
+
+ @Override public int getSoTimeout() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getSoTimeout();
+ return super.getSoTimeout();
+ }
+
+ @Override public void setSendBufferSize(int size) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setSendBufferSize(size);
+ else
+ super.setSendBufferSize(size);
+ }
+
+ @Override public int getSendBufferSize() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getSendBufferSize();
+ return super.getSendBufferSize();
+ }
+
+ @Override public void setReceiveBufferSize(int size) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setReceiveBufferSize(size);
+ else
+ underlyingSocket.setReceiveBufferSize(size);
+ }
+
+ @Override public int getReceiveBufferSize() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getReceiveBufferSize();
+ return super.getReceiveBufferSize();
+ }
+
+ @Override public void setKeepAlive(boolean on) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setKeepAlive(on);
+ else
+ super.setKeepAlive(on);
+ }
+
+ @Override public boolean getKeepAlive() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getKeepAlive();
+ return super.getKeepAlive();
+ }
+
+ @Override public void setTrafficClass(int tc) throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setTrafficClass(tc);
+ else
+ super.setTrafficClass(tc);
+ }
+
+ @Override public int getTrafficClass() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getTrafficClass();
+ return super.getTrafficClass();
+ }
+
+ @Override public void setReuseAddress(boolean reuseAddress)
+ throws SocketException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.setReuseAddress(reuseAddress);
+ else
+ super.setReuseAddress(reuseAddress);
+ }
+
+ @Override public boolean getReuseAddress() throws SocketException
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.getReuseAddress();
+ return super.getReuseAddress();
+ }
+
+ @Override public void close() throws IOException
+ {
+ // XXX closure alerts.
+ if (underlyingSocket != null && autoClose)
+ underlyingSocket.close();
+ else
+ super.close();
+ }
+
+ @Override public void shutdownInput() throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.shutdownInput();
+ else
+ super.shutdownInput();
+ }
+
+ @Override public void shutdownOutput() throws IOException
+ {
+ if (underlyingSocket != null)
+ underlyingSocket.shutdownOutput();
+ else
+ super.shutdownOutput();
+ }
+
+ @Override public boolean isConnected()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isConnected();
+ return super.isConnected();
+ }
+
+ @Override public boolean isBound()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isBound();
+ return super.isBound();
+ }
+
+ @Override public boolean isClosed()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isClosed();
+ return super.isClosed();
+ }
+
+ @Override public boolean isInputShutdown()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isInputShutdown();
+ return super.isInputShutdown();
+ }
+
+ @Override public boolean isOutputShutdown()
+ {
+ if (underlyingSocket != null)
+ return underlyingSocket.isOutputShutdown();
+ return super.isOutputShutdown();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java
deleted file mode 100644
index 69202ca33d8..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/* SSLSocketInputStream.java -- InputStream for SSL sockets.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.EOFException;
-import java.io.FilterInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import javax.net.ssl.SSLException;
-
-class SSLSocketInputStream extends FilterInputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final SSLSocket socket;
- private final boolean checkHandshake;
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLSocketInputStream(InputStream in, SSLSocket socket)
- {
- this(in, socket, true);
- }
-
- SSLSocketInputStream(InputStream in, SSLSocket socket, boolean checkHandshake)
- {
- super(in);
- this.socket = socket;
- this.checkHandshake = checkHandshake;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public int available() throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- int ret = 0;
- try
- {
- ret = super.available();
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert ();
- if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
- {
- return -1;
- }
- else
- {
- throw ae;
- }
- }
- return ret;
- }
-
- public int read() throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- int ret = 0;
- try
- {
- ret = in.read();
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert ();
- if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
- {
- return -1;
- }
- else
- {
- throw ae;
- }
- }
- return ret;
- }
-
- public int read(byte[] buf) throws IOException
- {
- return read(buf, 0, buf.length);
- }
-
- public int read(byte[] buf, int off, int len) throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- if (buf == null)
- {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off + len > buf.length)
- {
- throw new ArrayIndexOutOfBoundsException();
- }
- int ret = 0;
- try
- {
- ret = in.read(buf, off, len);
- }
- catch (AlertException ae)
- {
- Alert alert = ae.getAlert ();
- if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
- {
- return -1;
- }
- else
- {
- throw ae;
- }
- }
- return ret;
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private boolean checkAlert() throws IOException
- {
- Alert alert = socket.checkAlert();
- if (alert == null) return false;
- if (alert.getLevel().equals(Alert.Level.FATAL))
- throw new AlertException(alert, false);
- if (alert.getDescription().equals(Alert.Description.CLOSE_NOTIFY))
- {
- try { return (in.available() <= 0); }
- catch (IOException ioe) { }
- }
- return false;
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
deleted file mode 100644
index fe769a85fba..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/* SSLSocketOutputStream.java -- output stream for SSL sockets.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import javax.net.ssl.SSLException;
-
-class SSLSocketOutputStream extends FilterOutputStream
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final SSLSocket socket;
- private final boolean checkHandshake;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SSLSocketOutputStream(OutputStream out, SSLSocket socket)
- {
- this(out, socket, true);
- }
-
- SSLSocketOutputStream(OutputStream out, SSLSocket socket,
- boolean checkHandshake)
- {
- super(out);
- this.socket = socket;
- this.checkHandshake = checkHandshake;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(int b) throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- checkAlert();
- out.write(b);
- checkAlert();
- }
-
- public void write(byte[] buf) throws IOException
- {
- write(buf, 0, buf.length);
- }
-
- public void write(byte[] buf, int off, int len) throws IOException
- {
- if (checkHandshake)
- {
- socket.checkHandshakeDone();
- }
- if (buf == null)
- throw new NullPointerException();
- if (off < 0 || len < 0 || off + len > buf.length)
- throw new ArrayIndexOutOfBoundsException();
- checkAlert();
- out.write(buf, off, len);
- checkAlert();
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private synchronized void checkAlert() throws SSLException
- {
- Alert alert = socket.checkAlert();
- if (alert == null) return;
- if (alert.getLevel().equals(Alert.Level.FATAL))
- throw new AlertException(alert, false);
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java
new file mode 100644
index 00000000000..763bbaf3b77
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java
@@ -0,0 +1,116 @@
+/* SSLv3HMacMD5.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * @author csm
+ */
+public class SSLv3HMacMD5Impl extends MacSpi
+{
+ private final SSLHMac adaptee;
+
+ public SSLv3HMacMD5Impl()
+ {
+ adaptee = new SSLHMac("MD5");
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineDoFinal()
+ */
+ @Override protected byte[] engineDoFinal()
+ {
+ return adaptee.digest();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineGetMacLength()
+ */
+ @Override protected int engineGetMacLength()
+ {
+ return adaptee.macSize();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec)
+ */
+ @Override protected void engineInit(Key key, AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ if (!(key instanceof SecretKey)
+ || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-MD5"))
+ throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-MD5\"");
+ Map<String,byte[]> attr =
+ Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded());
+ adaptee.init(attr);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineReset()
+ */
+ @Override protected void engineReset()
+ {
+ adaptee.reset();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte)
+ */
+ @Override protected void engineUpdate(byte input)
+ {
+ adaptee.update(input);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int)
+ */
+ @Override protected void engineUpdate(byte[] input, int offset, int length)
+ {
+ adaptee.update(input, offset, length);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java
new file mode 100644
index 00000000000..008a21c049d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java
@@ -0,0 +1,116 @@
+/* SSLv3HMacSHA.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * @author csm
+ */
+public class SSLv3HMacSHAImpl extends MacSpi
+{
+ private final SSLHMac adaptee;
+
+ public SSLv3HMacSHAImpl()
+ {
+ adaptee = new SSLHMac("SHA-160");
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineDoFinal()
+ */
+ @Override protected byte[] engineDoFinal()
+ {
+ return adaptee.digest();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineGetMacLength()
+ */
+ @Override protected int engineGetMacLength()
+ {
+ return adaptee.macSize();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec)
+ */
+ @Override protected void engineInit(Key key, AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ if (!(key instanceof SecretKey)
+ || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-SHA"))
+ throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-SHA\"");
+ Map<String,byte[]> attr =
+ Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded());
+ adaptee.init(attr);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineReset()
+ */
+ @Override protected void engineReset()
+ {
+ adaptee.reset();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte)
+ */
+ @Override protected void engineUpdate(byte input)
+ {
+ adaptee.update(input);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int)
+ */
+ @Override protected void engineUpdate(byte[] input, int offset, int length)
+ {
+ adaptee.update(input, offset, length);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java
deleted file mode 100644
index aa06680e200..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/* SecurityParameters.java -- SSL security parameters.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import javax.net.ssl.SSLException;
-
-/**
- * The interface that all security parameters used by Jessie must implement.
- * Security parameters handle all transforming of data, including encryption,
- * authentication, and compression.
- */
-interface SecurityParameters
-{
-
- // Methods.
- // -------------------------------------------------------------------------
-
- /**
- * Decrypts, verifies, and inflates a fragment received. The fragment is
- * just the data field of a text object, without the version, type, and
- * length fields. An exception is thrown if any step fails.
- *
- * @param fragment The fragment being decrypted.
- * @param version The version field of the received text.
- * @param type The type field of the received text.
- * @return The decrypted fragment.
- * @throws MacException If the MAC could not be verified, or if the padding
- * on the decrypted fragment is incorrect.
- * @throws OverflowException If the processed text overflows the configured
- * maximum fragment size.
- * @throws SSLException If any other error occurs.
- */
- byte[] decrypt (byte[] fragment, ProtocolVersion version, ContentType type)
- throws MacException, OverflowException, SSLException;
-
- /**
- * Deflates, authenticates, and encrypts a fragment to be sent.
- *
- * @param buf The fragment being encrypted.
- * @param off The offset into the buffer to start at.
- * @param len The number of bytes in this fragment.
- * @param type The content type of this text.
- * @return The encrypted fragment.
- * @throws OverflowException If deflating increases the size of the fragment
- * too much.
- * @throws SSLException If any other error occurs.
- */
- byte[] encrypt (byte[] buf, int off, int len, ContentType type)
- throws OverflowException, SSLException;
-
- /**
- * Set all crypto primitives to <code>null</code>, meaning that any calls
- * to {@link #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} or
- * {@link #decrypt(byte[],org.metastatic.jessie.provider.ProtocolVersion,org.metastatic.jessie.provider.ContentType})
- * will perform the identity transformation.
- */
- void reset();
-
- /**
- * Returns the version of texts being sent.
- *
- * @return The version.
- */
- ProtocolVersion getVersion();
-
- /**
- * Sets the version of texts being sent. This affects the {@link
- * #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)}
- * method.
- *
- * @param version The version to set.
- */
- void setVersion (ProtocolVersion version);
-
- /**
- * Turns zlib deflating on or off.
- *
- * @param deflate Whether or not to deflate outgoing fragments.
- */
- void setDeflating (boolean deflate);
-
- /**
- * Turns zlib inflating on or off.
- *
- * @param inflate Whether or not to inflate incoming fragments.
- */
- void setInflating (boolean inflate);
-
- /**
- * Returns the maximum size that plaintext fragments may be.
- *
- * @return The fragment length.
- */
- int getFragmentLength();
-
- /**
- * Sets the maximum size that plaintext fragments may be.
- *
- * @param fragmentLength The new fragment length.
- */
- void setFragmentLength (int fragmentLength);
-
- /**
- * Set the cipher used to decrypt incoming fragments. The parameter must be
- * appropriate for the implementation.
- *
- * @param cipher The cipher.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setInCipher (Object cipher);
-
- /**
- * Set the cipher used to encrypt outgoing fragments. The parameter must be
- * appropriate for the implementation.
- *
- * @param cipher The cipher.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setOutCipher (Object cipher);
-
- /**
- * Set the MAC used to verify incoming fragments. The parameter must be
- * appropriate for the implementation.
- *
- * @param mac The MAC.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setInMac (Object mac);
-
- /**
- * Set the MAC used to authenticating outgoinging fragments. The parameter
- * must be appropriate for the implementation.
- *
- * @param mac The MAC.
- * @throws ClassCastException If the argument is not appropriate for the
- * implementation.
- */
- void setOutMac (Object mac);
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
new file mode 100644
index 00000000000..edc3ac259cb
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
@@ -0,0 +1,151 @@
+/* ServerDHE_PSKParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case diffie_hellman_psk: /* NEW &#42;/
+ opaque psk_identity_hint&lt;0..2^16-1&gt;;
+ ServerDHParams params;
+ };
+ } ServerKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyExchangeParams
+{
+ private ByteBuffer buffer;
+
+ public ServerDHE_PSKParameters(ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerDHE_PSKParameters(String identityHint, ServerDHParams dhParams)
+ {
+ this(identityHint, dhParams.buffer());
+ }
+
+ public ServerDHE_PSKParameters(String identityHint, ByteBuffer dhParams)
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer hintBuf = utf8.encode(identityHint);
+ buffer = ByteBuffer.allocate(2 + hintBuf.remaining() + dhParams.remaining());
+ buffer.putShort((short) hintBuf.remaining());
+ buffer.put(hintBuf);
+ buffer.put(dhParams);
+ }
+
+ public KeyExchangeAlgorithm algorithm()
+ {
+ return KeyExchangeAlgorithm.DHE_PSK;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2 + params().length();
+ }
+
+ private int hintLength()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identityHint()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+ (hintLength())).toString();
+ }
+
+ public ServerDHParams params()
+ {
+ return new ServerDHParams(((ByteBuffer) buffer.duplicate().position
+ (hintLength()).limit(buffer.capacity())).slice());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ public @Override String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity_hint = ");
+ out.print(identityHint());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.println(" params =");
+ out.println(params().toString(prefix != null ? prefix + " " : " "));
+ if (prefix != null) out.print(prefix);
+ out.print("} ServerDHE_PSKParameters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java
new file mode 100644
index 00000000000..55d4a41da94
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java
@@ -0,0 +1,248 @@
+/* ServerDHParams.java -- The server's Diffie-Hellman parameters.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The server's Diffie-Hellman parameters message.
+ *
+ * <pre>
+struct
+{
+ opaque dh_p&lt;1..2^16-1&gt;;
+ opaque dh_g&lt;1..2^16-1&gt;;
+ opaque dh_Ys&lt;1..2^16-1&gt;;
+} ServerDHParams;
+</pre>
+ */
+public class ServerDHParams implements Builder, ServerKeyExchangeParams
+{
+ private final ByteBuffer buffer;
+
+ public ServerDHParams (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerDHParams (final BigInteger p, final BigInteger g,
+ final BigInteger y)
+ {
+ byte[] p_bytes = p.toByteArray();
+ byte[] g_bytes = g.toByteArray();
+ byte[] y_bytes = y.toByteArray();
+ int len = p_bytes.length + g_bytes.length + y_bytes.length + 6;
+
+ int p_off = 0;
+ if (p_bytes[0] == 0x00)
+ {
+ p_off = 1;
+ len--;
+ }
+ int g_off = 0;
+ if (g_bytes[0] == 0x00)
+ {
+ g_off = 1;
+ len--;
+ }
+ int y_off = 0;
+ if (y_bytes[0] == 0x00)
+ {
+ y_off = 1;
+ len--;
+ }
+ int p_len = p_bytes.length - p_off;
+ int g_len = g_bytes.length - g_off;
+ int y_len = y_bytes.length - y_off;
+
+ buffer = ByteBuffer.allocate(len);
+ buffer.putShort((short) p_len);
+ buffer.put(p_bytes, p_off, p_len);
+ buffer.putShort((short) g_len);
+ buffer.put(g_bytes, g_off, g_len);
+ buffer.putShort((short) y_len);
+ buffer.put(y_bytes, y_off, y_len);
+ }
+
+ @Deprecated public KeyExchangeAlgorithm algorithm ()
+ {
+ return null; // XXX can't support this.
+ }
+
+ public int length ()
+ {
+ int offset1 = buffer.getShort (0) & 0xFFFF;
+ int offset2 = buffer.getShort (offset1 + 2) & 0xFFFF;
+ return ((buffer.getShort (offset1 + offset2 + 4) & 0xFFFF)
+ + offset1 + offset2 + 6);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().position(0).limit(length());
+ }
+
+ /**
+ * Returns the server's prime modulus.
+ *
+ * @return p.
+ */
+ public BigInteger p ()
+ {
+ int len = buffer.getShort (0) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Returns the server's generator value.
+ *
+ * @return g.
+ */
+ public BigInteger g ()
+ {
+ int off = (buffer.getShort (0) & 0xFFFF) + 2;
+ int len = buffer.getShort (off) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (off + 2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Returns the server's public value.
+ *
+ * @return Y.
+ */
+ public BigInteger y ()
+ {
+ int offset1 = (buffer.getShort (0) & 0xFFFF) + 2;
+ int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2;
+ int len = buffer.getShort (offset2) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (offset2 + 2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Sets the server's prime modulus, p.
+ *
+ * @param p The p parameter.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setP (final BigInteger p)
+ {
+ byte[] buf = p.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (buf, offset, length);
+ }
+
+ /**
+ * Sets the server's generator value, g.
+ *
+ * @param g The g parameter.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setG (final BigInteger g)
+ {
+ byte[] buf = g.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ int where = (buffer.getShort (0) & 0xFFFF) + 2;
+ buffer.putShort (where, (short) length);
+ buffer.position (where + 2);
+ buffer.put (buf, offset, length);
+ }
+
+ /**
+ * Sets the server's public value, Y.
+ *
+ * @param y The Y parameter.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setY (final BigInteger y)
+ {
+ int offset1 = (buffer.getShort (0) & 0xFFFF) + 2;
+ int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2;
+ byte[] buf = y.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ buffer.putShort (offset2, (short) length);
+ buffer.position (offset2 + 2);
+ buffer.put (buf, offset, length);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_p: ");
+ out.println (p ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_g: ");
+ out.println (g ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_Ys: ");
+ out.println (y ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerDHParams;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java
new file mode 100644
index 00000000000..300012a4b30
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java
@@ -0,0 +1,1377 @@
+/* ServerHandshake.java -- the server-side handshake.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import static gnu.javax.net.ssl.provider.Handshake.Type.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+import static gnu.javax.net.ssl.provider.ServerHandshake.State.*;
+
+import gnu.classpath.debug.Component;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.provider.Alert.Description;
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.x500.X500Principal;
+
+class ServerHandshake extends AbstractHandshake
+{
+ /**
+ * Handshake state enumeration.
+ */
+ static enum State
+ {
+ WRITE_HELLO_REQUEST (true, false),
+ WRITE_SERVER_HELLO (true, false),
+ WRITE_CERTIFICATE (true, false),
+ WRITE_SERVER_KEY_EXCHANGE (true, false),
+ WRITE_CERTIFICATE_REQUEST (true, false),
+ WRITE_SERVER_HELLO_DONE (true, false),
+ WRITE_FINISHED (true, false),
+ READ_CLIENT_HELLO (false, true),
+ READ_CERTIFICATE (false, true),
+ READ_CLIENT_KEY_EXCHANGE (false, true),
+ READ_CERTIFICATE_VERIFY (false, true),
+ READ_FINISHED (false, true),
+ DONE (false, false);
+
+ private final boolean isWriteState;
+ private final boolean isReadState;
+
+ private State(final boolean isWriteState, final boolean isReadState)
+ {
+ this.isWriteState = isWriteState;
+ this.isReadState = isReadState;
+ }
+
+ boolean isReadState()
+ {
+ return isReadState;
+ }
+
+ boolean isWriteState()
+ {
+ return isWriteState;
+ }
+ }
+
+ private State state;
+
+ /* Handshake result fields. */
+ private ByteBuffer outBuffer;
+ private boolean clientHadExtensions = false;
+ private boolean continuedSession = false;
+ private ServerNameList requestedNames = null;
+ private String keyAlias = null;
+ private X509Certificate clientCert = null;
+ private X509Certificate localCert = null;
+ private boolean helloV2 = false;
+ private KeyPair dhPair;
+ private PrivateKey serverKey;
+
+ // Delegated tasks we use.
+ private GenDH genDH;
+ private CertVerifier certVerifier;
+ private CertLoader certLoader;
+ private DelegatedTask keyExchangeTask;
+
+ ServerHandshake (boolean writeHelloRequest, final SSLEngineImpl engine)
+ throws NoSuchAlgorithmException
+ {
+ super(engine);
+ if (writeHelloRequest)
+ state = WRITE_HELLO_REQUEST;
+ else
+ state = READ_CLIENT_HELLO;
+ handshakeOffset = 0;
+ }
+
+ /**
+ * Choose the protocol version. Here we choose the largest protocol
+ * version we support that is not greater than the client's
+ * requested version.
+ */
+ private static ProtocolVersion chooseProtocol (final ProtocolVersion clientVersion,
+ final String[] enabledVersions)
+ throws SSLException
+ {
+ ProtocolVersion version = null;
+ for (int i = 0; i < enabledVersions.length; i++)
+ {
+ ProtocolVersion v = ProtocolVersion.forName (enabledVersions[i]);
+ if (v.compareTo (clientVersion) <= 0)
+ {
+ if (version == null
+ || v.compareTo (version) > 0)
+ version = v;
+ }
+ }
+
+ // The client requested a protocol version too old, or no protocol
+ // versions are enabled.
+ if (version == null)
+ throw new SSLException ("no acceptable protocol version available");
+ return version;
+ }
+
+ /**
+ * Choose the first cipher suite in the client's requested list that
+ * we have enabled.
+ */
+ private CipherSuite chooseSuite (final CipherSuiteList clientSuites,
+ final String[] enabledSuites,
+ final ProtocolVersion version)
+ throws SSLException
+ {
+ // Figure out which SignatureAlgorithms we can support.
+ HashSet<KeyExchangeAlgorithm> kexes = new HashSet<KeyExchangeAlgorithm>(8);
+
+ kexes.add(NONE);
+ X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+ if (km != null)
+ {
+ if (km.getServerAliases(DH_DSS.name(), null).length > 0)
+ kexes.add(DH_DSS);
+ if (km.getServerAliases(DH_RSA.name(), null).length > 0)
+ kexes.add(DH_RSA);
+ if (km.getServerAliases(DHE_DSS.name(), null).length > 0)
+ kexes.add(DHE_DSS);
+ if (km.getServerAliases(DHE_RSA.name(), null).length > 0)
+ kexes.add(DHE_RSA);
+ if (km.getServerAliases(RSA.name(), null).length > 0)
+ kexes.add(RSA);
+ if (km.getServerAliases(RSA_PSK.name(), null).length > 0
+ && engine.contextImpl.pskManager != null)
+ kexes.add(RSA_PSK);
+ }
+ if (engine.contextImpl.pskManager != null)
+ {
+ kexes.add(DHE_PSK);
+ kexes.add(PSK);
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "we have certs for key exchange algorithms {0}", kexes);
+
+ HashSet<CipherSuite> suites = new HashSet<CipherSuite>();
+ for (String s : enabledSuites)
+ {
+ CipherSuite suite = CipherSuite.forName(s);
+ if (suite == null)
+ continue;
+ if (!kexes.contains(suite.keyExchangeAlgorithm()))
+ continue;
+ suites.add(suite);
+ }
+ for (CipherSuite suite : clientSuites)
+ {
+ CipherSuite resolved = suite.resolve();
+ if (!resolved.isResolved())
+ continue;
+ if (suites.contains(resolved))
+ return resolved;
+ }
+
+ // We didn't find a match?
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.INSUFFICIENT_SECURITY));
+ }
+
+ /**
+ * Choose a compression method that we support, among the client's
+ * requested compression methods. We prefer ZLIB over NONE in this
+ * implementation.
+ *
+ * XXX Maybe consider implementing lzo (GNUTLS supports that).
+ */
+ private static CompressionMethod chooseCompression (final CompressionMethodList comps)
+ throws SSLException
+ {
+ GetSecurityPropertyAction gspa
+ = new GetSecurityPropertyAction("jessie.enable.compression");
+ String enable = AccessController.doPrivileged(gspa);
+ // Scan for ZLIB first.
+ if (Boolean.valueOf(enable))
+ {
+ for (CompressionMethod cm : comps)
+ {
+ if (cm.equals (CompressionMethod.ZLIB))
+ return CompressionMethod.ZLIB;
+ }
+ }
+ for (CompressionMethod cm : comps)
+ {
+ if (cm.equals (CompressionMethod.NULL))
+ return CompressionMethod.NULL;
+ }
+
+ throw new SSLException ("no supported compression method");
+ }
+
+ protected @Override boolean doHash()
+ {
+ boolean b = helloV2;
+ helloV2 = false;
+ return (state != WRITE_HELLO_REQUEST) && !b;
+ }
+
+ public @Override HandshakeStatus implHandleInput()
+ throws SSLException
+ {
+ if (state == DONE)
+ return HandshakeStatus.FINISHED;
+
+ if (state.isWriteState()
+ || (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+
+ // Copy the current buffer, and prepare it for reading.
+ ByteBuffer buffer = handshakeBuffer.duplicate ();
+ buffer.flip();
+ buffer.position(handshakeOffset);
+ Handshake handshake = new Handshake(buffer.slice(),
+ engine.session().suite,
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
+ state, handshake);
+
+ switch (state)
+ {
+ // Client Hello.
+ //
+ // This message is sent by the client to initiate a new handshake.
+ // On a new connection, it is the first handshake message sent.
+ //
+ // The state of the handshake, after this message is processed,
+ // will have a protocol version, cipher suite, compression method,
+ // session ID, and various extensions (that the server also
+ // supports).
+ case READ_CLIENT_HELLO:
+ if (handshake.type () != CLIENT_HELLO)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.UNEXPECTED_MESSAGE));
+
+ {
+ ClientHello hello = (ClientHello) handshake.body ();
+ engine.session().version
+ = chooseProtocol (hello.version (),
+ engine.getEnabledProtocols ());
+ engine.session().suite =
+ chooseSuite (hello.cipherSuites (),
+ engine.getEnabledCipherSuites (),
+ engine.session().version);
+ compression = chooseCompression (hello.compressionMethods ());
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "chose version:{0} suite:{1} compression:{2}",
+ engine.session().version, engine.session().suite,
+ compression);
+ clientRandom = hello.random().copy();
+ byte[] sessionId = hello.sessionId();
+ if (hello.hasExtensions())
+ {
+ ExtensionList exts = hello.extensions();
+ clientHadExtensions = exts.size() > 0;
+ for (Extension e : hello.extensions())
+ {
+ Extension.Type type = e.type();
+ if (type == null)
+ continue;
+ switch (type)
+ {
+ case TRUNCATED_HMAC:
+ engine.session().setTruncatedMac(true);
+ break;
+
+ case MAX_FRAGMENT_LENGTH:
+ MaxFragmentLength len = (MaxFragmentLength) e.value();
+ engine.session().maxLength = len;
+ engine.session().setApplicationBufferSize(len.maxLength());
+ break;
+
+ case SERVER_NAME:
+ requestedNames = (ServerNameList) e.value();
+ List<String> names
+ = new ArrayList<String>(requestedNames.size());
+ for (ServerNameList.ServerName name : requestedNames)
+ names.add(name.name());
+ engine.session().putValue("gnu.javax.net.ssl.RequestedServerNames", names);
+ break;
+
+ default:
+ logger.log(Level.INFO, "skipping unsupported extension {0}", e);
+ }
+ }
+ }
+ AbstractSessionContext sessions = (AbstractSessionContext)
+ engine.contextImpl.engineGetServerSessionContext();
+ SSLSession s = sessions.getSession(sessionId);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "looked up saved session {0}", s);
+ if (s != null && s.isValid() && (s instanceof SessionImpl))
+ {
+ engine.setSession((SessionImpl) s);
+ continuedSession = true;
+ }
+ else
+ {
+ // We *may* wind up with a badly seeded PRNG, and emit the
+ // same session ID over and over (this did happen to me,
+ // so we add this sanity check just in case).
+ if (engine.session().id().equals(new Session.ID(sessionId)))
+ {
+ byte[] newId = new byte[32];
+ engine.session().random().nextBytes(newId);
+ engine.session().setId(new Session.ID(newId));
+ }
+ sessions.put(engine.session());
+ }
+ state = WRITE_SERVER_HELLO;
+ }
+ break;
+
+ // Certificate.
+ //
+ // This message is sent by the client if the server had previously
+ // requested that the client authenticate itself with a certificate,
+ // and if the client has an appropriate certificate available.
+ //
+ // Processing this message will save the client's certificate,
+ // rejecting it if the certificate is not trusted, in preparation
+ // for the certificate verify message that will follow.
+ case READ_CERTIFICATE:
+ {
+ if (handshake.type() != CERTIFICATE)
+ {
+ if (engine.getNeedClientAuth()) // XXX throw better exception.
+ throw new SSLException("client auth required");
+ state = READ_CLIENT_KEY_EXCHANGE;
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ Certificate cert = (Certificate) handshake.body();
+ try
+ {
+ engine.session().setPeerVerified(false);
+ X509Certificate[] chain
+ = cert.certificates().toArray(new X509Certificate[0]);
+ if (chain.length == 0)
+ throw new CertificateException("no certificates in chain");
+ certVerifier = new CertVerifier(false, chain);
+ tasks.add(certVerifier);
+ engine.session().setPeerCertificates(chain);
+ clientCert = chain[0];
+ // Delay setting 'peerVerified' until CertificateVerify.
+ }
+ catch (CertificateException ce)
+ {
+ if (engine.getNeedClientAuth())
+ {
+ SSLPeerUnverifiedException x
+ = new SSLPeerUnverifiedException("client certificates could not be verified");
+ x.initCause(ce);
+ throw x;
+ }
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ state = READ_CLIENT_KEY_EXCHANGE;
+ }
+ break;
+
+ // Client Key Exchange.
+ //
+ // The client's key exchange. This message is sent either following
+ // the certificate message, or if no certificate is available or
+ // requested, following the server's hello done message.
+ //
+ // After receipt of this message, the session keys for this
+ // session will have been created.
+ case READ_CLIENT_KEY_EXCHANGE:
+ {
+ if (handshake.type() != CLIENT_KEY_EXCHANGE)
+ throw new SSLException("expecting client key exchange");
+ ClientKeyExchange kex = (ClientKeyExchange) handshake.body();
+
+ KeyExchangeAlgorithm alg = engine.session().suite.keyExchangeAlgorithm();
+ switch (alg)
+ {
+ case DHE_DSS:
+ case DHE_RSA:
+ case DH_anon:
+ {
+ ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic)
+ kex.exchangeKeys();
+ DHPublicKey myKey = (DHPublicKey) dhPair.getPublic();
+ DHPublicKey clientKey =
+ new GnuDHPublicKey(null, myKey.getParams().getP(),
+ myKey.getParams().getG(),
+ pub.publicValue());
+ keyExchangeTask = new DHPhase(clientKey);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case RSA:
+ {
+ EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret)
+ kex.exchangeKeys();
+ keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret());
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case PSK:
+ {
+ ClientPSKParameters params = (ClientPSKParameters)
+ kex.exchangeKeys();
+ generatePSKSecret(params.identity(), null, false);
+ }
+ break;
+
+ case DHE_PSK:
+ {
+ ClientDHE_PSKParameters params = (ClientDHE_PSKParameters)
+ kex.exchangeKeys();
+ DHPublicKey serverKey = (DHPublicKey) dhPair.getPublic();
+ DHPublicKey clientKey =
+ new GnuDHPublicKey(null, serverKey.getParams().getP(),
+ serverKey.getParams().getG(),
+ params.params().publicValue());
+ SecretKey psk = null;
+ try
+ {
+ psk = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ keyExchangeTask = new DHE_PSKGen(clientKey, psk, false);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case RSA_PSK:
+ {
+ ClientRSA_PSKParameters params = (ClientRSA_PSKParameters)
+ kex.exchangeKeys();
+ SecretKey psk = null;
+ try
+ {
+ psk = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ if (psk == null)
+ {
+ byte[] fakeKey = new byte[16];
+ engine.session().random().nextBytes(fakeKey);
+ psk = new SecretKeySpec(fakeKey, "DHE_PSK");
+ }
+ keyExchangeTask =
+ new RSA_PSKExchange(params.secret().encryptedSecret(), psk);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case NONE:
+ {
+ Inflater inflater = null;
+ Deflater deflater = null;
+ if (compression == CompressionMethod.ZLIB)
+ {
+ inflater = new Inflater();
+ deflater = new Deflater();
+ }
+ inParams = new InputSecurityParameters(null, null, inflater,
+ engine.session(),
+ engine.session().suite);
+ outParams = new OutputSecurityParameters(null, null, deflater,
+ engine.session(),
+ engine.session().suite);
+ engine.session().privateData.masterSecret = new byte[0];
+ }
+ break;
+ }
+ // XXX SRP
+
+ if (clientCert != null)
+ state = READ_CERTIFICATE_VERIFY;
+ else
+ state = READ_FINISHED;
+ }
+ break;
+
+ // Certificate Verify.
+ //
+ // This message is sent following the client key exchange message,
+ // but only when the client included its certificate in a previous
+ // message.
+ //
+ // After receipt of this message, the client's certificate (and,
+ // to a degree, the client's identity) will have been verified.
+ case READ_CERTIFICATE_VERIFY:
+ {
+ if (handshake.type() != CERTIFICATE_VERIFY)
+ throw new SSLException("expecting certificate verify message");
+
+ CertificateVerify verify = (CertificateVerify) handshake.body();
+ try
+ {
+ verifyClient(verify.signature());
+ if (certVerifier != null && certVerifier.verified())
+ engine.session().setPeerVerified(true);
+ }
+ catch (SignatureException se)
+ {
+ if (engine.getNeedClientAuth())
+ throw new SSLException("client auth failed", se);
+ }
+ if (continuedSession)
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ else
+ state = READ_FINISHED;
+ }
+ break;
+
+ // Finished.
+ //
+ // This message is sent immediately following the change cipher
+ // spec message (which is sent outside of the handshake layer).
+ // After receipt of this message, the session keys for the client
+ // side will have been verified (this is the first message the
+ // client sends encrypted and authenticated with the newly
+ // negotiated keys).
+ //
+ // In the case of a continued session, the client sends its
+ // finished message first. Otherwise, the server will send its
+ // finished message first.
+ case READ_FINISHED:
+ {
+ if (handshake.type() != FINISHED)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+
+ Finished clientFinished = (Finished) handshake.body();
+
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ Finished serverFinished =
+ new Finished(generateFinished(md5copy, shacopy,
+ true, engine.session()),
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "server finished: {0}",
+ serverFinished);
+
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ {
+ if (!Arrays.equals(clientFinished.md5Hash(),
+ serverFinished.md5Hash())
+ || !Arrays.equals(clientFinished.shaHash(),
+ serverFinished.shaHash()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+ else
+ {
+ if (!Arrays.equals(clientFinished.verifyData(),
+ serverFinished.verifyData()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+
+ if (continuedSession)
+ state = DONE;
+ else
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ }
+ break;
+ }
+
+ handshakeOffset += handshake.length() + 4;
+
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+ if (state.isWriteState())
+ return HandshakeStatus.NEED_WRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ public @Override HandshakeStatus implHandleOutput (ByteBuffer fragment)
+ throws SSLException
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "handle output state: {0}; output fragment: {1}",
+ state, fragment);
+
+ // Drain the output buffer, if it needs it.
+ if (outBuffer != null && outBuffer.hasRemaining())
+ {
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+
+ if (!fragment.hasRemaining())
+ {
+ if (state.isWriteState() || outBuffer.hasRemaining())
+ return HandshakeStatus.NEED_WRAP;
+ else
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ // XXX what we need to do here is generate a "stream" of handshake
+ // messages, and insert them into fragment amounts that we have available.
+ // A handshake message can span multiple records, and we can put
+ // multiple records into a single record.
+ //
+ // So, we can have one of two states:
+ //
+ // 1) We have enough space in the record we are creating to push out
+ // everything we need to on this round. This is easy; we just
+ // repeatedly fill in these messages in the buffer, so we get something
+ // that looks like this:
+ // ________________________________
+ // records: |________________________________|
+ // handshakes: |______|__|__________|
+ //
+ // 2) We can put part of one handshake message in the current record,
+ // but we must put the rest of it in the following record, or possibly
+ // more than one following record. So here, we'd see this:
+ //
+ // ________________________
+ // records: |_______|_______|________|
+ // handshakes: |____|_______|_________|
+ //
+ // We *could* make this a lot easier by just only ever emitting one
+ // record per call, but then we would waste potentially a lot of space
+ // and waste a lot of TCP packets by doing it the simple way. What
+ // we desire here is that we *maximize* our usage of the resources
+ // given to us, and to use as much space in the present fragment as
+ // we can.
+ //
+ // Note that we pretty much have to support this, anyway, because SSL
+ // provides no guarantees that the record size is large enough to
+ // admit *even one* handshake message. Also, callers could call on us
+ // with a short buffer, even though they aren't supposed to.
+ //
+ // This is somewhat complicated by the fact that we don't know, a priori,
+ // how large a handshake message will be until we've built it, and our
+ // design builds the message around the byte buffer.
+ //
+ // Some ways to handle this:
+ //
+ // 1. Write our outgoing handshake messages to a private buffer,
+ // big enough per message (and, if we run out of space, resize that
+ // buffer) and push (possibly part of) this buffer out to the
+ // outgoing buffer. This isn't that great because we'd need to
+ // store and copy things unnecessarily.
+ //
+ // 2. Build outgoing handshake objects “virtually,” that is, store them
+ // as collections of objects, then compute the length, and then write
+ // them to a buffer, instead of making the objects views on
+ // ByteBuffers for both input and output. This would complicate the
+ // protocol objects a bit (although, it would amount to doing
+ // separation between client objects and server objects, which is
+ // pretty OK), and we still need to figure out how exactly to chunk
+ // those objects across record boundaries.
+ //
+ // 3. Try to build these objects on the buffer we’re given, but detect
+ // when we run out of space in the output buffer, and split the
+ // overflow message. This sounds like the best, but also probably
+ // the hardest to code.
+output_loop:
+ while (fragment.remaining() >= 4 && state.isWriteState())
+ {
+ switch (state)
+ {
+ // Hello Request.
+ //
+ // This message is sent by the server to initiate a new
+ // handshake, to establish new session keys.
+ case WRITE_HELLO_REQUEST:
+ {
+ Handshake handshake = new Handshake(fragment);
+ handshake.setType(Handshake.Type.HELLO_REQUEST);
+ handshake.setLength(0);
+ fragment.position(fragment.position() + 4);
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", handshake);
+ state = READ_CLIENT_HELLO;
+ }
+ break output_loop; // XXX temporary
+
+ // Server Hello.
+ //
+ // This message is sent immediately following the client hello.
+ // It informs the client of the cipher suite, compression method,
+ // session ID (which may have been a continued session), and any
+ // supported extensions.
+ case WRITE_SERVER_HELLO:
+ {
+ ServerHelloBuilder hello = new ServerHelloBuilder();
+ hello.setVersion(engine.session().version);
+ Random r = hello.random();
+ r.setGmtUnixTime(Util.unixTime());
+ byte[] nonce = new byte[28];
+ engine.session().random().nextBytes(nonce);
+ r.setRandomBytes(nonce);
+ serverRandom = r.copy();
+ hello.setSessionId(engine.session().getId());
+ hello.setCipherSuite(engine.session().suite);
+ hello.setCompressionMethod(compression);
+ if (clientHadExtensions)
+ {
+ // XXX figure this out.
+ }
+ else // Don't send any extensions.
+ hello.setDisableExtensions(true);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", hello);
+
+ int typeLen = ((Handshake.Type.SERVER_HELLO.getValue() << 24)
+ | (hello.length() & 0xFFFFFF));
+ fragment.putInt(typeLen);
+
+ outBuffer = hello.buffer();
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ CipherSuite cs = engine.session().suite;
+ KeyExchangeAlgorithm kex = cs.keyExchangeAlgorithm();
+ if (continuedSession)
+ {
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ else if (kex == DHE_DSS || kex == DHE_RSA || kex == RSA
+ || kex == RSA_PSK)
+ {
+ certLoader = new CertLoader();
+ tasks.add(certLoader);
+ state = WRITE_CERTIFICATE;
+ if (kex == DHE_DSS || kex == DHE_RSA)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ }
+ break output_loop;
+ }
+ else if (kex == PSK)
+ {
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ }
+ else if (kex == DHE_PSK || kex == DH_anon)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ break output_loop;
+ }
+ else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+ {
+ state = WRITE_CERTIFICATE_REQUEST;
+ }
+ else
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break;
+
+ // Certificate.
+ //
+ // This message is sent immediately following the server hello,
+ // IF the cipher suite chosen requires that the server identify
+ // itself (usually, servers must authenticate).
+ case WRITE_CERTIFICATE:
+ {
+ // We must have scheduled a certificate loader to run.
+ assert(certLoader != null);
+ assert(certLoader.hasRun());
+ if (certLoader.thrown() != null)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE),
+ certLoader.thrown());
+ java.security.cert.Certificate[] chain
+ = engine.session().getLocalCertificates();
+ CertificateBuilder cert = new CertificateBuilder(CertificateType.X509);
+ try
+ {
+ cert.setCertificates(Arrays.asList(chain));
+ }
+ catch (CertificateException ce)
+ {
+ throw new SSLException(ce);
+ }
+
+ if (Debug.DEBUG)
+ {
+ logger.logv(Component.SSL_HANDSHAKE, "my cert:\n{0}", localCert);
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", cert);
+ }
+
+ int typeLen = ((CERTIFICATE.getValue() << 24)
+ | (cert.length() & 0xFFFFFF));
+ fragment.putInt(typeLen);
+
+ outBuffer = cert.buffer();
+ final int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ CipherSuite s = engine.session().suite;
+ KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ break output_loop;
+ }
+ else if (kexalg == RSA_PSK)
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+ {
+ state = WRITE_CERTIFICATE_REQUEST;
+ }
+ else
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break output_loop; // XXX temporary
+
+ // Server key exchange.
+ //
+ // This message is sent, following the certificate if sent,
+ // otherwise following the server hello, IF the chosen cipher
+ // suite requires that the server send explicit key exchange
+ // parameters (that is, if the key exchange parameters are not
+ // implicit in the server's certificate).
+ case WRITE_SERVER_KEY_EXCHANGE:
+ {
+ KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+
+ ByteBuffer paramBuffer = null;
+ ByteBuffer sigBuffer = null;
+ if (kex == DHE_DSS || kex == DHE_RSA || kex == DH_anon
+ || kex == DHE_PSK)
+ {
+ assert(genDH != null);
+ assert(genDH.hasRun());
+ if (genDH.thrown() != null)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE),
+ genDH.thrown());
+ assert(dhPair != null);
+ initDiffieHellman((DHPrivateKey) dhPair.getPrivate(),
+ engine.session().random());
+ paramBuffer = genDH.paramsBuffer;
+ sigBuffer = genDH.sigBuffer;
+
+ if (kex == DHE_PSK)
+ {
+ String identityHint
+ = engine.contextImpl.pskManager.chooseIdentityHint();
+ ServerDHE_PSKParameters psk =
+ new ServerDHE_PSKParameters(identityHint, paramBuffer);
+ paramBuffer = psk.buffer();
+ }
+ }
+ if (kex == RSA_PSK)
+ {
+ String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
+ if (idHint != null)
+ {
+ ServerRSA_PSKParameters params
+ = new ServerRSA_PSKParameters(idHint);
+ paramBuffer = params.buffer();
+ }
+ }
+ if (kex == PSK)
+ {
+ String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
+ if (idHint != null)
+ {
+ ServerPSKParameters params
+ = new ServerPSKParameters(idHint);
+ paramBuffer = params.buffer();
+ }
+ }
+ // XXX handle SRP
+
+ if (paramBuffer != null)
+ {
+ ServerKeyExchangeBuilder ske
+ = new ServerKeyExchangeBuilder(engine.session().suite);
+ ske.setParams(paramBuffer);
+ if (sigBuffer != null)
+ ske.setSignature(sigBuffer);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", ske);
+
+ outBuffer = ske.buffer();
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24)
+ | (ske.length() & 0xFFFFFF));
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit
+ (outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+
+ if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+ state = WRITE_CERTIFICATE_REQUEST;
+ else
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break;
+
+ // Certificate Request.
+ //
+ // This message is sent when the server desires or requires
+ // client authentication with a certificate; if it is sent, it
+ // will be sent just after the Certificate or Server Key
+ // Exchange messages, whichever is sent. If neither of the
+ // above are sent, it will be the message that follows the
+ // server hello.
+ case WRITE_CERTIFICATE_REQUEST:
+ {
+ CertificateRequestBuilder req = new CertificateRequestBuilder();
+
+ List<ClientCertificateType> types
+ = new ArrayList<ClientCertificateType>(4);
+ types.add(ClientCertificateType.RSA_SIGN);
+ types.add(ClientCertificateType.RSA_FIXED_DH);
+ types.add(ClientCertificateType.DSS_SIGN);
+ types.add(ClientCertificateType.DSS_FIXED_DH);
+ req.setTypes(types);
+
+ X509Certificate[] anchors
+ = engine.contextImpl.trustManager.getAcceptedIssuers();
+ List<X500Principal> issuers
+ = new ArrayList<X500Principal>(anchors.length);
+ for (X509Certificate cert : anchors)
+ issuers.add(cert.getIssuerX500Principal());
+ req.setAuthorities(issuers);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", req);
+
+ fragment.putInt((CERTIFICATE_REQUEST.getValue() << 24)
+ | (req.length() & 0xFFFFFF));
+
+ outBuffer = req.buffer();
+ int l = Math.min(outBuffer.remaining(), fragment.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break;
+
+ // Server Hello Done.
+ //
+ // This message is always sent by the server, to terminate its
+ // side of the handshake. Since the server's handshake message
+ // may comprise multiple, optional messages, this sentinel
+ // message lets the client know when the server's message stream
+ // is complete.
+ case WRITE_SERVER_HELLO_DONE:
+ {
+ // ServerHelloDone is zero-length; just put in the type
+ // field.
+ fragment.putInt(SERVER_HELLO_DONE.getValue() << 24);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "writing ServerHelloDone");
+ state = READ_CERTIFICATE;
+ }
+ break output_loop; // XXX temporary
+
+ // Finished.
+ //
+ // This is always sent by the server to verify the keys that the
+ // server will use to encrypt and authenticate. In a full
+ // handshake, this message will be sent after the client's
+ // finished message; in an abbreviated handshake (with a continued
+ // session) the server sends its finished message first.
+ //
+ // This message follows the change cipher spec message, which is
+ // sent out-of-band in a different SSL content-type.
+ //
+ // This is the first message that the server will send encrypted
+ // and authenticated with the newly negotiated session keys.
+ case WRITE_FINISHED:
+ {
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ outBuffer
+ = generateFinished(md5copy, shacopy, false,
+ engine.session());
+
+ fragment.putInt((FINISHED.getValue() << 24)
+ | outBuffer.remaining() & 0xFFFFFF);
+
+ int l = Math.min(outBuffer.remaining(), fragment.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ if (continuedSession)
+ state = READ_FINISHED;
+ else
+ state = DONE;
+ }
+ break;
+ }
+ }
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isWriteState() || outBuffer.hasRemaining())
+ return HandshakeStatus.NEED_WRAP;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ @Override HandshakeStatus status()
+ {
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+ if (state.isWriteState())
+ return HandshakeStatus.NEED_WRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ @Override void checkKeyExchange() throws SSLException
+ {
+ if (continuedSession) // No key exchange needed.
+ return;
+ KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+ if (kex == NONE || kex == PSK || kex == RSA_PSK) // Don't need one.
+ return;
+ if (keyExchangeTask == null) // An error if we never created one.
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR));
+ if (!keyExchangeTask.hasRun()) // An error if the caller never ran it.
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR));
+ if (keyExchangeTask.thrown() != null) // An error was thrown.
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE),
+ keyExchangeTask.thrown());
+ }
+
+ @Override void handleV2Hello(ByteBuffer hello)
+ {
+ int len = hello.getShort(0) & 0x7FFF;
+ md5.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
+ sha.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
+ helloV2 = true;
+ }
+
+ private ByteBuffer signParams(ByteBuffer serverParams)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ SignatureAlgorithm alg = engine.session().suite.signatureAlgorithm();
+ java.security.Signature sig
+ = java.security.Signature.getInstance(alg.algorithm());
+ PrivateKey key = engine.contextImpl.keyManager.getPrivateKey(keyAlias);
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_HANDSHAKE, "server key: {0}", key);
+ sig.initSign(key);
+ sig.update(clientRandom.buffer());
+ sig.update(serverRandom.buffer());
+ sig.update(serverParams);
+ byte[] sigVal = sig.sign();
+ Signature signature = new Signature(sigVal, engine.session().suite.signatureAlgorithm());
+ return signature.buffer();
+ }
+
+ private void verifyClient(byte[] sigValue) throws SSLException, SignatureException
+ {
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // Mis-configured with non-cloneable digests.
+ throw new SSLException(cnse);
+ }
+ byte[] toSign = null;
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ toSign = genV3CertificateVerify(md5copy, shacopy, engine.session());
+ else
+ {
+ if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+ toSign = Util.concat(md5copy.digest(), shacopy.digest());
+ else
+ toSign = shacopy.digest();
+ }
+
+ try
+ {
+ java.security.Signature sig = java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().toString());
+ sig.initVerify(clientCert);
+ sig.update(toSign);
+ sig.verify(sigValue);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+
+ // Delegated tasks.
+
+ class CertLoader extends DelegatedTask
+ {
+ CertLoader()
+ {
+ }
+
+ public void implRun() throws SSLException
+ {
+ KeyExchangeAlgorithm kexalg = engine.session().suite.keyExchangeAlgorithm();
+ X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+ Principal[] issuers = null; // XXX use TrustedAuthorities extension.
+ keyAlias = km.chooseEngineServerAlias(kexalg.name(), issuers, engine);
+ if (keyAlias == null)
+ throw new SSLException("no certificates available");
+ X509Certificate[] chain = km.getCertificateChain(keyAlias);
+ engine.session().setLocalCertificates(chain);
+ localCert = chain[0];
+ serverKey = km.getPrivateKey(keyAlias);
+ if (kexalg == DH_DSS || kexalg == DH_RSA)
+ dhPair = new KeyPair(localCert.getPublicKey(),
+ km.getPrivateKey(keyAlias));
+ }
+ }
+
+ /**
+ * Delegated task for generating Diffie-Hellman parameters.
+ */
+ private class GenDH extends DelegatedTask
+ {
+ ByteBuffer paramsBuffer;
+ ByteBuffer sigBuffer;
+
+ protected void implRun()
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+ InvalidKeyException, SignatureException
+ {
+ KeyPairGenerator dhGen = KeyPairGenerator.getInstance("DH");
+ DHParameterSpec dhparams = DiffieHellman.getParams().getParams();
+ dhGen.initialize(dhparams, engine.session().random());
+ dhPair = dhGen.generateKeyPair();
+ DHPublicKey pub = (DHPublicKey) dhPair.getPublic();
+
+ // Generate the parameters message.
+ ServerDHParams params = new ServerDHParams(pub.getParams().getP(),
+ pub.getParams().getG(),
+ pub.getY());
+ paramsBuffer = params.buffer();
+
+ // Sign the parameters, if needed.
+ if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+ {
+ sigBuffer = signParams(paramsBuffer);
+ paramsBuffer.rewind();
+ }
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE,
+ "Diffie-Hellman public:{0} private:{1}",
+ dhPair.getPublic(), dhPair.getPrivate());
+ }
+ }
+
+ class RSAKeyExchange extends DelegatedTask
+ {
+ private final byte[] encryptedPreMasterSecret;
+
+ RSAKeyExchange(byte[] encryptedPreMasterSecret)
+ {
+ this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+ }
+
+ public void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+ {
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, serverKey);
+ rsa.init(Cipher.DECRYPT_MODE, localCert);
+ preMasterSecret = rsa.doFinal(encryptedPreMasterSecret);
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ }
+ }
+
+ class RSA_PSKExchange extends DelegatedTask
+ {
+ private final byte[] encryptedPreMasterSecret;
+ private final SecretKey psKey;
+
+ RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey)
+ {
+ this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+ this.psKey = psKey;
+ }
+
+ public @Override void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+ {
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, serverKey);
+ rsa.init(Cipher.DECRYPT_MODE, localCert);
+ byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret);
+ byte[] psSecret = psKey.getEncoded();
+ preMasterSecret = new byte[rsaSecret.length + psSecret.length + 4];
+ preMasterSecret[0] = (byte) (rsaSecret.length >>> 8);
+ preMasterSecret[1] = (byte) rsaSecret.length;
+ System.arraycopy(rsaSecret, 0, preMasterSecret, 2, rsaSecret.length);
+ preMasterSecret[rsaSecret.length + 2] = (byte) (psSecret.length >>> 8);
+ preMasterSecret[rsaSecret.length + 3] = (byte) psSecret.length;
+ System.arraycopy(psSecret, 0, preMasterSecret, rsaSecret.length+4,
+ psSecret.length);
+
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ }
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java
index 8b7853c7f40..2bbce37fb3d 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java
@@ -38,179 +38,194 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.nio.ByteBuffer;
-import javax.net.ssl.SSLProtocolException;
-
-class ServerHello implements Handshake.Body
+/**
+ * The server hello message.
+ *
+ * <pre>
+struct
+{
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ Extensions server_hello_extension_list&lt;0..2^16-1&gt;
+} ServerHello;
+</pre>
+ *
+ * <p>Server hello messages may contain extra data after the
+ * <tt>compression_method</tt> field, which are interpreted as
+ * extensions to the basic handshake.
+ */
+public class ServerHello implements Handshake.Body
{
// Fields.
// -------------------------------------------------------------------------
- private final ProtocolVersion version;
- private final Random random;
- private final byte[] sessionId;
- private final CipherSuite suite;
- private final CompressionMethod comp;
- private final List extensions;
+ protected static final int RANDOM_OFFSET = 2;
+ protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET;
+ protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1;
+ protected ByteBuffer buffer;
+ protected boolean disableExtensions;
+
// Constructor.
// -------------------------------------------------------------------------
- ServerHello(ProtocolVersion version, Random random,
- byte[] sessionId, CipherSuite suite,
- CompressionMethod comp)
+ public ServerHello (final ByteBuffer buffer)
{
- this(version, random, sessionId, suite, comp, null);
+ this.buffer = buffer;
+ disableExtensions = false;
}
- ServerHello(ProtocolVersion version, Random random,
- byte[] sessionId, CipherSuite suite,
- CompressionMethod comp, List extensions)
+ public int length ()
{
- this.version = version;
- this.random = random;
- this.sessionId = sessionId;
- this.suite = suite;
- this.comp = comp;
- this.extensions = extensions;
+ int sessionLen = buffer.get(SESSID_OFFSET) & 0xFF;
+ int len = SESSID_OFFSET2 + sessionLen + 3;
+ int elen = 0;
+ if (!disableExtensions && len + 1 < buffer.limit()
+ && (elen = buffer.getShort(len)) != 0)
+ len += 2 + elen;
+ return len;
}
- // Class methods.
- // -------------------------------------------------------------------------
-
- static ServerHello read(InputStream in) throws IOException
+ /**
+ * Returns the server's protocol version. This will read two bytes
+ * from the beginning of the underlying buffer, and return an
+ * instance of the appropriate {@link ProtocolVersion}; if the
+ * version read is a supported version, this method returns a static
+ * constant instance.
+ *
+ * @return The server's protocol version.
+ */
+ public ProtocolVersion version()
{
- ProtocolVersion vers = ProtocolVersion.read(in);
- Random rand = Random.read(in);
- byte[] id = new byte[in.read() & 0xFF];
- in.read(id);
- CipherSuite suite = CipherSuite.read(in).resolve(vers);
- CompressionMethod comp = CompressionMethod.read(in);
- List ext = null;
- if (in.available() > 0)
- {
- ext = new LinkedList();
- int len = (in.read() >>> 8 & 0xFF) | (in.read() & 0xFF);
- int count = 0;
- while (count < len)
- {
- Extension e = Extension.read(in);
- ext.add(e);
- count += e.getValue().length + 4;
- }
- }
- return new ServerHello(vers, rand, id, suite, comp, ext);
+ return ProtocolVersion.getInstance (buffer.getShort (0));
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public void write(OutputStream out) throws IOException
+ /**
+ * Returns the server's random value. This method returns a
+ * lightwieght wrapper around the existing bytes; modifications to
+ * the underlying buffer will modify the returned object, and
+ * vice-versa.
+ *
+ * @return The server's random value.
+ */
+ public Random random()
{
- version.write(out);
- random.write(out);
- out.write(sessionId.length);
- out.write(sessionId);
- suite.write(out);
- out.write(comp.getValue());
- if (extensions != null)
- {
- ByteArrayOutputStream out2 = new ByteArrayOutputStream();
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- ((Extension) i.next()).write(out2);
- out.write(out2.size() >>> 8 & 0xFF);
- out.write(out2.size() & 0xFF);
- out2.writeTo(out);
- }
+ ByteBuffer randomBuf =
+ ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+ .limit (SESSID_OFFSET)).slice ();
+ return new Random (randomBuf);
}
- ProtocolVersion getVersion()
+ /**
+ * Returns the session ID. This method returns a new byte array with
+ * the session ID bytes.
+ *
+ * @return The session ID.
+ */
+ public byte[] sessionId()
{
- return version;
+ int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+ byte[] sessionId = new byte[idlen];
+ buffer.position (SESSID_OFFSET2);
+ buffer.get (sessionId);
+ return sessionId;
}
- Random getRandom()
+ /**
+ * Returns the server's chosen cipher suite. The returned cipher
+ * suite will be "resolved" to this structure's version.
+ *
+ * @return The server's chosen cipher suite.
+ */
+ public CipherSuite cipherSuite()
{
- return random;
+ int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF);
+ return CipherSuite.forValue(buffer.getShort(offset)).resolve();
}
- byte[] getSessionId()
+ /**
+ * Returns the server's chosen compression method.
+ *
+ * @return The chosen compression method.
+ */
+ public CompressionMethod compressionMethod()
{
- return (byte[]) sessionId.clone();
+ int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 2;
+ return CompressionMethod.getInstance(buffer.get(offset) & 0xFF);
}
- CipherSuite getCipherSuite()
+ public int extensionsLength()
{
- return suite;
+ int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+ if (offset + 1 >= buffer.limit())
+ return 0;
+ return buffer.getShort(offset) & 0xFFFF;
}
-
- CompressionMethod getCompressionMethod()
+
+ public ExtensionList extensions ()
{
- return comp;
+ int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+ if (offset + 1 >= buffer.limit())
+ return null;
+ int len = buffer.getShort(offset) & 0xFFFF;
+ if (len == 0)
+ len = buffer.limit() - offset - 2;
+ ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset)
+ .limit(offset + len + 2)).slice();
+ return new ExtensionList(ebuf);
}
- List getExtensions()
+ public String toString()
{
- return extensions;
+ return toString(null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
- out.println("struct {");
- out.println(" version = " + version + ";");
- BufferedReader r = new BufferedReader(new StringReader(random.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";");
- out.println(" cipherSuite = " + suite + ";");
- out.println(" compressionMethod = " + comp + ";");
- if (extensions != null)
- {
- out.println(" extensions = {");
- for (Iterator i = extensions.iterator(); i.hasNext(); )
- {
- r = new BufferedReader(new StringReader(i.next().toString()));
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println(" };");
- }
- out.println("} ServerHello;");
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix += prefix;
+ out.print (subprefix);
+ out.print ("version: ");
+ out.print (version ());
+ out.println (";");
+ out.print (subprefix);
+ out.println ("random:");
+ out.println (random ().toString (subprefix));
+ out.print (subprefix);
+ out.print ("sessionId: ");
+ out.print (Util.toHexString(sessionId (), ':'));
+ out.println (";");
+ out.print (subprefix);
+ out.print ("cipherSuite: ");
+ out.print (cipherSuite ());
+ out.println (";");
+ out.print (subprefix);
+ out.print ("compressionMethod: ");
+ out.print (compressionMethod ());
+ out.println (";");
+ ExtensionList exts = extensions ();
+ out.print (subprefix);
+ out.println ("extensions:");
+ out.println (exts != null ? exts.toString (subprefix+" ")
+ : subprefix + " (nil)");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} ServerHello;");
return str.toString();
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java
new file mode 100644
index 00000000000..09ad1d9e8a9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java
@@ -0,0 +1,131 @@
+/* ServerHelloBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author csm
+ *
+ */
+public class ServerHelloBuilder extends ServerHello implements Builder
+{
+ public ServerHelloBuilder()
+ {
+ // Allocate a large enough buffer to hold a hello with the maximum
+ // size session ID, and no extensions.
+ super(ByteBuffer.allocate(SESSID_OFFSET2 + 35));
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ // We don't reallocate the buffer in any of the following methods,
+ // because we always allocate a large enough buffer for the base
+ // object in the constructor.
+
+ public void setVersion (final ProtocolVersion version)
+ {
+ buffer.putShort (0, (short) version.rawValue ());
+ }
+
+ public void setSessionId (final byte[] sessionId)
+ {
+ setSessionId (sessionId, 0, sessionId.length);
+ }
+
+ public void setSessionId (final byte[] sessionId, final int offset,
+ final int length)
+ {
+ if (length < 0 || length > 32)
+ throw new IllegalArgumentException("length must be between 0 and 32");
+ buffer.put(SESSID_OFFSET, (byte) length);
+ ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2))
+ .put(sessionId, offset, length);
+ }
+
+ public void setCipherSuite (final CipherSuite suite)
+ {
+ int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 1;
+ ((ByteBuffer) buffer.duplicate().position(offset)).put(suite.id());
+ }
+
+ public void setCompressionMethod (final CompressionMethod comp)
+ {
+ int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 3;
+ buffer.put (offset, (byte) comp.getValue ());
+ }
+
+ // For extensions, we do reallocate the buffer.
+
+ public void setDisableExtensions(boolean disable)
+ {
+ disableExtensions = disable;
+ }
+
+ public void setExtensionsLength (final int length)
+ {
+ if (length < 0 || length > 16384)
+ throw new IllegalArgumentException("length must be nonnegative and not exceed 16384");
+ int needed = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 5 + length;
+ if (buffer.capacity() < needed)
+ ensureCapacity(needed);
+ buffer.putShort (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3,
+ (short) length);
+ }
+
+ public void setExtensions(ByteBuffer extensions)
+ {
+ extensions = (ByteBuffer)
+ extensions.duplicate().limit(extensions.position() + extensionsLength());
+ ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2
+ + (buffer.get(SESSID_OFFSET) & 0xFF)
+ )).put(extensions);
+ }
+
+ public void ensureCapacity(int newCapacity)
+ {
+ ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+ newBuffer.put(buffer);
+ newBuffer.position(0);
+ buffer = newBuffer;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java
new file mode 100644
index 00000000000..e09772250a5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java
@@ -0,0 +1,66 @@
+/* ServerHelloDone.java -- SSL ServerHelloDone message.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * An empty message that signals that the server is finished sending
+ * its handshake data.
+ *
+ * <pre>struct { } ServerHelloDone;</pre>
+ */
+public class ServerHelloDone implements Handshake.Body
+{
+ public ServerHelloDone () { }
+
+ public int length ()
+ {
+ return 0;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ return ((prefix != null ? prefix : "")
+ + "struct { } ServerHelloDone;");
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java
index 58304159300..1206ae6b28b 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java
@@ -38,249 +38,136 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.io.PrintWriter;
-import java.io.StringReader;
import java.io.StringWriter;
-import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-import java.security.PublicKey;
-import java.security.interfaces.RSAPublicKey;
-
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHParameterSpec;
-
-import javax.net.ssl.SSLProtocolException;
-
-import gnu.javax.crypto.key.dh.GnuDHPublicKey;
-import gnu.javax.crypto.key.srp6.SRPPublicKey;
-
-class ServerKeyExchange implements Handshake.Body
+/**
+ * The server key exchange message.
+ *
+ * <pre>
+struct
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private PublicKey publicKey;
- private Signature signature;
- private byte[] srpSalt;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- ServerKeyExchange(PublicKey publicKey, Signature signature)
- {
- this(publicKey, signature, null);
- }
-
- ServerKeyExchange(PublicKey publicKey, Signature signature, byte[] srpSalt)
+ select (KeyExchangeAlgorithm)
{
- this.publicKey = publicKey;
- this.signature = signature;
- this.srpSalt = srpSalt;
- }
-
- // Class methods.
- // -------------------------------------------------------------------------
-
- static ServerKeyExchange read(InputStream in, CipherSuite suite,
- PublicKey serverKey)
- throws IOException
- {
- DataInputStream din = new DataInputStream(in);
- PublicKey key = null;
- byte[] salt = null;
- String kex = suite.getKeyExchange();
- if (kex.equals("DHE"))
- {
- BigInteger p, g, y;
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- p = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- g = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- y = new BigInteger(1, buf);
- key = new GnuDHPublicKey(null, p, g, y);
- }
- else if (kex.equals("RSA"))
- {
- BigInteger n, e;
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- n = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- e = new BigInteger(1, buf);
- key = new JessieRSAPublicKey(n, e);
- }
- else if (kex.equals("SRP"))
- {
- BigInteger N, g, B;
- byte[] buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- N = new BigInteger(1, buf);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- g = new BigInteger(1, buf);
- salt = new byte[din.readUnsignedByte()];
- din.readFully(salt);
- buf = new byte[din.readUnsignedShort()];
- din.readFully(buf);
- B = new BigInteger(1, buf);
- try
- {
- key = new SRPPublicKey(N, g, B);
- }
- catch (IllegalArgumentException iae)
- {
- throw new SSLProtocolException(iae.getMessage());
- }
- }
- else
- {
- throw new SSLProtocolException("invalid kex algorithm");
- }
-
- Signature sig = null;
- if (!suite.getSignature().equals("anon"))
- {
- sig = Signature.read(in, suite, serverKey);
- }
- return new ServerKeyExchange(key, sig, salt);
- }
+ case diffie_hellman:
+ ServerDHParams params;
+ Signature signed_params;
+ case rsa:
+ ServerRSAParams params;
+ Signature signed_params;
+ case srp:
+ ServerSRPParams params;
+ Signature signed_params;
+ };
+} ServerKeyExchange;
+</pre>
+ */
+public class ServerKeyExchange implements Handshake.Body
+{
- // Instance methods.
- // -------------------------------------------------------------------------
+ protected ByteBuffer buffer;
+ protected final CipherSuite suite;
- public void write(OutputStream out) throws IOException
+ public ServerKeyExchange(final ByteBuffer buffer, final CipherSuite suite)
{
- write(out, ProtocolVersion.TLS_1);
+ suite.getClass();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.suite = suite;
}
- public void write(OutputStream out, ProtocolVersion version)
- throws IOException
+ public int length ()
{
- if (publicKey instanceof DHPublicKey)
- {
- writeBigint(out, ((DHPublicKey) publicKey).getParams().getP());
- writeBigint(out, ((DHPublicKey) publicKey).getParams().getG());
- writeBigint(out, ((DHPublicKey) publicKey).getY());
- }
- else if (publicKey instanceof RSAPublicKey)
- {
- writeBigint(out, ((RSAPublicKey) publicKey).getModulus());
- writeBigint(out, ((RSAPublicKey) publicKey).getPublicExponent());
- }
- else if (publicKey instanceof SRPPublicKey)
- {
- writeBigint(out, ((SRPPublicKey) publicKey).getN());
- writeBigint(out, ((SRPPublicKey) publicKey).getG());
- out.write(srpSalt.length);
- out.write(srpSalt);
- writeBigint(out, ((SRPPublicKey) publicKey).getY());
- }
- if (signature != null)
- {
- signature.write(out, version);
- }
+ if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
+ return 0;
+ int len = 0;
+ ServerKeyExchangeParams params = params();
+ Signature sig = signature();
+ if (params != null)
+ len += params.length();
+ if (sig != null)
+ len += sig.length();
+ return len;
}
- PublicKey getPublicKey()
+ /**
+ * Returns the server's key exchange parameters. The value returned will
+ * depend on the key exchange algorithm this object was created with.
+ *
+ * @return The server's key exchange parameters.
+ */
+ public ServerKeyExchangeParams params ()
{
- return publicKey;
+ KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm ();
+ if (kex == KeyExchangeAlgorithm.RSA)
+ return new ServerRSAParams(buffer.duplicate ());
+ else if (kex == KeyExchangeAlgorithm.DHE_DSS
+ || kex == KeyExchangeAlgorithm.DHE_RSA
+ || kex == KeyExchangeAlgorithm.DH_anon)
+ return new ServerDHParams(buffer.duplicate());
+// else if (kex.equals (KeyExchangeAlgorithm.SRP))
+// return new ServerSRPParams (buffer.duplicate ());
+ else if (kex == KeyExchangeAlgorithm.NONE)
+ return null;
+ else if (kex == KeyExchangeAlgorithm.DHE_PSK)
+ return new ServerDHE_PSKParameters(buffer.duplicate());
+ else if (kex == KeyExchangeAlgorithm.PSK)
+ return new ServerPSKParameters(buffer.duplicate());
+ else if (kex == KeyExchangeAlgorithm.RSA_PSK)
+ return new ServerPSKParameters(buffer.duplicate());
+ throw new IllegalArgumentException ("unsupported key exchange: " + kex);
}
- Signature getSignature()
+ /**
+ * Returns the digital signature made over the key exchange parameters.
+ *
+ * @return The signature.
+ */
+ public Signature signature ()
{
- return signature;
+ KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm();
+ if (kex == KeyExchangeAlgorithm.NONE
+ || kex == KeyExchangeAlgorithm.DH_anon
+ || kex == KeyExchangeAlgorithm.DHE_PSK
+ || kex == KeyExchangeAlgorithm.PSK
+ || kex == KeyExchangeAlgorithm.RSA_PSK)
+ return null;
+ ServerKeyExchangeParams params = params();
+ ByteBuffer sigbuf = ((ByteBuffer) buffer.position(params.length ())).slice ();
+ return new Signature (sigbuf, suite.signatureAlgorithm ());
}
- byte[] getSRPSalt()
+ public String toString()
{
- return srpSalt;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
out.println("struct {");
- out.println(" publicKey = struct {");
- if (publicKey instanceof DHPublicKey)
- {
- out.println(" p = " +
- ((DHPublicKey) publicKey).getParams().getP().toString(16) +
- ";");
- out.println(" g = " +
- ((DHPublicKey) publicKey).getParams().getG().toString(16) +
- ";");
- out.println(" y = " + ((DHPublicKey) publicKey).getY().toString(16) +
- ";");
- out.println(" } DHPublicKey;");
- }
- else if (publicKey instanceof RSAPublicKey)
+ if (prefix != null) out.print (prefix);
+ out.print (" algorithm: ");
+ out.print (suite.keyExchangeAlgorithm ());
+ out.println (";");
+ if (!suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
{
- out.println(" modulus = " +
- ((RSAPublicKey) publicKey).getModulus().toString(16) +
- ";");
- out.println(" exponent = " +
- ((RSAPublicKey) publicKey).getPublicExponent().toString(16) +
- ";");
- out.println(" } RSAPublicKey;");
+ if (prefix != null) out.print (prefix);
+ out.println (" parameters:");
+ out.println (params ().toString (prefix != null ? prefix+" " : " "));
}
- else if (publicKey instanceof SRPPublicKey)
+ if (!suite.signatureAlgorithm ().equals (SignatureAlgorithm.ANONYMOUS))
{
- out.println(" N = "+((SRPPublicKey) publicKey).getN().toString(16)+";");
- out.println(" g = "+((SRPPublicKey) publicKey).getG().toString(16)+";");
- out.println(" salt = " + Util.toHexString(srpSalt, ':') + ";");
- out.println(" B = "+((SRPPublicKey) publicKey).getY().toString(16)+";");
- out.println(" } SRPPublicKey;");
+ if (prefix != null) out.print (prefix);
+ out.println (" signature:");
+ out.println (signature ().toString (prefix != null ? prefix+" " : " "));
}
- if (signature != null)
- {
- out.println(" signature =");
- BufferedReader r = new BufferedReader(new StringReader(signature.toString()));
- String s;
- try
- {
- while ((s = r.readLine()) != null)
- {
- out.print(" ");
- out.println(s);
- }
- }
- catch (IOException ignored)
- {
- }
- }
- out.println("} ServerKeyExchange;");
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerKeyExchange;");
return str.toString();
}
-
- private void writeBigint(OutputStream out, BigInteger bigint)
- throws IOException
- {
- byte[] b = bigint.toByteArray();
- if (b[0] == 0x00)
- {
- out.write((b.length - 1) >>> 8 & 0xFF);
- out.write((b.length - 1) & 0xFF);
- out.write(b, 1, b.length - 1);
- }
- else
- {
- out.write(b.length >>> 8 & 0xFF);
- out.write(b.length & 0xFF);
- out.write(b);
- }
- }
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java
index 14cf829ac67..d4b6fa39736 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java
@@ -1,4 +1,4 @@
-/* RecordInputStream.java -- record layer input stream interface.
+/* ServerKeyExchangeBuilder.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -33,74 +33,57 @@ module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
+exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.io.IOException;
-import java.io.InputStream;
+import java.nio.ByteBuffer;
-class RecordInputStream extends InputStream
+/**
+ * Builder for {@link ServerKeyExchange} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerKeyExchangeBuilder extends ServerKeyExchange
+ implements Builder
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- /**
- * The record input instance.
- */
- private final RecordInput in;
-
- /**
- * The content type this stream is reading.
- */
- private final ContentType type;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- RecordInputStream (RecordInput in, ContentType type)
+ public ServerKeyExchangeBuilder(final CipherSuite suite)
{
- this.in = in;
- this.type = type;
+ super(ByteBuffer.allocate(1024), suite);
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public int available () throws IOException
- {
- return in.available (type);
- }
-
- public int read () throws IOException
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
{
- byte[] b = new byte[1];
- int ret;
- while ((ret = read (b)) != 1)
- {
- if (ret == -1)
- {
- return -1;
- }
- Thread.yield ();
- }
- return b[0] & 0xFF;
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
}
- public int read (byte[] buf) throws IOException
+ public void setParams(ByteBuffer params)
{
- return read (buf, 0, buf.length);
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ throw new IllegalArgumentException("key exchange algorithm is none");
+ ensureCapacity(params.remaining());
+ buffer.duplicate().put(params);
}
-
- public int read (byte[] buf, int off, int len) throws IOException
+
+ public void setSignature(ByteBuffer signature)
{
- return in.read (buf, off, len, type);
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ throw new IllegalArgumentException("key exchange algorithm is none");
+ int paramsLen = params().length();
+ ensureCapacity(paramsLen + signature.remaining());
+ ((ByteBuffer) buffer.duplicate().position(paramsLen)).put(signature);
}
-
- public String toString ()
+
+ public void ensureCapacity(int capacity)
{
- return RecordInputStream.class.getName () + " [ type=" + type + " ]";
+ if (buffer.capacity() >= capacity)
+ return;
+ ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+ newBuffer.duplicate().put(buffer);
+ buffer = newBuffer;
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java
new file mode 100644
index 00000000000..cb523650f25
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java
@@ -0,0 +1,50 @@
+/* ServerKeyExchangeParams.java -- Server key exchange parameters interface.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+/**
+ * A parameter structure sent by the server in an SSL key exchange.
+ *
+ * @see ServerRSAParams
+ * @see ServerDHParams
+ */
+interface ServerKeyExchangeParams extends Constructed
+{
+ KeyExchangeAlgorithm algorithm ();
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java
new file mode 100644
index 00000000000..5a268f542ab
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java
@@ -0,0 +1,311 @@
+/* ServerNameList.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * The ServerName extension.
+ *
+ * <pre>
+ struct {
+ NameType name_type;
+ select (name_type) {
+ case host_name: HostName;
+ } name;
+} ServerName;
+
+enum {
+ host_name(0), (255)
+} NameType;
+
+opaque HostName<1..2^16-1>;
+
+struct {
+ ServerName server_name_list<1..2^16-1>
+} ServerNameList;</pre>
+ *
+ * <p><b>Implementation note: this class does not currently contain a
+ * <code>set</code> method. If you are modifying this list, then use the
+ * {@link #get(int)} method, and modify the returned {@link ServerName}.
+ *
+ * @author csm
+ */
+public class ServerNameList extends Value implements Iterable<ServerNameList.ServerName>
+{
+ private ByteBuffer buffer;
+
+ public ServerNameList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerNameList(List<ServerName> names)
+ {
+ int length = 2;
+ for (ServerName name : names)
+ length += name.length();
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) (length - 2));
+ for (ServerName name : names)
+ buffer.put(name.buffer());
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public int size()
+ {
+ int n = 0;
+ final int len = length();
+ for (int i = 2; i < len; )
+ {
+ int l = buffer.getShort(i+1);
+ i += l + 3;
+ n++;
+ }
+ return n;
+ }
+
+ public ServerName get (int index)
+ {
+ final int len = length();
+ if (len == 0)
+ throw new IndexOutOfBoundsException("0; " + index);
+ int n = 0;
+ int i;
+ int l = buffer.getShort(3);
+ for (i = 2; i < len && n < index; )
+ {
+ l = buffer.getShort(i+1);
+ i += l + 3;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException(n + "; " + index);
+ ByteBuffer buf = ((ByteBuffer) buffer.duplicate().position(i).limit(i+l+3)).slice();
+ return new ServerName (buf);
+ }
+
+ public void setLength(final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException("length must be between 0 and 65535");
+ buffer.putShort(0, (short) newLength);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println ("ServerNameList {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for (ServerName name : this)
+ {
+ out.println (name.toString(subprefix));
+ }
+ if (prefix != null) out.print(prefix);
+ out.print ("};");
+ return str.toString();
+ }
+
+ public java.util.Iterator<ServerName> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<ServerName>
+ {
+ private int index;
+
+ public Iterator()
+ {
+ index = 0;
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public ServerName next() throws NoSuchElementException
+ {
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class ServerName implements Constructed
+ {
+ private ByteBuffer buffer;
+
+ public ServerName(final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerName(NameType type, String name)
+ {
+ CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder();
+ ByteBuffer nameBuf = null;
+ try
+ {
+ nameBuf = utf8.encode(CharBuffer.wrap(name));
+ }
+ catch (CharacterCodingException cce)
+ {
+ // We don't expect this to happen; it's UTF-8.
+ throw new IllegalArgumentException(cce);
+ }
+ int length = 3 + nameBuf.remaining();
+ buffer = ByteBuffer.allocate(length);
+ buffer.put((byte) type.getValue());
+ buffer.putShort((short) (length - 3));
+ buffer.put(nameBuf);
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return (buffer.getShort(1) & 0xFFFF) + 3;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public NameType type()
+ {
+ int v = (buffer.get(0) & 0xFF);
+ if (v == 0)
+ {
+ return NameType.HOST_NAME;
+ }
+ throw new IllegalArgumentException ("illegal name type: " + v);
+ }
+
+ public String name()
+ {
+ int len = length();
+ Charset cs = Charset.forName ("UTF-8");
+ return cs.decode(((ByteBuffer) buffer.duplicate().position(3).limit(len))).toString();
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" name_type = ");
+ out.print (type());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print (" server_name = ");
+ out.print (name());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerName;");
+ return str.toString();
+ }
+ }
+
+ public static enum NameType
+ {
+ HOST_NAME (0);
+
+ private final int value;
+
+ private NameType (int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java
new file mode 100644
index 00000000000..8acce6dde51
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java
@@ -0,0 +1,127 @@
+/* ServerPSKParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &ast;/
+ case psk: /* NEW &ast;/
+ opaque psk_identity_hint&lt;0..2^16-1&gt;;
+ };
+ } ServerKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerPSKParameters implements Builder, Constructed, ServerKeyExchangeParams
+{
+ private ByteBuffer buffer;
+
+ public ServerPSKParameters(ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerPSKParameters(String identityHint)
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer identityHintBuffer = utf8.encode(identityHint);
+ buffer = ByteBuffer.allocate(2 + identityHintBuffer.remaining());
+ buffer.putShort((short) identityHintBuffer.remaining());
+ buffer.put(identityHintBuffer);
+ buffer.rewind();
+ }
+
+ public KeyExchangeAlgorithm algorithm()
+ {
+ return KeyExchangeAlgorithm.PSK;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identityHint()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString();
+ }
+
+ public @Override String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity_hint = ");
+ out.print(identityHint());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.print("} ServerPSKParamaters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java
new file mode 100644
index 00000000000..ff265ce8aaa
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java
@@ -0,0 +1,163 @@
+/* ServerRSAParams.java -- The server's RSA parameters.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+/**
+ * The ServerRSAParams structure.
+ *
+ * <pre>
+struct
+{
+ opaque rsa_modulus&lt;1..2^16-1&gt;;
+ opaque rsa_exponent&lt;1..2^16-1&gt;;
+} ServerRSAParams;
+</pre>
+ */
+public class ServerRSAParams implements ServerKeyExchangeParams
+{
+
+ private final ByteBuffer buffer;
+
+ public ServerRSAParams (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public KeyExchangeAlgorithm algorithm ()
+ {
+ return KeyExchangeAlgorithm.RSA;
+ }
+
+ public int length ()
+ {
+ int offset = buffer.getShort (0) & 0xFFFF;
+ return (buffer.getShort (offset + 2) & 0xFFFF) + offset + 4;
+ }
+
+ /**
+ * Gets the modulus field.
+ *
+ * @return The modulus.
+ */
+ public BigInteger modulus ()
+ {
+ int len = buffer.getShort (0) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Returns the exponent field.
+ *
+ * @return The exponent.
+ */
+ public BigInteger exponent ()
+ {
+ int off = (buffer.getShort (0) & 0xFFFF) + 2;
+ int len = buffer.getShort (off) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (off + 2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Sets the modulus.
+ *
+ * @param modulus The modulus.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void setModulus (final BigInteger modulus)
+ {
+ byte[] buf = modulus.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (buf, offset, length);
+ }
+
+ /**
+ * Sets the exponent.
+ *
+ * @param exponent The exponent.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setExponent (final BigInteger exponent)
+ {
+ byte[] buf = exponent.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ int where = (buffer.getShort (0) & 0xFFFF) + 2;
+ buffer.putShort (where, (short) length);
+ buffer.position (where + 2);
+ buffer.put (buf, offset, length);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" rsa_modulus: ");
+ out.println (modulus ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print (" rsa_exponent: ");
+ out.println (exponent ());
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerRSAParams;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java
new file mode 100644
index 00000000000..0d7b590d27f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java
@@ -0,0 +1,62 @@
+/* ServerRSA_PSKParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerRSA_PSKParameters extends ServerPSKParameters
+{
+ public ServerRSA_PSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ServerRSA_PSKParameters(String identityHint)
+ {
+ super(identityHint);
+ }
+
+ public @Override KeyExchangeAlgorithm algorithm()
+ {
+ return KeyExchangeAlgorithm.RSA_PSK;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Session.java b/libjava/classpath/gnu/javax/net/ssl/provider/Session.java
deleted file mode 100644
index e13758b0330..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Session.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/* Session.java -- SSL and TLS session data.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLPermission;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLSessionBindingListener;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-import javax.security.cert.X509Certificate;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-/**
- * A generic SSL session implementation for SSL and TLS.
- */
-final class Session implements SSLSession
-{
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- private static final SSLPermission GET_SESSION_CONTEXT_PERMISSION =
- new SSLPermission("getSSLSessionContext");
-
- private final long creationTime;
- private Date lastAccessedTime;
- ID sessionId;
- Certificate[] localCerts;
- Certificate[] peerCerts;
- X509Certificate[] peerCertChain;
- String peerHost;
- boolean peerVerified;
- SessionContext context;
- HashMap values;
- boolean valid;
- List enabledSuites;
- CipherSuite cipherSuite;
- SortedSet enabledProtocols;
- ProtocolVersion protocol;
- byte[] masterSecret;
- SRPTrustManager srpTrustManager;
- X509TrustManager trustManager;
- X509KeyManager keyManager;
- SecureRandom random;
- SecurityParameters params;
- Alert currentAlert;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- Session()
- {
- this(System.currentTimeMillis());
- }
-
- Session(long creationTime)
- {
- peerVerified = false;
- valid = true;
- this.creationTime = creationTime;
- lastAccessedTime = new Date(0L);
- values = new HashMap();
- if (("true").equalsIgnoreCase (Util.getSecurityProperty ("jessie.with.jce")))
- params = new JCESecurityParameters();
- else
- params = new GNUSecurityParameters (this);
- }
-
- // Public instance methods.
- // -------------------------------------------------------------------------
-
- protected Object clone()
- {
- Session result = new Session(creationTime);
- result.lastAccessedTime = lastAccessedTime;
- result.sessionId = sessionId;
- result.localCerts = (localCerts != null ? (Certificate[]) localCerts.clone() : null);
- result.peerCerts = (peerCerts != null ? (Certificate[]) peerCerts.clone() : null);
- result.peerHost = peerHost;
- result.peerVerified = peerVerified;
- result.context = context;
- result.values = values;
- result.enabledSuites = new ArrayList(enabledSuites);
- result.cipherSuite = cipherSuite;
- result.enabledProtocols = new TreeSet(enabledProtocols);
- result.protocol = protocol;
- result.masterSecret = masterSecret;
- result.keyManager = keyManager;
- result.srpTrustManager = srpTrustManager;
- result.trustManager = trustManager;
- result.random = random;
- return result;
- }
-
- public String getCipherSuite()
- {
- return cipherSuite.toString();
- }
-
- public long getCreationTime()
- {
- return creationTime;
- }
-
- public byte[] getId()
- {
- return (sessionId != null ? sessionId.getId() : null);
- }
-
- public long getLastAccessedTime()
- {
- return lastAccessedTime.getTime();
- }
-
- public Certificate[] getLocalCertificates()
- {
- return (Certificate[]) (localCerts != null ? localCerts.clone() : null);
- }
-
- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
- {
- if (!peerVerified)
- {
- throw new SSLPeerUnverifiedException("peer not verified");
- }
- return (Certificate[]) (peerCerts != null ? peerCerts.clone() : null);
- }
-
- public X509Certificate[] getPeerCertificateChain()
- throws SSLPeerUnverifiedException
- {
- if (!peerVerified)
- {
- throw new SSLPeerUnverifiedException("peer not verified");
- }
- if (peerCerts == null)
- {
- return null;
- }
- if (peerCertChain != null)
- {
- return (X509Certificate[]) peerCertChain.clone();
- }
- try
- {
- peerCertChain = new X509Certificate[peerCerts.length];
- for (int i = 0; i < peerCerts.length; i++)
- {
- peerCertChain[i] = X509Certificate.getInstance(peerCerts[i].getEncoded());
- }
- return (X509Certificate[]) peerCertChain.clone();
- }
- catch (javax.security.cert.CertificateException ce)
- {
- return null;
- }
- catch (CertificateException ce2)
- {
- return null;
- }
- }
-
- public String getPeerHost()
- {
- return peerHost;
- }
-
- public String getProtocol()
- {
- return protocol.toString();
- }
-
- public SSLSessionContext getSessionContext()
- {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- {
- sm.checkPermission(GET_SESSION_CONTEXT_PERMISSION);
- }
- return context;
- }
-
- public String[] getValueNames()
- {
- Set names = values.keySet();
- return (String[]) names.toArray(new String[names.size()]);
- }
-
- public Object getValue(String name)
- {
- return values.get(name);
- }
-
- public void putValue(String name, Object value)
- {
- values.put(name, value);
- if (value instanceof SSLSessionBindingListener)
- {
- ((SSLSessionBindingListener) value).valueBound(
- new SSLSessionBindingEvent(this, name));
- }
- }
-
- public void removeValue(String name)
- {
- Object value = values.remove(name);
- if (value != null && (value instanceof SSLSessionBindingListener))
- {
- ((SSLSessionBindingListener) value).valueUnbound(
- new SSLSessionBindingEvent(this, name));
- }
- }
-
- public void invalidate()
- {
- if (masterSecret != null)
- {
- for (int i = 0; i < masterSecret.length; i++)
- {
- masterSecret[i] = 0;
- }
- masterSecret = null;
- }
- valid = false;
- }
-
- synchronized void access()
- {
- lastAccessedTime.setTime(System.currentTimeMillis());
- context.notifyAccess(this);
- }
-
- void setLastAccessedTime(long lastAccessedTime)
- {
- this.lastAccessedTime.setTime(lastAccessedTime);
- }
-
- // Inner classes.
- // -------------------------------------------------------------------------
-
- /**
- * A byte array with appropriate <code>equals()</code>,
- * <code>hashCode()</code>, and <code>compareTo()</code> semantics.
- */
- static final class ID implements Comparable
- {
-
- // Fields.
- // -----------------------------------------------------------------------
-
- /** The ID itself. */
- private final byte[] id;
-
- // Constructor.
- // -----------------------------------------------------------------------
-
- /**
- * Creates a new ID.
- *
- * @param id The ID. The array is not cloned.
- */
- ID(byte[] id)
- {
- if (id == null)
- {
- throw new IllegalArgumentException();
- }
- this.id = id;
- }
-
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public byte[] getId()
- {
- return (byte[]) id.clone();
- }
-
- public boolean equals(Object other)
- {
- if (other == null || !(other instanceof ID))
- {
- return false;
- }
- return Arrays.equals(id, ((ID) other).id);
- }
-
- public int hashCode()
- {
- int code = 0;
- for (int i = 0; i < id.length; i++)
- {
- code |= (id[i] & 0xFF) << ((i & 3) << 3);
- }
- return code;
- }
-
- public int compareTo(Object other)
- {
- if (other == null || !(other instanceof ID))
- {
- return 1;
- }
- byte[] id2 = ((ID) other).id;
- if (id.length != id2.length)
- {
- return (id.length < id2.length) ? -1 : 1;
- }
- for (int i = 0; i < id.length; i++)
- {
- if (id[i] < id2[i])
- {
- return -1;
- }
- else if (id[i] > id2[i])
- {
- return 1;
- }
- }
- return 0;
- }
-
- public String toString()
- {
- return Util.toHexString(id, ':');
- }
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java
deleted file mode 100644
index 9e265429aab..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/* SessionContext.java -- Implementation of a session context.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.security.Security;
-
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Vector;
-
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-
-/**
- * A collection of SSL sessions. This implementation is a memory-only
- * store; subclasses may implement persistent storage.
- */
-class SessionContext implements SSLSessionContext
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- /** The map of Session.ID objects to Sessions. */
- protected final HashMap sessions;
-
- /** The number of sessions to cache. */
- protected int cacheSize;
-
- /** The session timeout, in seconds. */
- protected int timeout;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SessionContext()
- {
- sessions = new HashMap();
- cacheSize = 0;
- try
- {
- timeout = Integer.parseInt(Util.getSecurityProperty("jessie.session.timeout"));
- }
- catch (Exception x)
- {
- // Default 24-hour timeout.
- timeout = 86400;
- }
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public synchronized Enumeration getIds()
- {
- Vector ids = new Vector();
- for(Iterator i = sessions.keySet().iterator(); i.hasNext(); )
- {
- Session.ID id = (Session.ID) i.next();
- ids.add(id.getId());
- }
- return ids.elements();
- }
-
- public synchronized SSLSession getSession(byte[] sessionId)
- {
- Session session = (Session) sessions.get(new Session.ID(sessionId));
- if (session == null)
- return null;
- long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
- if ((int) (elapsed / 1000) > timeout)
- {
- removeSession(session.sessionId);
- session.invalidate();
- return null;
- }
- if (!session.valid)
- {
- removeSession(session.sessionId);
- session.invalidate();
- return null;
- }
- return session;
- }
-
- public int getSessionCacheSize()
- {
- return cacheSize;
- }
-
- public void setSessionCacheSize(int cacheSize)
- {
- if (cacheSize < 0)
- throw new IllegalArgumentException();
- this.cacheSize = cacheSize;
- }
-
- public int getSessionTimeout()
- {
- return timeout;
- }
-
- public void setSessionTimeout(int timeout)
- {
- if (timeout <= 0)
- throw new IllegalArgumentException();
- this.timeout = timeout;
- }
-
- public String toString()
- {
- return sessions.keySet().toString();
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- /**
- * Adds a session to this context. This method:
- *
- * <ol>
- * <li>Will do nothing if the cache already contains the given ID.</li>
- * <li>Will do nothing if the cache limit has been reached (and is
- * not zero).</li>
- * <li>Will remove any invalid sessions in the cache before trying to insert
- * the new one.</li>
- * <li>Will remove any expired sessions before trying to insert the new
- * one.</li>
- * </ol>
- *
- * @param sessionId This session's ID.
- * @param session The session to add.
- * @return True if the session was added, false otherwise.
- */
- synchronized boolean addSession(Session.ID sessionId, Session session)
- {
- if (sessions.containsKey(sessionId))
- return false;
- if (cacheSize > 0 && sessions.size() > cacheSize)
- {
- boolean removed = false;
- for (Iterator i = sessions.values().iterator(); i.hasNext(); )
- {
- Session s = (Session) i.next();
- long elapsed = System.currentTimeMillis() - s.getCreationTime();
- if (!s.valid)
- {
- removeSession(session.sessionId);
- removed = true;
- }
- else if ((int) (elapsed / 1000) > timeout)
- {
- removeSession(session.sessionId);
- removed = true;
- }
- }
- if (removed)
- {
- sessions.put(sessionId, session);
- session.context = this;
- session.sessionId = sessionId;
- return true;
- }
- return false;
- }
- else
- {
- sessions.put(sessionId, session);
- session.context = this;
- session.sessionId = sessionId;
- return true;
- }
- }
-
- /**
- * Returns whether or not a session with the given ID is cached by this
- * context.
- */
- synchronized boolean containsSessionID(Session.ID sessionId)
- {
- Session s = (Session) sessions.get(sessionId);
- if (s == null)
- {
- return false;
- }
- long elapsed = System.currentTimeMillis() - s.getCreationTime();
- if (!s.valid || (int) (elapsed / 1000) > timeout)
- {
- removeSession(sessionId);
- return false;
- }
- return true;
- }
-
- /**
- * Removes a session from this context.
- *
- * @param sessionId The ID of the session to remove.
- */
- synchronized boolean removeSession(Session.ID sessionId)
- {
- return sessions.remove(sessionId) != null;
- }
-
- /**
- * Notifies this context of an access event on a session.
- *
- * @param session The session that was accessed.
- */
- void notifyAccess(Session session)
- {
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java
new file mode 100644
index 00000000000..86dcb4915cd
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java
@@ -0,0 +1,198 @@
+/* SessionImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.crypto.key.GnuPBEKey;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.Session.ID;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import java.security.Certificate;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SealedObject;
+import javax.crypto.spec.PBEKeySpec;
+import javax.net.ssl.SSLException;
+
+public class SessionImpl extends Session
+{
+ static final long serialVersionUID = 8932976607588442485L;
+ CipherSuite suite;
+ ProtocolVersion version;
+ byte[] privateDataSalt;
+ SealedObject sealedPrivateData;
+ MaxFragmentLength maxLength;
+
+ transient PrivateData privateData;
+
+ public SessionImpl()
+ {
+ super();
+ privateData = new PrivateData();
+ }
+
+ SecureRandom random ()
+ {
+ return random;
+ }
+
+ public String getProtocol()
+ {
+ return version.toString();
+ }
+
+ public void prepare(char[] passwd) throws SSLException
+ {
+ try
+ {
+ privateDataSalt = new byte[32];
+ random.nextBytes(privateDataSalt);
+ GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000);
+ Cipher cipher = Cipher.getInstance("PBEWithHMacSHA256AndAES/OFB/PKCS7Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ sealedPrivateData = new SealedObject(privateData, cipher);
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ throw new SSLException(ibse);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (IOException ioe)
+ {
+ throw new SSLException(ioe);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ catch (NoSuchPaddingException nspe)
+ {
+ throw new SSLException(nspe);
+ }
+ }
+
+ public void repair(char[] passwd) throws SSLException
+ {
+ try
+ {
+ GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000);
+ privateData = (PrivateData) sealedPrivateData.getObject(key);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ throw new SSLException(cnfe);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (IOException ioe)
+ {
+ throw new SSLException(ioe);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+
+ public SealedObject privateData() throws SSLException
+ {
+ if (privateData == null)
+ throw new SSLException("this session has not been prepared");
+ return sealedPrivateData;
+ }
+
+ public void setPrivateData(SealedObject so) throws SSLException
+ {
+ this.sealedPrivateData = so;
+ }
+
+ void setApplicationBufferSize(int size)
+ {
+ applicationBufferSize = size;
+ }
+
+ void setRandom(SecureRandom random)
+ {
+ this.random = random;
+ }
+
+ void setTruncatedMac(boolean truncatedMac)
+ {
+ this.truncatedMac = truncatedMac;
+ }
+
+ void setId(Session.ID id)
+ {
+ this.sessionId = id;
+ }
+
+ void setLocalCertificates(java.security.cert.Certificate[] chain)
+ {
+ this.localCerts = chain;
+ }
+
+ void setPeerCertificates(java.security.cert.Certificate[] chain)
+ {
+ this.peerCerts = chain;
+ }
+
+ void setPeerVerified(boolean peerVerified)
+ {
+ this.peerVerified = peerVerified;
+ }
+
+ static class PrivateData implements Serializable
+ {
+ static final long serialVersionUID = -8040597659545984581L;
+ byte[] masterSecret;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java
index c9be641431f..8c6cfadc734 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java
@@ -1,4 +1,4 @@
-/* Signature.java -- SSL signature message.
+/* Signature.java -- SSL Signature structure.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -49,6 +49,8 @@ import java.io.StringWriter;
import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
import java.security.PublicKey;
import java.security.interfaces.RSAKey;
@@ -56,103 +58,115 @@ import java.util.Arrays;
import gnu.java.security.der.*;
-class Signature implements Constructed
+/**
+ * The signature structure.
+ *
+ * <pre>
+select (SignatureAlgorithm)
+{
+case anonymous:
+ struct { };
+case rsa:
+ digitally-signed struct
+ {
+ opaque md5_hash[16];
+ opaque sha_hash[20];
+ };
+case dsa:
+ digitally-signed struct
+ {
+ opaque sha_hash[20];
+ };
+} Signature;</pre>
+ */
+public class Signature implements Builder, Constructed
{
// Fields.
// -------------------------------------------------------------------------
- private final Object sigValue;
- private final String sigAlg;
+ private final ByteBuffer buffer;
+ private final SignatureAlgorithm alg;
// Constructor.
// -------------------------------------------------------------------------
- Signature(Object sigValue, String sigAlg)
+ public Signature (final ByteBuffer buffer, final SignatureAlgorithm alg)
{
- this.sigValue = sigValue;
- this.sigAlg = sigAlg;
+ this.buffer = buffer;
+ this.alg = alg;
}
-
- // Class method.
- // -------------------------------------------------------------------------
-
- static Signature read(InputStream in, CipherSuite suite, PublicKey key)
- throws IOException
+
+ public Signature (final byte[] sigValue, final SignatureAlgorithm alg)
{
- Object sigValue = null;
- DataInputStream din = new DataInputStream(in);
- int len = din.readUnsignedShort();
- sigValue = new byte[len];
- din.readFully((byte[]) sigValue);
- if (suite.getSignature() == "DSS")
- {
- DERReader der = new DERReader(new ByteArrayInputStream((byte[]) sigValue));
- if (der.read().getTag() != DER.SEQUENCE)
- {
- throw new IOException("expecting DER SEQUENCE");
- }
- BigInteger r = (BigInteger) der.read().getValue();
- BigInteger s = (BigInteger) der.read().getValue();
- sigValue = new BigInteger[] { r, s };
- }
- return new Signature(sigValue, suite.getSignature());
+ buffer = ByteBuffer.allocate(sigValue.length + 2);
+ buffer.putShort((short) sigValue.length);
+ buffer.put(sigValue);
+ buffer.position(0);
+ this.alg = alg;
}
// Instance methods.
// -------------------------------------------------------------------------
- public void write(OutputStream out) throws IOException
+ public int length ()
+ {
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return 0;
+ return (buffer.getShort (0) & 0xFFFF) + 2;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public byte[] signature ()
{
- write(out, ProtocolVersion.TLS_1);
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return new byte[0];
+ int length = buffer.getShort (0) & 0xFFFF;
+ byte[] buf = new byte[length];
+ ((ByteBuffer) buffer.duplicate().position(2)).get(buf);
+ return buf;
}
- public void write(OutputStream out, ProtocolVersion version)
- throws IOException
+ public void setSignature (final byte[] signature)
{
- byte[] result = null;
- if (sigValue instanceof byte[])
- {
- result = (byte[]) sigValue;
- }
- else
- {
- DERValue r = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[0]);
- DERValue s = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[1]);
- DERValue sig = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED,
- Arrays.asList(new Object[] { r, s }));
- result = sig.getEncoded();
- }
- out.write(result.length >>> 8 & 0xFF);
- out.write(result.length & 0xFF);
- out.write(result);
+ setSignature (signature, 0, signature.length);
}
- Object getSigValue()
+ public void setSignature (final byte[] signature, final int offset, final int length)
{
- return sigValue;
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return;
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (signature, offset, length);
}
- String getSigAlg()
+ public String toString ()
{
- return sigAlg;
+ return toString (null);
}
- public String toString()
+ public String toString (final String prefix)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
out.println("struct {");
- if (sigAlg.equals("RSA"))
- {
- out.print(Util.hexDump((byte[]) sigValue, " "));
- }
- else
+ if (!alg.equals (SignatureAlgorithm.ANONYMOUS))
{
- out.println(" r = " + ((BigInteger[]) sigValue)[0].toString(16) + ";");
- out.println(" s = " + ((BigInteger[]) sigValue)[1].toString(16) + ";");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.print (Util.hexDump (signature (), subprefix));
}
- out.println("} Signature;");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Signature;");
return str.toString();
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java
new file mode 100644
index 00000000000..a789576db90
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java
@@ -0,0 +1,62 @@
+/* SignatureAlgorithm.java -- Signature algorithm enumeration.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+public enum SignatureAlgorithm
+{
+ ANONYMOUS, RSA, DSA;
+
+ /**
+ * Returns the algorithm name for this signature algorithm, which can
+ * be used with the JCA API to get a {@link java.security.Signature} for
+ * that algorithm.
+ *
+ * @return The algorithm name.
+ */
+ public String algorithm()
+ {
+ switch (this)
+ {
+ case ANONYMOUS: return null;
+ case RSA: return "TLSv1.1-RSA";
+ case DSA: return "DSS";
+ }
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java
new file mode 100644
index 00000000000..b9d0f95519d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java
@@ -0,0 +1,146 @@
+/* SimpleSessionContext.java -- memory-only session store.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.SessionStoreException;
+import gnu.javax.net.ssl.Session.ID;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A simple, non-persistent SessionContext.
+ *
+ * @author csm
+ */
+public final class SimpleSessionContext
+ extends AbstractSessionContext
+{
+ /**
+ * By default, sessions last for 5 minutes.
+ */
+ public static final int DEFAULT_TIMEOUT = 300;
+
+ private final HashMap<Session.ID, Session> store;
+ private int storeLimit;
+
+ public SimpleSessionContext()
+ {
+ super(DEFAULT_TIMEOUT);
+ storeLimit = 0;
+ store = new HashMap<Session.ID, Session>();
+ }
+
+ @Override
+ protected Session implGet(byte[] sessionId)
+ {
+ return store.get(new Session.ID(sessionId));
+ }
+
+ @Override
+ public void load(char[] password) throws SessionStoreException
+ {
+ // Not supported. Memory-only.
+ }
+
+ @Override
+ public void put(Session session)
+ {
+ if (storeLimit > 0 && store.size() >= storeLimit)
+ {
+ Session oldest = null;
+ for (Map.Entry<Session.ID, Session> e : store.entrySet())
+ {
+ Session s = e.getValue();
+ long stamp = s.getLastAccessedTime();
+ if (oldest == null || oldest.getLastAccessedTime() > stamp)
+ oldest = s;
+ }
+ store.remove(oldest.id());
+ }
+ store.put(session.id(), session);
+ }
+
+ @Override
+ public void remove(byte[] sessionId)
+ {
+ store.remove(new Session.ID(sessionId));
+ }
+
+ @Override
+ public void store(char[] password) throws SessionStoreException
+ {
+ // Not supported. Memory-only.
+ }
+
+ public Enumeration getIds()
+ {
+ return new Enumeration()
+ {
+ Iterator<Session.ID> it = store.keySet().iterator();
+
+ public boolean hasMoreElements()
+ {
+ return it.hasNext();
+ }
+
+ public Object nextElement()
+ {
+ return it.next().id();
+ }
+ };
+ }
+
+ public int getSessionCacheSize()
+ {
+ return storeLimit;
+ }
+
+ public void setSessionCacheSize(int size)
+ {
+ if (size < 0)
+ throw new IllegalArgumentException("cache size must be nonnegative");
+ this.storeLimit = size;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java
deleted file mode 100644
index 4e22f08be08..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/* SynchronizedRandom.java -- Thread-safe IRandom wrapper.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.util.Map;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-
-class SynchronizedRandom implements IRandom
-{
-
- // Field.
- // -------------------------------------------------------------------------
-
- private final IRandom random;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- SynchronizedRandom(IRandom random)
- {
- this.random = random;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String name()
- {
- return random.name();
- }
-
- public synchronized void init(Map attrib)
- {
- random.init(attrib);
- }
-
- public synchronized byte nextByte()
- throws IllegalStateException, LimitReachedException
- {
- return random.nextByte();
- }
-
- public synchronized void nextBytes(byte[] buf, int off, int len)
- throws IllegalStateException, LimitReachedException
- {
- random.nextBytes(buf, off, len);
- }
-
- public synchronized Object clone()
- throws CloneNotSupportedException
- {
- return new SynchronizedRandom((IRandom) random.clone());
- }
-
- // For future versions of GNU Crypto. No-ops.
- public void addRandomByte (byte b)
- {
- }
-
- public void addRandomBytes(byte[] buffer) {
- addRandomBytes(buffer, 0, buffer.length);
- }
-
- public void addRandomBytes (byte[] b, int i, int j)
- {
- }
-}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java
index 1997458dd24..0595f87a7a6 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java
@@ -1,4 +1,4 @@
-/* JessieDHPrivateKey.java -- simple DH private key.
+/* TruncatedHMAC.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,62 +38,39 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.math.BigInteger;
+import gnu.javax.net.ssl.provider.Extension.Value;
-import javax.crypto.interfaces.DHPrivateKey;
-import javax.crypto.spec.DHParameterSpec;
+import java.nio.ByteBuffer;
-class JessieDHPrivateKey implements DHPrivateKey
+/**
+ * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension.
+ * This extension has an empty value; this class is thusly empty.
+ *
+ * @author csm
+ */
+public class TruncatedHMAC extends Value
{
- // Fields.
- // -------------------------------------------------------------------------
-
- private final DHParameterSpec params;
- private final BigInteger x;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieDHPrivateKey(DHParameterSpec params, BigInteger x)
+ public int length()
{
- this.params = params;
- this.x = x;
+ return 0;
}
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
+
+ public ByteBuffer buffer()
{
- return "Diffie-Hellman";
+ return ByteBuffer.wrap(new byte[0]);
}
-
- public String getFormat()
- {
- return "NONE";
- }
-
- public byte[] getEncoded()
- {
- return null;
- }
-
- public DHParameterSpec getParams()
- {
- return params;
- }
-
- public BigInteger getX()
+
+ public String toString()
{
- return x;
+ return toString(null);
}
- public String toString()
+ public String toString(String prefix)
{
- String nl = System.getProperty("line.separator");
- return "P: " + params.getP() + nl +
- "G: " + params.getG() + nl +
- "X: " + x;
+ String s = "TruncatedHMAC;";
+ if (prefix != null)
+ s = prefix + s;
+ return s;
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java
new file mode 100644
index 00000000000..1e4b173595d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java
@@ -0,0 +1,298 @@
+/* TrustedAuthorities.java
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.x509.X500DistinguishedName;
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The trusted authorities hello extension.
+ *
+ * <pre>
+struct {
+ TrustedAuthority trusted_authorities_list&lt;0..2^16-1&gt;;
+} TrustedAuthorities;
+
+struct {
+ IdentifierType identifier_type;
+ select (identifier_type) {
+ case pre_agreed: struct {};
+ case key_sha1_hash: SHA1Hash;
+ case x509_name: DistinguishedName;
+ case cert_sha1_hash: SHA1Hash;
+ } identifier;
+} TrustedAuthority;
+
+enum {
+ pre_agreed(0), key_sha1_hash(1), x509_name(2),
+ cert_sha1_hash(3), (255)
+} IdentifierType;
+
+opaque DistinguishedName&lt;1..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class TrustedAuthorities extends Value
+ implements Iterable<TrustedAuthorities.TrustedAuthority>
+{
+ private final ByteBuffer buffer;
+
+ public TrustedAuthorities(final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ // XXX really implement Builder.
+
+ public int length()
+ {
+ return 2 + (buffer.getShort(0) & 0xFFFF);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ int n = 0;
+ for (int i = 2; i < len; i++)
+ {
+ TrustedAuthority auth =
+ new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+ i += auth.length();
+ n++;
+ }
+ return n;
+ }
+
+ public TrustedAuthority get(final int index)
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ int n = 0;
+ int i = 2;
+ while (i < len && n <= index)
+ {
+ TrustedAuthority auth =
+ new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+ if (n == index)
+ return auth;
+ i += auth.length();
+ n++;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for(TrustedAuthority ta : this)
+ out.println(ta);
+ if (prefix != null) out.print(prefix);
+ out.print("} TrustedAuthorities;");
+ return str.toString();
+ }
+
+ public Iterator<TrustedAuthority> iterator()
+ {
+ return new AuthoritiesIterator();
+ }
+
+ public class AuthoritiesIterator implements Iterator<TrustedAuthority>
+ {
+ private int index;
+
+ public AuthoritiesIterator()
+ {
+ index = 0;
+ }
+
+ public TrustedAuthority next() throws NoSuchElementException
+ {
+ try
+ {
+ return get(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class TrustedAuthority implements Constructed
+ {
+ private final ByteBuffer buffer;
+
+ public TrustedAuthority(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ switch (type().getValue())
+ {
+ case 0: return 1;
+ case 1:
+ case 3: return 21;
+ case 2: return 3 + (buffer.getShort(1) & 0xFFFF);
+ }
+ throw new IllegalArgumentException("unknown authority type");
+ }
+
+ public byte[] sha1Hash()
+ {
+ IdentifierType t = type();
+ if (t != IdentifierType.CERT_SHA1_HASH
+ && t != IdentifierType.KEY_SHA1_HASH)
+ throw new IllegalArgumentException(t + " does not have a hash value");
+ byte[] b = new byte[20];
+ ((ByteBuffer) buffer.duplicate().position(1)).get(b);
+ return b;
+ }
+
+ public X500Principal name()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ byte[] b = new byte[len];
+ ((ByteBuffer) buffer.duplicate().position(3)).get(b);
+ return new X500Principal(b);
+ }
+
+ public IdentifierType type()
+ {
+ switch (buffer.get(0))
+ {
+ case 0: return IdentifierType.PRE_AGREED;
+ case 1: return IdentifierType.KEY_SHA1_HASH;
+ case 2: return IdentifierType.X509_NAME;
+ case 3: return IdentifierType.CERT_SHA1_HASH;
+ }
+
+ throw new IllegalArgumentException("invalid IdentifierType");
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identifier_type = ");
+ out.print(type());
+ out.println(";");
+ switch (type().getValue())
+ {
+ case 0: break;
+ case 1:
+ case 3:
+ if (prefix != null) out.print(prefix);
+ out.print(" sha1_hash = ");
+ out.print(Util.toHexString(sha1Hash(), ':'));
+ out.println(";");
+ break;
+
+ case 2:
+ if (prefix != null) out.print(prefix);
+ out.print(" name = ");
+ out.print(name());
+ out.println(";");
+ }
+ if (prefix != null) out.print(prefix);
+ out.print("} TrustedAuthority;");
+ return str.toString();
+ }
+ }
+
+ public static enum IdentifierType
+ {
+ PRE_AGREED (0), KEY_SHA1_HASH (1), X509_NAME (2), CERT_SHA1_HASH (3);
+
+ private final int value;
+
+ private IdentifierType(final int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
index dc6587288e6..2094daf9098 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
@@ -1,4 +1,4 @@
-/* JessieDHPublicKey.java -- simple DH public key.
+/* UnresolvedExtensionValue.jav --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -38,62 +38,46 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
-import java.math.BigInteger;
+import gnu.javax.net.ssl.provider.Extension.Value;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHParameterSpec;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
-class JessieDHPublicKey implements DHPublicKey
+public class UnresolvedExtensionValue extends Value
{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final DHParameterSpec params;
- private final BigInteger y;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieDHPublicKey(DHParameterSpec params, BigInteger y)
+ private final ByteBuffer buffer;
+
+ public UnresolvedExtensionValue (final ByteBuffer buffer)
{
- this.params = params;
- this.y = y;
+ this.buffer = buffer;
}
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
+
+ public int length()
{
- return "Diffie-Hellman";
+ return buffer.limit();
}
-
- public String getFormat()
+
+ public ByteBuffer buffer()
{
- return "NONE";
+ return value();
}
-
- public byte[] getEncoded()
+
+ public ByteBuffer value()
{
- return null;
+ return buffer.slice();
}
-
- public DHParameterSpec getParams()
- {
- return params;
- }
-
- public BigInteger getY()
+
+ public String toString()
{
- return y;
+ return toString(null);
}
-
- public String toString()
+
+ public String toString(final String prefix)
{
- String nl = System.getProperty("line.separator");
- return "P: " + params.getP() + nl +
- "G: " + params.getG() + nl +
- "Y: " + y;
+ String s = Util.hexDump(buffer);
+ if (prefix != null)
+ s = prefix + s;
+ return s;
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Util.java b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
index 15790dd26f8..ba8ea7db70b 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
@@ -38,11 +38,16 @@ exception statement from your version. */
package gnu.javax.net.ssl.provider;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Security;
@@ -52,7 +57,7 @@ import java.security.Security;
*
* @author Casey Marshall (rsdio@metastatic.org)
*/
-final class Util
+public final class Util
{
// Constants.
@@ -66,13 +71,40 @@ final class Util
// Class methods.
// -------------------------------------------------------------------------
+ public static Object wrapBuffer(ByteBuffer buffer)
+ {
+ return wrapBuffer(buffer, "");
+ }
+
+ public static Object wrapBuffer(ByteBuffer buffer, String prefix)
+ {
+ return new WrappedBuffer(buffer, prefix);
+ }
+
+ private static class WrappedBuffer
+ {
+ private final ByteBuffer buffer;
+ private final String prefix;
+
+ WrappedBuffer(ByteBuffer buffer, String prefix)
+ {
+ this.buffer = buffer;
+ this.prefix = prefix;
+ }
+
+ public String toString()
+ {
+ return hexDump(buffer, prefix);
+ }
+ }
+
/**
* Convert a hexadecimal string into its byte representation.
*
* @param hex The hexadecimal string.
* @return The converted bytes.
*/
- static byte[] toByteArray(String hex)
+ public static byte[] toByteArray(String hex)
{
hex = hex.toLowerCase();
byte[] buf = new byte[hex.length() / 2];
@@ -94,7 +126,7 @@ final class Util
* @param len The number of bytes to format.
* @return A hexadecimal representation of the specified bytes.
*/
- static String toHexString(byte[] buf, int off, int len)
+ public static String toHexString(byte[] buf, int off, int len)
{
StringBuffer str = new StringBuffer();
for (int i = 0; i < len; i++)
@@ -108,7 +140,7 @@ final class Util
/**
* See {@link #toHexString(byte[],int,int)}.
*/
- static String toHexString(byte[] buf)
+ public static String toHexString(byte[] buf)
{
return Util.toHexString(buf, 0, buf.length);
}
@@ -123,7 +155,7 @@ final class Util
* @param sep The character to insert between octets.
* @return A hexadecimal representation of the specified bytes.
*/
- static String toHexString(byte[] buf, int off, int len, char sep)
+ public static String toHexString(byte[] buf, int off, int len, char sep)
{
StringBuffer str = new StringBuffer();
for (int i = 0; i < len; i++)
@@ -139,7 +171,7 @@ final class Util
/**
* See {@link #toHexString(byte[],int,int,char)}.
*/
- static String toHexString(byte[] buf, char sep)
+ public static String toHexString(byte[] buf, char sep)
{
return Util.toHexString(buf, 0, buf.length, sep);
}
@@ -159,7 +191,7 @@ final class Util
* @param prefix A string to prepend to every line.
* @return The formatted string.
*/
- static String hexDump(byte[] buf, int off, int len, String prefix)
+ public static String hexDump(byte[] buf, int off, int len, String prefix)
{
String nl = getProperty("line.separator");
StringBuffer str = new StringBuffer();
@@ -172,7 +204,7 @@ final class Util
str.append(" ");
String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' ');
str.append(s);
- for (int j = 56 - (56 - s.length()); j < 56; j++)
+ for (int j = s.length(); j < 49; j++)
str.append(" ");
for (int j = 0; j < Math.min(16, len - i); j++)
{
@@ -187,10 +219,49 @@ final class Util
return str.toString();
}
+ public static String hexDump (ByteBuffer buf)
+ {
+ return hexDump (buf, null);
+ }
+
+ public static String hexDump (ByteBuffer buf, String prefix)
+ {
+ buf = buf.duplicate();
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ int i = 0;
+ int len = buf.remaining();
+ byte[] line = new byte[16];
+ while (i < len)
+ {
+ if (prefix != null)
+ out.print(prefix);
+ out.print(Util.formatInt (i, 16, 8));
+ out.print(" ");
+ int l = Math.min(16, len - i);
+ buf.get(line, 0, l);
+ String s = Util.toHexString(line, 0, l, ' ');
+ out.print(s);
+ for (int j = s.length(); j < 49; j++)
+ out.print(' ');
+ for (int j = 0; j < l; j++)
+ {
+ int c = line[j] & 0xFF;
+ if (c < 0x20 || c > 0x7E)
+ out.print('.');
+ else
+ out.print((char) c);
+ }
+ out.println();
+ i += 16;
+ }
+ return str.toString();
+ }
+
/**
* See {@link #hexDump(byte[],int,int,String)}.
*/
- static String hexDump(byte[] buf, int off, int len)
+ public static String hexDump(byte[] buf, int off, int len)
{
return hexDump(buf, off, len, "");
}
@@ -198,7 +269,7 @@ final class Util
/**
* See {@link #hexDump(byte[],int,int,String)}.
*/
- static String hexDump(byte[] buf, String prefix)
+ public static String hexDump(byte[] buf, String prefix)
{
return hexDump(buf, 0, buf.length, prefix);
}
@@ -206,7 +277,7 @@ final class Util
/**
* See {@link #hexDump(byte[],int,int,String)}.
*/
- static String hexDump(byte[] buf)
+ public static String hexDump(byte[] buf)
{
return hexDump(buf, 0, buf.length);
}
@@ -220,7 +291,7 @@ final class Util
* zero-padded to this length, but may be longer.
* @return The formatted integer.
*/
- static String formatInt(int i, int radix, int len)
+ public static String formatInt(int i, int radix, int len)
{
String s = Integer.toString(i, radix);
StringBuffer buf = new StringBuffer();
@@ -237,7 +308,7 @@ final class Util
* @param b2 The second byte array.
* @return The concatenation of b1 and b2.
*/
- static byte[] concat(byte[] b1, byte[] b2)
+ public static byte[] concat(byte[] b1, byte[] b2)
{
byte[] b3 = new byte[b1.length+b2.length];
System.arraycopy(b1, 0, b3, 0, b1.length);
@@ -248,7 +319,7 @@ final class Util
/**
* See {@link #trim(byte[],int,int)}.
*/
- static byte[] trim(byte[] buffer, int len)
+ public static byte[] trim(byte[] buffer, int len)
{
return trim(buffer, 0, len);
}
@@ -266,7 +337,7 @@ final class Util
* length.
* @return The trimmed byte array.
*/
- static byte[] trim(byte[] buffer, int off, int len)
+ public static byte[] trim(byte[] buffer, int off, int len)
{
if (off < 0 || len < 0 || off > buffer.length)
throw new IndexOutOfBoundsException("max=" + buffer.length +
@@ -286,7 +357,7 @@ final class Util
* @return The byte representation of the big integer, with any leading
* zero removed.
*/
- static byte[] trim(BigInteger bi)
+ public static byte[] trim(BigInteger bi)
{
byte[] buf = bi.toByteArray();
if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO))
@@ -305,7 +376,7 @@ final class Util
*
* @return The current time, in seconds.
*/
- static int unixTime()
+ public static int unixTime()
{
return (int) (System.currentTimeMillis() / 1000L);
}
@@ -385,7 +456,7 @@ final class Util
* @throws SecurityException If the Jessie code still does not have
* permission to read the property.
*/
- static String getProperty(final String name)
+ @Deprecated static String getProperty(final String name)
{
return (String) AccessController.doPrivileged(
new PrivilegedAction()
@@ -407,7 +478,7 @@ final class Util
* @throws SecurityException If the Jessie code still does not have
* permission to read the property.
*/
- static String getSecurityProperty(final String name)
+ @Deprecated static String getSecurityProperty(final String name)
{
return (String) AccessController.doPrivileged(
new PrivilegedAction()
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java
new file mode 100644
index 00000000000..1c88479cbbc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java
@@ -0,0 +1,272 @@
+/* X500PrincipalList.java -- A list of X.500 names.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+public final class X500PrincipalList implements Iterable<X500Principal>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public X500PrincipalList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ public int size ()
+ {
+ return (buffer.getShort (0) & 0xFFFF);
+ }
+
+ public int count ()
+ {
+ int size = size ();
+ int i = 0;
+ for (int offset = 2; offset < size; i++)
+ {
+ int _size = (buffer.getShort (offset) & 0xFFFF);
+ // We don't want this going into an infinite loop if
+ // you mistakenly put a zero-length name.
+ if (_size == 0)
+ break;
+ offset += _size + 2;
+ }
+ return i;
+ }
+
+ public X500Principal get (final int index)
+ {
+ if (index < 0)
+ throw new IndexOutOfBoundsException ("negative index");
+ int size = size ();
+ int i = 0;
+ for (int offset = 2; offset < size; i++)
+ {
+ int _size = (buffer.getShort (offset) & 0xFFFF);
+ if (_size == 0)
+ throw new IndexOutOfBoundsException ("zero-length name encountered");
+ if (i == index)
+ {
+ byte[] buf = new byte[_size];
+ buffer.position (offset + 2);
+ buffer.get (buf);
+ return new X500Principal (buf);
+ }
+ offset += 2 + _size;
+ }
+ throw new IndexOutOfBoundsException ("limit: " + i + "; requested: " + index);
+ }
+
+ public void put (final int index, final X500Principal principal)
+ {
+ put (index, principal.getEncoded ());
+ }
+
+ public void put (final int index, final byte[] encoded)
+ {
+ if (index < 0)
+ throw new IndexOutOfBoundsException ("negative index");
+ int size = size ();
+ int i = 0;
+ for (int offset = 2; offset < size; i++)
+ {
+ int off = (buffer.getShort (offset) & 0xFFFF);
+ if (i == index)
+ {
+ buffer.putShort (offset, (short) encoded.length);
+ buffer.position (offset + 2);
+ buffer.put (encoded);
+ modCount++;
+ return;
+ }
+ offset += 2 + off;
+ }
+ throw new IndexOutOfBoundsException ("limit: " + (i-1) + "; requested: " + index);
+ }
+
+ public void setSize (final int numNames, final int namesSize)
+ {
+ if (numNames < 1)
+ throw new IllegalArgumentException ("must have at least one name");
+ int size = (numNames * 2) + namesSize;
+ if (size < 3 || size > buffer.capacity () || size > 0xFFFF)
+ throw new IllegalArgumentException ("size out of range; maximum: "
+ + Math.min (buffer.capacity (), 0xFFFF));
+ buffer.putShort (0, (short) size);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.print ("[");
+ out.print (count ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ if (prefix != null) out.print (prefix);
+ out.print (" ");
+ out.println (it.next ());
+ }
+ if (prefix != null) out.print (prefix);
+ out.print ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof X500PrincipalList))
+ return false;
+ X500PrincipalList that = (X500PrincipalList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public java.util.Iterator<X500Principal> iterator ()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements ListIterator<X500Principal>
+ {
+ private final int modCount;
+ private int index;
+ private final int count;
+
+ public Iterator ()
+ {
+ this.modCount = X500PrincipalList.this.modCount;
+ index = 0;
+ count = count ();
+ }
+
+ public void add (X500Principal o)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < count);
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public X500Principal next () throws NoSuchElementException
+ {
+ if (modCount != X500PrincipalList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public X500Principal previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != X500PrincipalList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final X500Principal o)
+ {
+ throw new UnsupportedOperationException ();
+ }
+ }
+} \ No newline at end of file
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
index 476655c45da..dc772886697 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
@@ -54,7 +54,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
-import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
@@ -76,6 +75,8 @@ import javax.crypto.interfaces.DHPublicKey;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactorySpi;
import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
import gnu.javax.net.ssl.NullManagerParameters;
@@ -122,13 +123,17 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
}
else if (params instanceof PrivateCredentials)
{
- List chains = ((PrivateCredentials) params).getCertChains();
- List keys = ((PrivateCredentials) params).getPrivateKeys();
+ List<X509Certificate[]> chains
+ = ((PrivateCredentials) params).getCertChains();
+ List<PrivateKey> keys
+ = ((PrivateCredentials) params).getPrivateKeys();
int i = 0;
- HashMap certMap = new HashMap();
- HashMap keyMap = new HashMap();
- Iterator c = chains.iterator();
- Iterator k = keys.iterator();
+ HashMap<String, X509Certificate[]> certMap
+ = new HashMap<String, X509Certificate[]>();
+ HashMap<String, PrivateKey> keyMap
+ = new HashMap<String, PrivateKey>();
+ Iterator<X509Certificate[]> c = chains.iterator();
+ Iterator<PrivateKey> k = keys.iterator();
while (c.hasNext() && k.hasNext())
{
certMap.put(String.valueOf(i), c.next());
@@ -171,8 +176,9 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
}
}
- HashMap p = new HashMap();
- HashMap c = new HashMap();
+ HashMap<String, PrivateKey> p = new HashMap<String, PrivateKey>();
+ HashMap<String, X509Certificate[]> c
+ = new HashMap<String, X509Certificate[]>();
Enumeration aliases = store.aliases();
UnrecoverableKeyException exception = null;
while (aliases.hasMoreElements())
@@ -236,18 +242,19 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
// Inner class.
// -------------------------------------------------------------------------
- private class Manager implements X509KeyManager
+ private class Manager extends X509ExtendedKeyManager
{
// Fields.
// -----------------------------------------------------------------------
- private final Map privateKeys;
- private final Map certChains;
+ private final Map<String, PrivateKey> privateKeys;
+ private final Map<String, X509Certificate[]> certChains;
// Constructor.
// -----------------------------------------------------------------------
- Manager(Map privateKeys, Map certChains)
+ Manager(Map<String, PrivateKey> privateKeys,
+ Map<String, X509Certificate[]> certChains)
{
this.privateKeys = privateKeys;
this.certChains = certChains;
@@ -267,6 +274,19 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
}
return null;
}
+
+ public @Override String chooseEngineClientAlias(String[] keyTypes,
+ Principal[] issuers,
+ SSLEngine engine)
+ {
+ for (String type : keyTypes)
+ {
+ String[] s = getClientAliases(type, issuers);
+ if (s.length > 0)
+ return s[0];
+ }
+ return null;
+ }
public String[] getClientAliases(String keyType, Principal[] issuers)
{
@@ -281,6 +301,16 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
return s[0];
return null;
}
+
+ public @Override String chooseEngineServerAlias(String keyType,
+ Principal[] issuers,
+ SSLEngine engine)
+ {
+ String[] s = getServerAliases(keyType, issuers);
+ if (s.length > 0)
+ return s[0];
+ return null;
+ }
public String[] getServerAliases(String keyType, Principal[] issuers)
{
@@ -289,7 +319,7 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
private String[] getAliases(String keyType, Principal[] issuers)
{
- LinkedList l = new LinkedList();
+ LinkedList<String> l = new LinkedList<String>();
for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); )
{
String alias = (String) i.next();
@@ -300,21 +330,27 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
if (privKey == null)
continue;
PublicKey pubKey = chain[0].getPublicKey();
- if (keyType.equals("RSA") || keyType.equals("DHE_RSA") ||
- keyType.equals("SRP_RSA") || keyType.equals("rsa_sign"))
+ if (keyType.equalsIgnoreCase("RSA")
+ || keyType.equalsIgnoreCase("DHE_RSA")
+ || keyType.equalsIgnoreCase("SRP_RSA")
+ || keyType.equalsIgnoreCase("rsa_sign")
+ || keyType.equalsIgnoreCase("RSA_PSK"))
{
if (!(privKey instanceof RSAPrivateKey) ||
!(pubKey instanceof RSAPublicKey))
continue;
}
- if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") ||
- keyType.equals("SRP_DSS"))
+ else if (keyType.equalsIgnoreCase("DHE_DSS")
+ || keyType.equalsIgnoreCase("dss_sign")
+ || keyType.equalsIgnoreCase("SRP_DSS")
+ || keyType.equalsIgnoreCase("DSA"))
{
if (!(privKey instanceof DSAPrivateKey) ||
!(pubKey instanceof DSAPublicKey))
continue;
}
- if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh"))
+ else if (keyType.equalsIgnoreCase("DH_RSA")
+ || keyType.equalsIgnoreCase("rsa_fixed_dh"))
{
if (!(privKey instanceof DHPrivateKey) ||
!(pubKey instanceof DHPublicKey))
@@ -322,7 +358,8 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
continue;
}
- if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh"))
+ else if (keyType.equalsIgnoreCase("DH_DSS")
+ || keyType.equalsIgnoreCase("dss_fixed_dh"))
{
if (!(privKey instanceof DHPrivateKey) ||
!(pubKey instanceof DHPublicKey))
@@ -330,19 +367,23 @@ public class X509KeyManagerFactory extends KeyManagerFactorySpi
if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA"))
continue;
}
+ else // Unknown key type; ignore it.
+ continue;
if (issuers == null || issuers.length == 0)
{
l.add(alias);
continue;
}
- for (int j = 0; j < issuers.length; j++)
- if (chain[0].getIssuerDN().equals(issuers[j]))
- {
- l.add(alias);
- break;
- }
+ for (Principal issuer : issuers)
+ {
+ if (chain[0].getIssuerDN().equals(issuer))
+ {
+ l.add(alias);
+ break;
+ }
+ }
}
- return (String[]) l.toArray(new String[l.size()]);
+ return l.toArray(new String[l.size()]);
}
public X509Certificate[] getCertificateChain(String alias)
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
index 4f049e916d9..1a0591284a4 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
@@ -45,17 +45,20 @@ import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.Set;
+import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Security;
-import java.security.SignatureException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import javax.net.ssl.ManagerFactoryParameters;
@@ -63,6 +66,8 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactorySpi;
import javax.net.ssl.X509TrustManager;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.x509.X509CertPath;
import gnu.javax.net.ssl.NullManagerParameters;
import gnu.javax.net.ssl.StaticTrustAnchors;
@@ -76,21 +81,22 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
// Constants and fields.
// -------------------------------------------------------------------------
+ private static final String sep
+ = AccessController.doPrivileged(new GetPropertyAction("file.separator"));
+
/**
* The location of the JSSE key store.
*/
- private static final String JSSE_CERTS = Util.getProperty("java.home")
- + Util.getProperty("file.separator") + "lib"
- + Util.getProperty("file.separator") + "security"
- + Util.getProperty("file.separator") + "jssecerts";
+ private static final String JSSE_CERTS
+ = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+ + sep + "lib" + sep + "security" + sep + "jssecerts";
/**
* The location of the system key store, containing the CA certs.
*/
- private static final String CA_CERTS = Util.getProperty("java.home")
- + Util.getProperty("file.separator") + "lib"
- + Util.getProperty("file.separator") + "security"
- + Util.getProperty("file.separator") + "cacerts";
+ private static final String CA_CERTS
+ = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+ + sep + "lib" + sep + "security" + sep + "cacerts";
private Manager current;
@@ -135,13 +141,14 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
{
if (store == null)
{
- String s = Util.getProperty("javax.net.ssl.trustStoreType");
+ GetPropertyAction gpa = new GetPropertyAction("javax.net.ssl.trustStoreType");
+ String s = AccessController.doPrivileged(gpa);
if (s == null)
s = KeyStore.getDefaultType();
store = KeyStore.getInstance(s);
try
{
- s = Util.getProperty("javax.net.ssl.trustStore");
+ s = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStore"));
FileInputStream in = null;
if (s == null)
{
@@ -158,24 +165,24 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
{
in = new FileInputStream(s);
}
- String p = Util.getProperty("javax.net.ssl.trustStorePassword");
+ String p = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStorePassword"));
store.load(in, p != null ? p.toCharArray() : null);
}
catch (IOException ioe)
{
- throw new KeyStoreException(ioe.toString());
+ throw new KeyStoreException(ioe);
}
catch (CertificateException ce)
{
- throw new KeyStoreException(ce.toString());
+ throw new KeyStoreException(ce);
}
catch (NoSuchAlgorithmException nsae)
{
- throw new KeyStoreException(nsae.toString());
+ throw new KeyStoreException(nsae);
}
}
- LinkedList l = new LinkedList();
+ LinkedList<X509Certificate> l = new LinkedList<X509Certificate>();
Enumeration aliases = store.aliases();
while (aliases.hasMoreElements())
{
@@ -185,10 +192,9 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
Certificate c = store.getCertificate(alias);
if (!(c instanceof X509Certificate))
continue;
- l.add(c);
+ l.add((X509Certificate) c);
}
- current = this.new Manager((X509Certificate[])
- l.toArray(new X509Certificate[l.size()]));
+ current = this.new Manager(l.toArray(new X509Certificate[l.size()]));
}
// Inner class.
@@ -203,14 +209,21 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
// Fields.
// -----------------------------------------------------------------------
- private final X509Certificate[] trusted;
+ private final Set<TrustAnchor> anchors;
// Constructor.
// -----------------------------------------------------------------------
Manager(X509Certificate[] trusted)
{
- this.trusted = trusted;
+ anchors = new HashSet<TrustAnchor>();
+ if (trusted != null)
+ {
+ for (X509Certificate cert : trusted)
+ {
+ anchors.add(new TrustAnchor(cert, null));
+ }
+ }
}
// Instance methodns.
@@ -230,9 +243,7 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
public X509Certificate[] getAcceptedIssuers()
{
- if (trusted == null)
- return new X509Certificate[0];
- return (X509Certificate[]) trusted.clone();
+ return anchors.toArray(new X509Certificate[anchors.size()]);
}
// Own methods.
@@ -241,58 +252,44 @@ public class X509TrustManagerFactory extends TrustManagerFactorySpi
private void checkTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
- // NOTE: this is not a full-featured path validation algorithm.
- //
- // Step 0: check if the target is valid now.
- chain[0].checkValidity();
-
- // Step 1: verify that the chain is complete and valid.
- for (int i = 1; i < chain.length; i++)
+ CertPathValidator validator = null;
+
+ try
{
- chain[i].checkValidity();
- try
- {
- chain[i-1].verify(chain[i].getPublicKey());
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new CertificateException(nsae.toString());
- }
- catch (NoSuchProviderException nspe)
- {
- throw new CertificateException(nspe.toString());
- }
- catch (InvalidKeyException ike)
- {
- throw new CertificateException(ike.toString());
- }
- catch (SignatureException se)
- {
- throw new CertificateException(se.toString());
- }
+ validator = CertPathValidator.getInstance("PKIX");
}
-
- // Step 2: verify that the root of the chain was issued by a trust anchor.
- if (trusted == null || trusted.length == 0)
- throw new CertificateException("no trust anchors");
- for (int i = 0; i < trusted.length; i++)
+ catch (NoSuchAlgorithmException nsae)
{
- try
- {
- trusted[i].checkValidity();
- chain[chain.length-1].verify(trusted[i].getPublicKey());
- return;
- }
- catch (Exception e)
- {
- }
- //catch (CertificateException ce) { }
- //catch (NoSuchAlgorithmException nsae) { }
- //catch (NoSuchProviderException nspe) { }
- //catch (InvalidKeyException ike) { }
- //catch (SignatureException se) { }
+ throw new CertificateException(nsae);
+ }
+
+ CertPath path = new X509CertPath(Arrays.asList(chain));
+
+ PKIXParameters params = null;
+ try
+ {
+ params = new PKIXParameters(anchors);
+ // XXX we probably do want to enable revocation, but it's a pain
+ // in the ass.
+ params.setRevocationEnabled(false);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new CertificateException(iape);
+ }
+
+ try
+ {
+ validator.validate(path, params);
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ throw new CertificateException(cpve);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new CertificateException(iape);
}
- throw new CertificateException();
}
}
}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java
deleted file mode 100644
index dcfa9d4adc9..00000000000
--- a/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java
+++ /dev/null
@@ -1,619 +0,0 @@
-/* XMLSessionContext.java -- XML-encoded persistent SSL sessions.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is a part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
-USA
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-
-package gnu.javax.net.ssl.provider;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-
-import java.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateFactory;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mac.MacFactory;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.mode.ModeFactory;
-import gnu.javax.crypto.prng.IPBE;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.PRNGFactory;
-
-import gnu.javax.net.ssl.Base64;
-
-/**
- * An implementation of session contexts that stores session data on the
- * filesystem in a simple XML-encoded file.
- */
-class XMLSessionContext extends SessionContext
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final File file;
- private final IRandom pbekdf;
- private final boolean compress;
- private final SecureRandom random;
- private boolean encoding;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- XMLSessionContext() throws IOException, SAXException
- {
- file = new File(Util.getSecurityProperty("jessie.SessionContext.xml.file"));
- String password = Util.getSecurityProperty("jessie.SessionContext.xml.password");
- compress = new Boolean(Util.getSecurityProperty("jessie.SessionContext.xml.compress")).booleanValue();
- if (password == null)
- {
- password = "";
- }
- pbekdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA1");
- HashMap kdfattr = new HashMap();
- kdfattr.put(IPBE.PASSWORD, password.toCharArray());
- // Dummy salt. This is replaced by a real salt when encoding.
- kdfattr.put(IPBE.SALT, new byte[8]);
- kdfattr.put(IPBE.ITERATION_COUNT, new Integer(1000));
- pbekdf.init(kdfattr);
- encoding = false;
- if (file.exists())
- {
- decode();
- }
- encoding = true;
- random = new SecureRandom ();
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- synchronized boolean addSession(Session.ID sessionId, Session session)
- {
- boolean ret = super.addSession(sessionId, session);
- if (ret && encoding)
- {
- try
- {
- encode();
- }
- catch (IOException ioe)
- {
- }
- }
- return ret;
- }
-
- synchronized void notifyAccess(Session session)
- {
- try
- {
- encode();
- }
- catch (IOException ioe)
- {
- }
- }
-
- synchronized boolean removeSession(Session.ID sessionId)
- {
- if (super.removeSession(sessionId))
- {
- try
- {
- encode();
- }
- catch (Exception x)
- {
- }
- return true;
- }
- return false;
- }
-
- private void decode() throws IOException, SAXException
- {
- SAXParser parser = null;
- try
- {
- parser = SAXParserFactory.newInstance().newSAXParser();
- }
- catch (Exception x)
- {
- throw new Error(x.toString());
- }
- SAXHandler handler = new SAXHandler(this, pbekdf);
- InputStream in = null;
- if (compress)
- in = new GZIPInputStream(new FileInputStream(file));
- else
- in = new FileInputStream(file);
- parser.parse(in, handler);
- }
-
- private void encode() throws IOException
- {
- IMode cipher = ModeFactory.getInstance("CBC", "AES", 16);
- HashMap cipherAttr = new HashMap();
- IMac mac = MacFactory.getInstance("HMAC-SHA1");
- HashMap macAttr = new HashMap();
- byte[] key = new byte[32];
- byte[] iv = new byte[16];
- byte[] mackey = new byte[20];
- byte[] salt = new byte[8];
- byte[] encryptedSecret = new byte[48];
- cipherAttr.put(IMode.KEY_MATERIAL, key);
- cipherAttr.put(IMode.IV, iv);
- cipherAttr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- macAttr.put(IMac.MAC_KEY_MATERIAL, mackey);
- PrintStream out = null;
- if (compress)
- {
- out = new PrintStream(new GZIPOutputStream(new FileOutputStream(file)));
- }
- else
- {
- out = new PrintStream(new FileOutputStream(file));
- }
- out.println("<?xml version=\"1.0\"?>");
- out.println("<!DOCTYPE sessions [");
- out.println(" <!ELEMENT sessions (session*)>");
- out.println(" <!ATTLIST sessions size CDATA \"0\">");
- out.println(" <!ATTLIST sessions timeout CDATA \"86400\">");
- out.println(" <!ELEMENT session (peer, certificates?, secret)>");
- out.println(" <!ATTLIST session id CDATA #REQUIRED>");
- out.println(" <!ATTLIST session protocol (SSLv3|TLSv1|TLSv1.1) #REQUIRED>");
- out.println(" <!ATTLIST session suite CDATA #REQUIRED>");
- out.println(" <!ATTLIST session created CDATA #REQUIRED>");
- out.println(" <!ATTLIST session timestamp CDATA #REQUIRED>");
- out.println(" <!ELEMENT peer (certificates?)>");
- out.println(" <!ATTLIST peer host CDATA #REQUIRED>");
- out.println(" <!ELEMENT certificates (#PCDATA)>");
- out.println(" <!ATTLIST certificates type CDATA \"X.509\">");
- out.println(" <!ELEMENT secret (#PCDATA)>");
- out.println(" <!ATTLIST secret salt CDATA #REQUIRED>");
- out.println("]>");
- out.println();
- out.print("<sessions size=\"");
- out.print(cacheSize);
- out.print("\" timeout=\"");
- out.print(timeout);
- out.println("\">");
- for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); )
- {
- Map.Entry entry = (Map.Entry) it.next();
- Session.ID id = (Session.ID) entry.getKey();
- Session session = (Session) entry.getValue();
- if (!session.valid)
- {
- continue;
- }
- out.print("<session id=\"");
- out.print(Base64.encode(id.getId(), 0));
- out.print("\" suite=\"");
- out.print(session.getCipherSuite());
- out.print("\" protocol=\"");
- out.print(session.getProtocol());
- out.print("\" created=\"");
- out.print(session.getCreationTime());
- out.print("\" timestamp=\"");
- out.print(session.getLastAccessedTime());
- out.println("\">");
- out.print("<peer host=\"");
- out.print(session.getPeerHost());
- out.println("\">");
- Certificate[] certs = session.getPeerCertificates();
- if (certs != null && certs.length > 0)
- {
- out.print("<certificates type=\"");
- out.print(certs[0].getType());
- out.println("\">");
- for (int i = 0; i < certs.length; i++)
- {
- out.println("-----BEGIN CERTIFICATE-----");
- try
- {
- out.print(Base64.encode(certs[i].getEncoded(), 70));
- }
- catch (CertificateEncodingException cee)
- {
- throw new IOException(cee.toString());
- }
- out.println("-----END CERTIFICATE-----");
- }
- out.println("</certificates>");
- }
- out.println("</peer>");
- certs = session.getLocalCertificates();
- if (certs != null && certs.length > 0)
- {
- out.print("<certificates type=\"");
- out.print(certs[0].getType());
- out.println("\">");
- for (int i = 0; i < certs.length; i++)
- {
- out.println("-----BEGIN CERTIFICATE-----");
- try
- {
- out.print(Base64.encode(certs[i].getEncoded(), 70));
- }
- catch (CertificateEncodingException cee)
- {
- throw new IOException(cee.toString());
- }
- out.println("-----END CERTIFICATE-----");
- }
- out.println("</certificates>");
- }
- random.nextBytes (salt);
- pbekdf.init(Collections.singletonMap(IPBE.SALT, salt));
- try
- {
- pbekdf.nextBytes(key, 0, key.length);
- pbekdf.nextBytes(iv, 0, iv.length);
- pbekdf.nextBytes(mackey, 0, mackey.length);
- cipher.reset();
- cipher.init(cipherAttr);
- mac.init(macAttr);
- }
- catch (Exception ex)
- {
- throw new Error(ex.toString());
- }
- for (int i = 0; i < session.masterSecret.length; i += 16)
- {
- cipher.update(session.masterSecret, i, encryptedSecret, i);
- }
- mac.update(encryptedSecret, 0, encryptedSecret.length);
- byte[] macValue = mac.digest();
- out.print("<secret salt=\"");
- out.print(Base64.encode(salt, 0));
- out.println("\">");
- out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70));
- out.println("</secret>");
- out.println("</session>");
- }
- out.println("</sessions>");
- out.close();
- }
-
- // Inner class.
- // -------------------------------------------------------------------------
-
- private class SAXHandler extends DefaultHandler
- {
-
- // Field.
- // -----------------------------------------------------------------------
-
- private SessionContext context;
- private Session current;
- private IRandom pbekdf;
- private StringBuffer buf;
- private String certType;
- private int state;
- private IMode cipher;
- private HashMap cipherAttr;
- private IMac mac;
- private HashMap macAttr;
- private byte[] key;
- private byte[] iv;
- private byte[] mackey;
-
- private static final int START = 0;
- private static final int SESSIONS = 1;
- private static final int SESSION = 2;
- private static final int PEER = 3;
- private static final int PEER_CERTS = 4;
- private static final int CERTS = 5;
- private static final int SECRET = 6;
-
- // Constructor.
- // -----------------------------------------------------------------------
-
- SAXHandler(SessionContext context, IRandom pbekdf)
- {
- this.context = context;
- this.pbekdf = pbekdf;
- buf = new StringBuffer();
- state = START;
- cipher = ModeFactory.getInstance("CBC", "AES", 16);
- cipherAttr = new HashMap();
- mac = MacFactory.getInstance("HMAC-SHA1");
- macAttr = new HashMap();
- key = new byte[32];
- iv = new byte[16];
- mackey = new byte[20];
- cipherAttr.put(IMode.KEY_MATERIAL, key);
- cipherAttr.put(IMode.IV, iv);
- cipherAttr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- macAttr.put(IMac.MAC_KEY_MATERIAL, mackey);
- }
-
- // Instance methods.
- // -----------------------------------------------------------------------
-
- public void startElement(String u, String n, String qname, Attributes attr)
- throws SAXException
- {
- qname = qname.toLowerCase();
- switch (state)
- {
- case START:
- if (qname.equals("sessions"))
- {
- try
- {
- timeout = Integer.parseInt(attr.getValue("timeout"));
- cacheSize = Integer.parseInt(attr.getValue("size"));
- if (timeout <= 0 || cacheSize < 0)
- throw new SAXException("timeout or cache size out of range");
- }
- catch (NumberFormatException nfe)
- {
- throw new SAXException(nfe);
- }
- state = SESSIONS;
- }
- else
- throw new SAXException("expecting sessions");
- break;
-
- case SESSIONS:
- if (qname.equals("session"))
- {
- try
- {
- current = new Session(Long.parseLong(attr.getValue("created")));
- current.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
- current.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
- current.context = context;
- current.sessionId = new Session.ID(Base64.decode(attr.getValue("id")));
- current.setLastAccessedTime(Long.parseLong(attr.getValue("timestamp")));
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- String prot = attr.getValue("protocol");
- if (prot.equals("SSLv3"))
- current.protocol = ProtocolVersion.SSL_3;
- else if (prot.equals("TLSv1"))
- current.protocol = ProtocolVersion.TLS_1;
- else if (prot.equals("TLSv1.1"))
- current.protocol = ProtocolVersion.TLS_1_1;
- else
- throw new SAXException("bad protocol: " + prot);
- current.cipherSuite = CipherSuite.forName(attr.getValue("suite"));
- state = SESSION;
- }
- else
- throw new SAXException("expecting session");
- break;
-
- case SESSION:
- if (qname.equals("peer"))
- {
- current.peerHost = attr.getValue("host");
- state = PEER;
- }
- else if (qname.equals("certificates"))
- {
- certType = attr.getValue("type");
- state = CERTS;
- }
- else if (qname.equals("secret"))
- {
- byte[] salt = null;
- try
- {
- salt = Base64.decode(attr.getValue("salt"));
- }
- catch (IOException ioe)
- {
- throw new SAXException(ioe);
- }
- pbekdf.init(Collections.singletonMap(IPBE.SALT, salt));
- state = SECRET;
- }
- else
- throw new SAXException("bad element: " + qname);
- break;
-
- case PEER:
- if (qname.equals("certificates"))
- {
- certType = attr.getValue("type");
- state = PEER_CERTS;
- }
- else
- throw new SAXException("bad element: " + qname);
- break;
-
- default:
- throw new SAXException("bad element: " + qname);
- }
- }
-
- public void endElement(String uri, String name, String qname)
- throws SAXException
- {
- qname = qname.toLowerCase();
- switch (state)
- {
- case SESSIONS:
- if (qname.equals("sessions"))
- state = START;
- else
- throw new SAXException("expecting sessions");
- break;
-
- case SESSION:
- if (qname.equals("session"))
- {
- current.valid = true;
- context.addSession(current.sessionId, current);
- state = SESSIONS;
- }
- else
- throw new SAXException("expecting session");
- break;
-
- case PEER:
- if (qname.equals("peer"))
- state = SESSION;
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- case PEER_CERTS:
- if (qname.equals("certificates"))
- {
- try
- {
- CertificateFactory fact = CertificateFactory.getInstance(certType);
- current.peerCerts = (Certificate[])
- fact.generateCertificates(new ByteArrayInputStream(
- buf.toString().getBytes())).toArray(new Certificate[0]);
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- current.peerVerified = true;
- state = PEER;
- }
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- case CERTS:
- if (qname.equals("certificates"))
- {
- try
- {
- CertificateFactory fact = CertificateFactory.getInstance(certType);
- current.localCerts = (Certificate[])
- fact.generateCertificates(new ByteArrayInputStream(
- buf.toString().getBytes())).toArray(new Certificate[0]);
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- state = SESSION;
- }
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- case SECRET:
- if (qname.equals("secret"))
- {
- byte[] encrypted = null;
- try
- {
- encrypted = Base64.decode(buf.toString());
- if (encrypted.length != 68)
- throw new IOException("encrypted secret not 68 bytes long");
- pbekdf.nextBytes(key, 0, key.length);
- pbekdf.nextBytes(iv, 0, iv.length);
- pbekdf.nextBytes(mackey, 0, mackey.length);
- cipher.reset();
- cipher.init(cipherAttr);
- mac.init(macAttr);
- }
- catch (Exception ex)
- {
- throw new SAXException(ex);
- }
- mac.update(encrypted, 0, 48);
- byte[] macValue = mac.digest();
- for (int i = 0; i < macValue.length; i++)
- {
- if (macValue[i] != encrypted[48+i])
- throw new SAXException("MAC mismatch");
- }
- current.masterSecret = new byte[48];
- for (int i = 0; i < current.masterSecret.length; i += 16)
- {
- cipher.update(encrypted, i, current.masterSecret, i);
- }
- state = SESSION;
- }
- else
- throw new SAXException("unexpected element: " + qname);
- break;
-
- default:
- throw new SAXException("unexpected element: " + qname);
- }
- buf.setLength(0);
- }
-
- public void characters(char[] ch, int off, int len) throws SAXException
- {
- if (state != CERTS && state != PEER_CERTS && state != SECRET)
- {
- throw new SAXException("illegal character data");
- }
- buf.append(ch, off, len);
- }
- }
-}
diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java
index 66a4e24ff18..b9dc7a3d2a5 100644
--- a/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java
+++ b/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java
@@ -1,5 +1,5 @@
/* UtilDelegateImpl.java --
- Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.javax.rmi.CORBA;
+import gnu.classpath.VMStackWalker;
+
import gnu.CORBA.Minor;
import gnu.CORBA.ObjectCreator;
import gnu.CORBA.Poa.ORB_1_4;
@@ -70,6 +72,7 @@ import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.net.MalformedURLException;
import java.rmi.AccessException;
import java.rmi.MarshalException;
import java.rmi.NoSuchObjectException;
@@ -374,37 +377,24 @@ public class UtilDelegateImpl
throws ClassNotFoundException
{
if (loader == null)
- loader = Thread.currentThread().getContextClassLoader();
+ loader = VMStackWalker.firstNonNullClassLoader();
String p_useCodebaseOnly = System.getProperty("java.rmi.server.useCodebaseOnly");
boolean useCodebaseOnly = p_useCodebaseOnly != null
&& p_useCodebaseOnly.trim().equalsIgnoreCase("true");
- try
- {
- if (remoteCodebase != null && !useCodebaseOnly)
- return RMIClassLoader.loadClass(remoteCodebase, className);
- }
- catch (Exception e)
- {
- // This failed but try others.
- }
+ if (useCodebaseOnly)
+ remoteCodebase = null;
try
{
- if (remoteCodebase == null || useCodebaseOnly)
- return RMIClassLoader.loadClass(remoteCodebase, className);
+ return RMIClassLoader.loadClass(remoteCodebase, className, loader);
}
- catch (Exception e)
+ catch (MalformedURLException x)
{
- // This failed but try others.
+ throw new ClassNotFoundException(className, x);
}
-
- if (loader != null)
- return Class.forName(className, true, loader);
-
- throw new ClassNotFoundException(className + " at " + remoteCodebase);
}
/**
diff --git a/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java
index eeedf2605db..5144f58ea4c 100644
--- a/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java
+++ b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java
@@ -83,65 +83,102 @@ public abstract class AbstractCallbackHandler implements CallbackHandler
this.name = name;
}
- // Class methods.
- // -------------------------------------------------------------------------
-
+ /**
+ * Create an instance of <code>CallbackHandler</code> of the designated
+ * <code>type</code> from the first Security Provider which offers it.
+ *
+ * @param type the type of callback handler to create.
+ * @return a newly created instance of <code>ClassbackHandler</code>.
+ * @throws NoSuchAlgorithmException if no security provider is found to offer
+ * an implementation of <code>CallbackHandler</code> of the
+ * designated <code>type</code>.
+ */
public static CallbackHandler getInstance(String type)
- throws NoSuchAlgorithmException
+ throws NoSuchAlgorithmException
{
Provider[] p = Security.getProviders();
+ NoSuchAlgorithmException lastException = null;
for (int i = 0; i < p.length; i++)
- {
- try
- {
- return getInstance(type, p[i]);
- }
- catch (NoSuchAlgorithmException ignored)
- {
- }
- }
+ try
+ {
+ return getInstance(type, p[i]);
+ }
+ catch (NoSuchAlgorithmException x)
+ {
+ lastException = x;
+ }
+ if (lastException != null)
+ throw lastException;
throw new NoSuchAlgorithmException(type);
}
+ /**
+ * Create an instance of <code>CallbackHandler</code> of the designated
+ * <code>type</code> from the named security <code>provider</code>.
+ *
+ * @param type the type of callback handler to create.
+ * @param provider a named security provider to use.
+ * @return a newly created instance of <code>ClassbackHandler</code>.
+ * @throws NoSuchAlgorithmException if no security provider is found to offer
+ * an implementation of <code>CallbackHandler</code> of the
+ * designated <code>type</code>.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
+ */
public static CallbackHandler getInstance(String type, String provider)
- throws NoSuchAlgorithmException, NoSuchProviderException
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
+ if (provider == null)
+ throw new IllegalArgumentException("provider MUST NOT be null");
Provider p = Security.getProvider(provider);
if (p == null)
- {
- throw new NoSuchProviderException(provider);
- }
+ throw new NoSuchProviderException(provider);
return getInstance(type, p);
}
+ /**
+ * Create an instance of <code>CallbackHandler</code> of the designated
+ * <code>type</code> from the designated security <code>provider</code>.
+ *
+ * @param type the type of callback handler to create.
+ * @param provider a security provider to use.
+ * @return a newly created instance of <code>ClassbackHandler</code>.
+ * @throws NoSuchAlgorithmException if no security provider is found to offer
+ * an implementation of <code>CallbackHandler</code> of the
+ * designated <code>type</code>.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> is an empty string.
+ */
public static CallbackHandler getInstance(String type, Provider provider)
throws NoSuchAlgorithmException
{
+ StringBuilder sb = new StringBuilder("CallbackHandler of type [")
+ .append(type).append("] from provider[")
+ .append(provider).append("] could not be created");
+ Throwable cause;
try
{
return (CallbackHandler) Engine.getInstance(SERVICE, type, provider);
}
- catch (InvocationTargetException ite)
+ catch (InvocationTargetException x)
{
- Throwable cause = ite.getCause();
+ cause = x.getCause();
if (cause instanceof NoSuchAlgorithmException)
throw (NoSuchAlgorithmException) cause;
- NoSuchAlgorithmException nsae = new NoSuchAlgorithmException(type);
- if (cause != null)
- nsae.initCause (cause);
- throw nsae;
+ if (cause == null)
+ cause = x;
}
- catch (ClassCastException cce)
+ catch (ClassCastException x)
{
- NoSuchAlgorithmException nsae = new NoSuchAlgorithmException(type);
- nsae.initCause (cce);
- throw nsae;
+ cause = x;
}
+ NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
+ x.initCause(cause);
+ throw x;
}
- // Instance methods.
- // -------------------------------------------------------------------------
-
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException
{
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java
index 19921d98c67..fcec1196235 100644
--- a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java
+++ b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java
@@ -1,4 +1,4 @@
-/* JessieRSAPublicKey.java -- simple RSA public key.
+/* CertificateCallback.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a part of GNU Classpath.
@@ -33,66 +33,32 @@ module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
+exception statement from your version. */
-package gnu.javax.net.ssl.provider;
+package gnu.javax.security.auth.callback;
-import java.math.BigInteger;
-import java.security.interfaces.RSAPublicKey;
+import java.security.cert.Certificate;
-class JessieRSAPublicKey implements RSAPublicKey
-{
-
- // Fields.
- // -------------------------------------------------------------------------
-
- private final BigInteger modulus;
- private final BigInteger exponent;
-
- // Constructor.
- // -------------------------------------------------------------------------
-
- JessieRSAPublicKey(BigInteger modulus, BigInteger exponent)
- {
- this.modulus = modulus;
- this.exponent = exponent;
- }
-
- // Instance methods.
- // -------------------------------------------------------------------------
-
- public String getAlgorithm()
- {
- return "RSA";
- }
-
- public String getFormat()
- {
- return "NONE";
- }
-
- public byte[] getEncoded()
- {
- return null;
- }
-
- public BigInteger getModulus()
- {
- return modulus;
- }
-
- public BigInteger getPublicExponent()
- {
- return exponent;
- }
+import javax.security.auth.callback.ConfirmationCallback;
- public String toString()
+/**
+ * A {@link javax.security.auth.callback.Callback} for confirming whether or
+ * not a certificate may be used. This works similarly to
+ * {@link ConfirmationCallback}, but additionally contains the certificate
+ * being verified. Thus, handlers may present the certificate to the user, when
+ * handling this callback.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateCallback extends ConfirmationCallback
+{
+ static final long serialVersionUID = 8343869651419225634L;
+ public final Certificate certificate;
+
+ public CertificateCallback(Certificate cert, String prompt)
{
- String nl = System.getProperty("line.separator");
- return "RSAPublicKey {" + nl +
- " modulus = " + modulus.toString(16) + ";" + nl +
- " exponent = " + exponent.toString(16) + ";" + nl +
- "};";
+ super(prompt, ERROR, YES_NO_OPTION, NO);
+ this.certificate = cert;
}
}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java
new file mode 100644
index 00000000000..d75beea5247
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java
@@ -0,0 +1,64 @@
+/* BorderStyle.java -- Utility for dealing with border styles
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+/**
+ * Utility class for handling border styles.
+ */
+public class BorderStyle
+{
+
+ /**
+ * Determines if a given value makes up a valid border style value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> when this is a valid border style,
+ * <code>false</code> otherwise
+ */
+ public static boolean isValidStyle(String value)
+ {
+ return value.equals("none") || value.equals("hidden")
+ || value.equals("dotted") || value.equals("dashed")
+ || value.equals("solid") || value.equals("double")
+ || value.equals("groove") || value.equals("ridge")
+ || value.equals("inset") || value.equals("outset");
+
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java
new file mode 100644
index 00000000000..ae64c21101c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java
@@ -0,0 +1,78 @@
+/* BorderWidth.java -- A CSS metric for border widths
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+/**
+ * A special CSS metric for border widths. It basically understands everything
+ * as Length, and in addition to that provides a mapping for the border-width's
+ * thin, medium and think values.
+ */
+public class BorderWidth
+ extends Length
+{
+
+ /**
+ * Creates a new BorderWidth instance.
+ *
+ * @param val the CSS value to be interpreted
+ */
+ public BorderWidth(String val)
+ {
+ super(val);
+ if (val.equals("thin"))
+ floatValue = 1.F;
+ else if (val.equals("medium"))
+ floatValue = 2.F;
+ else if (val.equals("thick"))
+ floatValue = 3.F;
+ }
+
+ /**
+ * Checks if the specified value makes up a valid border-width value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> if the value is a valid border-width
+ */
+ public static boolean isValid(String value)
+ {
+ return value.equals("thin") || value.equals("medium")
+ || value.equals("thick") || Length.isValid(value);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java
new file mode 100644
index 00000000000..ea4b94ae0a5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java
@@ -0,0 +1,170 @@
+/* CSSColor.java -- Converts CSS color values
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.awt.Color;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Converts CSS color values into AWT Color values.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class CSSColor
+{
+
+ private static final HashMap COLOR_MAP;
+ static
+ {
+ COLOR_MAP = new HashMap();
+ COLOR_MAP.put("maroon", "#800000");
+ COLOR_MAP.put("red", "#ff0000");
+ COLOR_MAP.put("orange", "#ffa500");
+ COLOR_MAP.put("yellow", "#ffff00");
+ COLOR_MAP.put("olive", "#808000");
+ COLOR_MAP.put("purple", "#800080");
+ COLOR_MAP.put("fuchsia", "#ff00ff");
+ COLOR_MAP.put("white", "#ffffff");
+ COLOR_MAP.put("lime", "#00ff00");
+ COLOR_MAP.put("green", "#008000");
+ COLOR_MAP.put("navy", "#000080");
+ COLOR_MAP.put("blue", "#0000ff");
+ COLOR_MAP.put("aqua", "#00ffff");
+ COLOR_MAP.put("teal", "#008080");
+ COLOR_MAP.put("black", "#000000");
+ COLOR_MAP.put("silver", "#c0c0c0");
+ COLOR_MAP.put("gray", "#808080");
+ }
+
+ /**
+ * The CSS value.
+ */
+ private String value;
+
+ /**
+ * The converted color.
+ */
+ private Color color;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param val the CSS value
+ */
+ public CSSColor(String val)
+ {
+ value = val;
+ color = convertValue(value);
+ }
+
+ /**
+ * Converts a CSS color value to an AWT color.
+ *
+ * @param value the CSS color value
+ *
+ * @return the converted color value
+ */
+ public static Color convertValue(String value)
+ {
+ Color color;
+ String val1 = value.toLowerCase();
+ if (val1.charAt(0) != '#')
+ val1 = (String) COLOR_MAP.get(val1);
+ if (val1 != null)
+ {
+ String hexVal = val1.substring(1).trim();
+ try
+ {
+ int rgb = Integer.parseInt(hexVal, 16);
+ color = new Color(rgb);
+ }
+ catch (NumberFormatException ex)
+ {
+ color = Color.BLACK;
+ }
+ }
+ else
+ color = null;
+ return color;
+ }
+
+ /**
+ * Returns the converted color.
+ *
+ * @return the converted color
+ */
+ public Color getValue()
+ {
+ return color;
+ }
+
+ public String toString()
+ {
+ return value;
+ }
+
+ /**
+ * Returns <code>true</code> if the specified value is a valid color value,
+ * <code>false</code> otherwise.
+ *
+ * @param val the value to check
+ *
+ * @return <code>true</code> if the specified value is a valid color value,
+ * <code>false</code> otherwise
+ */
+ public static boolean isValidColor(String val)
+ {
+ boolean ret = false;
+ if (val.charAt(0) == '#')
+ ret = true;
+ else
+ {
+ Set colors = COLOR_MAP.keySet();
+ for (Iterator i = colors.iterator(); i.hasNext() && ret == false;)
+ {
+ String color = (String) i.next();
+ if (color.equalsIgnoreCase(val))
+ ret = true;
+ }
+ }
+ return ret;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java
new file mode 100644
index 00000000000..13968e4d2cd
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java
@@ -0,0 +1,60 @@
+/* CSSLexicalException.java -- Indicates a failure in the lexical analyser
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.io.IOException;
+
+/**
+ * Indicates a failure in the lexical analyser of the CSS parser.
+ */
+public class CSSLexicalException
+ extends IOException
+{
+
+ public CSSLexicalException()
+ {
+ super();
+ }
+
+ public CSSLexicalException(String message)
+ {
+ super(message);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java
new file mode 100644
index 00000000000..5647e25069d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java
@@ -0,0 +1,500 @@
+/* CSSParser.java -- A parser for CSS stylesheets
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.StringTokenizer;
+
+/**
+ * A parser for CSS stylesheets.
+ *
+ * This parser is based on the simple CSS grammar describe in
+ *
+ * http://www.w3.org/TR/CSS21/syndata.html .
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+// TODO: Maybe use more restrictive grammar:
+// http://www.w3.org/TR/CSS21/grammar.html#q1
+public class CSSParser
+{
+
+ /**
+ * The scanner used to read the input streams into more usable tokens.
+ */
+ private CSSScanner scanner;
+
+ /**
+ * The parser callback.
+ */
+ private CSSParserCallback callback;
+
+ /**
+ * One lookahead token.
+ */
+ private int lookahead;
+
+ /**
+ * The parse error.
+ */
+ private String error;
+
+ /**
+ * Creates a new CSSParser that parses the specified input.
+ *
+ * @param in the source to parse
+ */
+ public CSSParser(Reader in, CSSParserCallback cb)
+ {
+ scanner = new CSSScanner(in);
+ callback = cb;
+ lookahead = -1;
+ }
+
+ /**
+ * Parses the input source specified in the constructor.
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ public void parse()
+ throws IOException
+ {
+ boolean success = parseStylesheet();
+ if (! success)
+ {
+ throw new CSSParserException(error);
+ }
+ }
+
+ /**
+ * Parses a stylesheet.
+ *
+ * @return <code>true</code> if the stylesheet could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseStylesheet()
+ throws IOException
+ {
+ int token = peekToken();
+ while (token != CSSScanner.EOF && (token == CSSScanner.CDC
+ || token == CSSScanner.CDO || token == CSSScanner.S
+ || parseStatement()))
+ {
+ if (token == CSSScanner.CDC || token == CSSScanner.CDO
+ || token == CSSScanner.S)
+ readToken();
+ token = peekToken();
+ }
+ // Last token must be EOF for valid stylesheets, I'd think.
+ return token == CSSScanner.EOF;
+ }
+
+ /**
+ * Parses a CSS statement.
+ * @return <code>true</code> if the stylesheet could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseStatement()
+ throws IOException
+ {
+ return parseRuleset() || parseAtRule();
+ }
+
+ /**
+ * Parses a CSS rule set.
+ *
+ * @return <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseRuleset()
+ throws IOException
+ {
+ StringBuilder selector = new StringBuilder();
+ parseSelector(selector);
+ StringTokenizer selSplitter =
+ new StringTokenizer(selector.toString(), ",");
+ Selector[] sels = new Selector[selSplitter.countTokens()];
+ for (int i = 0; selSplitter.hasMoreTokens(); i++)
+ {
+ String sel = selSplitter.nextToken().trim();
+ sels[i] = new Selector(sel);
+ }
+ callback.startStatement(sels);
+ // Read any number of whitespace.
+ int token;
+ do
+ {
+ token = readToken();
+ } while (token == CSSScanner.S);
+ boolean ret = true;
+
+ if (token == CSSScanner.CURLY_LEFT)
+ {
+ // Read any number of whitespace.
+ do
+ {
+ token = readToken();
+ } while (token == CSSScanner.S);
+ lookahead = token;
+
+ // Maybe read declaration.
+ boolean decl = parseDeclaration();
+ token = peekToken();
+ while (token == CSSScanner.SEMICOLON)
+ {
+ readToken(); // Read the semicolon.
+ // Read any number of whitespace.
+ do
+ {
+ token = readToken();
+ } while (token == CSSScanner.S);
+ lookahead = token;
+
+ // Maybe read declaration.
+ parseDeclaration();
+ token = peekToken();
+ }
+ if (token != CSSScanner.CURLY_RIGHT)
+ {
+ error = "Expected right curly brace";
+ ret = false;
+ }
+ else
+ {
+ readToken();
+ // Read any number of whitespace.
+ do
+ {
+ token = readToken();
+ } while (token == CSSScanner.S);
+ lookahead = token;
+ callback.endStatement();
+ }
+ }
+ else
+ {
+ ret = false;
+ error = "Expected left curly brace";
+ }
+ return ret;
+ }
+
+ /**
+ * Parses a CSS declaration.
+ *
+ * @return <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseDeclaration()
+ throws IOException
+ {
+ // Maybe fetch one DELIM.
+ int token = readToken();
+ if (token == CSSScanner.DELIM)
+ token = readToken();
+
+ boolean ret = true;
+
+ // Parse property
+ String property = null;
+ if (token == CSSScanner.IDENT)
+ {
+ property = new String(scanner.parseBuffer, 0, scanner.tokenEnd);
+ // Read any number of whitespace.
+ do
+ {
+ token = readToken();
+ } while (token == CSSScanner.S);
+
+ // Read ':'.
+ if (token == CSSScanner.DELIM && scanner.parseBuffer[0] == ':')
+ {
+ // Read any number of whitespace.
+ do
+ {
+ token = readToken();
+ } while (token == CSSScanner.S);
+ lookahead = token;
+
+ StringBuilder value = new StringBuilder();
+ if (parseValue(value))
+ {
+ callback.declaration(property, value.toString().trim());
+ }
+ else
+ {
+ ret = false;
+ error = "Error while reading the property value";
+ }
+ }
+ else
+ {
+ ret = false;
+ error = "Expected colon to separate property and value";
+ }
+
+ }
+ else
+ {
+ lookahead = token;
+ ret = false;
+ error = "Expected IDENT token for property";
+ }
+ return ret;
+ }
+
+ /**
+ * Parses a property value.
+ *
+ * @param s the string builder to read the value into
+ *
+ * @return <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseValue(StringBuilder s)
+ throws IOException
+ {
+ // FIXME: Handle block and ATKEYWORD.
+ boolean success = parseAny(s);
+ while (parseAny(s));
+ return success;
+ }
+
+ /**
+ * Parses a selector.
+ *
+ * @param sel the string buffer to put the selector into
+ *
+ * @return <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseSelector(StringBuilder sel)
+ throws IOException
+ {
+ // At least one any needs to be parsed.
+ boolean ret = parseAny(sel);
+ if (ret)
+ {
+ while (parseAny(sel));
+ }
+ return ret;
+ }
+
+ /**
+ * Parses the any rule. If s is not null, then the contents of the
+ * tokens is appended verbatim.
+ *
+ * @param s the string builder to append to
+ *
+ * @return <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseAny(StringBuilder s)
+ throws IOException
+ {
+ int token = peekToken();
+ boolean ret = false;
+ if (token == CSSScanner.IDENT || token == CSSScanner.NUMBER
+ || token == CSSScanner.PERCENTAGE || token == CSSScanner.DIMENSION
+ || token == CSSScanner.STRING || token == CSSScanner.DELIM
+ || token == CSSScanner.URI || token == CSSScanner.HASH
+ || token == CSSScanner.UNICODE_RANGE || token == CSSScanner.INCLUDES
+ || token == CSSScanner.DASHMATCH)
+ {
+ if (s != null)
+ s.append(scanner.parseBuffer, 0, scanner.tokenEnd);
+ readToken();
+ ret = true;
+ }
+ else if (token == CSSScanner.FUNCTION)
+ System.err.println("Implement parseAny for FUNCTION");
+ else if (token == CSSScanner.PAREN_LEFT)
+ System.err.println("Implement parseAny for (");
+ else if (token == CSSScanner.BRACE_LEFT)
+ System.err.println("Implement parseAny for [");
+
+ // Parse any following whitespace too.
+ token = peekToken();
+ while (token == CSSScanner.S)
+ {
+ if (s != null)
+ s.append(scanner.parseBuffer, 0, scanner.tokenEnd);
+ readToken();
+ token = peekToken();
+ }
+ return ret;
+ }
+
+ /**
+ * Parses a CSS at-rule.
+ *
+ * @return <code>true</code> if the at-rule could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseAtRule()
+ throws IOException
+ {
+ // FIXME: Implement.
+ return false;
+ }
+
+ /**
+ * Reads the next token, and skips the comments.
+ *
+ * @return the next non-comment token
+ */
+ private int readToken()
+ throws IOException
+ {
+ int token;
+ if (lookahead == -1)
+ {
+ do
+ {
+ token = scanner.nextToken();
+ } while (token == CSSScanner.COMMENT);
+ }
+ else
+ {
+ token = lookahead;
+ lookahead = -1;
+ }
+ return token;
+ }
+
+ /**
+ * Returns the next token to be read, without really reading it. The next
+ * call to readToken() will return the same token again.
+ *
+ * @return the next token to be read, without really reading it
+ */
+ private int peekToken()
+ throws IOException
+ {
+ int token;
+ if (lookahead == -1)
+ {
+ do
+ {
+ token = scanner.nextToken();
+ } while (token == CSSScanner.COMMENT);
+ lookahead = token;
+ }
+ else
+ token = lookahead;
+ return token;
+ }
+
+ /**
+ * For testing, we read in the default.css in javax/swing/text/html
+ *
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ InputStream in;
+ if (args.length > 0)
+ {
+ File file = new File(args[0]);
+ in = new FileInputStream(file);
+ }
+ else
+ {
+ String name = "/javax/swing/text/html/default.css";
+ in = CSSScanner.class.getResourceAsStream(name);
+ }
+ BufferedInputStream bin = new BufferedInputStream(in);
+ InputStreamReader r = new InputStreamReader(bin);
+ CSSParserCallback cb = new CSSParserCallback()
+ {
+ public void startStatement(Selector[] selector)
+ {
+ System.out.print("startStatement: ");
+ for (int i = 0; i < selector.length; i++)
+ {
+ System.out.print(selector[i]);
+ if (i < selector.length - 1)
+ System.out.print(',');
+ else
+ System.out.println();
+ }
+ }
+ public void endStatement()
+ {
+ System.out.println("endStatement");
+ }
+ public void declaration(String property, String value)
+ {
+ System.out.println("declaration: " + property + ", " + value);
+ }
+ };
+ CSSParser p = new CSSParser(r, cb);
+ p.parse();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java
new file mode 100644
index 00000000000..f49ffa232de
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java
@@ -0,0 +1,81 @@
+/* CSSParserCallback.java -- Callback for parsing CSS
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+/**
+ * Defines the callback that is used by the CSSParser to notify the
+ * backend of the parsing process.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public interface CSSParserCallback
+{
+
+ /**
+ * Signals the beginning of a statement.
+ *
+ * A CSS statement is build up like follows:
+ * <pre>
+ * <selector> {
+ * ... declarations...
+ * }
+ * </pre>
+ *
+ * After startStatement(), the callback will receive zero to n callbacks
+ * to declaration, followed by an endStatement() call.
+ *
+ * @param selector the selector of the statement.
+ */
+ void startStatement(Selector[] selector);
+
+ /**
+ * Signals the end of a statement.
+ */
+ void endStatement();
+
+ /**
+ * Signals the parsing of one declaration, which defines a mapping
+ * from a property to a value.
+ *
+ * @param property the property
+ * @param value the value
+ */
+ void declaration(String property, String value);
+
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java
new file mode 100644
index 00000000000..2328d539804
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java
@@ -0,0 +1,62 @@
+/* CSSParserException.java -- The CSS parser exception
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.io.IOException;
+
+/**
+ * This exception is raised when the CSS parser hits a syntax error.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class CSSParserException
+ extends IOException
+{
+
+ /**
+ * Creates a new CSSParserException.
+ *
+ * @param message the exception message
+ */
+ public CSSParserException(String message)
+ {
+ super(message);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java
new file mode 100644
index 00000000000..9cc6209a549
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java
@@ -0,0 +1,718 @@
+/* CSSScanner.java -- A parser for CSS stylesheets
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+/**
+ * A tokenizer for CSS stylesheets. This is based on the scanner definition
+ * from:
+ *
+ * http://www.w3.org/TR/CSS21/syndata.html#tokenization
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+// TODO: Maybe implement more restrictive scanner:
+// http://www.w3.org/TR/CSS21/grammar.html#q2
+class CSSScanner
+{
+
+ // The tokens. This list is taken from:
+ // http://www.w3.org/TR/CSS21/syndata.html#tokenization
+ static final int IDENT = 1;
+ static final int ATKEYWORD = 2;
+ static final int STRING = 3;
+ static final int INVALID = 4;
+ static final int HASH = 5;
+ static final int NUMBER = 6;
+ static final int PERCENTAGE = 7;
+ static final int DIMENSION = 8;
+ static final int URI = 9;
+ static final int UNICODE_RANGE = 10;
+ static final int CDO = 11;
+ static final int CDC = 12;
+ static final int SEMICOLON = 13;
+ static final int CURLY_LEFT = 14;
+ static final int CURLY_RIGHT = 15;
+ static final int PAREN_LEFT = 16;
+ static final int PAREN_RIGHT = 17;
+ static final int BRACE_LEFT = 16;
+ static final int BRACE_RIGHT = 17;
+ static final int S = 18;
+ static final int COMMENT = 19;
+ static final int FUNCTION = 20;
+ static final int INCLUDES = 21;
+ static final int DASHMATCH = 22;
+ static final int DELIM = 23;
+
+ // Additional tokens defined for convenience.
+ static final int EOF = -1;
+
+ /**
+ * The input source.
+ */
+ private Reader in;
+
+ /**
+ * The parse buffer.
+ */
+ char[] parseBuffer;
+
+ /**
+ * The end index in the parseBuffer of the current token.
+ */
+ int tokenEnd;
+
+ /**
+ * The lookahead 'buffer'.
+ */
+ private int[] lookahead;
+
+ CSSScanner(Reader r)
+ {
+ lookahead = new int[2];
+ lookahead[0] = -1;
+ lookahead[1] = -1;
+ parseBuffer = new char[2048];
+ in = r;
+ }
+
+ /**
+ * Fetches the next token. The actual character data is in the parseBuffer
+ * afterwards with the tokenStart at index 0 and the tokenEnd field
+ * pointing to the end of the token.
+ *
+ * @return the next token
+ */
+ int nextToken()
+ throws IOException
+ {
+ tokenEnd = 0;
+ int token = -1;
+ int next = read();
+ if (next != -1)
+ {
+ switch (next)
+ {
+ case ';':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = SEMICOLON;
+ break;
+ case '{':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = CURLY_LEFT;
+ break;
+ case '}':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = CURLY_RIGHT;
+ break;
+ case '(':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = PAREN_LEFT;
+ break;
+ case ')':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = PAREN_RIGHT;
+ break;
+ case '[':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = BRACE_LEFT;
+ break;
+ case ']':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = BRACE_RIGHT;
+ break;
+ case '@':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ readIdent();
+ token = ATKEYWORD;
+ break;
+ case '#':
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ readName();
+ token = HASH;
+ break;
+ case '\'':
+ case '"':
+ lookahead[0] = next;
+ readString();
+ token = STRING;
+ break;
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '\f':
+ lookahead[0] = next;
+ readWhitespace();
+ token = S;
+ break;
+ // FIXME: Detecting an URI involves several characters lookahead.
+// case 'u':
+// lookahead[0] = ch;
+// readURI();
+// token = URI;
+// break;
+ case '<':
+ parseBuffer[0] = (char) next;
+ parseBuffer[1] = (char) read();
+ parseBuffer[2] = (char) read();
+ parseBuffer[3] = (char) read();
+ if (parseBuffer[1] == '!' && parseBuffer[2] == '-'
+ && parseBuffer[3] == '-')
+ {
+ token = CDO;
+ tokenEnd = 4;
+ }
+ else
+ throw new CSSLexicalException("expected CDO token");
+ break;
+ case '/':
+ lookahead[0] = next;
+ readComment();
+ token = COMMENT;
+ break;
+ case '~':
+ parseBuffer[0] = (char) next;
+ parseBuffer[1] = (char) read();
+ if (parseBuffer[1] == '=')
+ token = INCLUDES;
+ else
+ throw new CSSLexicalException("expected INCLUDES token");
+ break;
+ case '|':
+ parseBuffer[0] = (char) next;
+ parseBuffer[1] = (char) read();
+ if (parseBuffer[1] == '=')
+ token = DASHMATCH;
+ else
+ throw new CSSLexicalException("expected DASHMATCH token");
+ break;
+ case '-':
+ int ch2 = read();
+ if (ch2 == '-')
+ {
+ int ch3 = read();
+ if (ch3 == '>')
+ {
+ parseBuffer[0] = (char) next;
+ parseBuffer[1] = (char) ch2;
+ parseBuffer[2] = (char) ch3;
+ tokenEnd = 3;
+ token = CDC;
+ }
+ else
+ throw new CSSLexicalException("expected CDC token");
+ }
+ else
+ {
+ lookahead[0] = next;
+ lookahead[1] = ch2;
+ readIdent();
+ int ch3 = read();
+ if (ch3 == -1 || ch3 != '(')
+ {
+ lookahead[0] = ch3;
+ token = IDENT;
+ }
+ else
+ {
+ parseBuffer[tokenEnd] = (char) ch3;
+ tokenEnd++;
+ token = FUNCTION;
+ }
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ lookahead[0] = next;
+ readNum();
+ int ch3 = read();
+ if (ch3 == '%')
+ {
+ parseBuffer[tokenEnd] = (char) ch3;
+ tokenEnd++;
+ token = PERCENTAGE;
+ }
+ else if (ch3 == -1 || (! (ch3 == '_'
+ || (ch3 >= 'a' && ch3 <= 'z')
+ || (ch3 >= 'A' && ch3 <= 'Z')
+ || ch3 == '\\' || ch3 > 177)))
+ {
+ lookahead[0] = ch3;
+ token = NUMBER;
+ }
+ else
+ {
+ lookahead[0] = ch3;
+ readIdent();
+ token = DIMENSION;
+ }
+ break;
+ default:
+ // Handle IDENT that don't begin with '-'.
+ if (next == '_' || (next >= 'a' && next <= 'z')
+ || (next >= 'A' && next <= 'Z') || next == '\\' || next > 177)
+ {
+ lookahead[0] = next;
+ readIdent();
+ int ch4 = read();
+ if (ch4 == -1 || ch4 != '(')
+ {
+ lookahead[0] = ch4;
+ token = IDENT;
+ }
+ else
+ {
+ parseBuffer[tokenEnd] = (char) ch4;
+ tokenEnd++;
+ token = FUNCTION;
+ }
+ }
+ else
+ {
+ parseBuffer[0] = (char) next;
+ tokenEnd = 1;
+ token = DELIM;
+ }
+ break;
+ }
+ }
+ return token;
+ }
+
+ String currentTokenString()
+ {
+ return new String(parseBuffer, 0, tokenEnd);
+ }
+
+ /**
+ * Reads one character from the input stream or from the lookahead
+ * buffer, if it contains one character.
+ *
+ * @return the next character
+ *
+ * @throws IOException if problems occur on the input source
+ */
+ private int read()
+ throws IOException
+ {
+ int ret;
+ if (lookahead[0] != -1)
+ {
+ ret = lookahead[0];
+ lookahead[0] = -1;
+ }
+ else if (lookahead[1] != -1)
+ {
+ ret = lookahead[1];
+ lookahead[1] = -1;
+ }
+ else
+ {
+ ret = in.read();
+ }
+ return ret;
+ }
+
+ /**
+ * Reads and identifier.
+ *
+ * @throws IOException if something goes wrong in the input source or if
+ * the lexical analyser fails to read an identifier
+ */
+ private void readIdent()
+ throws IOException
+ {
+ int ch1 = read();
+ // Read possibly leading '-'.
+ if (ch1 == '-')
+ {
+ parseBuffer[tokenEnd] = (char) ch1;
+ tokenEnd++;
+ ch1 = read();
+ }
+ // What follows must be '_' or a-z or A-Z or nonascii (>177) or an
+ // escape.
+ if (ch1 == '_' || (ch1 >= 'a' && ch1 <= 'z')
+ || (ch1 >= 'A' && ch1 <= 'Z') || ch1 > 177)
+ {
+ parseBuffer[tokenEnd] = (char) ch1;
+ tokenEnd++;
+ }
+ else if (ch1 == '\\')
+ {
+ // Try to read an escape.
+ lookahead[0] = ch1;
+ readEscape();
+ }
+ else
+ throw new CSSLexicalException("First character of identifier incorrect");
+
+ // Read any number of [_a-zA-Z0-9-] chars.
+ int ch = read();
+ while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z')
+ || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ }
+
+ // Push back last read character since it doesn't belong to the IDENT.
+ lookahead[0] = ch;
+ }
+
+ /**
+ * Reads an escape.
+ *
+ * @throws IOException if something goes wrong in the input source or if
+ * the lexical analyser fails to read an escape
+ */
+ private void readEscape()
+ throws IOException
+ {
+ int ch = read();
+ if (ch != -1 && ch == '\\')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f'))
+ {
+ // Read unicode escape.
+ // Zero to five 0-9a-f chars can follow.
+ int hexcount = 0;
+ ch = read();
+ while (((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f'))
+ && hexcount < 5)
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ hexcount++;
+ ch = read();
+ }
+ // Now we can have a \r\n or any whitespace character following.
+ if (ch == '\r')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ if (ch == '\n')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ }
+ else
+ {
+ lookahead[0] = ch;
+ }
+ }
+ else if (ch == ' ' || ch == '\n' || ch == '\f' || ch == '\t')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ }
+ else
+ {
+ lookahead[0] = ch;
+ }
+ }
+ else if (ch != '\n' && ch != '\r' && ch != '\f')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ }
+ else
+ throw new CSSLexicalException("Can't read escape");
+ }
+ else
+ throw new CSSLexicalException("Escape must start with '\\'");
+
+ }
+
+ private void readName()
+ throws IOException
+ {
+ // Read first name character.
+ int ch = read();
+ if (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z')
+ || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ }
+ else
+ throw new CSSLexicalException("Invalid name");
+
+ // Read any number (at least one) of [_a-zA-Z0-9-] chars.
+ ch = read();
+ while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z')
+ || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ }
+
+ // Push back last read character since it doesn't belong to the IDENT.
+ lookahead[0] = ch;
+ }
+
+ /**
+ * Reads in a string.
+ *
+ * @throws IOException
+ */
+ private void readString()
+ throws IOException
+ {
+ int ch1 = read();
+ if (ch1 != -1 && (ch1 == '\'' || ch1 == '\"'))
+ {
+ parseBuffer[tokenEnd] = (char) ch1;
+ tokenEnd++;
+
+ // Read any number of chars until we hit another chc1 char.
+ // Reject newlines, except if prefixed with \.
+ int ch = read();
+ while (ch != -1 && ch != ch1)
+ {
+ // Every non-newline and non-\ char should be ok.
+ if (ch != '\n' && ch != '\r' && ch != '\f' && ch != '\\')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ }
+ // Ok when followed by newline or as part of escape.
+ else if (ch == '\\')
+ {
+ int ch2 = read();
+ if (ch2 == '\n' || ch2 == '\r')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ parseBuffer[tokenEnd + 1] = (char) ch2;
+ tokenEnd += 2;
+ }
+ else
+ {
+ // Try to parse an escape.
+ lookahead[0] = ch;
+ lookahead[1] = ch2;
+ readEscape();
+ }
+ }
+ else
+ throw new CSSLexicalException("Invalid string");
+
+ ch = read();
+ }
+ if (ch != -1)
+ {
+ // Push the final char on the buffer.
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ }
+ else
+ throw new CSSLexicalException("Unterminated string");
+ }
+ else
+ throw new CSSLexicalException("Invalid string");
+ }
+
+ /**
+ * Reads a chunk of whitespace.
+ *
+ * @throws IOException
+ */
+ private void readWhitespace()
+ throws IOException
+ {
+ int ch = read();
+ while (ch != -1 && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'
+ || ch == '\f'))
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ }
+ // Push back last character read.
+ lookahead[0] = ch;
+
+ }
+
+ private void readURI()
+ throws IOException
+ {
+ // FIXME: Implement.
+ }
+
+ /**
+ * Reads a comment block.
+ *
+ * @throws IOException
+ */
+ private void readComment()
+ throws IOException
+ {
+ // First we need a / and a *
+ int ch = read();
+ if (ch != -1 && ch == '/')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ if (ch != -1 && ch == '*')
+ {
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ boolean finished = false;
+ int lastChar = ch;
+ ch = read();
+ while (! finished && ch != -1)
+ {
+ if (lastChar == '*' && ch == '/')
+ finished = true;
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ lastChar = ch;
+ ch = read();
+ }
+ }
+ }
+ if (ch == -1)
+ throw new CSSLexicalException("Unterminated comment");
+
+ // Push back last character read.
+ lookahead[0] = ch;
+ }
+
+ /**
+ * Reads a number.
+ *
+ * @throws IOException
+ */
+ private void readNum()
+ throws IOException
+ {
+ boolean hadDot = false;
+ // First char must be number or .
+ int ch = read();
+ if (ch != -1 && ((ch >= '0' && ch <= '9') || ch == '.'))
+ {
+ if (ch == '.')
+ hadDot = true;
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ // Now read in any number of digits afterwards, and maybe one dot,
+ // if we hadn't one already.
+ ch = read();
+ while (ch != -1 && ((ch >= '0' && ch <= '9')
+ || (ch == '.' && ! hadDot)))
+ {
+ if (ch == '.')
+ hadDot = true;
+ parseBuffer[tokenEnd] = (char) ch;
+ tokenEnd++;
+ ch = read();
+ }
+ }
+ else
+ throw new CSSLexicalException("Invalid number");
+
+ // Check if we haven't accidentally finished with a dot.
+ if (parseBuffer[tokenEnd - 1] == '.')
+ throw new CSSLexicalException("Invalid number");
+
+ // Push back last character read.
+ lookahead[0] = ch;
+ }
+
+ /**
+ * For testing, we read in the default.css in javax/swing/text/html
+ *
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ String name = "/javax/swing/text/html/default.css";
+ InputStream in = CSSScanner.class.getResourceAsStream(name);
+ BufferedInputStream bin = new BufferedInputStream(in);
+ InputStreamReader r = new InputStreamReader(bin);
+ CSSScanner s = new CSSScanner(r);
+ int token;
+ do
+ {
+ token = s.nextToken();
+ System.out.println("token: " + token + ": "
+ + s.currentTokenString());
+ } while (token != -1);
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java
new file mode 100644
index 00000000000..2795b678401
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java
@@ -0,0 +1,273 @@
+/* FontSize.java -- Converts CSS font size values into real values
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+/**
+ * Converts CSS font-size values into real (point) values.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class FontSize
+{
+
+ /**
+ * The CSS value.
+ */
+ private String value;
+
+ /**
+ * The actual font size.
+ */
+ private int size;
+
+ /**
+ * The index of one of the standard sizes that this font size maps to.
+ * This is -1 if this fontsize doesn't map to one of the standard sizes.
+ *
+ * @see #SCALE
+ */
+ private int sizeIndex;
+
+ /**
+ * True when this font size is relative.
+ */
+ private boolean isRelative;
+
+ /**
+ * The default size for 'medium' absolute size. The other absolute sizes
+ * are calculated from this.
+ */
+ public static final int DEFAULT_FONT_SIZE = 12;
+
+ /**
+ * The scaling factors relative to the medium size. Medium is at index 2.
+ */
+ private static final double[] SCALE = {0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8 };
+
+ /**
+ * Creates a new FontSize for the specified value.
+ *
+ * @param val the value to convert
+ */
+ public FontSize(String val)
+ {
+ value = val;
+ sizeIndex = -1;
+ isRelative = false;
+ size = mapValue();
+ }
+
+ /**
+ * Returns the font size value.
+ *
+ * @return the font size value
+ */
+ public int getValue(int p)
+ {
+ if (isRelative)
+ mapRelative(p);
+ return size;
+ }
+
+ public int getValue()
+ {
+ assert ! isRelative;
+ return size;
+ }
+
+ /**
+ * Returns the converted real value in point.
+ *
+ * @return the converted real value in point
+ */
+ private int mapValue()
+ {
+ int intVal;
+ if (value.contains("pt"))
+ intVal = mapPoints();
+ else if (value.contains("px"))
+ intVal = mapPixels();
+ else if (value.contains("em") || value.contains("%")
+ || value.contains("larger") || value.contains("smaller"))
+ {
+ intVal = -1;
+ isRelative = true;
+ }
+ else
+ intVal = mapAbsolute();
+ return intVal;
+ }
+
+ /**
+ * Maps point values ('XXXpt').
+ *
+ * @return the real font size
+ */
+ private int mapPoints()
+ {
+ int end = value.indexOf("pt");
+ String number = value.substring(0, end);
+ int intVal = Integer.parseInt(number);
+ return intVal;
+ }
+
+ /**
+ * Maps pixel values ('XXXpx').
+ *
+ * @return the real font size
+ */
+ private int mapPixels()
+ {
+ int end = value.indexOf("px");
+ if (end == -1)
+ end = value.length();
+ String number = value.substring(0, end);
+ try
+ {
+ int intVal = Integer.parseInt(number);
+ return intVal;
+ }
+ catch (NumberFormatException ex)
+ {
+ return DEFAULT_FONT_SIZE;
+ }
+ }
+
+ private int mapPercent(int par)
+ {
+ int end = value.indexOf("%");
+ if (end == -1)
+ end = value.length();
+ String number = value.substring(0, end);
+ try
+ {
+ int intVal = Integer.parseInt(number);
+ return intVal * par / 100;
+ }
+ catch (NumberFormatException ex)
+ {
+ System.err.println("couldn't map value: '" + value + "'");
+ return DEFAULT_FONT_SIZE;
+ }
+ }
+
+ private int mapEM(int par)
+ {
+ int end = value.indexOf("em");
+ if (end == -1)
+ end = value.length();
+ String number = value.substring(0, end);
+ try
+ {
+ float factor = Float.parseFloat(number);
+ // FIXME: Should be relative to the parent element's size.
+ return (int) (factor * par);
+ }
+ catch (NumberFormatException ex)
+ {
+ return DEFAULT_FONT_SIZE;
+ }
+ }
+
+ private int mapSmaller(int par)
+ {
+ return (int) (par * 0.9);
+ }
+
+ private int mapLarger(int par)
+ {
+ return (int) (par * 0.9);
+ }
+
+ /**
+ * Maps absolute font-size values.
+ *
+ * @return the real value
+ */
+ private int mapAbsolute()
+ {
+ int index;
+ if (value.equals("xx-small") || value.equals("x-small"))
+ index = 0;
+ else if (value.equals("small"))
+ index = 1;
+ else if (value.equals("medium"))
+ index = 2;
+ else if (value.equals("large"))
+ index = 3;
+ else if (value.equals("x-large"))
+ index = 4;
+ else if (value.equals("xx-large"))
+ index = 5;
+ else
+ index = 2;
+ double scale = SCALE[index];
+ // FIXME: Scale the real medium size of the document, rather than the
+ // constant here.
+ int intVal = (int) (scale * DEFAULT_FONT_SIZE);
+ sizeIndex = index;
+ return intVal;
+ }
+
+ /**
+ * Returns the string representation.
+ */
+ public String toString()
+ {
+ return value;
+ }
+
+ private int mapRelative(int par)
+ {
+ if (value.indexOf('%') != -1)
+ size = mapPercent(par);
+ else if (value.indexOf("em") != -1)
+ size = mapEM(par);
+ else if (value.indexOf("larger") != -1)
+ size = mapLarger(par);
+ else if (value.indexOf("smaller") != -1)
+ size = mapSmaller(par);
+ return size;
+ }
+
+ public boolean isRelative()
+ {
+ return isRelative;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java
new file mode 100644
index 00000000000..e52893193cb
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java
@@ -0,0 +1,80 @@
+/* FontStyle.java -- Converts font-size CSS values
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.awt.Font;
+
+/**
+ * Converts font-size CSS values to a form to be used by {@link java.awt.Font}.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class FontStyle
+{
+
+ /**
+ * The real value.
+ */
+ private String value;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param val the CSS value
+ */
+ public FontStyle(String val)
+ {
+ value = val;
+ }
+
+ /**
+ * Returns the converted value.
+ *
+ * @return the converted value
+ */
+ public int getValue()
+ {
+ int intVal;
+ if (value.equals("italic") || value.equals("oblique"))
+ intVal = Font.ITALIC;
+ else
+ intVal = Font.PLAIN;
+ return intVal;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java
new file mode 100644
index 00000000000..d338c6f5514
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java
@@ -0,0 +1,84 @@
+/* FontWeight.java -- Converts font-weight values
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.awt.Font;
+
+/**
+ * Converts font-weight CSS values to the constants defined for
+ * {@link java.awt.Font}
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class FontWeight
+{
+
+ /**
+ * The value to convert.
+ */
+ private String value;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param val the value to convert
+ */
+ public FontWeight(String val)
+ {
+ value = val;
+ }
+
+ /**
+ * Returns the converted value.
+ *
+ * @return the converted value
+ */
+ public int getValue()
+ {
+ int intVal;
+ if (value.equals("normal"))
+ intVal = Font.PLAIN;
+ else if (value.equals("bold"))
+ intVal = Font.BOLD;
+ else
+ // FIXME: Implement finer-grained weights.
+ intVal = Font.PLAIN;
+ return intVal;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Length.java b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java
new file mode 100644
index 00000000000..06fa36e3d29
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java
@@ -0,0 +1,283 @@
+/* Length.java -- Converts CSS length values
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+/**
+ * Converts CSS length values to usable length values.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class Length
+{
+
+ /**
+ * The original value.
+ */
+ private String value;
+
+ /**
+ * The converted value.
+ */
+ protected float floatValue;
+
+ /**
+ * Indicates when the value is a percentage value.
+ */
+ private boolean isPercentage;
+
+ /**
+ * Indicates a length value that is relative to the font size (em).
+ */
+ private boolean isFontEMRelative;
+
+ /**
+ * Indicates a length value that is relative to the font size (ex).
+ */
+ private boolean isFontEXRelative;
+
+ /**
+ * The EM base size.
+ */
+ private float emBase;
+
+ /**
+ * The EX base size.
+ */
+ private float exBase;
+
+ /**
+ * Creates a new length converter instance.
+ *
+ * @param val the CSS value
+ */
+ public Length(String val)
+ {
+ isFontEMRelative = false;
+ isFontEXRelative = false;
+ isPercentage = false;
+ value = val;
+ int i = value.indexOf("px");
+ int percent = value.indexOf("%");
+ int em = value.indexOf("em");
+ int ex = value.indexOf("ex");
+ try
+ {
+ floatValue = 0.0F;
+ if (i != -1)
+ {
+ String sub = value.substring(0, i);
+ floatValue = Float.parseFloat(sub);
+ }
+ else if (percent != -1)
+ {
+ isPercentage = true;
+ String sub = value.substring(0, percent);
+ floatValue = Float.parseFloat(sub) / 100;
+ }
+ else if (em != -1)
+ {
+ isFontEMRelative = true;
+ String sub = value.substring(0, em);
+ floatValue = Float.parseFloat(sub);
+ }
+ else if (ex != -1)
+ {
+ isFontEXRelative = true;
+ String sub = value.substring(0, ex);
+ floatValue = Float.parseFloat(sub);
+ }
+ else
+ {
+ floatValue = Float.parseFloat(value);
+ }
+ }
+ catch (NumberFormatException exc)
+ {
+ // Don't let such small problems interrupt CSS parsing.
+ System.err.println("couldn't parse: " + val);
+ }
+ }
+
+ /**
+ * Returns the value converted to pixels.
+ *
+ * @return the value converted to pixels
+ */
+ public float getValue()
+ {
+ return floatValue;
+ }
+
+ /**
+ * Returns the absolute span for the case when this length value is
+ * a relative value.
+ *
+ * @param base the base span
+ *
+ * @return the absolute span
+ */
+ public float getValue(float base)
+ {
+ float span = floatValue;
+ if (isPercentage)
+ span *= base;
+ else if (isFontEMRelative)
+ span *= emBase;
+ else if (isFontEXRelative)
+ span *= exBase;
+ return span;
+ }
+
+ /**
+ * Sets the font relative EM base.
+ *
+ * @param base the font relative EM base
+ */
+ public void setEMBase(float base)
+ {
+ emBase = base;
+ }
+
+ /**
+ * Sets the font relative EX base.
+ *
+ * @param base the font relative EX base
+ */
+ public void setEXBase(float base)
+ {
+ exBase = base;
+ }
+
+ /**
+ * Sets the font relative base values.
+ *
+ * @param emBase the EM base
+ * @param exBase the EX base
+ */
+ public void setFontBases(float emBase, float exBase)
+ {
+ setEMBase(emBase);
+ setEXBase(exBase);
+ }
+
+ /**
+ * Returns true when this length value is an em font relative value. In
+ * order to get correct results, you need the exBase property set up
+ * correctly.
+ *
+ * @return true when this length value is an ex font relative value
+ */
+ public boolean isFontEMRelative()
+ {
+ return isFontEMRelative;
+ }
+
+ /**
+ * Returns true when this length value is an ex font relative value. In
+ * order to get correct results, you need the emBase property set up
+ * correctly.
+ *
+ * @return true when this length value is an ex font relative value
+ */
+ public boolean isFontEXRelative()
+ {
+ return isFontEXRelative;
+ }
+
+ /**
+ * Returns <code>true</code> when the length value is a percentage
+ * value, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> when the length value is a percentage
+ * value, <code>false</code> otherwise
+ */
+ public boolean isPercentage()
+ {
+ return isPercentage;
+ }
+
+ /**
+ * Checks if the specified value makes up a valid length value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> if the value is a valid length
+ */
+ public static boolean isValid(String value)
+ {
+ boolean isValid = true;
+ int px = value.indexOf("px");
+ int em = value.indexOf("em");
+ int ex = value.indexOf("ex");
+ int pc = value.indexOf('%');
+ try
+ {
+ if (px != -1)
+ {
+ Integer.parseInt(value.substring(0, px));
+ }
+ else if (em != -1)
+ {
+ Integer.parseInt(value.substring(0, em));
+ }
+ else if (ex != -1)
+ {
+ Integer.parseInt(value.substring(0, ex));
+ }
+ else if (pc != -1)
+ {
+ Integer.parseInt(value.substring(0, ex));
+ }
+ else
+ {
+ Integer.parseInt(value);
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ isValid = false;
+ }
+ return isValid;
+ }
+
+ public String toString()
+ {
+ return value;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java
new file mode 100644
index 00000000000..210df3a7b65
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java
@@ -0,0 +1,244 @@
+/* Selector.java -- A CSS selector
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.swing.text.html.css;
+
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * A CSS selector. This provides methods to interpret a selector and
+ * query matches with an actual HTML element tree.
+ */
+public class Selector
+{
+
+ /**
+ * The actual selector. The selector tokens are stored backwards, that
+ * is the last token first. This makes matching easier.
+ */
+ private String[] selector;
+
+ private String[] elements;
+ private String[] ids;
+ private String[] classes;
+
+ /**
+ * The specificity of the selector.
+ */
+ private int specificity;
+
+ /**
+ * An implicit selector has true here. This is the case for CSS rules that
+ * are attached to HTML elements directly via style="<CSS rule>".
+ */
+ private boolean implicit;
+
+ /**
+ * Creates a new Selector instance for the specified selector string.
+ *
+ * @param sel the selector
+ */
+ public Selector(String sel)
+ {
+ StringTokenizer selectorTokens = new StringTokenizer(sel, " ");
+ selector = new String[selectorTokens.countTokens()];
+ for (int i = selector.length - 1; selectorTokens.hasMoreTokens(); i--)
+ {
+ selector[i] = selectorTokens.nextToken();
+ }
+ calculateSpecificity();
+ }
+
+ /**
+ * Determines if this selector matches the element path specified in the
+ * arguments. The arguments hold the element names as well as class
+ * and id attibutes of the HTML element to be queried. The first item
+ * in the array is the deepest element and the last on the highest up (for
+ * instance, the html tag).
+ *
+ * @param tags
+ * @param classes
+ * @param ids
+ *
+ * @return <code>true</code> when this selector matches the element path,
+ * <code>false</code> otherwise
+ */
+ public boolean matches(String[] tags, Map[] attributes)
+ {
+ // TODO: This implements class, id and descendent matching. These are
+ // the most commonly used selector matchers in CSS together with HTML.
+ // However, the CSS spec defines a couple of more sophisticated matches
+ // which should be implemented.
+ // http://www.w3.org/TR/CSS21/selector.html
+
+ // All parts of the selector must match at some point.
+ boolean match = false;
+ int numTags = tags.length;
+ int numSel = selector.length;
+ if (numSel <= numTags)
+ {
+ match = true;
+ int tagIndex = 0;
+ for (int j = 0; j < numSel && match; j++)
+ {
+ boolean tagMatch = false;
+ for (; tagIndex < numTags && tagMatch == false; tagIndex++)
+ {
+ Object pathClass = attributes[tagIndex].get("class");
+ // Try pseudo class too.
+ Object pseudoClass = attributes[tagIndex].get("_pseudo");
+ Object dynClass = attributes[tagIndex].get("_dynamic");
+ Object pathId = attributes[tagIndex].get("id");
+ String tag = elements[j];
+ String clazz = classes[j];
+ String id = ids[j];
+ tagMatch = tag.equals("") || tag.equals("*")
+ || tag.equals(tags[tagIndex]);
+ tagMatch = tagMatch && (clazz.equals("*")
+ || clazz.equals(dynClass)
+ || clazz.equals(pseudoClass)
+ || clazz.equals(pathClass));
+ tagMatch = tagMatch && (id.equals("*")
+ || id.equals(pathId));
+ // For the last element in the selector we must not look
+ // further.
+ if (j == 0)
+ break;
+ }
+ // If we don't come out here with a matching tag, then we're
+ // not matching at all.
+ match = tagMatch;
+ }
+ }
+ return match;
+ }
+
+ /**
+ * Returns the specificity of the selector. This is calculated according
+ * to:
+ * http://www.w3.org/TR/CSS21/cascade.html#specificity
+ *
+ * @return the specificity of the selector
+ */
+ public int getSpecificity()
+ {
+ return specificity;
+ }
+
+ /**
+ * Returns a string representation of the selector. This tries to reconstruct
+ * the original selector as closely as possible.
+ *
+ * @return a string representation of the selector
+ */
+ public String toString()
+ {
+ StringBuilder b = new StringBuilder();
+ for (int i = selector.length - 1; i >= 0; i--)
+ {
+ b.append(selector[i]);
+ if (i > 0)
+ b.append(' ');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Calculates the specificity of the selector. This is calculated according
+ * to:
+ * http://www.w3.org/TR/CSS21/cascade.html#specificity
+ */
+ private void calculateSpecificity()
+ {
+ int a = implicit ? 1 : 0;
+ int b = 0;
+ int c = 0;
+ int d = 0;
+ int numSel = selector.length;
+ elements = new String[numSel];
+ ids = new String[numSel];
+ classes = new String[numSel];
+ for (int i = 0; i < numSel; i++)
+ {
+ String sel = selector[i];
+ int clazzIndex = sel.indexOf('.');
+ // Try pseudo class too.
+ if (clazzIndex == -1)
+ clazzIndex = sel.indexOf(':');
+ int idIndex = sel.indexOf('#');
+ String clazz;
+ if (clazzIndex == -1)
+ {
+ clazz = "*";
+ clazzIndex = sel.length();
+ }
+ else
+ {
+ c++;
+ clazz = sel.substring(clazzIndex + 1,
+ idIndex > 0 ? Math.min(idIndex, sel.length())
+ : sel.length());
+ }
+ String id;
+ if (idIndex == -1)
+ {
+ id = "*";
+ idIndex = sel.length();
+ }
+ else
+ {
+ b++;
+ id = sel.substring(idIndex + 1,
+ clazzIndex > 0 ? Math.min(clazzIndex, sel.length())
+ : sel.length());
+ }
+ String tag = sel.substring(0,
+ Math.min(Math.min(clazzIndex, idIndex),
+ sel.length()));
+ if (! tag.equals("") && ! tag.equals("*"))
+ d++;
+
+ elements[i] = tag;
+ ids[i] = id;
+ classes[i] = clazz;
+ }
+ // An order of 20 should be enough for everybody.
+ specificity = a * 20 ^ 3 + b * 20 ^ 2 + c * 20 + d;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java
index 841db667e84..273461a721e 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java
@@ -43,6 +43,7 @@ import java.io.Reader;
import java.io.Serializable;
import javax.swing.text.BadLocationException;
+import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.swing.text.html.parser.DTD;
@@ -92,7 +93,7 @@ public class GnuParserDelegator extends ParserDelegator implements Serializable
protected final void handleStartTag(TagElement tag)
{
- htmlAttributeSet attributes = gnu.getAttributes();
+ SimpleAttributeSet attributes = gnu.getAttributes();
if (tag.fictional())
attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE);
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java
index c3c347e36e3..1894b6a1ac6 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java
@@ -2445,8 +2445,10 @@ public class HTML_401F
attr(VALUE, null, null, 0, IMPLIED)
}
);
+
+ // Headers in the paragraph are not allowed.
defElement(P, 0, false, true, new ContentModel( 0,
- new noTagModel(P), null),
+ new noTagModel(new String[] { P, H1, H2, H3, H4, H5, H6 }), null),
NONE
,
new String[] {
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java
index 4d287a67763..7507850e8f9 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java
@@ -153,7 +153,7 @@ public abstract class htmlValidator
* Remove the given tag from the stack or (if found) from the list
* of the forcibly closed tags.
*/
- public void closeTag(TagElement tElement)
+ public boolean closeTag(TagElement tElement)
{
HTML.Tag tag = tElement.getHTMLTag();
hTag x;
@@ -191,11 +191,12 @@ public abstract class htmlValidator
}
stack.remove(x);
- return;
+ return true;
}
}
}
s_error("Closing unopened <" + tag + ">");
+ return false;
}
/**
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java
index 92f9b27c5d9..3a407310e74 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java
@@ -56,6 +56,7 @@ import java.util.TreeSet;
import java.util.Vector;
import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.parser.AttributeList;
import javax.swing.text.html.parser.DTD;
@@ -250,9 +251,9 @@ public class Parser
* Get the attributes of the current tag.
* @return The attribute set, representing the attributes of the current tag.
*/
- public htmlAttributeSet getAttributes()
+ public SimpleAttributeSet getAttributes()
{
- return attributes;
+ return new SimpleAttributeSet(attributes);
}
/**
@@ -497,6 +498,9 @@ public class Parser
mustBe(t.kind);
}
hTag = new Token(start, last);
+
+ // Consume any whitespace immediately following a comment.
+ optional(WS);
handleComment();
}
@@ -579,6 +583,8 @@ public class Parser
);
}
}
+ // Consume any whitespace that follows the Sgml insertion.
+ optional(WS);
}
/**
@@ -658,7 +664,10 @@ public class Parser
else
text = textProcessor.preprocess(buffer);
- if (text != null && text.length > 0)
+ if (text != null && text.length > 0
+ // According to the specs we need to discard whitespace immediately
+ // before a closing tag.
+ && (text.length > 1 || text[0] != ' ' || ! TAG_CLOSE.matches(this)))
{
TagElement pcdata = new TagElement(dtd.getElement("#pcdata"));
attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET;
@@ -889,6 +898,8 @@ public class Parser
protected void parseDocument()
throws ParseException
{
+ // Read up any initial whitespace.
+ optional(WS);
while (getTokenAhead().kind != EOF)
{
advanced = false;
@@ -979,13 +990,15 @@ public class Parser
+ next.getImage() + "'");
attrValue = value.getImage();
}
- else if (next.kind == SLASH)
- // The slash in this context is treated as the ordinary
- // character, not as a token. The slash may be part of
+ else if (next.kind == SLASH || next.kind == OTHER)
+ // The slash and other characters (like %) in this context is
+ // treated as the ordinary
+ // character, not as a token. The character may be part of
// the unquoted URL.
{
StringBuffer image = new StringBuffer(value.getImage());
- while (next.kind == NUMTOKEN || next.kind == SLASH)
+ while (next.kind == NUMTOKEN || next.kind == SLASH
+ || next.kind == OTHER)
{
image.append(getNextToken().getImage());
next = getTokenAhead();
@@ -1177,6 +1190,13 @@ public class Parser
{
validator.validateTag(tag, attributes);
handleEmptyTag(tag);
+ HTML.Tag h = tag.getHTMLTag();
+ // When a block tag is closed, consume whitespace that follows after
+ // it.
+ // For some unknown reason a FRAME tag is not treated as block element.
+ // However in this case it should be treated as such.
+ if (isBlock(h))
+ optional(WS);
}
catch (ChangedCharSetException ex)
{
@@ -1192,8 +1212,8 @@ public class Parser
*/
private void _handleEndTag(TagElement tag)
{
- validator.closeTag(tag);
- _handleEndTag_remaining(tag);
+ if (validator.closeTag(tag))
+ _handleEndTag_remaining(tag);
}
/**
@@ -1213,6 +1233,11 @@ public class Parser
if (preformatted < 0)
preformatted = 0;
+ // When a block tag is closed, consume whitespace that follows after
+ // it.
+ if (isBlock(h))
+ optional(WS);
+
if (h == HTML.Tag.TITLE)
{
titleOpen = false;
@@ -1239,6 +1264,9 @@ public class Parser
HTML.Tag h = tag.getHTMLTag();
+ if (isBlock(h))
+ optional(WS);
+
if (h.isPreformatted())
preformatted++;
@@ -1418,8 +1446,6 @@ public class Parser
hTag = new Token(start, next);
- attributes.setResolveParent(defaulter.getDefaultParameters(name.getImage()));
-
if (!end)
{
// The tag body contains errors. If additionally the tag
@@ -1457,7 +1483,12 @@ public class Parser
if (te.getElement().type == DTDConstants.EMPTY)
_handleEmptyTag(te);
else
- _handleStartTag(te);
+ {
+ // According to the specs we need to consume whitespace following
+ // immediately after a opening tag.
+ optional(WS);
+ _handleStartTag(te);
+ }
}
}
@@ -1483,4 +1514,19 @@ public class Parser
{
error("Whitespace here is not permitted");
}
+
+ /**
+ * Returns true when the specified tag should be considered a block tag
+ * wrt whitespace handling. We need this special handling, since there
+ * are a couple of tags that we must treat as block tags but which aren't
+ * officially block tags.
+ *
+ * @param tag the tag to check
+ * @return true when the specified tag should be considered a block tag
+ * wrt whitespace handling
+ */
+ private boolean isBlock(HTML.Tag tag)
+ {
+ return tag.isBlock() || tag == HTML.Tag.STYLE || tag == HTML.Tag.FRAME;
+ }
}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java
index 283d32385ef..5416582adca 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java
@@ -209,6 +209,17 @@ public class Constants
}
);
+ /**
+ * Ordinary HTML tag closing pattern.
+ */
+ public static final pattern TAG_CLOSE =
+ new pattern(new node[]
+ {
+ new node(BEGIN), new node(WS, true), new node(SLASH),
+ new node(WS, true), new node(NUMTOKEN)
+ }
+ );
+
/* Special tokens */
/**
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java
index cc1610585a6..6fd79e2589e 100644
--- a/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java
@@ -42,17 +42,17 @@ import gnu.javax.swing.text.html.parser.support.low.Constants;
/**
* Pre - processes text in text parts of the html document.
- * Not thread - safe.
+ *
* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
*/
public class textPreProcessor
{
/**
- * Pre - process non-preformatted text.
- * \t, \r and \n mutate into spaces, then multiple spaces mutate
- * into single one, all whitespace around tags is consumed.
- * The content of the passed buffer is destroyed.
- * @param text A text to pre-process.
+ * Pre - process non-preformatted text. \t, \r and \n mutate into spaces, then
+ * multiple spaces mutate into single one, all whitespace around tags is
+ * consumed. The content of the passed buffer is destroyed.
+ *
+ * @param a_text A text to pre-process.
*/
public char[] preprocess(StringBuffer a_text)
{
@@ -64,18 +64,15 @@ public class textPreProcessor
int a = 0;
int b = text.length - 1;
- try
- {
- while (Constants.bWHITESPACE.get(text [ a ]))
- a++;
- while (Constants.bWHITESPACE.get(text [ b ]))
- b--;
- }
- catch (ArrayIndexOutOfBoundsException sx)
- {
- // A text fragment, consisting from line breaks only.
- return null;
- }
+ // Remove leading/trailing whitespace, leaving at most one character
+ int len = text.length;
+ while (a + 1 < len && Constants.bWHITESPACE.get(text[a])
+ && Constants.bWHITESPACE.get(text[a + 1]))
+ a++;
+
+ while (b > a && Constants.bWHITESPACE.get(text[b])
+ && Constants.bWHITESPACE.get(text[b - 1]))
+ b--;
a_text.setLength(0);
@@ -83,10 +80,9 @@ public class textPreProcessor
boolean spaceNow;
char c;
- chars:
- for (int i = a; i <= b; i++)
+ chars: for (int i = a; i <= b; i++)
{
- c = text [ i ];
+ c = text[i];
spaceNow = Constants.bWHITESPACE.get(c);
if (spacesWere && spaceNow)
continue chars;
diff --git a/libjava/classpath/gnu/test/.cvsignore b/libjava/classpath/gnu/test/.cvsignore
new file mode 100644
index 00000000000..70845e08eb0
--- /dev/null
+++ b/libjava/classpath/gnu/test/.cvsignore
@@ -0,0 +1 @@
+Makefile.in
diff --git a/libjava/classpath/gnu/xml/dom/DomAttr.java b/libjava/classpath/gnu/xml/dom/DomAttr.java
index 8673a796161..31d7af2d2f1 100644
--- a/libjava/classpath/gnu/xml/dom/DomAttr.java
+++ b/libjava/classpath/gnu/xml/dom/DomAttr.java
@@ -316,7 +316,7 @@ public class DomAttr
private void mutating(String oldValue, String newValue, short why)
{
- if (!reportMutations || parent == null)
+ if (!reportMutations || parent == null || equal(newValue, oldValue))
{
return;
}
diff --git a/libjava/classpath/gnu/xml/dom/DomNode.java b/libjava/classpath/gnu/xml/dom/DomNode.java
index f0915eb5e93..9af3f3e5498 100644
--- a/libjava/classpath/gnu/xml/dom/DomNode.java
+++ b/libjava/classpath/gnu/xml/dom/DomNode.java
@@ -668,6 +668,7 @@ public abstract class DomNode
{
insertionEvent(null, child);
}
+ length++;
}
return child;
@@ -1561,7 +1562,7 @@ public abstract class DomNode
// Climb to the top of this subtree and handle capture, letting
// each node (from the top down) capture until one stops it or
// until we get to this one.
- current = parent;
+ current = (parent == null) ? this : parent;
if (current.depth >= ANCESTORS_INIT)
{
DomNode[] newants = new DomNode[current.depth + 1];
diff --git a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
index aad5ac76e70..8c5b104b9f2 100644
--- a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
+++ b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
@@ -43,6 +43,7 @@ import java.util.LinkedList;
import java.util.List;
import javax.xml.XMLConstants;
import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Entity;
@@ -72,7 +73,7 @@ import gnu.xml.dom.DomNode;
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
-class SAXEventSink
+public class SAXEventSink
implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler
{
@@ -110,6 +111,11 @@ class SAXEventSink
interrupted = true;
}
+ protected Document getDocument()
+ {
+ return doc;
+ }
+
// -- ContentHandler2 --
public void setDocumentLocator(Locator locator)
diff --git a/libjava/classpath/gnu/xml/stream/SAXParser.java b/libjava/classpath/gnu/xml/stream/SAXParser.java
index e58d5fb52ff..1329ab2971c 100644
--- a/libjava/classpath/gnu/xml/stream/SAXParser.java
+++ b/libjava/classpath/gnu/xml/stream/SAXParser.java
@@ -1021,9 +1021,18 @@ public class SAXParser
SAXParser parser = new SAXParser(validating, namespaceAware,
xIncludeAware);
InputSource input = new InputSource(args[pos]);
- XMLReader reader = parser.getXMLReader();
- reader.setContentHandler(handler);
- reader.parse(input);
+ java.io.FileReader fr = new java.io.FileReader(args[pos]);
+ input.setCharacterStream(fr);
+ try
+ {
+ XMLReader reader = parser.getXMLReader();
+ reader.setContentHandler(handler);
+ reader.parse(input);
+ }
+ finally
+ {
+ fr.close();
+ }
pos++;
}
}
diff --git a/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java
index 291016e6716..4be9992a73d 100644
--- a/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java
+++ b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java
@@ -664,12 +664,10 @@ public class XMLStreamWriterImpl
public void writeDTD(String dtd)
throws XMLStreamException
{
- // Really thoroughly pointless method...
try
{
- if (!isName(dtd))
- throw new IllegalArgumentException("illegal Name: " + dtd);
-
+ // XXX: Should we parse the doctypedecl at this point to ensure
+ // wellformedness?
writer.write("<!DOCTYPE ");
writer.write(dtd);
writer.write('>');
diff --git a/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java b/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java
new file mode 100644
index 00000000000..2c5a4686f10
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java
@@ -0,0 +1,97 @@
+/* SAXTemplatesHandler.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.transform;
+
+import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.TemplatesHandler;
+import org.w3c.dom.Document;
+import gnu.xml.dom.ls.SAXEventSink;
+
+/**
+ * A content handler that acts as a sink for SAX parse events,
+ * constructing an XSL stylesheet.
+ * Internally, this class simply creates a DOM tree from the events,
+ * and then parses the DOM into a Templates object.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class SAXTemplatesHandler
+ extends SAXEventSink
+ implements TemplatesHandler
+{
+
+ final TransformerFactoryImpl factory;
+ String systemId;
+
+ SAXTemplatesHandler(TransformerFactoryImpl factory)
+ {
+ this.factory = factory;
+ }
+
+ public String getSystemId()
+ {
+ return systemId;
+ }
+
+ public void setSystemId(String systemId)
+ {
+ this.systemId = systemId;
+ }
+
+ public Templates getTemplates()
+ {
+ Document doc = getDocument();
+ if (doc == null)
+ throw new IllegalStateException("Parsing of stylesheet incomplete");
+ DOMSource ds = new DOMSource(doc, systemId);
+ try
+ {
+ return factory.newTemplates(ds);
+ }
+ catch (TransformerConfigurationException e)
+ {
+ String msg = "Unable to construct templates from this event stream";
+ IllegalStateException e2 = new IllegalStateException(msg);
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java b/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java
new file mode 100644
index 00000000000..83cc3754be9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java
@@ -0,0 +1,111 @@
+/* SAXTransformerHandler.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.transform;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.TransformerHandler;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+import gnu.xml.dom.ls.SAXEventSink;
+
+/**
+ * A SAX event sink that processes an XML source represented as a stream of
+ * SAX events into a result tree.
+ * This works by simply buffering all the events into a DOM tree and then
+ * using this DOM tree as the source of the transformation.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class SAXTransformerHandler
+ extends SAXEventSink
+ implements TransformerHandler
+{
+
+ final TransformerFactoryImpl factory;
+ final Transformer transformer;
+ String systemId;
+ Result result;
+
+ SAXTransformerHandler(TransformerFactoryImpl factory, Transformer transformer)
+ {
+ this.factory = factory;
+ this.transformer = transformer;
+ }
+
+ public String getSystemId()
+ {
+ return systemId;
+ }
+
+ public void setSystemId(String systemId)
+ {
+ this.systemId = systemId;
+ }
+
+ public Transformer getTransformer()
+ {
+ return transformer;
+ }
+
+ public void setResult(Result result)
+ {
+ this.result = result;
+ }
+
+ public void endDocument()
+ throws SAXException
+ {
+ super.endDocument();
+ try
+ {
+ Document doc = getDocument();
+ DOMSource ds = new DOMSource(doc, systemId);
+ transformer.transform(ds, result);
+ }
+ catch (TransformerException e)
+ {
+ SAXException e2 = new SAXException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/StreamSerializer.java b/libjava/classpath/gnu/xml/transform/StreamSerializer.java
index fb8b1a601bc..26bdda8b325 100644
--- a/libjava/classpath/gnu/xml/transform/StreamSerializer.java
+++ b/libjava/classpath/gnu/xml/transform/StreamSerializer.java
@@ -324,7 +324,8 @@ public class StreamSerializer
break;
case Node.TEXT_NODE:
value = node.getNodeValue();
- if (!"yes".equals(node.getUserData("disable-output-escaping")))
+ if (!"yes".equals(node.getUserData("disable-output-escaping")) &&
+ mode != Stylesheet.OUTPUT_TEXT)
value = encode(value, false, false);
out.write(encodeText(value));
break;
diff --git a/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
index 16e3363f8c6..1e8fea3e3a6 100644
--- a/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
+++ b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
@@ -60,11 +60,15 @@ import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TemplatesHandler;
+import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
+import org.xml.sax.XMLFilter;
import gnu.xml.dom.DomDocument;
/**
@@ -73,7 +77,7 @@ import gnu.xml.dom.DomDocument;
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
public class TransformerFactoryImpl
- extends TransformerFactory
+ extends SAXTransformerFactory
{
final XPathFactory xpathFactory;
@@ -316,7 +320,8 @@ public class TransformerFactoryImpl
StreamSource.FEATURE.equals(name) ||
StreamResult.FEATURE.equals(name) ||
DOMSource.FEATURE.equals(name) ||
- DOMResult.FEATURE.equals(name))
+ DOMResult.FEATURE.equals(name) ||
+ SAXTransformerFactory.FEATURE.equals(name))
{
return true;
}
@@ -346,6 +351,49 @@ public class TransformerFactoryImpl
return userListener;
}
+ // -- SAXTransformerFactory --
+
+ public TemplatesHandler newTemplatesHandler()
+ throws TransformerConfigurationException
+ {
+ return new SAXTemplatesHandler(this);
+ }
+
+ public TransformerHandler newTransformerHandler()
+ throws TransformerConfigurationException
+ {
+ Transformer transformer = newTransformer();
+ return new SAXTransformerHandler(this, transformer);
+ }
+
+ public TransformerHandler newTransformerHandler(Source source)
+ throws TransformerConfigurationException
+ {
+ Transformer transformer = newTransformer(source);
+ return new SAXTransformerHandler(this, transformer);
+ }
+
+ public TransformerHandler newTransformerHandler(Templates templates)
+ throws TransformerConfigurationException
+ {
+ Transformer transformer = templates.newTransformer();
+ return new SAXTransformerHandler(this, transformer);
+ }
+
+ public XMLFilter newXMLFilter(Source source)
+ throws TransformerConfigurationException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public XMLFilter newXMLFilter(Templates templates)
+ throws TransformerConfigurationException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ // -- SAXTransformerFactory end --
+
/**
* Syntax: TransformerFactoryImpl [<stylesheet> [<input> [<output>]]]
*/
diff --git a/libjava/classpath/gnu/xml/transform/XSLURIResolver.java b/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
index 6a49caab458..8d7e3fcb485 100644
--- a/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
+++ b/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
@@ -53,6 +53,7 @@ import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
@@ -118,10 +119,9 @@ class XSLURIResolver
try
{
- URL url = resolveURL(systemId, base, href);
Node node = null;
InputStream in = null;
- if (source instanceof StreamSource)
+ if (source != null && source instanceof StreamSource)
{
StreamSource ss = (StreamSource) source;
in = ss.getInputStream();
@@ -134,8 +134,25 @@ class XSLURIResolver
}
}
}
+ else if (source != null && source instanceof SAXSource)
+ {
+ SAXSource ss = (SAXSource) source;
+ if (ss.getInputSource() != null)
+ {
+ in = ss.getInputSource().getByteStream();
+ if (in == null)
+ {
+ Reader reader = ss.getInputSource().getCharacterStream();
+ if (reader != null)
+ {
+ in = new ReaderInputStream(reader);
+ }
+ }
+ }
+ }
if (in == null)
{
+ URL url = resolveURL(systemId, base, href);
if (url != null)
{
systemId = url.toString();
diff --git a/libjava/classpath/gnu/xml/xpath/Expr.java b/libjava/classpath/gnu/xml/xpath/Expr.java
index 76fd49eeff5..cafc83b0d37 100644
--- a/libjava/classpath/gnu/xml/xpath/Expr.java
+++ b/libjava/classpath/gnu/xml/xpath/Expr.java
@@ -59,6 +59,7 @@ import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -80,6 +81,38 @@ public abstract class Expr
".####################################################",
new DecimalFormatSymbols(Locale.US));
+ static class ExprNodeSet implements NodeList
+ {
+
+ private ArrayList list;
+
+ ExprNodeSet(Collection collection)
+ {
+ if (collection instanceof ArrayList)
+ list = (ArrayList) collection;
+ else
+ list = new ArrayList(collection);
+ }
+
+ public int getLength()
+ {
+ return list.size();
+ }
+
+ public Node item(int index)
+ {
+ try
+ {
+ return (Node) list.get(index);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ return null;
+ }
+ }
+
+ }
+
public Object evaluate(Object item, QName returnType)
throws XPathExpressionException
{
@@ -132,6 +165,8 @@ public abstract class Expr
{
throw new XPathExpressionException("return value is not a node-set");
}
+ if (ret != null)
+ ret = new ExprNodeSet((Collection) ret);
}
}
return ret;
OpenPOWER on IntegriCloud