mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8198753: (dc) DatagramChannel throws unspecified exceptions
Reviewed-by: alanb
This commit is contained in:
parent
9aff9cb645
commit
37f1b2b1e3
7 changed files with 217 additions and 75 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -279,6 +279,9 @@ public abstract class DatagramChannel
|
||||||
*
|
*
|
||||||
* @return This datagram channel
|
* @return This datagram channel
|
||||||
*
|
*
|
||||||
|
* @throws AlreadyConnectedException
|
||||||
|
* If this channel is already connected
|
||||||
|
*
|
||||||
* @throws ClosedChannelException
|
* @throws ClosedChannelException
|
||||||
* If this channel is closed
|
* If this channel is closed
|
||||||
*
|
*
|
||||||
|
@ -292,6 +295,12 @@ public abstract class DatagramChannel
|
||||||
* closing the channel and setting the current thread's
|
* closing the channel and setting the current thread's
|
||||||
* interrupt status
|
* interrupt status
|
||||||
*
|
*
|
||||||
|
* @throws UnresolvedAddressException
|
||||||
|
* If the given remote address is not fully resolved
|
||||||
|
*
|
||||||
|
* @throws UnsupportedAddressTypeException
|
||||||
|
* If the type of the given remote address is not supported
|
||||||
|
*
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
* If a security manager has been installed
|
* If a security manager has been installed
|
||||||
* and it does not permit access to the given remote address
|
* and it does not permit access to the given remote address
|
||||||
|
@ -444,6 +453,10 @@ public abstract class DatagramChannel
|
||||||
* zero if there was insufficient room for the datagram in the
|
* zero if there was insufficient room for the datagram in the
|
||||||
* underlying output buffer
|
* underlying output buffer
|
||||||
*
|
*
|
||||||
|
* @throws AlreadyConnectedException
|
||||||
|
* If this channel is connected to a different address
|
||||||
|
* from that specified by {@code target}
|
||||||
|
*
|
||||||
* @throws ClosedChannelException
|
* @throws ClosedChannelException
|
||||||
* If this channel is closed
|
* If this channel is closed
|
||||||
*
|
*
|
||||||
|
@ -457,6 +470,12 @@ public abstract class DatagramChannel
|
||||||
* closing the channel and setting the current thread's
|
* closing the channel and setting the current thread's
|
||||||
* interrupt status
|
* interrupt status
|
||||||
*
|
*
|
||||||
|
* @throws UnresolvedAddressException
|
||||||
|
* If the given remote address is not fully resolved
|
||||||
|
*
|
||||||
|
* @throws UnsupportedAddressTypeException
|
||||||
|
* If the type of the given remote address is not supported
|
||||||
|
*
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
* If a security manager has been installed
|
* If a security manager has been installed
|
||||||
* and it does not permit datagrams to be sent
|
* and it does not permit datagrams to be sent
|
||||||
|
|
|
@ -508,8 +508,7 @@ class DatagramChannelImpl
|
||||||
if (remote != null) {
|
if (remote != null) {
|
||||||
// connected
|
// connected
|
||||||
if (!target.equals(remote)) {
|
if (!target.equals(remote)) {
|
||||||
throw new IllegalArgumentException(
|
throw new AlreadyConnectedException();
|
||||||
"Connected address not equal to target address");
|
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
n = IOUtil.write(fd, src, -1, nd);
|
n = IOUtil.write(fd, src, -1, nd);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -102,7 +102,7 @@ public class Connect {
|
||||||
try {
|
try {
|
||||||
dc.send(bb, bogus);
|
dc.send(bb, bogus);
|
||||||
throw new RuntimeException("Allowed bogus send while connected");
|
throw new RuntimeException("Allowed bogus send while connected");
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (AlreadyConnectedException ace) {
|
||||||
// Correct behavior
|
// Correct behavior
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code 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
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8198753
|
||||||
|
* @summary Test DatagramChannel connect exceptions
|
||||||
|
* @library ..
|
||||||
|
* @run testng ConnectExceptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import org.testng.annotations.AfterTest;
|
||||||
|
import org.testng.annotations.BeforeTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
public class ConnectExceptions {
|
||||||
|
static DatagramChannel sndChannel;
|
||||||
|
static DatagramChannel rcvChannel;
|
||||||
|
static InetSocketAddress sender;
|
||||||
|
static InetSocketAddress receiver;
|
||||||
|
|
||||||
|
@BeforeTest
|
||||||
|
public static void setup() throws Exception {
|
||||||
|
sndChannel = DatagramChannel.open();
|
||||||
|
sndChannel.bind(null);
|
||||||
|
InetAddress address = InetAddress.getLocalHost();
|
||||||
|
if (address.isLoopbackAddress()) {
|
||||||
|
address = InetAddress.getLoopbackAddress();
|
||||||
|
}
|
||||||
|
sender = new InetSocketAddress(address,
|
||||||
|
sndChannel.socket().getLocalPort());
|
||||||
|
|
||||||
|
rcvChannel = DatagramChannel.open();
|
||||||
|
rcvChannel.bind(null);
|
||||||
|
receiver = new InetSocketAddress(address,
|
||||||
|
rcvChannel.socket().getLocalPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = UnsupportedAddressTypeException.class)
|
||||||
|
public static void unsupportedAddressTypeException() throws Exception {
|
||||||
|
rcvChannel.connect(sender);
|
||||||
|
sndChannel.connect(new SocketAddress() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = UnresolvedAddressException.class)
|
||||||
|
public static void unresolvedAddressException() throws Exception {
|
||||||
|
String host = TestUtil.UNRESOLVABLE_HOST;
|
||||||
|
InetSocketAddress unresolvable = new InetSocketAddress (host, 37);
|
||||||
|
sndChannel.connect(unresolvable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AlreadyConnectedException.class)
|
||||||
|
public static void alreadyConnectedException() throws Exception {
|
||||||
|
sndChannel.connect(receiver);
|
||||||
|
InetSocketAddress random = new InetSocketAddress(0);
|
||||||
|
sndChannel.connect(random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTest
|
||||||
|
public static void cleanup() throws Exception {
|
||||||
|
rcvChannel.close();
|
||||||
|
sndChannel.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -24,6 +24,8 @@
|
||||||
/* @test
|
/* @test
|
||||||
* @bug 4849277 7183800
|
* @bug 4849277 7183800
|
||||||
* @summary Test DatagramChannel send while connected
|
* @summary Test DatagramChannel send while connected
|
||||||
|
* @library ..
|
||||||
|
* @run testng ConnectedSend
|
||||||
* @author Mike McCloskey
|
* @author Mike McCloskey
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -32,20 +34,16 @@ import java.net.*;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
public class ConnectedSend {
|
public class ConnectedSend {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
test1();
|
|
||||||
test2();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if DatagramChannel.send while connected can include
|
// Check if DatagramChannel.send while connected can include
|
||||||
// address without throwing
|
// address without throwing
|
||||||
private static void test1() throws Exception {
|
@Test
|
||||||
|
public static void sendToConnectedAddress() throws Exception {
|
||||||
DatagramChannel sndChannel = DatagramChannel.open();
|
DatagramChannel sndChannel = DatagramChannel.open();
|
||||||
sndChannel.socket().bind(null);
|
sndChannel.bind(null);
|
||||||
InetAddress address = InetAddress.getLocalHost();
|
InetAddress address = InetAddress.getLocalHost();
|
||||||
if (address.isLoopbackAddress()) {
|
if (address.isLoopbackAddress()) {
|
||||||
address = InetAddress.getLoopbackAddress();
|
address = InetAddress.getLoopbackAddress();
|
||||||
|
@ -55,7 +53,7 @@ public class ConnectedSend {
|
||||||
sndChannel.socket().getLocalPort());
|
sndChannel.socket().getLocalPort());
|
||||||
|
|
||||||
DatagramChannel rcvChannel = DatagramChannel.open();
|
DatagramChannel rcvChannel = DatagramChannel.open();
|
||||||
rcvChannel.socket().bind(null);
|
rcvChannel.bind(null);
|
||||||
InetSocketAddress receiver = new InetSocketAddress(
|
InetSocketAddress receiver = new InetSocketAddress(
|
||||||
address,
|
address,
|
||||||
rcvChannel.socket().getLocalPort());
|
rcvChannel.socket().getLocalPort());
|
||||||
|
@ -71,8 +69,7 @@ public class ConnectedSend {
|
||||||
rcvChannel.receive(bb);
|
rcvChannel.receive(bb);
|
||||||
bb.flip();
|
bb.flip();
|
||||||
CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb);
|
CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb);
|
||||||
if (!cb.toString().startsWith("h"))
|
assertTrue(cb.toString().startsWith("h"), "Unexpected message content");
|
||||||
throw new RuntimeException("Test failed");
|
|
||||||
|
|
||||||
rcvChannel.close();
|
rcvChannel.close();
|
||||||
sndChannel.close();
|
sndChannel.close();
|
||||||
|
@ -81,9 +78,10 @@ public class ConnectedSend {
|
||||||
// Check if the datagramsocket adaptor can send with a packet
|
// Check if the datagramsocket adaptor can send with a packet
|
||||||
// that has not been initialized with an address; the legacy
|
// that has not been initialized with an address; the legacy
|
||||||
// datagram socket will send in this case
|
// datagram socket will send in this case
|
||||||
private static void test2() throws Exception {
|
@Test
|
||||||
|
public static void sendAddressedPacket() throws Exception {
|
||||||
DatagramChannel sndChannel = DatagramChannel.open();
|
DatagramChannel sndChannel = DatagramChannel.open();
|
||||||
sndChannel.socket().bind(null);
|
sndChannel.bind(null);
|
||||||
InetAddress address = InetAddress.getLocalHost();
|
InetAddress address = InetAddress.getLocalHost();
|
||||||
if (address.isLoopbackAddress()) {
|
if (address.isLoopbackAddress()) {
|
||||||
address = InetAddress.getLoopbackAddress();
|
address = InetAddress.getLoopbackAddress();
|
||||||
|
@ -93,7 +91,7 @@ public class ConnectedSend {
|
||||||
sndChannel.socket().getLocalPort());
|
sndChannel.socket().getLocalPort());
|
||||||
|
|
||||||
DatagramChannel rcvChannel = DatagramChannel.open();
|
DatagramChannel rcvChannel = DatagramChannel.open();
|
||||||
rcvChannel.socket().bind(null);
|
rcvChannel.bind(null);
|
||||||
InetSocketAddress receiver = new InetSocketAddress(
|
InetSocketAddress receiver = new InetSocketAddress(
|
||||||
address,
|
address,
|
||||||
rcvChannel.socket().getLocalPort());
|
rcvChannel.socket().getLocalPort());
|
||||||
|
@ -109,13 +107,12 @@ public class ConnectedSend {
|
||||||
rcvChannel.receive(bb);
|
rcvChannel.receive(bb);
|
||||||
bb.flip();
|
bb.flip();
|
||||||
CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb);
|
CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb);
|
||||||
if (!cb.toString().startsWith("h"))
|
assertTrue(cb.toString().startsWith("h"), "Unexpected message content");
|
||||||
throw new RuntimeException("Test failed");
|
|
||||||
|
|
||||||
// Check that the pkt got set with the target address;
|
// Check that the pkt got set with the target address;
|
||||||
// This is legacy behavior
|
// This is legacy behavior
|
||||||
if (!pkt.getSocketAddress().equals(receiver))
|
assertEquals(pkt.getSocketAddress(), receiver,
|
||||||
throw new RuntimeException("Test failed");
|
"Unexpected address set on packet");
|
||||||
|
|
||||||
rcvChannel.close();
|
rcvChannel.close();
|
||||||
sndChannel.close();
|
sndChannel.close();
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code 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
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 4675045 8198753
|
||||||
|
* @summary Test DatagramChannel send exceptions
|
||||||
|
* @library ..
|
||||||
|
* @run testng SendExceptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import org.testng.annotations.AfterTest;
|
||||||
|
import org.testng.annotations.BeforeTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
public class SendExceptions {
|
||||||
|
static DatagramChannel sndChannel;
|
||||||
|
static DatagramChannel rcvChannel;
|
||||||
|
static InetSocketAddress sender;
|
||||||
|
static InetSocketAddress receiver;
|
||||||
|
static ByteBuffer buf = ByteBuffer.allocate(17);
|
||||||
|
|
||||||
|
@BeforeTest
|
||||||
|
public static void setup() throws Exception {
|
||||||
|
sndChannel = DatagramChannel.open();
|
||||||
|
sndChannel.bind(null);
|
||||||
|
InetAddress address = InetAddress.getLocalHost();
|
||||||
|
if (address.isLoopbackAddress()) {
|
||||||
|
address = InetAddress.getLoopbackAddress();
|
||||||
|
}
|
||||||
|
sender = new InetSocketAddress(address,
|
||||||
|
sndChannel.socket().getLocalPort());
|
||||||
|
|
||||||
|
rcvChannel = DatagramChannel.open();
|
||||||
|
rcvChannel.bind(null);
|
||||||
|
receiver = new InetSocketAddress(address,
|
||||||
|
rcvChannel.socket().getLocalPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = UnsupportedAddressTypeException.class)
|
||||||
|
public static void unsupportedAddressTypeException() throws Exception {
|
||||||
|
rcvChannel.connect(sender);
|
||||||
|
sndChannel.send(buf, new SocketAddress() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = UnresolvedAddressException.class)
|
||||||
|
public static void unresolvedAddressException() throws Exception {
|
||||||
|
String host = TestUtil.UNRESOLVABLE_HOST;
|
||||||
|
InetSocketAddress unresolvable = new InetSocketAddress (host, 37);
|
||||||
|
sndChannel.send(buf, unresolvable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AlreadyConnectedException.class)
|
||||||
|
public static void alreadyConnectedException() throws Exception {
|
||||||
|
sndChannel.connect(receiver);
|
||||||
|
InetSocketAddress random = new InetSocketAddress(0);
|
||||||
|
sndChannel.send(buf, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTest
|
||||||
|
public static void cleanup() throws Exception {
|
||||||
|
rcvChannel.close();
|
||||||
|
sndChannel.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code 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
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* @test
|
|
||||||
* @bug 4675045
|
|
||||||
* @summary Test DatagramChannel send to unresolved address
|
|
||||||
* @library ..
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.*;
|
|
||||||
import java.nio.channels.*;
|
|
||||||
|
|
||||||
public class SendToUnresolved {
|
|
||||||
public static void main(String [] argv) throws Exception {
|
|
||||||
String host = TestUtil.UNRESOLVABLE_HOST;
|
|
||||||
DatagramChannel dc = DatagramChannel.open();
|
|
||||||
ByteBuffer bb = ByteBuffer.allocate(4);
|
|
||||||
InetSocketAddress sa = new InetSocketAddress (host, 37);
|
|
||||||
InetAddress inetaddr = sa.getAddress();
|
|
||||||
try {
|
|
||||||
dc.send(bb, sa);
|
|
||||||
throw new RuntimeException("Expected exception not thrown");
|
|
||||||
} catch (IOException | UnresolvedAddressException e) {
|
|
||||||
// Correct result
|
|
||||||
}
|
|
||||||
dc.close();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue