OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [javax/] [net/] [ssl/] [provider/] [SSLSocketImpl.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* SSLSocketImpl.java -- implementation of an SSL client socket.
2
   Copyright (C) 2006  Free Software Foundation, Inc.
3
 
4
This file is a part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or (at
9
your option) any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19
USA
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package gnu.javax.net.ssl.provider;
40
 
41
import gnu.classpath.debug.Component;
42
import gnu.classpath.debug.SystemLogger;
43
 
44
import java.io.DataInputStream;
45
import java.io.EOFException;
46
import java.io.IOException;
47
import java.io.InputStream;
48
import java.io.OutputStream;
49
import java.net.InetAddress;
50
import java.net.Socket;
51
import java.net.SocketAddress;
52
import java.net.SocketException;
53
import java.nio.ByteBuffer;
54
import java.nio.channels.SocketChannel;
55
import java.util.HashSet;
56
import java.util.Set;
57
 
58
import javax.net.ssl.HandshakeCompletedEvent;
59
import javax.net.ssl.HandshakeCompletedListener;
60
import javax.net.ssl.SSLEngineResult;
61
import javax.net.ssl.SSLException;
62
import javax.net.ssl.SSLSession;
63
import javax.net.ssl.SSLSocket;
64
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
65
import javax.net.ssl.SSLEngineResult.Status;
66
 
67
/**
68
 * @author Casey Marshall (csm@gnu.org)
69
 */
70
public class SSLSocketImpl extends SSLSocket
71
{
72
  private class SocketOutputStream extends OutputStream
73
  {
74
    private final ByteBuffer buffer;
75
    private final OutputStream out;
76
 
77
    SocketOutputStream() throws IOException
78
    {
79
      buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
80
      if (underlyingSocket != null)
81
        out = underlyingSocket.getOutputStream();
82
      else
83
        out = SSLSocketImpl.super.getOutputStream();
84
    }
85
 
86
    @Override public void write(byte[] buf, int off, int len) throws IOException
87
    {
88
      if (!initialHandshakeDone
89
          || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
90
        {
91
          doHandshake();
92
          if (handshakeException != null)
93
            throw handshakeException;
94
        }
95
 
96
      int k = 0;
97
      while (k < len)
98
        {
99
          synchronized (engine)
100
            {
101
              int l = Math.min(len-k, getSession().getApplicationBufferSize());
102
              ByteBuffer in = ByteBuffer.wrap(buf, off+k, l);
103
              SSLEngineResult result = engine.wrap(in, buffer);
104
              if (result.getStatus() == Status.CLOSED)
105
                return;
106
              if (result.getStatus() != Status.OK)
107
                throw new SSLException("unexpected SSL state " + result.getStatus());
108
              buffer.flip();
109
              out.write(buffer.array(), 0, buffer.limit());
110
              k += result.bytesConsumed();
111
              buffer.clear();
112
            }
113
        }
114
    }
115
 
116
    @Override public void write(int b) throws IOException
117
    {
118
      write(new byte[] { (byte) b });
119
    }
120
 
121
    @Override public void close() throws IOException
122
    {
123
      SSLSocketImpl.this.close();
124
    }
125
  }
126
 
127
  private class SocketInputStream extends InputStream
128
  {
129
    private final ByteBuffer inBuffer;
130
    private final ByteBuffer appBuffer;
131
    private final DataInputStream in;
132
 
133
    SocketInputStream() throws IOException
134
    {
135
      inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
136
      inBuffer.limit(0);
137
      appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize());
138
      appBuffer.flip();
139
      if (underlyingSocket != null)
140
        in = new DataInputStream(underlyingSocket.getInputStream());
141
      else
142
        in = new DataInputStream(SSLSocketImpl.super.getInputStream());
143
    }
144
 
145
    @Override public int read(byte[] buf, int off, int len) throws IOException
146
    {
147
      if (!initialHandshakeDone ||
148
          engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
149
        {
150
          doHandshake();
151
          if (handshakeException != null)
152
            throw handshakeException;
153
        }
154
 
155
      if (!appBuffer.hasRemaining())
156
        {
157
          int x = in.read();
158
          if (x == -1)
159
            return -1;
160
          inBuffer.clear();
161
          inBuffer.put((byte) x);
162
          inBuffer.putInt(in.readInt());
163
          int reclen = inBuffer.getShort(3) & 0xFFFF;
164
          in.readFully(inBuffer.array(), 5, reclen);
165
          inBuffer.position(0).limit(reclen + 5);
166
          synchronized (engine)
167
            {
168
              appBuffer.clear();
169
              SSLEngineResult result = engine.unwrap(inBuffer, appBuffer);
170
              Status status = result.getStatus();
171
              if (status == Status.CLOSED && result.bytesProduced() == 0)
172
                return -1;
173
            }
174
          inBuffer.compact();
175
          appBuffer.flip();
176
        }
177
      int l = Math.min(len, appBuffer.remaining());
178
      appBuffer.get(buf, off, l);
179
      return l;
180
    }
181
 
182
    @Override public int read() throws IOException
183
    {
184
      byte[] b = new byte[1];
185
      if (read(b) == -1)
186
        return -1;
187
      return b[0] & 0xFF;
188
    }
189
  }
190
 
191
  private static final SystemLogger logger = SystemLogger.getSystemLogger();
192
 
193
  private SSLEngineImpl engine;
194
  private Set<HandshakeCompletedListener> listeners;
195
  private Socket underlyingSocket;
196
  private boolean isHandshaking;
197
  private IOException handshakeException;
198
  private boolean initialHandshakeDone = false;
199
  private final boolean autoClose;
200
 
201
  public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port)
202
  {
203
    this(contextImpl, host, port, new Socket(), true);
204
  }
205
 
206
  public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port,
207
                       Socket underlyingSocket, boolean autoClose)
208
  {
209
    engine = new SSLEngineImpl(contextImpl, host, port);
210
    engine.setUseClientMode(true); // default to client mode
211
    listeners = new HashSet<HandshakeCompletedListener>();
212
    this.underlyingSocket = underlyingSocket;
213
    this.autoClose = autoClose;
214
  }
215
 
216
  /* (non-Javadoc)
217
   * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
218
   */
219
  @Override
220
  public void addHandshakeCompletedListener(HandshakeCompletedListener listener)
221
  {
222
    listeners.add(listener);
223
  }
224
 
225
  /* (non-Javadoc)
226
   * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
227
   */
228
  @Override public boolean getEnableSessionCreation()
229
  {
230
    return engine.getEnableSessionCreation();
231
  }
232
 
233
  /* (non-Javadoc)
234
   * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
235
   */
236
  @Override public String[] getEnabledCipherSuites()
237
  {
238
    return engine.getEnabledCipherSuites();
239
  }
240
 
241
  /* (non-Javadoc)
242
   * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
243
   */
244
  @Override public String[] getEnabledProtocols()
245
  {
246
    return engine.getEnabledProtocols();
247
  }
248
 
249
  /* (non-Javadoc)
250
   * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
251
   */
252
  @Override public boolean getNeedClientAuth()
253
  {
254
    return engine.getNeedClientAuth();
255
  }
256
 
257
  /* (non-Javadoc)
258
   * @see javax.net.ssl.SSLSocket#getSession()
259
   */
260
  @Override public SSLSession getSession()
261
  {
262
    return engine.getSession();
263
  }
264
 
265
  /* (non-Javadoc)
266
   * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
267
   */
268
  @Override public String[] getSupportedCipherSuites()
269
  {
270
    return engine.getSupportedCipherSuites();
271
  }
272
 
273
  /* (non-Javadoc)
274
   * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
275
   */
276
  @Override public String[] getSupportedProtocols()
277
  {
278
    return engine.getSupportedProtocols();
279
  }
280
 
281
  /* (non-Javadoc)
282
   * @see javax.net.ssl.SSLSocket#getUseClientMode()
283
   */
284
  @Override public boolean getUseClientMode()
285
  {
286
    return engine.getUseClientMode();
287
  }
288
 
289
  /* (non-Javadoc)
290
   * @see javax.net.ssl.SSLSocket#getWantClientAuth()
291
   */
292
  @Override public boolean getWantClientAuth()
293
  {
294
    return engine.getWantClientAuth();
295
  }
296
 
297
  /* (non-Javadoc)
298
   * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
299
   */
300
  @Override
301
  public void removeHandshakeCompletedListener(HandshakeCompletedListener listener)
302
  {
303
    listeners.remove(listener);
304
  }
305
 
306
  /* (non-Javadoc)
307
   * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
308
   */
309
  @Override public void setEnableSessionCreation(boolean enable)
310
  {
311
    engine.setEnableSessionCreation(enable);
312
  }
313
 
314
  /* (non-Javadoc)
315
   * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[])
316
   */
317
  @Override public void setEnabledCipherSuites(String[] suites)
318
  {
319
    engine.setEnabledCipherSuites(suites);
320
  }
321
 
322
  /* (non-Javadoc)
323
   * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[])
324
   */
325
  @Override public void setEnabledProtocols(String[] protocols)
326
  {
327
    engine.setEnabledProtocols(protocols);
328
  }
329
 
330
  /* (non-Javadoc)
331
   * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
332
   */
333
  @Override public void setNeedClientAuth(boolean needAuth)
334
  {
335
    engine.setNeedClientAuth(needAuth);
336
  }
337
 
338
  /* (non-Javadoc)
339
   * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
340
   */
341
  @Override public void setUseClientMode(boolean clientMode)
342
  {
343
    engine.setUseClientMode(clientMode);
344
  }
345
 
346
  /* (non-Javadoc)
347
   * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
348
   */
349
  @Override public void setWantClientAuth(boolean wantAuth)
350
  {
351
    engine.setWantClientAuth(wantAuth);
352
  }
353
 
354
  /* (non-Javadoc)
355
   * @see javax.net.ssl.SSLSocket#startHandshake()
356
   */
357
  @Override public void startHandshake() throws IOException
358
  {
359
    if (isHandshaking)
360
      return;
361
 
362
    if (handshakeException != null)
363
      throw handshakeException;
364
 
365
    Thread t = new Thread(new Runnable()
366
    {
367
      public void run()
368
      {
369
        try
370
          {
371
            doHandshake();
372
          }
373
        catch (IOException ioe)
374
          {
375
            handshakeException = ioe;
376
          }
377
      }
378
    }, "HandshakeThread@" + System.identityHashCode(this));
379
    t.start();
380
  }
381
 
382
  void doHandshake() throws IOException
383
  {
384
    synchronized (engine)
385
      {
386
        if (isHandshaking)
387
          {
388
            try
389
              {
390
                engine.wait();
391
              }
392
            catch (InterruptedException ie)
393
              {
394
              }
395
            return;
396
          }
397
        isHandshaking = true;
398
      }
399
 
400
    if (initialHandshakeDone)
401
      throw new SSLException("rehandshaking not yet implemented");
402
 
403
    long now = -System.currentTimeMillis();
404
    engine.beginHandshake();
405
 
406
    HandshakeStatus status = engine.getHandshakeStatus();
407
    assert(status != HandshakeStatus.NOT_HANDSHAKING);
408
 
409
    ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
410
    inBuffer.position(inBuffer.limit());
411
    ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
412
    ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
413
    SSLEngineResult result = null;
414
 
415
    DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream());
416
    OutputStream sockOut = underlyingSocket.getOutputStream();
417
 
418
    try
419
      {
420
        while (status != HandshakeStatus.NOT_HANDSHAKING
421
               && status != HandshakeStatus.FINISHED)
422
          {
423
            logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}",
424
                        status);
425
 
426
            if (inBuffer.capacity() != getSession().getPacketBufferSize())
427
              {
428
                ByteBuffer b
429
                  = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
430
                if (inBuffer.hasRemaining())
431
                  b.put(inBuffer).flip();
432
                inBuffer = b;
433
              }
434
            if (outBuffer.capacity() != getSession().getPacketBufferSize())
435
              outBuffer
436
              = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
437
 
438
            switch (status)
439
              {
440
                case NEED_UNWRAP:
441
                  // Read in a single SSL record.
442
                  inBuffer.clear();
443
                  int i = sockIn.read();
444
                  if (i == -1)
445
                    throw new EOFException();
446
                  if ((i & 0x80) == 0x80) // SSLv2 client hello.
447
                    {
448
                      inBuffer.put((byte) i);
449
                      int v2len = (i & 0x7f) << 8;
450
                      i = sockIn.read();
451
                      v2len = v2len | (i & 0xff);
452
                      inBuffer.put((byte) i);
453
                      sockIn.readFully(inBuffer.array(), 2, v2len);
454
                      inBuffer.position(0).limit(v2len + 2);
455
                    }
456
                  else
457
                    {
458
                      inBuffer.put((byte) i);
459
                      inBuffer.putInt(sockIn.readInt());
460
                      int reclen = inBuffer.getShort(3) & 0xFFFF;
461
                      sockIn.readFully(inBuffer.array(), 5, reclen);
462
                      inBuffer.position(0).limit(reclen + 5);
463
                    }
464
                  result = engine.unwrap(inBuffer, emptyBuffer);
465
                  status = result.getHandshakeStatus();
466
                  if (result.getStatus() != Status.OK)
467
                    throw new SSLException("unexpected SSL status "
468
                                           + result.getStatus());
469
                  break;
470
 
471
                case NEED_WRAP:
472
                {
473
                  outBuffer.clear();
474
                  result = engine.wrap(emptyBuffer, outBuffer);
475
                  status = result.getHandshakeStatus();
476
                  if (result.getStatus() != Status.OK)
477
                    throw new SSLException("unexpected SSL status "
478
                                           + result.getStatus());
479
                  outBuffer.flip();
480
                  sockOut.write(outBuffer.array(), outBuffer.position(),
481
                                outBuffer.limit());
482
                }
483
                break;
484
 
485
                case NEED_TASK:
486
                {
487
                  Runnable task;
488
                  while ((task = engine.getDelegatedTask()) != null)
489
                    task.run();
490
                  status = engine.getHandshakeStatus();
491
                }
492
                break;
493
 
494
                case FINISHED:
495
                  break;
496
              }
497
          }
