1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package test.java.net.UnixDomainSocketAddress;
25 
26 import java.io.ByteArrayInputStream;
27 import java.io.ByteArrayOutputStream;
28 import java.io.DataOutputStream;
29 import java.io.IOException;
30 import java.io.InvalidObjectException;
31 import java.io.ObjectInputStream;
32 import java.io.ObjectOutputStream;
33 import java.io.ObjectStreamClass;
34 import java.io.Serializable;
35 import java.net.UnixDomainSocketAddress;
36 import java.nio.file.Path;
37 import static java.io.ObjectStreamConstants.*;
38 import org.testng.annotations.Test;
39 import static org.testng.Assert.assertEquals;
40 import static org.testng.Assert.assertTrue;
41 import static org.testng.Assert.expectThrows;
42 
43 /*
44  * @test
45  * @summary UnixDomainSocketAddress serialization test
46  * @run testng/othervm UnixDomainSocketAddressSerializationTest
47  */
48 public class UnixDomainSocketAddressSerializationTest {
49     private static final UnixDomainSocketAddress addr =
50             UnixDomainSocketAddress.of(Path.of("test.sock"));
51 
52     @Test
test()53     public static void test() throws Exception {
54         assertTrue(addr instanceof Serializable);
55 
56         byte[] serialized = serialize(addr);
57         assertTrue(serialized.length > 0);
58 
59         UnixDomainSocketAddress deserialized =
60                 deserialize(serialized, UnixDomainSocketAddress.class);
61         assertEquals(deserialized.getPath(), addr.getPath());
62         assertEquals(deserialized.toString(), addr.toString());
63         assertEquals(deserialized.hashCode(), addr.hashCode());
64         assertEquals(deserialized, addr);
65     }
66 
67     static final Class<InvalidObjectException> IOE = InvalidObjectException.class;
68     static final Class<NullPointerException> NPE = NullPointerException.class;
69 
70     /** Tests that UnixDomainSocketAddress in the byte-stream is disallowed. */
71     @Test
testUnixDomainSocketAddressInStream()72     public static void testUnixDomainSocketAddressInStream() throws Exception {
73         long suid = ObjectStreamClass.lookup(UnixDomainSocketAddress.class).getSerialVersionUID();
74         byte[] bytes = byteStreamFor(UnixDomainSocketAddress.class.getName(), suid);
75         expectThrows(IOE, () -> deserialize(bytes, UnixDomainSocketAddress.class));
76     }
77 
78     /** Tests that SerialProxy with a null/absent path value in the byte-stream is disallowed. */
79     @Test
testSerialProxyNoStreamValues()80     public static void testSerialProxyNoStreamValues() throws Exception {
81         Class<?> c = Class.forName("java.net.UnixDomainSocketAddress$Ser");
82         long suid = ObjectStreamClass.lookup(c).getSerialVersionUID();
83         byte[] bytes = byteStreamFor(c.getName(), suid);
84         expectThrows(NPE, () -> deserialize(bytes, UnixDomainSocketAddress.class));
85     }
86 
serialize(T t)87     private static <T extends Serializable> byte[] serialize(T t)
88             throws IOException {
89         ByteArrayOutputStream bos = new ByteArrayOutputStream();
90         ObjectOutputStream oos = new ObjectOutputStream(bos);
91         oos.writeObject(t);
92         oos.flush();
93         oos.close();
94         return bos.toByteArray();
95     }
96 
deserialize(byte[] b, Class<T> cl)97     private static <T extends Serializable> T deserialize(byte[] b, Class<T> cl)
98             throws IOException, ClassNotFoundException {
99         try (ObjectInputStream ois =
100                      new ObjectInputStream(new ByteArrayInputStream(b))) {
101             Object o = ois.readObject();
102             return cl.cast(o);
103         }
104     }
105 
106     /**
107      * Returns a stream with the given classname and suid. The stream will have
108      * no stream field values.
109      */
byteStreamFor(String classname, long suid)110     static byte[] byteStreamFor(String classname, long suid) throws Exception {
111         ByteArrayOutputStream baos = new ByteArrayOutputStream();
112         DataOutputStream dos = new DataOutputStream(baos);
113         dos.writeShort(STREAM_MAGIC);
114         dos.writeShort(STREAM_VERSION);
115         dos.writeByte(TC_OBJECT);
116         dos.writeByte(TC_CLASSDESC);
117         dos.writeUTF(classname);
118         dos.writeLong(suid);
119         dos.writeByte(SC_SERIALIZABLE);
120         dos.writeShort(0);                // number of stream fields
121         dos.writeByte(TC_ENDBLOCKDATA);   // no annotations
122         dos.writeByte(TC_NULL);           // no superclasses
123         dos.write(TC_ENDBLOCKDATA);       // end block - for SC_WRITE_METHOD
124         dos.close();
125         return baos.toByteArray();
126     }
127 }