1#!/usr/bin/python
2
3import os
4import smtplib
5import thread
6import time
7import sys
8import mailbox
9import string
10from optparse import OptionParser
11
12
13# default host
14HOST = "localhost"
15
16# default port
17PORT = 10024
18
19# default number of concurrent lmtp clients to create
20CLIENTS = 20
21
22# default number of messages to send per lmtp client
23MESSAGES = 100
24
25# default mailbox
26MAILBOX = os.path.join(os.path.dirname(__file__), "testbox")
27
28# username
29USERNAME = "testuser1"
30
31# number of messages to send per session
32RECONNECT = 5
33
34DEBUG = False
35
36tlocks = {}
37tdict = {}
38
39
40class LMTPClient:
41    def __init__(self, hostname, port):
42        self._hostname = hostname
43        self._port = port
44        self.conn = smtplib.SMTP(self._hostname, self._port)
45        self.conn.set_debuglevel(DEBUG)
46
47    def lhlo(self, hostname):
48        return self.conn.docmd('LHLO', hostname)
49
50    def send(self, fromaddr, toaddrs, message):
51        r = self.conn.mail(fromaddr)
52        assert(r[0] == 250)
53        r = self.conn.rcpt(toaddrs)
54        assert(r[0] == 250)
55        r = self.conn.data(message)
56        assert(r[0] == 215)
57        r = self.conn.rset()
58        assert(r[0] == 250)
59
60    def quit(self):
61        return self.conn.quit()
62
63
64def frontloader(*args):
65    tid = args[0]
66    tlocks[tid].acquire()
67    c = LMTPClient(HOST, PORT)
68    r = c.lhlo('host')
69    assert(r[0] == 250)
70    mb = mailbox.mbox(MAILBOX, factory=None, create=False)
71    i = 1
72    while i < MESSAGES:
73        for msg in mb.values():
74            addr = string.split(msg.get_from())[0]
75            c.send(addr, USERNAME, msg.as_string())
76            if not i % RECONNECT:
77                c.quit()
78                c = LMTPClient(HOST, PORT)
79                c.lhlo('host')
80                sys.stdout.write('_')
81            else:
82                sys.stdout.write('.')
83            sys.stdout.flush()
84            i = i + 1
85            if i >= MESSAGES:
86                break
87
88    c.quit()
89    tlocks[tid].release()
90
91if __name__ == '__main__':
92
93    parser = OptionParser()
94    parser.add_option("-H", "--host", dest="HOST",
95                      help="Hostname to connect to [default: %default]",
96                      default=HOST)
97    parser.add_option("-P", "--port", dest="PORT",
98                      help="Port to connect to [default: %default]",
99                      default=PORT)
100    parser.add_option("-c", "--clients", dest="CLIENTS",
101                      help="Number of concurrent clients [default: %default]",
102                      default=CLIENTS)
103    parser.add_option("-m", "--mailbox", dest="MAILBOX",
104                      help="mailbox to feed to LMTP [default: %default]",
105                      default=MAILBOX)
106    parser.add_option("-n", "--messages", dest="MESSAGES",
107                      default=MESSAGES,
108                      help="number of messsages clients sends [default: %default]")
109    parser.add_option("-u", "--username", dest="USERNAME",
110                      default=USERNAME,
111                      help="deliver to username [default: %default]")
112    parser.add_option("-r", "--reconnect", dest="RECONNECT",
113                      default=RECONNECT,
114                      help="Number of messages to send before " \
115                        "reconnecting [default: %default]")
116
117    (options, args) = parser.parse_args()
118
119    HOST = options.HOST
120    PORT = int(options.PORT)
121    CLIENTS = int(options.CLIENTS)
122    MESSAGES = int(options.MESSAGES)
123    MAILBOX = options.MAILBOX
124    USERNAME = options.USERNAME
125    RECONNECT = int(options.RECONNECT)
126
127    # start the client threads
128    for i in range(0, CLIENTS):
129        tlocks[i] = thread.allocate_lock()
130
131    print "Connect to LMTP server: %s:%d" % (HOST, PORT)
132    print "Starting %d clients" % CLIENTS
133    print "Deliver %d messages per client to %s" % (MESSAGES, USERNAME)
134    print "Use messages from %s" % MAILBOX
135
136    for i in range(0, CLIENTS):
137        id = thread.start_new_thread(frontloader, (i,))
138        tdict[i] = id
139        time.sleep(1)
140
141    time.sleep(5)
142    # wait for the clients to finish
143    while 1:
144        for i in range(0, CLIENTS):
145            done = []
146            if i in tdict:
147                r = tlocks[i].acquire(0)
148                if r:
149                    sys.stdout.write('Q')
150                    sys.stdout.flush()
151                    tlocks[i].release()
152                    done.append(i)
153            for x in done:
154                del(tlocks[x])
155                del(tdict[x])
156        if len(tdict.items()) == 0:
157            break
158        time.sleep(1)
159
160
161#EOF
162