#!/usr/bin/env python

import sys
import socket
import select


class ForwardServer:
	"""Forward-proxy server"""
	def __init__(self, host, port):
		self.host = host
		self.port = int(port)
		self.forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

	def start_server(self):
		try:
			self.forward.connect((self.host, self.port))
			return self.forward
		except Exception as e:
			print(e)
			return False


class ServerConnection:
	"""For server connection and transmission of data"""

	BUFFER_SIZE = 1024
	DELAY = 0.001
	MAX_CONNECTIONS = 100
	input_list = []
	channels = {}
	
	def __init__(self, host, port = 9876):
		self.host = host
		self.port = int(port)
		self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		self.server.bind((self.host, self.port))
		self.server.listen(self.MAX_CONNECTIONS)

	def listening_loop(self):
		self.input_list.append(self.server)
		while True:
			try:
				readlist, writelist, exceptlist = select.select(self.input_list, [], [], self.DELAY)
			except Exception as e:
				print(e)
				break
			for ready_server in readlist:
				if ready_server == self.server:
					self.on_accept()
					break
				self.data = ready_server.recv(self.BUFFER_SIZE)
				if len(self.data):
					self.on_recv(ready_server)
				else:
					self.on_close(ready_server)
					break

	def on_accept(self):
		#forward_sock = ForwardServer(self.host, self.port).start_server()
		client_sock, client_addr = self.server.accept()
		self.input_list.append(client_sock)
		self.channels[client_sock] = client_addr[1]
		print("{}:{} has connected.".format(client_addr[0], client_addr[1]))
		print(client_sock.getpeername())
		# if forward_sock:
		# 	print("{} has connected.".format(client_addr))
		# 	self.input_list.append(client_sock)
		# 	self.input_list.append(forward_sock)
		# 	self.channels[client_sock] = forward_sock
		# 	self.channels[forward_sock] = client_sock
		# else:
		# 	print("Could not establish connection with server.")
		# 	print("Closing connection with client {}.".format(client_addr))
		# 	client_sock.close()


	def on_recv(self, dest):
		self.channels[dest].send(self.data)

	def on_close(self, dest):
		print("{} has disconnected.".format(dest.getpeername()))
		self.input_list.remove(dest)
		#self.input_list.remove(self.channels[dest])
		#self.channels[dest].close()
		#del self.channels[self.channels[out]]
		del self.channels[dest]
		dest.close()

	def start_server(self):
		try:
			self.listening_loop()
		except KeyboardInterrupt:
			print("\nStopping server...")
			self.server.close()
			sys.exit(0)


class ClientConnection:
	"""For client connection"""
	
	def __init__(self, host, port = 9876):
		self.host = host
		self.port = int(port)
		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # create TCP socket

	def connect_to_server(self):
		try:
			self.sock.connect((self.host, self.port))
		except KeyboardInterrupt:
			print("\nStopping client...")
			self.sock.close()
			sys.exit(0)

@@ -506,12 +506,12 @@
 E = 
-1024
+4096
 %0A%09DE
@@ -1593,19 +1593,16 @@
 ent_addr
-%5B1%5D
 %0A%09%09print
@@ -1609,11 +1609,8 @@
 (%22%7B%7D
-:%7B%7D
  has
@@ -1644,62 +1644,8 @@
 addr
-%5B0%5D, client_addr%5B1%5D))%0A%09%09print(client_sock.getpeername(
 ))%0A%09
@@ -2079,24 +2079,81 @@
 elf, dest):%0A
+%09%09print(%22Received from %7B%7D:%5Cn%7B%7D%22.format(dest, self.data))%0A
 %09%09self.chann
@@ -2166,16 +2166,19 @@
 st%5D.send
+all
 (self.da
@@ -2702,32 +2702,49 @@
 ost, port = 9876
+, username = 'me'
 ):%0A%09%09self.host =
@@ -2765,32 +2765,59 @@
 ort = int(port)%0A
+%09%09self.username = username%0A
 %09%09self.sock = so
@@ -2967,16 +2967,164 @@
 .port))%0A
+%09%09%09line = input(str(self.username) + %22%3E %22)%0A%09%09%09while line.lower() != %22exit%22:%0A%09%09%09%09self.sock.sendall(line)%0A%09%09%09%09line = input(str(self.username) + %22%3E %22)%0A
 %09%09except
@@ -3172,24 +3172,24 @@
 client...%22)%0A
-
 %09%09%09self.sock
@@ -3189,31 +3189,42 @@
 lf.sock.close()%0A
+%09%09finally:%0A
 %09%09%09sys.exit(0)%0A

Allow clients to send data to the server