Milter 协议(2)
先贴一段 twisted 框架下实现 Milter 协议解析的核心函数 :)
-
class MilterServer(Protocol):
-
def init_dataReceived(self):
-
self.lastdata = ""
-
self.len = 0
-
-
def __init__(self):
-
self.init_dataReceived()
-
-
# 注意:实践中发现一次 recv 中包括了两个完整的 packet; 而且理论上存在
-
# 一个 packet 需要两次 recv 才能取出来的可能
-
def dataReceived(self, data):
-
if len(data): print len(data)
-
if self.lastdata != "":
-
data = self.lastdata + data
-
if self.len != 0:
-
if self.len <= len(data):
-
next = data[self.len:]
-
self.proc(data[:self.len])
-
self.init_dataReceived()
-
if len(next) > 0:
-
self.dataReceived(next)
-
else: #继续等待输入
-
self.lastdata = data
-
else:
-
if len(data) < 4:
-
self.lastdata = data
-
else:
-
self.len = struct.unpack(">i", data[:4])[0]
-
self.lastdata = data[4:]
-
print self.len, len(self.lastdata)
-
self.dataReceived("")
-
-
def proc(self, data):
-
...
-
...
上述代码在线上曾短时间的跑了跑,协议解析的逻辑部分应该是没有问题滴(稳妥起见,目前我们实际用的还是 libmilter 的 python binding)
实现 Milter Server 需要注意的一个事情就是:和 SMTP 一样,是要能支持在一次
connection 中完成多次 transaction 的!!还有 abort 命令,实际上就是一次 RSET 请求。
由于相当然的以为 eom (EndOfMessage) 事件后会话就应该结束了,结果碰到了问题怎么也想不出头绪,绕了一个多星期的弯路才找到程序的毛病所在。
另外在 Postfix 实现里面,自定义的 replymsg 的格式要求严格遵循 RFC,格式是:
"%s %s %s" % (code, Enhanced-Status-Code, msg)
E-S-C 的第一个数字要和 code 的第一个数字保持一致,见 postfix 源代码 milter8.c 里 SMFIR_REPLYCODE 的处理
仔细阅读了一下 sendmail 的 Milter Technical Overview,原来在 DATA 阶段,MTA 是需要把信件整个接受下来以后,再依次发给各个 Milter 的,而且是给一个 Milter 完整的传送完一个 message 后,再接着向下一个 Milter 发送。以前一直理解有误,觉得应该是 on-the-fly 的把数据依次传递给 Milter,这样效率最高.
最新评论