Isolate our patches to the VNC client from the upstream TightVNC
[invirt/packages/invirt-vnc-client.git] / debian / patches / invirt-ssl-proxy.patch
1 Index: invirt-vnc-client/InvirtTrustManager.java
2 ===================================================================
3 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
4 +++ invirt-vnc-client/InvirtTrustManager.java   2008-10-31 06:09:10.000000000 -0400
5 @@ -0,0 +1,122 @@
6 +/*
7 + * Copyright 2006 Perry Nguyen <pfnguyen@hanhuy.com>
8 + * Licensed under the Apache License, Version 2.0 (the "License");
9 + * you may not use this file except in compliance with the License.
10 + * You may obtain a copy of the License at
11 + *
12 + *     http://www.apache.org/licenses/LICENSE-2.0
13 + *
14 + * Unless required by applicable law or agreed to in writing, software
15 + * distributed under the License is distributed on an "AS IS" BASIS,
16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 + * See the License for the specific language governing permissions and
18 + * limitations under the License.
19 + */
20 +import java.io.IOException;
21 +import java.io.InputStream;
22 +import java.security.KeyStore;
23 +import java.security.KeyStoreException;
24 +import java.security.NoSuchAlgorithmException;
25 +import java.security.cert.CertificateException;
26 +import java.security.cert.X509Certificate;
27 +import java.util.Enumeration;
28 +import java.util.logging.Level;
29 +import java.util.logging.Logger;
30 +
31 +import javax.net.ssl.TrustManager;
32 +import javax.net.ssl.TrustManagerFactory;
33 +import javax.net.ssl.X509TrustManager;
34 +
35 +public class InvirtTrustManager implements X509TrustManager {
36 +    private X509TrustManager trustManager;
37 +    private final static char[] KEY_STORE_PASSWORD =
38 +        { 'f', 'o', 'o', 'b', 'a', 'r' };
39 +    private final static String KEY_STORE_RESOURCE =
40 +        "trust.store";
41 +
42 +    private KeyStore loadKeyStore() throws Exception {
43 +        InputStream in = getClass().getClassLoader().getResourceAsStream(
44 +                KEY_STORE_RESOURCE);
45 +        KeyStore ks = null;
46 +        try {
47 +            if (in == null) {
48 +                //log.severe("Unable to open KeyStore");
49 +                throw new NullPointerException();
50 +            }
51 +            ks = KeyStore.getInstance(KeyStore.getDefaultType());
52 +            ks.load(in, KEY_STORE_PASSWORD);
53 +           /*if (log.isLoggable(Level.FINEST)) {
54 +                for (Enumeration<String> aliases = ks.aliases();
55 +                aliases.hasMoreElements();) {
56 +                    String alias = aliases.nextElement();
57 +                    log.finest("ALIAS: " + alias);
58 +                }
59 +               }*/
60 +        } catch (NoSuchAlgorithmException e) {
61 +            throwError(e);
62 +        } catch (CertificateException e) {
63 +            throwError(e);
64 +        } catch (IOException e) {
65 +            throwError(e);
66 +        } catch (KeyStoreException e) {
67 +            throwError(e);
68 +        } finally {
69 +            try {
70 +                if (in != null)
71 +                    in.close();
72 +            }
73 +            catch (IOException e) { } // ignore
74 +        }
75 +        return ks;
76 +    }
77 +    private void createTrustManager() {
78 +       try {
79 +           try {
80 +               KeyStore keystore = loadKeyStore();
81 +               TrustManagerFactory factory = TrustManagerFactory.getInstance(
82 +                                                                             TrustManagerFactory.getDefaultAlgorithm());
83 +               factory.init(keystore);
84 +               TrustManager[] trustManagers = factory.getTrustManagers();
85 +               if (trustManagers.length == 0)
86 +                   throw new IllegalStateException("No trust manager found");
87 +               setTrustManager((X509TrustManager) trustManagers[0]);
88 +           } catch (NoSuchAlgorithmException e) {
89 +               throwError(e);
90 +           } catch (KeyStoreException e) {
91 +               throwError(e);
92 +           }
93 +       } catch (Exception e) {
94 +           e.printStackTrace();
95 +       }
96 +    }
97 +    private void throwError(Exception e) throws Exception {
98 +        //HttpClientError error = new HttpClientError(e.getMessage());
99 +        //error.initCause(e);
100 +        throw e;
101 +    }
102 +    public X509TrustManager getTrustManager() {
103 +        if (trustManager == null)
104 +            createTrustManager();
105 +        return trustManager;
106 +    }
107 +
108 +    public void setTrustManager(X509TrustManager trustManager) {
109 +        this.trustManager = trustManager;
110 +    }
111 +
112 +    public void checkClientTrusted(X509Certificate[] chain, String authType)
113 +            throws CertificateException {
114 +        getTrustManager().checkClientTrusted(chain, authType);
115 +    }
116 +
117 +    public void checkServerTrusted(X509Certificate[] chain, String authType)
118 +            throws CertificateException {
119 +        getTrustManager().checkServerTrusted(chain, authType);
120 +
121 +    }
122 +
123 +    public X509Certificate[] getAcceptedIssuers() {
124 +        return getTrustManager().getAcceptedIssuers();
125 +    }
126 +
127 +}
128 \ No newline at end of file
129 Index: invirt-vnc-client/Makefile
130 ===================================================================
131 --- invirt-vnc-client.orig/Makefile     2008-10-31 06:09:10.000000000 -0400
132 +++ invirt-vnc-client/Makefile  2008-10-31 06:09:10.000000000 -0400
133 @@ -17,8 +17,10 @@
134           DesCipher.class CapabilityInfo.class CapsContainer.class \
135           RecordingFrame.class SessionRecorder.class \
136           SocketFactory.class HTTPConnectSocketFactory.class \
137 +         VNCProxyConnectSocketFactory.class VNCProxyConnectSocket.class \
138           HTTPConnectSocket.class ReloginPanel.class \
139 -         InStream.class MemInStream.class ZlibInStream.class
140 +         InStream.class MemInStream.class ZlibInStream.class \
141 +         VNCProxyConnectSocketWrapper.class SocketWrapper.class SocketWrapper\$$WrappingSocketImpl.class InvirtTrustManager.class
142  
143  SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \
144           VncCanvas2.java \
145 @@ -26,8 +28,10 @@
146           DesCipher.java CapabilityInfo.java CapsContainer.java \
147           RecordingFrame.java SessionRecorder.java \
148           SocketFactory.java HTTPConnectSocketFactory.java \
149 +         VNCProxyConnectSocketFactory.java VNCProxyConnectSocket.java \
150           HTTPConnectSocket.java ReloginPanel.java \
151 -         InStream.java MemInStream.java ZlibInStream.java
152 +         InStream.java MemInStream.java ZlibInStream.java \
153 +         VNCProxyConnectSocketWrapper.java SocketWrapper.java InvirtTrustManager.java
154  
155  all: $(CLASSES) $(ARCHIVE)
156  
157 Index: invirt-vnc-client/RfbProto.java
158 ===================================================================
159 --- invirt-vnc-client.orig/RfbProto.java        2007-04-26 22:36:00.000000000 -0400
160 +++ invirt-vnc-client/RfbProto.java     2008-10-31 06:09:10.000000000 -0400
161 @@ -208,11 +208,13 @@
162      port = p;
163  
164      if (viewer.socketFactory == null) {
165 +       System.out.println("Null socketFactory");
166        sock = new Socket(host, port);
167      } else {
168        try {
169         Class factoryClass = Class.forName(viewer.socketFactory);
170         SocketFactory factory = (SocketFactory)factoryClass.newInstance();
171 +       System.out.println("Using socketFactory " + factory);
172         if (viewer.inAnApplet)
173           sock = factory.createSocket(host, port, viewer);
174         else
175 @@ -236,7 +238,7 @@
176      try {
177        sock.close();
178        closed = true;
179 -      System.out.println("RFB socket closed");
180 +      System.out.println("RFB socket closed " + sock);
181        if (rec != null) {
182         rec.close();
183         rec = null;
184 Index: invirt-vnc-client/SocketWrapper.java
185 ===================================================================
186 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
187 +++ invirt-vnc-client/SocketWrapper.java        2008-10-31 06:09:10.000000000 -0400
188 @@ -0,0 +1,262 @@
189 +/*
190 + * Written by Dawid Kurzyniec and released to the public domain, as explained
191 + * at http://creativecommons.org/licenses/publicdomain
192 + */
193 +
194 +//package edu.emory.mathcs.util.net;
195 +
196 +import java.io.*;
197 +import java.net.*;
198 +import java.nio.channels.*;
199 +
200 +/**
201 + * Wrapper for sockets which enables to add functionality in subclasses
202 + * on top of existing, connected sockets. It is useful when direct subclassing
203 + * of delegate socket class is not possible, e.g. if the delegate socket is
204 + * created by a library. Possible usage example is socket factory chaining.
205 + * This class delegates all socket-related requests to the wrapped delegate,
206 + * as of JDK 1.4.
207 + *
208 + * @author Dawid Kurzyniec
209 + * @version 1.4
210 + */
211 +public abstract class SocketWrapper extends Socket {
212 +
213 +    /**
214 +     * the wrapped delegate socket.
215 +     */
216 +    protected final Socket delegate;
217 +
218 +    /**
219 +     * Creates new socket wrapper for a given socket. The delegate
220 +     * must be connected and bound and it must not be closed.
221 +     * @param delegate the delegate socket to wrap
222 +     * @throws SocketException if the delegate socket is closed, not bound,
223 +     *                         or not connected
224 +     */
225 +    protected SocketWrapper(Socket delegate) throws SocketException {
226 +        super(new WrappingSocketImpl(delegate));
227 +        this.delegate = delegate;
228 +       System.out.println("Creating SocketWrapper $Rev$");
229 +    }
230 +
231 +    public SocketChannel getChannel() {
232 +        return delegate.getChannel();
233 +    }
234 +
235 +    /**
236 +     * Returns true, indicating that the socket is bound.
237 +     *
238 +     * @return true
239 +     */
240 +    public boolean isBound() {
241 +        return true;
242 +    }
243 +
244 +    public boolean isClosed() {
245 +        return super.isClosed() || delegate.isClosed();
246 +    }
247 +
248 +    /**
249 +     * Returns true, indicating that the socket is connected.
250 +     *
251 +     * @return true
252 +     */
253 +    public boolean isConnected() {
254 +        return true;
255 +    }
256 +
257 +    public boolean isInputShutdown() {
258 +        return super.isInputShutdown() || delegate.isInputShutdown();
259 +    }
260 +
261 +    public boolean isOutputShutdown() {
262 +        return super.isInputShutdown() || delegate.isOutputShutdown();
263 +    }
264 +
265 +    private static class WrappingSocketImpl extends SocketImpl {
266 +        private final Socket delegate;
267 +        WrappingSocketImpl(Socket delegate) throws SocketException {
268 +            if (delegate == null) {
269 +                throw new NullPointerException();
270 +            }
271 +            if (delegate.isClosed()) {
272 +                throw new SocketException("Delegate server socket is closed");
273 +            }
274 +            if (!(delegate.isBound())) {
275 +                throw new SocketException("Delegate server socket is not bound");
276 +            }
277 +            if (!(delegate.isConnected())) {
278 +                throw new SocketException("Delegate server socket is not connected");
279 +            }
280 +            this.delegate = delegate;
281 +        }
282 +
283 +        protected void create(boolean stream) {}
284 +
285 +        protected void connect(String host, int port) {
286 +            // delegate is always connected, thus this method is never called
287 +            throw new UnsupportedOperationException();
288 +        }
289 +
290 +        protected void connect(InetAddress address, int port) {
291 +            // delegate is always connected, thus this method is never called
292 +            throw new UnsupportedOperationException();
293 +        }
294 +
295 +        protected void connect(SocketAddress address, int timeout) {
296 +            // delegate is always connected, thus this method is never called
297 +            throw new UnsupportedOperationException();
298 +        }
299 +
300 +        protected void bind(InetAddress host, int port) {
301 +            // delegate is always bound, thus this method is never called
302 +            throw new UnsupportedOperationException();
303 +        }
304 +
305 +        protected void listen(int backlog) {
306 +            // this wrapper is never used by a ServerSocket
307 +            throw new UnsupportedOperationException();
308 +        }
309 +
310 +        protected void accept(SocketImpl s) {
311 +            // this wrapper is never used by a ServerSocket
312 +            throw new UnsupportedOperationException();
313 +        }
314 +
315 +        protected InputStream getInputStream() throws IOException {
316 +            return delegate.getInputStream();
317 +        }
318 +
319 +        protected OutputStream getOutputStream() throws IOException {
320 +            return delegate.getOutputStream();
321 +        }
322 +
323 +        protected int available() throws IOException {
324 +            return getInputStream().available();
325 +        }
326 +
327 +        protected void close() throws IOException {
328 +           System.out.println("Calling delegate.close");
329 +            delegate.close();
330 +        }
331 +
332 +        protected void shutdownInput() throws IOException {
333 +            delegate.shutdownInput();
334 +        }
335 +
336 +        protected void shutdownOutput() throws IOException {
337 +            delegate.shutdownOutput();
338 +        }
339 +
340 +        protected FileDescriptor getFileDescriptor() {
341 +            // this wrapper is never used by a ServerSocket
342 +            throw new UnsupportedOperationException();
343 +        }
344 +
345 +        protected InetAddress getInetAddress() {
346 +            return delegate.getInetAddress();
347 +        }
348 +
349 +        protected int getPort() {
350 +            return delegate.getPort();
351 +        }
352 +
353 +        protected boolean supportsUrgentData() {
354 +            return false; // must be overridden in sub-class
355 +        }
356 +
357 +        protected void sendUrgentData (int data) throws IOException {
358 +            delegate.sendUrgentData(data);
359 +        }
360 +
361 +        protected int getLocalPort() {
362 +            return delegate.getLocalPort();
363 +        }
364 +
365 +        public Object getOption(int optID) throws SocketException {
366 +            switch (optID) {
367 +                case SocketOptions.IP_TOS:
368 +                    return new Integer(delegate.getTrafficClass());
369 +                case SocketOptions.SO_BINDADDR:
370 +                    return delegate.getLocalAddress();
371 +                case SocketOptions.SO_KEEPALIVE:
372 +                    return Boolean.valueOf(delegate.getKeepAlive());
373 +                case SocketOptions.SO_LINGER:
374 +                    return new Integer(delegate.getSoLinger());
375 +                case SocketOptions.SO_OOBINLINE:
376 +                    return Boolean.valueOf(delegate.getOOBInline());
377 +                case SocketOptions.SO_RCVBUF:
378 +                    return new Integer(delegate.getReceiveBufferSize());
379 +                case SocketOptions.SO_REUSEADDR:
380 +                    return Boolean.valueOf(delegate.getReuseAddress());
381 +                case SocketOptions.SO_SNDBUF:
382 +                    return new Integer(delegate.getSendBufferSize());
383 +                case SocketOptions.SO_TIMEOUT:
384 +                    return new Integer(delegate.getSoTimeout());
385 +                case SocketOptions.TCP_NODELAY:
386 +                    return Boolean.valueOf(delegate.getTcpNoDelay());
387 +                case SocketOptions.SO_BROADCAST:
388 +                default:
389 +                    throw new IllegalArgumentException("Unsupported option type");
390 +            }
391 +        }
392 +
393 +        public void setOption(int optID, Object value) throws SocketException {
394 +            switch (optID) {
395 +                case SocketOptions.SO_BINDADDR:
396 +                    throw new IllegalArgumentException("Socket is bound");
397 +                case SocketOptions.SO_KEEPALIVE:
398 +                    delegate.setKeepAlive(((Boolean)value).booleanValue());
399 +                    break;
400 +                case SocketOptions.SO_LINGER:
401 +                    if (value instanceof Boolean) {
402 +                        delegate.setSoLinger(((Boolean)value).booleanValue(), 0);
403 +                    }
404 +                    else {
405 +                        delegate.setSoLinger(true, ((Integer)value).intValue());
406 +                    }
407 +                    break;
408 +                case SocketOptions.SO_OOBINLINE:
409 +                    delegate.setOOBInline(((Boolean)value).booleanValue());
410 +                    break;
411 +                case SocketOptions.SO_RCVBUF:
412 +                    delegate.setReceiveBufferSize(((Integer)value).intValue());
413 +                    break;
414 +                case SocketOptions.SO_REUSEADDR:
415 +                    delegate.setReuseAddress(((Boolean)value).booleanValue());
416 +                    break;
417 +                case SocketOptions.SO_SNDBUF:
418 +                    delegate.setSendBufferSize(((Integer)value).intValue());
419 +                    break;
420 +                case SocketOptions.SO_TIMEOUT:
421 +                    delegate.setSoTimeout(((Integer)value).intValue());
422 +                    break;
423 +                case SocketOptions.TCP_NODELAY:
424 +                    delegate.setTcpNoDelay(((Boolean)value).booleanValue());
425 +                    break;
426 +                case SocketOptions.SO_BROADCAST:
427 +                default:
428 +                    throw new IllegalArgumentException("Unsupported option type");
429 +            }
430 +        }
431 +    }
432 +
433 +    public void close() throws IOException {
434 +       System.out.println("Calling SocketWrapper.delegate.close");
435 +       delegate.close();
436 +    }
437 +
438 +    public boolean equals(Object obj) {
439 +        if (!(obj instanceof SocketWrapper)) return false;
440 +        SocketWrapper that = (SocketWrapper)obj;
441 +        return this.delegate.equals(that.delegate);
442 +    }
443 +
444 +    public int hashCode() {
445 +        return delegate.hashCode() ^ 0x01010101;
446 +    }
447 +    public String toString() {
448 +       return "<SocketWrapper " + super.toString() + "(delegating to " + delegate.toString() +  ")" + ">";
449 +    }
450 +}
451 \ No newline at end of file
452 Index: invirt-vnc-client/VNCProxyConnectSocket.java
453 ===================================================================
454 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
455 +++ invirt-vnc-client/VNCProxyConnectSocket.java        2008-10-31 06:09:10.000000000 -0400
456 @@ -0,0 +1,61 @@
457 +//
458 +//  Copyright (C) 2002 Constantin Kaplinsky, Inc.  All Rights Reserved.
459 +//  Copyright 2007 MIT Student Information Processing Board
460 +//
461 +//  This is free software; you can redistribute it and/or modify
462 +//  it under the terms of the GNU General Public License as published by
463 +//  the Free Software Foundation; either version 2 of the License, or
464 +//  (at your option) any later version.
465 +//
466 +//  This software is distributed in the hope that it will be useful,
467 +//  but WITHOUT ANY WARRANTY; without even the implied warranty of
468 +//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
469 +//  GNU General Public License for more details.
470 +//
471 +//  You should have received a copy of the GNU General Public License
472 +//  along with this software; if not, write to the Free Software
473 +//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
474 +//  USA.
475 +//
476 +
477 +//
478 +// VNCProxySocket.java together with VNCProxySocketFactory.java
479 +// implement an alternate way to connect to VNC servers via one or two
480 +// VNCProxy proxies supporting the VNCProxy VNCCONNECT method.
481 +//
482 +
483 +import java.net.*;
484 +import java.io.*;
485 +
486 +class VNCProxyConnectSocket extends Socket {
487 +
488 +  public VNCProxyConnectSocket(String host, int port,
489 +                               String vmname, String authtoken)
490 +    throws IOException {
491 +
492 +    // Connect to the specified HTTP proxy
493 +    super(host, port);
494 +
495 +    // Send the CONNECT request
496 +    getOutputStream().write(("CONNECTVNC " + vmname +
497 +                             " VNCProxy/1.0\r\nAuth-token: " + authtoken +
498 +                             "\r\n\r\n").getBytes());
499 +
500 +    // Read the first line of the response
501 +    DataInputStream is = new DataInputStream(getInputStream());
502 +    String str = is.readLine();
503 +
504 +    // Check the HTTP error code -- it should be "200" on success
505 +    if (!str.startsWith("VNCProxy/1.0 200 ")) {
506 +      if (str.startsWith("VNCProxy/1.0 "))
507 +        str = str.substring(13);
508 +      throw new IOException("Proxy reports \"" + str + "\"");
509 +    }
510 +
511 +    // Success -- skip remaining HTTP headers
512 +    do {
513 +      str = is.readLine();
514 +    } while (str.length() != 0);
515 +  }
516 +}
517 +
518 Index: invirt-vnc-client/VNCProxyConnectSocketFactory.java
519 ===================================================================
520 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
521 +++ invirt-vnc-client/VNCProxyConnectSocketFactory.java 2008-10-31 06:09:10.000000000 -0400
522 @@ -0,0 +1,98 @@
523 +//
524 +//  Copyright (C) 2002 Constantin Kaplinsky, Inc.  All Rights Reserved.
525 +//  Copyright 2007 MIT Student Information Processing Board
526 +//
527 +//  This is free software; you can redistribute it and/or modify
528 +//  it under the terms of the GNU General Public License as published by
529 +//  the Free Software Foundation; either version 2 of the License, or
530 +//  (at your option) any later version.
531 +//
532 +//  This software is distributed in the hope that it will be useful,
533 +//  but WITHOUT ANY WARRANTY; without even the implied warranty of
534 +//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
535 +//  GNU General Public License for more details.
536 +//
537 +//  You should have received a copy of the GNU General Public License
538 +//  along with this software; if not, write to the Free Software
539 +//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
540 +//  USA.
541 +//
542 +
543 +//
544 +// VNCProxyConnectSocketFactory.java together with VNCProxyConnectSocket.java
545 +// implement an alternate way to connect to VNC servers via one or two
546 +// VNCProxy proxies supporting the VNCProxy CONNECT method.
547 +//
548 +
549 +import java.applet.*;
550 +import java.net.*;
551 +import javax.net.ssl.*;
552 +import java.io.*;
553 +
554 +class VNCProxyConnectSocketFactory implements SocketFactory {
555 +
556 +    SSLSocketFactory factory;
557 +    
558 +    public VNCProxyConnectSocketFactory() {
559 +       try {
560 +           SSLContext c = SSLContext.getInstance("SSL");
561 +           c.init(null,
562 +                  new TrustManager[] { new InvirtTrustManager() },
563 +                  null);
564 +           factory =
565 +               (SSLSocketFactory)c.getSocketFactory();
566 +       } catch (Exception e) {
567 +           e.printStackTrace();
568 +       }
569 +    }
570 +
571 +  public Socket createSocket(String host, int port, Applet applet)
572 +    throws IOException {
573 +
574 +    return createSocket(host, port,
575 +                       applet.getParameter("VMNAME"),
576 +                       applet.getParameter("AUTHTOKEN"));
577 +  }
578 +
579 +  public Socket createSocket(String host, int port, String[] args)
580 +    throws IOException {
581 +
582 +    return createSocket(host, port,
583 +                       readArg(args, "VMNAME"),
584 +                       readArg(args, "AUTHTOKEN"));
585 +  }
586 +
587 +  public Socket createSocket(String host, int port,
588 +                            String vmname, String authtoken)
589 +    throws IOException {
590 +
591 +    if (vmname == null || authtoken == null) {
592 +      System.out.println("Incomplete parameter list for VNCProxyConnectSocket");
593 +      return new Socket(host, port);
594 +    }
595 +
596 +    System.out.println("VNCProxy CONNECT via proxy " + host +
597 +                      " port " + port + " to vm " + vmname);
598 +    SSLSocket ssls = (SSLSocket)factory.createSocket(host, port);
599 +    ssls.startHandshake();
600 +    VNCProxyConnectSocketWrapper s =
601 +      new VNCProxyConnectSocketWrapper(ssls, vmname, authtoken);
602 +
603 +    return (Socket)s;
604 +  }
605 +
606 +  private String readArg(String[] args, String name) {
607 +
608 +    for (int i = 0; i < args.length; i += 2) {
609 +      if (args[i].equalsIgnoreCase(name)) {
610 +       try {
611 +         return args[i+1];
612 +       } catch (Exception e) {
613 +         return null;
614 +       }
615 +      }
616 +    }
617 +    return null;
618 +  }
619 +}
620 +
621 Index: invirt-vnc-client/VNCProxyConnectSocketWrapper.java
622 ===================================================================
623 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
624 +++ invirt-vnc-client/VNCProxyConnectSocketWrapper.java 2008-10-31 06:09:10.000000000 -0400
625 @@ -0,0 +1,60 @@
626 +//
627 +//  Copyright (C) 2002 Constantin Kaplinsky, Inc.  All Rights Reserved.
628 +//  Copyright 2007 MIT Student Information Processing Board
629 +//
630 +//  This is free software; you can redistribute it and/or modify
631 +//  it under the terms of the GNU General Public License as published by
632 +//  the Free Software Foundation; either version 2 of the License, or
633 +//  (at your option) any later version.
634 +//
635 +//  This software is distributed in the hope that it will be useful,
636 +//  but WITHOUT ANY WARRANTY; without even the implied warranty of
637 +//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
638 +//  GNU General Public License for more details.
639 +//
640 +//  You should have received a copy of the GNU General Public License
641 +//  along with this software; if not, write to the Free Software
642 +//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
643 +//  USA.
644 +//
645 +
646 +//
647 +// VNCProxySocket.java together with VNCProxySocketFactory.java
648 +// implement an alternate way to connect to VNC servers via one or two
649 +// VNCProxy proxies supporting the VNCProxy VNCCONNECT method.
650 +//
651 +
652 +import java.net.*;
653 +import java.io.*;
654 +
655 +class VNCProxyConnectSocketWrapper extends SocketWrapper {
656 +
657 +  public VNCProxyConnectSocketWrapper(Socket sock,
658 +                               String vmname, String authtoken)
659 +    throws IOException {
660 +
661 +    super(sock);
662 +
663 +    // Send the CONNECT request
664 +    getOutputStream().write(("CONNECTVNC " + vmname +
665 +                             " VNCProxy/1.0\r\nAuth-token: " + authtoken +
666 +                             "\r\n\r\n").getBytes());
667 +
668 +    // Read the first line of the response
669 +    DataInputStream is = new DataInputStream(getInputStream());
670 +    String str = is.readLine();
671 +
672 +    // Check the HTTP error code -- it should be "200" on success
673 +    if (!str.startsWith("VNCProxy/1.0 200 ")) {
674 +      if (str.startsWith("VNCProxy/1.0 "))
675 +        str = str.substring(13);
676 +      throw new IOException("Proxy reports \"" + str + "\"");
677 +    }
678 +
679 +    // Success -- skip remaining HTTP headers
680 +    do {
681 +      str = is.readLine();
682 +    } while (str.length() != 0);
683 +  }
684 +}
685 +