498
 
499
        initialHandshakeDone = true;
500
 
501
        HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession());
502
        for (HandshakeCompletedListener l : listeners)
503
          {
504
            try
505
              {
506
                l.handshakeCompleted(hce);
507
              }
508
            catch (ThreadDeath td)
509
              {
510
                throw td;
511
              }
512
            catch (Throwable x)
513
              {
514
                logger.log(Component.WARNING,
515
                           "HandshakeCompletedListener threw exception", x);
516
              }
517
          }
518
 
519
        now += System.currentTimeMillis();
520
        if (Debug.DEBUG)
521
          logger.logv(Component.SSL_HANDSHAKE,
522
                      "handshake completed in {0}ms in thread {1}", now,
523
                      Thread.currentThread().getName());
524
      }
525
    catch (SSLException ssle)
526
      {
527
        handshakeException = ssle;
528
        throw ssle;
529
      }
530
    finally
531
      {
532
        synchronized (engine)
533
          {
534
            isHandshaking = false;
535
            engine.notifyAll();
536
          }
537
      }
538
  }
539
 
540
  // Methods overriding Socket.
541
 
542
  @Override public void bind(SocketAddress bindpoint) throws IOException
543
  {
544
    underlyingSocket.bind(bindpoint);
545
  }
546
 
