public synchronized void establish() throws IOException, InterruptedException {
		if (this.isActive()) {
			Utilities.log("closing existing connection");
			this.close(false); // we are re-connecting
		}
		Utilities.log("Connecting to " + this.addr.getAddress() + ":" + this.addr.getPort());
		this.socket = createInsecureSSLConnection(this.addr);
		if (this.socket != null) {
			this.isConnected = true;
			this.isClosing = false;

			Charset charset = Charset.forName("UTF-8");

			this.reader = new InputStreamReader(socket.getInputStream(), charset);
			this.writer = new OutputStreamWriter(this.socket.getOutputStream(), charset);
			this.receiverThread = this.createReceiverThread(this.reader);
			this.writerThread = this.createWriterThread(this.writer);

			Utilities.log("Connection established to " + this.addr.getAddress() + ":" + this.addr.getPort());

			this.write(String.format("SESSION|CONFIG|%d|END", PROTOCOL_VERSION));

			Certificate[] servercerts = ((SSLSocket) this.socket).getSession().getPeerCertificates();
			if (servercerts.length > 0) {
				Utilities.log("Fixing certificates");
				try {
					this.peerCertificate = this.fixCertificate(servercerts[0].getEncoded());
				} catch (CertificateEncodingException e) {
					e.printStackTrace();
					this.close();
					throw new IOException("peer certificate encoding problem");
				}
				Utilities.log("Certificates fixed and saved.");
			} else {
				Utilities.log(Level.SEVERE, "unable to get peer certificate");
				this.close();
				throw new IOException("unable to get peer certificate");
			}

			this.isConnected = this.socket.isConnected();

		}
	}