Document threading limitations and show multiprocessing example.
This commit is contained in:
+9
-6
@@ -28,6 +28,7 @@ def uniqueID():
|
|||||||
_seq_lock.release()
|
_seq_lock.release()
|
||||||
return seqno
|
return seqno
|
||||||
|
|
||||||
|
## @private
|
||||||
OPTIONAL_CALLBACKS = {
|
OPTIONAL_CALLBACKS = {
|
||||||
'connect':(P_NR_CONN,P_NOCONNECT),
|
'connect':(P_NR_CONN,P_NOCONNECT),
|
||||||
'hello':(P_NR_HELO,P_NOHELO),
|
'hello':(P_NR_HELO,P_NOHELO),
|
||||||
@@ -40,6 +41,7 @@ OPTIONAL_CALLBACKS = {
|
|||||||
'header':(P_NR_HDR,P_NOHDRS)
|
'header':(P_NR_HDR,P_NOHDRS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## @private
|
||||||
def decode_mask(bits,names):
|
def decode_mask(bits,names):
|
||||||
t = [ (s,getattr(milter,s)) for s in names]
|
t = [ (s,getattr(milter,s)) for s in names]
|
||||||
nms = [s for s,m in t if bits & m]
|
nms = [s for s,m in t if bits & m]
|
||||||
@@ -47,6 +49,13 @@ def decode_mask(bits,names):
|
|||||||
if bits: nms += hex(bits)
|
if bits: nms += hex(bits)
|
||||||
return nms
|
return nms
|
||||||
|
|
||||||
|
## @fn set_flags(flags)
|
||||||
|
# @brief Enable optional %milter actions.
|
||||||
|
# Certain %milter actions need to be enabled before calling milter.runmilter()
|
||||||
|
# or they throw an exception.
|
||||||
|
# @param flags Bit ored mask of optional actions to enable
|
||||||
|
|
||||||
|
|
||||||
## Class decorator to enable optional protocol steps.
|
## Class decorator to enable optional protocol steps.
|
||||||
# P_SKIP is enabled by default when supported, but
|
# P_SKIP is enabled by default when supported, but
|
||||||
# applications may wish to enable P_HDR_LEADSPC
|
# applications may wish to enable P_HDR_LEADSPC
|
||||||
@@ -538,12 +547,6 @@ class Milter(Base):
|
|||||||
# change in configuration.
|
# change in configuration.
|
||||||
factory = Milter
|
factory = Milter
|
||||||
|
|
||||||
## @fn set_flags(flags)
|
|
||||||
# @brief Enable optional %milter actions.
|
|
||||||
# Certain %milter actions need to be enabled before calling milter.runmilter()
|
|
||||||
# or they throw an exception.
|
|
||||||
# @param flags Bit ored mask of optional actions to enable
|
|
||||||
|
|
||||||
## @private
|
## @private
|
||||||
# @brief Connect context to connection instance and return enabled callbacks.
|
# @brief Connect context to connection instance and return enabled callbacks.
|
||||||
def negotiate_callback(ctx,opts):
|
def negotiate_callback(ctx,opts):
|
||||||
|
|||||||
@@ -69,8 +69,7 @@ Not-so-quick Installation
|
|||||||
First install Sendmail. Make sure you read libmilter/README in the Sendmail
|
First install Sendmail. Make sure you read libmilter/README in the Sendmail
|
||||||
source directory, and make sure you enable libmilter before you build. The
|
source directory, and make sure you enable libmilter before you build. The
|
||||||
8.11 series had libmilter marked as FFR (For Future Release); 8.12
|
8.11 series had libmilter marked as FFR (For Future Release); 8.12
|
||||||
officially
|
officially supports libmilter, but it's still not built by default.
|
||||||
supports libmilter, but it's still not built by default.
|
|
||||||
|
|
||||||
Install Python, and enable threading in Modules/Setup.
|
Install Python, and enable threading in Modules/Setup.
|
||||||
|
|
||||||
|
|||||||
+18
-1
@@ -1,6 +1,5 @@
|
|||||||
## @mainpage Writing Milters in Python
|
## @mainpage Writing Milters in Python
|
||||||
#
|
#
|
||||||
#
|
|
||||||
# At the lowest level, the <code>milter</code> module provides a thin wrapper
|
# At the lowest level, the <code>milter</code> module provides a thin wrapper
|
||||||
# around the <a href="https://www.milter.org/developers/api/index"> sendmail
|
# around the <a href="https://www.milter.org/developers/api/index"> sendmail
|
||||||
# libmilter API</a>. This API lets you register callbacks for a number of
|
# libmilter API</a>. This API lets you register callbacks for a number of
|
||||||
@@ -34,3 +33,21 @@
|
|||||||
# The <code>mime</code> module provides a wrapper for the Python email package
|
# The <code>mime</code> module provides a wrapper for the Python email package
|
||||||
# that fixes some bugs, and simplifies modifying selected parts of a MIME
|
# that fixes some bugs, and simplifies modifying selected parts of a MIME
|
||||||
# message.
|
# message.
|
||||||
|
#
|
||||||
|
# @section threading
|
||||||
|
#
|
||||||
|
# The libmilter library which pymilter wraps
|
||||||
|
# <a href="https://www.milter.org/developers/overview#SignalHandling">handles
|
||||||
|
# all signals</a> itself, and expects to be called from a single main thread.
|
||||||
|
# It handles SIGTERM, SIGHUP, and SIGINT, mapping the first two to
|
||||||
|
# <a href="https://www.milter.org/developers/api/smfi_stop">smfi_stop</a>
|
||||||
|
# and the last to an internal ABORT.
|
||||||
|
#
|
||||||
|
# If you use python threads or threading modules, then signal handling gets
|
||||||
|
# confused. Threads may still be useful, but you may need to provide an
|
||||||
|
# alternate means of causing graceful shutdown.
|
||||||
|
#
|
||||||
|
# You may find the
|
||||||
|
# <a href="http://docs.python.org/release/2.6.6/library/multiprocessing.html">
|
||||||
|
# multiprocessing</a> module useful. It can be a drop-in
|
||||||
|
# replacement for threading as illustrated in @ref milter-template.py.
|
||||||
|
|||||||
+20
-4
@@ -14,7 +14,13 @@ import email
|
|||||||
import sys
|
import sys
|
||||||
from socket import AF_INET, AF_INET6
|
from socket import AF_INET, AF_INET6
|
||||||
from Milter.utils import parse_addr
|
from Milter.utils import parse_addr
|
||||||
|
if True:
|
||||||
|
from multiprocessing import Process as Thread, Queue
|
||||||
|
else:
|
||||||
|
from threading import Thread
|
||||||
|
from Queue import Queue
|
||||||
|
|
||||||
|
logq = Queue(maxsize=4)
|
||||||
|
|
||||||
class myMilter(Milter.Base):
|
class myMilter(Milter.Base):
|
||||||
|
|
||||||
@@ -117,16 +123,24 @@ class myMilter(Milter.Base):
|
|||||||
## === Support Functions ===
|
## === Support Functions ===
|
||||||
|
|
||||||
def log(self,*msg):
|
def log(self,*msg):
|
||||||
print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S'),self.id),
|
logq.put((msg,self.id,time.time()))
|
||||||
|
|
||||||
|
def background():
|
||||||
|
while True:
|
||||||
|
t = logq.get()
|
||||||
|
if not t: break
|
||||||
|
msg,id,ts = t
|
||||||
|
print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S',time.localtime(ts)),id),
|
||||||
# 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
|
# 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
|
||||||
for i in msg: print i,
|
for i in msg: print i,
|
||||||
print
|
print
|
||||||
|
|
||||||
|
|
||||||
## ===
|
## ===
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
socketname = "/tmp/pythonsock"
|
bt = Thread(target=background)
|
||||||
|
bt.start()
|
||||||
|
socketname = "/home/stuart/pythonsock"
|
||||||
timeout = 600
|
timeout = 600
|
||||||
# Register to have the Milter factory create instances of your class:
|
# Register to have the Milter factory create instances of your class:
|
||||||
Milter.factory = myMilter
|
Milter.factory = myMilter
|
||||||
@@ -136,7 +150,9 @@ def main():
|
|||||||
Milter.set_flags(flags) # tell Sendmail which features we use
|
Milter.set_flags(flags) # tell Sendmail which features we use
|
||||||
print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
|
print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
Milter.runmilter("test",socketname,timeout)
|
Milter.runmilter("pythonfilter",socketname,timeout)
|
||||||
|
logq.put(None)
|
||||||
|
bt.join()
|
||||||
print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
|
print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+4
-2
@@ -13,8 +13,9 @@ License: GPLv2+
|
|||||||
Group: Development/Libraries
|
Group: Development/Libraries
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
|
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
|
||||||
Url: http://www.bmsi.com/python/milter.html
|
Url: http://www.bmsi.com/python/milter.html
|
||||||
Requires: %{pythonbase}, sendmail >= 8.13
|
# python-2.6.4 gets RuntimeError: not holding the import lock
|
||||||
# Need python2.4 specific pydns, not the version for system python
|
Requires: %{pythonbase} >= 2.6.5, sendmail >= 8.13
|
||||||
|
# Need python2.6 specific pydns, not the version for system python
|
||||||
Requires: %{pythonbase}-pydns
|
Requires: %{pythonbase}-pydns
|
||||||
# Needed for callbacks, not a core function but highly useful for milters
|
# Needed for callbacks, not a core function but highly useful for milters
|
||||||
BuildRequires: ed, %{pythonbase}-devel, sendmail-devel >= 8.13
|
BuildRequires: ed, %{pythonbase}-devel, sendmail-devel >= 8.13
|
||||||
@@ -77,6 +78,7 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.5-1
|
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.5-1
|
||||||
- Print milter.error for invalid callback return type.
|
- Print milter.error for invalid callback return type.
|
||||||
(Since stacktrace is empty, the TypeError exception is confusing.)
|
(Since stacktrace is empty, the TypeError exception is confusing.)
|
||||||
|
- Fix milter-template.py
|
||||||
|
|
||||||
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.4-1
|
* Wed Mar 02 2010 Stuart Gathman <stuart@bmsi.com> 0.9.4-1
|
||||||
- Handle IP6 in Milter.utils.iniplist()
|
- Handle IP6 in Milter.utils.iniplist()
|
||||||
|
|||||||
Reference in New Issue
Block a user