Created
November 1, 2014 17:28
-
-
Save jackyyf/744ef802c26f29f64cfb to your computer and use it in GitHub Desktop.
Gist by paste.py @ 2014-11-02 01:28:06.038742
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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