547
  @Override public void connect(SocketAddress endpoint) throws IOException
548
  {
549
    underlyingSocket.connect(endpoint);
550
  }
551
 
552
  @Override public void connect(SocketAddress endpoint, int timeout)
553
    throws IOException
554
  {
555
    underlyingSocket.connect(endpoint, timeout);
556
  }
557
 
558
  @Override public InetAddress getInetAddress()
559
  {
560
    return underlyingSocket.getInetAddress();
561
  }
562
 
563
  @Override public InetAddress getLocalAddress()
564
  {
565
    return underlyingSocket.getLocalAddress();
566
  }
567
 
568
  @Override public int getPort()
569
  {
570
    return underlyingSocket.getPort();
571
  }
572
 
573
  @Override public int getLocalPort()
574
  {
575
    return underlyingSocket.getLocalPort();
576
  }
577
 
578
  @Override public SocketAddress getRemoteSocketAddress()
579
  {
580
    return underlyingSocket.getRemoteSocketAddress();
581
  }
582
 
583
  public SocketAddress getLocalSocketAddress()
584
  {
585
    return underlyingSocket.getLocalSocketAddress();
586
  }
587
 
588
  @Override public SocketChannel getChannel()
589
  {
590
    throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO");
591
  }
592
 
593
  @Override public InputStream getInputStream() throws IOException
594
  {
595
    return new SocketInputStream();
596
  }
597
 
598
  @Override public OutputStream getOutputStream() throws IOException
599
  {
600
    return new SocketOutputStream();
601
  }
602
 
603
  @Override public void setTcpNoDelay(boolean on) throws SocketException
604
  {
605
    underlyingSocket.setTcpNoDelay(on);
606
  }
607
 
608
  @Override public boolean getTcpNoDelay() throws SocketException
609
  {
610
    return underlyingSocket.getTcpNoDelay();
611
  }
612
 
613
  @Override public void setSoLinger(boolean on, int linger) throws SocketException
614
  {
615
    underlyingSocket.setSoLinger(on, linger);
616
  }
617
 
618
  public int getSoLinger() throws SocketException
619
  {
620
    return underlyingSocket.getSoLinger();
621
  }
622
 
623
  @Override public void sendUrgentData(int x) throws IOException
624
  {
625
    throw new UnsupportedOperationException("not supported");
626
  }
627
 
628
  @Override public void setOOBInline(boolean on) throws SocketException
629
  {
630
    underlyingSocket.setOOBInline(on);
631
  }
632
 
633
  @Override public boolean getOOBInline() throws SocketException
634
  {
635
    return underlyingSocket.getOOBInline();
636
  }
