Skip to content

Instantly share code, notes, and snippets.

@jackyyf
Created November 1, 2014 17:28
Show Gist options
  • Save jackyyf/744ef802c26f29f64cfb to your computer and use it in GitHub Desktop.
Save jackyyf/744ef802c26f29f64cfb to your computer and use it in GitHub Desktop.
Gist by paste.py @ 2014-11-02 01:28:06.038742
#!/usr/bin/python3
import sys
import threading
import socket
import time
def usage():
print('Usage:', sys.argv[0], '[Threads]')
class err(Exception):
pass
def getline(socket):
ch = ' '
buff = ''.encode("ascii")
first = True
#sys.stderr.write('Debug:')
while True:
ch = socket.recv(1)
#sys.stderr.write(str(ch))
if len(ch) == 0 and first:
raise err
first = False
if ch == '\n'.encode("ascii") or len(ch) == 0:
break
elif ch == '\r'.encode("ascii"):
socket.recv(1)
break
else:
buff = buff + ch
if first and len(ch) == 0:
raise err
print('Client:', buff)
return buff
class Queue(object):
def __init__(self):
self.data = []
self.flag = False
def get(self):
while self.flag:
time.sleep(0.05)
self.flag = True
try:
t = self.data[0]
del self.data[0]
self.flag = False
return t
except:
self.flag = False
return False
def put(self, obj):
while self.flag:
time.sleep(0.05)
self.flag = True
self.data.append(obj)
self.flag = False
def empty(self):
return len(self.data) == 0
def size(self):
return len(self.data)
class Server(object):
def __init__(self, port = 25, thread = 10):
self.thread = thread
self.filebase = '/home/mails/'
print('Server Loading...')
self.ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
self.ssock.bind(('', port))
except:
print('Unable to bind to port', port, ',somebody is using this port?')
exit()
print('Bind to port', port, 'successfully')
self.ssock.listen(thread * 2)
print('Start listening on port', port)
self.running = True
def mainThread(self):
self.connection = Queue()
self.threads = []
print('Starting', server.thread, 'thread(s)...')
for _ in range(1, self.thread + 1):
self.threads.append(threading.Thread(target = self.processThread, args = (_, )))
self.threads[_ - 1].start()
print('Threads started.')
while self.running:
try:
(conn, addr) = self.ssock.accept()
except:
exit()
self.connection.put(conn)
print('['+addr[0]+':'+str(addr[1])+'] connected, awaiting process...')
print('Currently Load: '+str(self.connection.size())+' connection pending')
def processUnit(self, socket):
socket.sendall('220 labs.jackyyf.com SMTP Server Ready\r\n'.encode('ascii'))
print('Server: 220 labs.jackyyf.com SMTP Server Ready')
try:
st = getline(socket)
except err:
return True
try:
lst = st.split(' '.encode("ascii"), 1)
command = lst[0].upper()
domain = lst[1]
except:
domain = ''.encode("ascii")
command = st.upper()
if (command != 'EHLO'.encode("ascii")) and (command != 'HELO'.encode("ascii")):
print(command)
return True
socket.send('250 labs.jackyyf.com greets '.encode('ascii') + domain + '\r\n'.encode('ascii'))
print('Server:', '250 labs.jackyyf.com greets '.encode('ascii') + domain + '\r\n'.encode('ascii'))
while True:
try:
st = getline(socket)
except err:
break
try:
lst = st.split(' '.encode("ascii"), 1)
command = lst[0].upper()
except:
command = st.upper()
if len(command) == 0:
continue
if command == 'QUIT'.encode("ascii") or command == b'RSET':
break
elif command == 'RCPT'.encode("ascii"):
socket.sendall('250 OK\r\n'.encode('ascii'))
print('Server: 250 OK')
elif command == 'MAIL'.encode("ascii"):
socket.sendall('250 OK\r\n'.encode('ascii'))
print('Server: 250 OK')
continue
elif command == 'DATA'.encode("ascii"):
socket.sendall('354 End Transmission with <CRLF>.<CRLF>\r\n'.encode('ascii'))
print('Server: 354 End Transmission with <CRLF>.<CRLF>')
try:
cntf = open(self.filebase + '.cnt', 'r')
cnt = int(cntf.readline()) + 1
cntf.close()
cntf = open(self.filebase + '.cnt', 'w')
cntf.write(str(cnt))
cntf.close()
except:
cnt = 0
cntf = open(self.filebase + '.cnt', 'w')
cntf.write(str(cnt))
cntf.close()
f = open(self.filebase + str(cnt), 'wb')
while True:
line = getline(socket)
if line == b'.':
f.close()
socket.sendall('250 Saved\r\n'.encode('ascii'))
print('Server: 250 Saved')
return True
break
f.write(line+'\n'.encode('utf-8'))
else :
socket.sendall('500 Error...\r\n'.encode('ascii'))
print('Server: 500 Error...')
break
socket.sendall('221 Goodbye.\r\n'.encode('ascii'))
print('Server 221 Goodbye.')
return True
def processThread(self, pid):
while self.running:
if self.connection.empty():
time.sleep(0.5)
else:
socket = self.connection.get()
if not socket:
continue
print('Thread', pid, 'processing...')
while not(self.processUnit(socket)):
continue
socket.close()
print('Thread', pid, 'finished.')
def close(self):
print('Server shutting down...')
self.running = False
self.ssock.close()
if __name__ == '__main__':
if len(sys.argv) == 2:
try:
threadcnt = int(sys.argv[1]);
except:
usage()
exit()
if str(threadcnt) != sys.argv[1]:
usage()
exit()
elif len(sys.argv) > 2:
usage()
exit()
else:
threadcnt = 10
print('Will use 10 threads as default.')
server = Server(thread = threadcnt)
serverThread = threading.Thread(target = server.mainThread)
serverThread.start()
while 1:
command = input().strip().upper()
if command == 'SHUTDOWN' or command == 'STOP':
server.close()
time.sleep(0.5)
exit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment