1
2
3
4local type , tostring , setmetatable = type , tostring , setmetatable
5local min = math . min
6local format = string . format
7
8local socket = socket or package . loaded . socket or require ( " socket.core " )
9
10local connect = socket . connect
11local tcp4 = socket . tcp4
12local tcp6 = socket . tcp6
13local getaddrinfo = socket . dns . getaddrinfo
14
15local defaulthost = " 0.0.0.0 "
16
17local function report ( fmt , first , ... )
18 if logs then
19 report = logs and logs . reporter ( " socket " )
20 report ( fmt , first , ... )
21 elseif fmt then
22 fmt = " socket: " . . fmt
23 if first then
24 print ( format ( fmt , first , ... ) )
25 else
26 print ( fmt )
27 end
28 end
29end
30
31socket . report = report
32
33function socket . connect4 ( address , port , laddress , lport )
34 return connect ( address , port , laddress , lport , " inet " )
35end
36
37function socket . connect6 ( address , port , laddress , lport )
38 return connect ( address , port , laddress , lport , " inet6 " )
39end
40
41function socket . bind ( host , port , backlog )
42 if host = = " * " or host = = " " then
43 host = defaulthost
44 end
45 local addrinfo , err = getaddrinfo ( host )
46 if not addrinfo then
47 return nil , err
48 end
49 for i = 1 , # addrinfo do
50 local alt = addrinfo [ i ]
51 local sock , err = ( alt . family = = " inet " and tcp4 or tcp6 ) ( )
52 if not sock then
53 return nil , err or " unknown error "
54 end
55 sock : setoption ( " reuseaddr " , true )
56 local res , err = sock : bind ( alt . addr , port )
57 if res then
58 res , err = sock : listen ( backlog )
59 if res then
60 return sock
61 else
62 sock : close ( )
63 end
64 else
65 sock : close ( )
66 end
67 end
68 return nil , " invalid address "
69end
70
71socket . try = socket . newtry ( )
72
73function socket . choose ( list )
74 return function ( name , opt1 , opt2 )
75 if type ( name ) ~ = " string " then
76 name , opt1 , opt2 = " default " , name , opt1
77 end
78 local f = list [ name or " nil " ]
79 if f then
80 return f ( opt1 , opt2 )
81 else
82 report ( " error: unknown key '%s' " , tostring ( name ) )
83 end
84 end
85end
86
87local sourcet = { }
88local sinkt = { }
89
90socket . sourcet = sourcet
91socket . sinkt = sinkt
92
93socket . BLOCKSIZE = 2048
94
95sinkt [ " close-when-done " ] = function ( sock )
96 return setmetatable (
97 {
98 getfd = function ( ) return sock : getfd ( ) end ,
99 dirty = function ( ) return sock : dirty ( ) end ,
100 } ,
101 {
102 __call = function ( self , chunk , err )
103 if chunk then
104 return sock : send ( chunk )
105 else
106 sock : close ( )
107 return 1
108 end
109 end
110 }
111 )
112end
113
114sinkt [ " keep-open " ] = function ( sock )
115 return setmetatable (
116 {
117 getfd = function ( ) return sock : getfd ( ) end ,
118 dirty = function ( ) return sock : dirty ( ) end ,
119 } , {
120 __call = function ( self , chunk , err )
121 if chunk then
122 return sock : send ( chunk )
123 else
124 return 1
125 end
126 end
127 }
128 )
129end
130
131sinkt [ " default " ] = sinkt [ " keep-open " ]
132
133socket . sink = socket . choose ( sinkt )
134
135sourcet [ " by-length " ] = function ( sock , length )
136 local blocksize = socket . BLOCKSIZE
137 return setmetatable (
138 {
139 getfd = function ( ) return sock : getfd ( ) end ,
140 dirty = function ( ) return sock : dirty ( ) end ,
141 } ,
142 {
143 __call = function ( )
144 if length < = 0 then
145 return nil
146 end
147 local chunk , err = sock : receive ( min ( blocksize , length ) )
148 if err then
149 return nil , err
150 end
151 length = length - # chunk
152 return chunk
153 end
154 }
155 )
156end
157
158sourcet [ " until-closed " ] = function ( sock )
159 local blocksize = socket . BLOCKSIZE
160 local done = false
161 return setmetatable (
162 {
163 getfd = function ( ) return sock : getfd ( ) end ,
164 dirty = function ( ) return sock : dirty ( ) end ,
165 } , {
166 __call = function ( )
167 if done then
168 return nil
169 end
170 local chunk , status , partial = sock : receive ( blocksize )
171 if not status then
172 return chunk
173 elseif status = = " closed " then
174 sock : close ( )
175 done = true
176 return partial
177 else
178 return nil , status
179 end
180 end
181 }
182 )
183end
184
185sourcet [ " default " ] = sourcet [ " until-closed " ]
186
187socket . source = socket . choose ( sourcet )
188
189_G . socket = socket
190
191package . loaded [ " socket " ] = socket
192
193return socket
194 |