637
 
638
  @Override public void setSoTimeout(int timeout) throws SocketException
639
  {
640
    underlyingSocket.setSoTimeout(timeout);
641
  }
642
 
643
  @Override public int getSoTimeout() throws SocketException
644
  {
645
    return underlyingSocket.getSoTimeout();
646
  }
647
 
648
  @Override public void setSendBufferSize(int size) throws SocketException
649
  {
650
    underlyingSocket.setSendBufferSize(size);
651
  }
652
 
653
  @Override public int getSendBufferSize() throws SocketException
654
  {
655
    return underlyingSocket.getSendBufferSize();
656
  }
657
 
658
  @Override public void setReceiveBufferSize(int size) throws SocketException
659
  {
660
    underlyingSocket.setReceiveBufferSize(size);
661
  }
662
 
663
  @Override public int getReceiveBufferSize() throws SocketException
664
  {
665
    return underlyingSocket.getReceiveBufferSize();
666
  }
667
 
668
  @Override public void setKeepAlive(boolean on) throws SocketException
669
  {
670
    underlyingSocket.setKeepAlive(on);
671
  }
672
 
673
  @Override public boolean getKeepAlive() throws SocketException
674
  {
675
    return underlyingSocket.getKeepAlive();
676
  }
677
 
678
  @Override public void setTrafficClass(int tc) throws SocketException
679
  {
680
    underlyingSocket.setTrafficClass(tc);
681
  }
682
 
683
  @Override public int getTrafficClass() throws SocketException
684
  {
685
    return underlyingSocket.getTrafficClass();
686
  }
687
 
688
  @Override public void setReuseAddress(boolean reuseAddress)
689
    throws SocketException
690
  {
691
    underlyingSocket.setReuseAddress(reuseAddress);
692
  }
693
 
694
  @Override public boolean getReuseAddress() throws SocketException
695
  {
696
    return underlyingSocket.getReuseAddress();
697
  }
698
 
699
  @Override public void close() throws IOException
700
  {
701
    // XXX closure alerts.
702
    if (autoClose)
703
      underlyingSocket.close();
704
  }
705
 
706
  @Override public void shutdownInput() throws IOException
707
  {
708
    underlyingSocket.shutdownInput();
709
  }
710
 
711
  @Override public void shutdownOutput() throws IOException
712
  {
713
    underlyingSocket.shutdownOutput();
714
  }
715
 
716
  @Override public boolean isConnected()
717
  {
718
    return underlyingSocket.isConnected();
719
  }
720
 
721
  @Override public boolean isBound()
722
  {
723
    return underlyingSocket.isBound();
724
  }
725
 
726
  @Override public boolean isClosed()
727
  {
728
    return underlyingSocket.isClosed();
729
  }
730
 
731
  @Override public boolean isInputShutdown()
732
  {
733
    return underlyingSocket.isInputShutdown();
734
  }
735
 
736
  @Override public boolean isOutputShutdown()
737
  {
738
    return underlyingSocket.isOutputShutdown();
739
  }
740
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.