@@ -24,182 +24,141 @@ const common = require('../common');
24
24
const assert = require ( 'assert' ) ;
25
25
const fork = require ( 'child_process' ) . fork ;
26
26
const net = require ( 'net' ) ;
27
-
28
- function ProgressTracker ( missing , callback ) {
29
- this . missing = missing ;
30
- this . callback = callback ;
31
- }
32
- ProgressTracker . prototype . done = function ( ) {
33
- this . missing -= 1 ;
34
- this . check ( ) ;
35
- } ;
36
- ProgressTracker . prototype . check = function ( ) {
37
- if ( this . missing === 0 ) this . callback ( ) ;
38
- } ;
27
+ const count = 12 ;
39
28
40
29
if ( process . argv [ 2 ] === 'child' ) {
30
+ const needEnd = [ ] ;
31
+ const id = process . argv [ 3 ] ;
32
+
33
+ process . on ( 'message' , function ( m , socket ) {
34
+ if ( ! socket ) return ;
41
35
42
- let serverScope ;
36
+ console . error ( `[ ${ id } ] got socket ${ m } ` ) ;
43
37
44
- process . on ( 'message' , function onServer ( msg , server ) {
45
- if ( msg . what !== 'server' ) return ;
46
- process . removeListener ( 'message' , onServer ) ;
38
+ // will call .end('end') or .write('write');
39
+ socket [ m ] ( m ) ;
47
40
48
- serverScope = server ;
41
+ socket . resume ( ) ;
49
42
50
- server . on ( 'connection' , function ( socket ) {
51
- console . log ( 'CHILD: got connection' ) ;
52
- process . send ( { what : 'connection' } ) ;
53
- socket . destroy ( ) ;
43
+ socket . on ( 'data' , function ( ) {
44
+ console . error ( `[${ id } ] socket.data ${ m } ` ) ;
54
45
} ) ;
55
46
56
- // Start making connection from parent.
57
- console . log ( 'CHILD: server listening' ) ;
58
- process . send ( { what : 'listening' } ) ;
59
- } ) ;
47
+ socket . on ( 'end' , function ( ) {
48
+ console . error ( `[${ id } ] socket.end ${ m } ` ) ;
49
+ } ) ;
60
50
61
- process . on ( 'message' , function onClose ( msg ) {
62
- if ( msg . what !== 'close' ) return ;
63
- process . removeListener ( 'message' , onClose ) ;
51
+ // store the unfinished socket
52
+ if ( m === 'write' ) {
53
+ needEnd . push ( socket ) ;
54
+ }
64
55
65
- serverScope . on ( 'close' , function ( ) {
66
- process . send ( { what : ' close' } ) ;
56
+ socket . on ( 'close' , function ( had_error ) {
57
+ console . error ( `[ ${ id } ] socket. close ${ had_error } ${ m } ` ) ;
67
58
} ) ;
68
- serverScope . close ( ) ;
69
- } ) ;
70
59
71
- process . on ( 'message' , function onSocket ( msg , socket ) {
72
- if ( msg . what !== 'socket' ) return ;
73
- process . removeListener ( 'message' , onSocket ) ;
74
- socket . end ( 'echo' ) ;
75
- console . log ( 'CHILD: got socket' ) ;
60
+ socket . on ( 'finish' , function ( ) {
61
+ console . error ( `[${ id } ] socket finished ${ m } ` ) ;
62
+ } ) ;
76
63
} ) ;
77
64
78
- process . send ( { what : 'ready' } ) ;
79
- } else {
65
+ process . on ( 'message' , function ( m ) {
66
+ if ( m !== 'close' ) return ;
67
+ console . error ( `[${ id } ] got close message` ) ;
68
+ needEnd . forEach ( function ( endMe , i ) {
69
+ console . error ( `[${ id } ] ending ${ i } /${ needEnd . length } ` ) ;
70
+ endMe . end ( 'end' ) ;
71
+ } ) ;
72
+ } ) ;
80
73
81
- const child = fork ( process . argv [ 1 ] , [ 'child' ] ) ;
74
+ process . on ( 'disconnect' , function ( ) {
75
+ console . error ( `[${ id } ] process disconnect, ending` ) ;
76
+ needEnd . forEach ( function ( endMe , i ) {
77
+ console . error ( `[${ id } ] ending ${ i } /${ needEnd . length } ` ) ;
78
+ endMe . end ( 'end' ) ;
79
+ } ) ;
80
+ } ) ;
82
81
83
- child . on ( 'exit' , common . mustCall ( function ( code , signal ) {
84
- const message = `CHILD: died with ${ code } , ${ signal } ` ;
85
- assert . strictEqual ( code , 0 , message ) ;
86
- } ) ) ;
82
+ } else {
87
83
88
- // Send net.Server to child and test by connecting.
89
- function testServer ( callback ) {
84
+ const child1 = fork ( process . argv [ 1 ] , [ 'child' , '1' ] ) ;
85
+ const child2 = fork ( process . argv [ 1 ] , [ 'child' , '2' ] ) ;
86
+ const child3 = fork ( process . argv [ 1 ] , [ 'child' , '3' ] ) ;
87
+
88
+ const server = net . createServer ( ) ;
89
+
90
+ let connected = 0 ;
91
+ let closed = 0 ;
92
+ server . on ( 'connection' , function ( socket ) {
93
+ switch ( connected % 6 ) {
94
+ case 0 :
95
+ child1 . send ( 'end' , socket ) ; break ;
96
+ case 1 :
97
+ child1 . send ( 'write' , socket ) ; break ;
98
+ case 2 :
99
+ child2 . send ( 'end' , socket ) ; break ;
100
+ case 3 :
101
+ child2 . send ( 'write' , socket ) ; break ;
102
+ case 4 :
103
+ child3 . send ( 'end' , socket ) ; break ;
104
+ case 5 :
105
+ child3 . send ( 'write' , socket ) ; break ;
106
+ }
107
+ connected += 1 ;
90
108
91
- // Destroy server execute callback when done.
92
- const progress = new ProgressTracker ( 2 , function ( ) {
93
- server . on ( 'close' , function ( ) {
94
- console . log ( 'PARENT: server closed' ) ;
95
- child . send ( { what : 'close' } ) ;
96
- } ) ;
97
- server . close ( ) ;
109
+ socket . once ( 'close' , function ( ) {
110
+ console . log ( `[m] socket closed, total ${ ++ closed } ` ) ;
98
111
} ) ;
99
112
100
- // We expect 4 connections and close events.
101
- const connections = new ProgressTracker ( 4 , progress . done . bind ( progress ) ) ;
102
- const closed = new ProgressTracker ( 4 , progress . done . bind ( progress ) ) ;
103
-
104
- // Create server and send it to child.
105
- const server = net . createServer ( ) ;
106
- server . on ( 'connection' , function ( socket ) {
107
- console . log ( 'PARENT: got connection' ) ;
108
- socket . destroy ( ) ;
109
- connections . done ( ) ;
110
- } ) ;
111
- server . on ( 'listening' , function ( ) {
112
- console . log ( 'PARENT: server listening' ) ;
113
- child . send ( { what : 'server' } , server ) ;
114
- } ) ;
115
- server . listen ( 0 ) ;
116
-
117
- // Handle client messages.
118
- function messageHandlers ( msg ) {
119
-
120
- if ( msg . what === 'listening' ) {
121
- // Make connections.
122
- let socket ;
123
- for ( let i = 0 ; i < 4 ; i ++ ) {
124
- socket = net . connect ( server . address ( ) . port , function ( ) {
125
- console . log ( 'CLIENT: connected' ) ;
126
- } ) ;
127
- socket . on ( 'close' , function ( ) {
128
- closed . done ( ) ;
129
- console . log ( 'CLIENT: closed' ) ;
130
- } ) ;
131
- }
132
-
133
- } else if ( msg . what === 'connection' ) {
134
- // child got connection
135
- connections . done ( ) ;
136
- } else if ( msg . what === 'close' ) {
137
- child . removeListener ( 'message' , messageHandlers ) ;
138
- callback ( ) ;
139
- }
113
+ if ( connected === count ) {
114
+ closeServer ( ) ;
140
115
}
116
+ } ) ;
141
117
142
- child . on ( 'message' , messageHandlers ) ;
143
- }
144
-
145
- // Send net.Socket to child.
146
- function testSocket ( callback ) {
118
+ let disconnected = 0 ;
119
+ server . on ( 'listening' , function ( ) {
147
120
148
- // Create a new server and connect to it,
149
- // but the socket will be handled by the child.
150
- const server = net . createServer ( ) ;
151
- server . on ( 'connection' , function ( socket ) {
152
- socket . on ( 'close' , function ( ) {
153
- console . log ( 'CLIENT: socket closed' ) ;
121
+ let j = count ;
122
+ while ( j -- ) {
123
+ const client = net . connect ( this . address ( ) . port , '127.0.0.1' ) ;
124
+ client . on ( 'error' , function ( ) {
125
+ // This can happen if we kill the child too early.
126
+ // The client should still get a close event afterwards.
127
+ console . error ( '[m] CLIENT: error event' ) ;
154
128
} ) ;
155
- child . send ( { what : 'socket' } , socket ) ;
156
- } ) ;
157
- server . on ( 'close' , function ( ) {
158
- console . log ( 'PARENT: server closed' ) ;
159
- callback ( ) ;
160
- } ) ;
161
- // Don't listen on the same port, because SmartOS sometimes says
162
- // that the server's fd is closed, but it still cannot listen
163
- // on the same port again.
164
- //
165
- // An isolated test for this would be lovely, but for now, this
166
- // will have to do.
167
- server . listen ( 0 , function ( ) {
168
- console . log ( 'testSocket, listening' ) ;
169
- const connect = net . connect ( server . address ( ) . port ) ;
170
- let store = '' ;
171
- connect . on ( 'data' , function ( chunk ) {
172
- store += chunk ;
173
- console . log ( 'CLIENT: got data' ) ;
174
- } ) ;
175
- connect . on ( 'close' , function ( ) {
176
- console . log ( 'CLIENT: closed' ) ;
177
- assert . strictEqual ( store , 'echo' ) ;
178
- server . close ( ) ;
129
+ client . on ( 'close' , function ( ) {
130
+ console . error ( '[m] CLIENT: close event' ) ;
131
+ disconnected += 1 ;
179
132
} ) ;
180
- } ) ;
181
- }
133
+ client . resume ( ) ;
134
+ }
135
+ } ) ;
182
136
183
- // Create server and send it to child.
184
- let serverSuccess = false ;
185
- let socketSuccess = false ;
186
- child . on ( 'message' , function onReady ( msg ) {
187
- if ( msg . what !== 'ready' ) return ;
188
- child . removeListener ( 'message' , onReady ) ;
137
+ let closeEmitted = false ;
138
+ server . on ( 'close' , common . mustCall ( function ( ) {
139
+ closeEmitted = true ;
189
140
190
- testServer ( function ( ) {
191
- serverSuccess = true ;
141
+ child1 . kill ( ) ;
142
+ child2 . kill ( ) ;
143
+ child3 . kill ( ) ;
144
+ } ) ) ;
192
145
193
- testSocket ( function ( ) {
194
- socketSuccess = true ;
195
- } ) ;
196
- } ) ;
146
+ server . listen ( 0 , '127.0.0.1' ) ;
197
147
198
- } ) ;
148
+ function closeServer ( ) {
149
+ server . close ( ) ;
150
+
151
+ setTimeout ( function ( ) {
152
+ assert ( ! closeEmitted ) ;
153
+ child1 . send ( 'close' ) ;
154
+ child2 . send ( 'close' ) ;
155
+ child3 . disconnect ( ) ;
156
+ } , 200 ) ;
157
+ }
199
158
200
159
process . on ( 'exit' , function ( ) {
201
- assert . ok ( serverSuccess ) ;
202
- assert . ok ( socketSuccess ) ;
160
+ assert . strictEqual ( server . _workers . length , 0 ) ;
161
+ assert . strictEqual ( disconnected , count ) ;
162
+ assert . strictEqual ( connected , count ) ;
203
163
} ) ;
204
-
205
164
}
0 commit comments