1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.newsclub.net.unix.demo.server;
19
20 import java.io.BufferedOutputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.net.Socket;
25 import java.net.SocketAddress;
26 import java.net.SocketException;
27
28
29
30
31
32
33
34 public final class ChargenServer extends DemoServerBase {
35 private static final Chargen SIMPLE_CHARGEN = new SimpleChargen();
36 private final boolean fast;
37 private FastChargen cachedChargen = null;
38
39
40
41
42
43
44 private interface Chargen {
45 void write(Socket socket) throws IOException;
46 }
47
48 public ChargenServer(SocketAddress listenAddress) {
49 this(listenAddress, true);
50 }
51
52 public ChargenServer(SocketAddress listenAddress, boolean fast) {
53 super(listenAddress);
54 this.fast = fast;
55 }
56
57 @Override
58 protected void onServerStarting() {
59 super.onServerStarting();
60 System.out.println("- Fast chargen: " + fast);
61 }
62
63 @Override
64 protected void doServeSocket(Socket socket) throws IOException {
65 try (OutputStream os = socket.getOutputStream()) {
66 getChargen(socket).write(socket);
67 }
68 }
69
70 private synchronized Chargen getChargen(Socket socket) throws SocketException {
71 if (!fast) {
72 return SIMPLE_CHARGEN;
73 }
74
75 int bufferSize = socket.getSendBufferSize();
76 FastChargen chargen = cachedChargen;
77 if (chargen == null || chargen.cacheSize != bufferSize) {
78 chargen = new FastChargen(bufferSize);
79 cachedChargen = chargen;
80 }
81 return chargen;
82 }
83
84
85
86
87
88
89
90
91 private static final class SimpleChargen implements Chargen {
92 @Override
93 public void write(Socket socket) throws IOException {
94 try (BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream(), socket
95 .getSendBufferSize())) {
96 while (true) {
97 int offset = 1;
98 for (int row = 0; row < 95; row++) {
99 for (int i = 0; i < 72; i++) {
100 int asciiChar = (32 + (offset + i) % 95);
101 bos.write(asciiChar);
102 }
103 bos.write(13);
104 bos.write(10);
105
106 offset++;
107 }
108 }
109 }
110 }
111 }
112
113
114
115
116
117
118
119 private static final class FastChargen implements Chargen {
120
121
122
123 private final int ourDataSize;
124
125
126
127
128 private final int cacheSize;
129
130
131
132
133 private final byte[] cache;
134
135 FastChargen(int sendBufferSize) {
136 this.cacheSize = sendBufferSize;
137
138 final int lineWidth = 72;
139 final int firstPrintableCharacter = 32;
140 final int lastPrintableCharacter = 126;
141
142 final int numPrintableCharacters = (lastPrintableCharacter + 1) - firstPrintableCharacter;
143 final int linefeedLen = 2;
144
145 this.ourDataSize = numPrintableCharacters * (lineWidth + linefeedLen);
146 final int bufLen = sendBufferSize + ourDataSize;
147
148 ByteArrayOutputStream bos = new ByteArrayOutputStream(bufLen);
149 int nWritten = 0;
150
151 bigLoop : while (nWritten < bufLen) {
152 int offset = 1;
153 for (int row = 0; row < numPrintableCharacters; row++) {
154 for (int i = 0; i < lineWidth; i++) {
155 int asciiChar = (32 + (offset + i) % numPrintableCharacters);
156 bos.write(asciiChar);
157 if (++nWritten == bufLen) {
158 break bigLoop;
159 }
160 }
161 bos.write(13);
162 bos.write(10);
163 if (++nWritten == bufLen) {
164 break bigLoop;
165 }
166 offset++;
167 }
168 }
169
170 this.cache = bos.toByteArray();
171 }
172
173 @Override
174 public void write(Socket socket) throws IOException {
175 try (OutputStream os = socket.getOutputStream()) {
176 int offset = 0;
177 while (true) {
178 os.write(cache, offset, cacheSize);
179 offset = (offset + cacheSize) % ourDataSize;
180 }
181 }
182 }
183 }
184 }