postfix_daemon 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +69 -0
- data/lib/postfix_daemon.rb +137 -0
- data/lib/postfix_daemon/version.rb +3 -0
- data/sample/postfix_daemon-sample.rb +8 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 223491e9a76a10604afa95773510d3a217345f67d33839d4a2accef7c8202d67
|
4
|
+
data.tar.gz: 5ae079ffdb492bc9fb52c80e793cafcb1ceedb956237b1418b05dcfde93c967a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3cd7e3a6715ecb3f6efec02901c1835453b7763c4e9df0c5522eb0e04a1d3a37a6bd45aff22ae051278fe684b3c6000a12d981b77a141d2ed47f5aaca4434ee0
|
7
|
+
data.tar.gz: 5e6076d6dd6cc709ba2417569a581c6e7b95f83c269c8daa1bbeb0259c20db4e9ede45ff68d3e038f2b8e0267bdf661b0bfefb48b148802455ce3d5a6fe2f87d
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# PostfixDaemon
|
2
|
+
|
3
|
+
Postfixのデーモンプログラムを作るためのライブラリです。
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'postfix_daemon'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install postfix_daemon
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
プログラムを書きます。
|
24
|
+
|
25
|
+
入力を大文字に変換して返すプログラムの例:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
#!/path/to/ruby
|
29
|
+
|
30
|
+
require 'postfix_daemon'
|
31
|
+
|
32
|
+
# エラー終了してもどこにも出力されないのでリダイレクトしといた方がよさそう
|
33
|
+
$stderr.reopen("/tmp/error.log", "a+")
|
34
|
+
|
35
|
+
PostfixDaemon.start do |socket, addr|
|
36
|
+
socket.puts "you are #{addr.inspect}"
|
37
|
+
while s = socket.gets
|
38
|
+
s = s.force_encoding("utf-8").scrub
|
39
|
+
socket.puts s.upcase
|
40
|
+
end
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
プログラムを /usr/lib/postfix/sbin に置きます。
|
45
|
+
|
46
|
+
```
|
47
|
+
# cp hoge.rb /usr/lib/postfix/sbin/hoge
|
48
|
+
# chmod +x /usr/lib/postfix/sbin/hoge
|
49
|
+
```
|
50
|
+
|
51
|
+
master.cf に追加:
|
52
|
+
|
53
|
+
```
|
54
|
+
12345 inet - - - - - hoge
|
55
|
+
```
|
56
|
+
|
57
|
+
postfix reload
|
58
|
+
|
59
|
+
```
|
60
|
+
# postfix reload
|
61
|
+
```
|
62
|
+
|
63
|
+
```
|
64
|
+
% nc localhost 12345
|
65
|
+
you are #<Addrinfo: 127.0.0.1:59312 TCP>
|
66
|
+
abcdefg
|
67
|
+
ABCDEFG
|
68
|
+
^C
|
69
|
+
```
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "postfix_daemon/version"
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'socket'
|
5
|
+
require 'syslog'
|
6
|
+
|
7
|
+
# Postfix daemon program
|
8
|
+
class PostfixDaemon
|
9
|
+
DEFAULT_MAX_IDLE = 100
|
10
|
+
DEFAULT_MAX_USE = 100
|
11
|
+
|
12
|
+
MASTER_STATUS_FD = 5
|
13
|
+
MASTER_LISTEN_FD = 6
|
14
|
+
|
15
|
+
# @param args [Array<String>] command line arguments
|
16
|
+
# @yield [socket, addr]
|
17
|
+
# @yieldparam socket [Socket]
|
18
|
+
# @yieldparam addr [Addrinfo]
|
19
|
+
def self.start(args=ARGV, &block)
|
20
|
+
self.new(args).run(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param args [Array<String>] command line arguments
|
24
|
+
# @param setup [Proc] called on starting
|
25
|
+
# @param service [Proc] called when client connect
|
26
|
+
def initialize(args, setup: nil, service: nil)
|
27
|
+
@args = args.dup
|
28
|
+
@setup = setup
|
29
|
+
@service = service
|
30
|
+
@nsocks = nil
|
31
|
+
@max_idle = nil
|
32
|
+
@max_use = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# @yield [socket, addr]
|
36
|
+
# @yieldparam socket [Socket]
|
37
|
+
# @yieldparam addr [Addrinfo]
|
38
|
+
def run(&block)
|
39
|
+
parse_args
|
40
|
+
setup
|
41
|
+
@setup.call if @setup
|
42
|
+
@service = block if block
|
43
|
+
raise 'block required' unless @service
|
44
|
+
main
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# general Postfix server options:
|
50
|
+
# -c master.cf chroot is y, so this process should chroot to queue_directory.
|
51
|
+
# -d not daemon mode
|
52
|
+
# -D debug mode
|
53
|
+
# -i # set max_idle=#
|
54
|
+
# -l master.cf maxproc is 1
|
55
|
+
# -m # set max_use=#
|
56
|
+
# -n name master.cf service name
|
57
|
+
# -o param=value param=value
|
58
|
+
# -s # number of server sockets
|
59
|
+
# -S stdin stream mode
|
60
|
+
# -t type master.cf service type (inet, unix, pass)
|
61
|
+
# -u master.cf unpriv is y, so this process should setuid to mail_owner.
|
62
|
+
# -v verbose mode
|
63
|
+
# -V message to stderr
|
64
|
+
# -z master.cf maxproc is 0
|
65
|
+
#
|
66
|
+
# This library support only '-s', '-i', '-m' option.
|
67
|
+
def parse_args
|
68
|
+
@args.extend OptionParser::Arguable
|
69
|
+
opts = @args.getopts('cdDi:lm:n:o:s:St:uvVz')
|
70
|
+
@nsocks = opts['s'] ? opts['s'].to_i : 1
|
71
|
+
@max_idle = opts['i'] ? opts['i'].to_i : DEFAULT_MAX_IDLE
|
72
|
+
@max_use = opts['m'] ? opts['m'].to_i : DEFAULT_MAX_USE
|
73
|
+
$VERBOSE = true if opts['v']
|
74
|
+
end
|
75
|
+
|
76
|
+
def setup
|
77
|
+
Syslog.open(File.basename($0), nil, Syslog::LOG_MAIL) unless Syslog.opened?
|
78
|
+
@socks = []
|
79
|
+
fd = MASTER_LISTEN_FD
|
80
|
+
@nsocks.times do
|
81
|
+
@socks.push Socket.for_fd(fd)
|
82
|
+
fd += 1
|
83
|
+
end
|
84
|
+
@stat_fd = IO.for_fd(MASTER_STATUS_FD)
|
85
|
+
@generation = ENV['GENERATION'].to_i(8)
|
86
|
+
end
|
87
|
+
|
88
|
+
def log(message)
|
89
|
+
Syslog.log(Syslog::LOG_INFO, message) if $VERBOSE
|
90
|
+
end
|
91
|
+
|
92
|
+
def main
|
93
|
+
used_count = 0
|
94
|
+
while used_count < @max_use
|
95
|
+
sock, addr = accept
|
96
|
+
break unless sock
|
97
|
+
to_master(0) or break
|
98
|
+
used_count += 1
|
99
|
+
begin
|
100
|
+
@service.call(sock, addr)
|
101
|
+
ensure
|
102
|
+
sock.close rescue nil
|
103
|
+
to_master(1) or break
|
104
|
+
end
|
105
|
+
end
|
106
|
+
rescue => e
|
107
|
+
log "#{e.class}: #{e.message}"
|
108
|
+
raise e
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Socket, Addrinfo]
|
112
|
+
def accept
|
113
|
+
while true
|
114
|
+
rs, = select(@socks + [@stat_fd], nil, nil, @max_idle)
|
115
|
+
unless rs
|
116
|
+
log 'idle timeout'
|
117
|
+
return nil
|
118
|
+
end
|
119
|
+
if rs.include? @stat_fd
|
120
|
+
log 'master disconnect'
|
121
|
+
return nil
|
122
|
+
end
|
123
|
+
sock, addr = rs.first.accept_nonblock(exception: false)
|
124
|
+
return sock, addr unless sock == :wait_readable
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# @param x [Integer]
|
129
|
+
# @return [Boolean]
|
130
|
+
def to_master(x)
|
131
|
+
@stat_fd.syswrite [Process.pid, @generation, x].pack('iIi')
|
132
|
+
return true
|
133
|
+
rescue Errno::EPIPE
|
134
|
+
log 'master disconnect'
|
135
|
+
return false
|
136
|
+
end
|
137
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: postfix_daemon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TOMITA Masahiro
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Postfix daemon
|
56
|
+
email:
|
57
|
+
- tommy@tmtm.org
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- README.md
|
63
|
+
- lib/postfix_daemon.rb
|
64
|
+
- lib/postfix_daemon/version.rb
|
65
|
+
- sample/postfix_daemon-sample.rb
|
66
|
+
homepage: https://github.com/tmtm/postfix_daemon
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.7.4
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Postfix daemon
|
90
|
+
test_files: []
|