正在显示
1 个修改的文件
包含
904 行增加
和
0 行删除
src/server/spserver/spwin32iocp.cpp
0 → 100644
1 | +/* | |
2 | + * Copyright 2008 Stephen Liu | |
3 | + * For license terms, see the file COPYING along with this library. | |
4 | + */ | |
5 | + | |
6 | +#include <assert.h> | |
7 | +#include <time.h> | |
8 | + | |
9 | +#include "spwin32iocp.hpp" | |
10 | + | |
11 | +#include "spsession.hpp" | |
12 | +#include "spbuffer.hpp" | |
13 | +#include "spmsgdecoder.hpp" | |
14 | +#include "sprequest.hpp" | |
15 | +#include "sputils.hpp" | |
16 | +#include "sphandler.hpp" | |
17 | +#include "spexecutor.hpp" | |
18 | +#include "spioutils.hpp" | |
19 | +#include "spmsgblock.hpp" | |
20 | +#include "spwin32buffer.hpp" | |
21 | +#include "spiochannel.hpp" | |
22 | + | |
23 | +BOOL SP_IocpEventCallback :: addSession( SP_IocpEventArg * eventArg, HANDLE client, SP_Session * session ) | |
24 | +{ | |
25 | + BOOL ret = TRUE; | |
26 | + | |
27 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)malloc( sizeof( SP_IocpSession_t ) ); | |
28 | + if( NULL == iocpSession ) { | |
29 | + sp_syslog( LOG_ERR, "malloc fail, errno %d", GetLastError() ); | |
30 | + ret = FALSE; | |
31 | + } | |
32 | + | |
33 | + DWORD completionKey = 0; | |
34 | + SP_Sid_t sid = session->getSid(); | |
35 | + assert( sizeof( completionKey ) == sizeof( SP_Sid_t ) ); | |
36 | + memcpy( &completionKey, &sid, sizeof( completionKey ) ); | |
37 | + | |
38 | + if( ret ) { | |
39 | + memset( iocpSession, 0, sizeof( SP_IocpSession_t ) ); | |
40 | + iocpSession->mRecvEvent.mHeapIndex = -1; | |
41 | + iocpSession->mSendEvent.mHeapIndex = -1; | |
42 | + iocpSession->mRecvEvent.mType = SP_IocpEvent_t::eEventRecv; | |
43 | + iocpSession->mSendEvent.mType = SP_IocpEvent_t::eEventSend; | |
44 | + | |
45 | + iocpSession->mHandle = client; | |
46 | + iocpSession->mSession = session; | |
47 | + iocpSession->mEventArg = eventArg; | |
48 | + session->setArg( iocpSession ); | |
49 | + | |
50 | + if( NULL == CreateIoCompletionPort( client, eventArg->getCompletionPort(), completionKey, 0 ) ) { | |
51 | + sp_syslog( LOG_ERR, "CreateIoCompletionPort fail, errno %d", WSAGetLastError() ); | |
52 | + ret = FALSE; | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + if( ! ret ) { | |
57 | + sp_close( (SOCKET)client ); | |
58 | + | |
59 | + if( NULL != iocpSession ) free( iocpSession ); | |
60 | + session->setArg( NULL ); | |
61 | + } | |
62 | + | |
63 | + return ret; | |
64 | + | |
65 | +} | |
66 | + | |
67 | +BOOL SP_IocpEventCallback :: addRecv( SP_Session * session ) | |
68 | +{ | |
69 | + BOOL ret = TRUE; | |
70 | + | |
71 | + if( 0 == session->getReading() && SP_Session::eNormal == session->getStatus() ) { | |
72 | + SP_Sid_t sid = session->getSid(); | |
73 | + | |
74 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
75 | + SP_IocpEvent_t * recvEvent = &( iocpSession->mRecvEvent ); | |
76 | + | |
77 | + const int SP_MAX_RETRY = 5; | |
78 | + | |
79 | + for( int retry = 0; retry < SP_MAX_RETRY; retry++ ) { | |
80 | + memset( &( recvEvent->mOverlapped ), 0, sizeof( OVERLAPPED ) ); | |
81 | + recvEvent->mType = SP_IocpEvent_t::eEventRecv; | |
82 | + recvEvent->mWsaBuf.buf = NULL; | |
83 | + recvEvent->mWsaBuf.len = 0; | |
84 | + | |
85 | + DWORD recvBytes = 0, flags = 0; | |
86 | + if( SOCKET_ERROR == WSARecv( (SOCKET)iocpSession->mHandle, &(recvEvent->mWsaBuf), 1, | |
87 | + &recvBytes, &flags, &( recvEvent->mOverlapped ), NULL ) ) { | |
88 | + int lastError = WSAGetLastError(); | |
89 | + if( ERROR_IO_PENDING != lastError ) { | |
90 | + sp_syslog( LOG_ERR, "session(%d.%d) WSARecv fail, errno %d, retry %d", | |
91 | + sid.mKey, sid.mSeq, lastError, retry ); | |
92 | + } | |
93 | + | |
94 | + if( WSAENOBUFS == lastError && retry < SP_MAX_RETRY - 1 ) { | |
95 | + Sleep( 50 * retry ); | |
96 | + continue; | |
97 | + } else { | |
98 | + if( ERROR_IO_PENDING != lastError ) ret = FALSE; | |
99 | + break; | |
100 | + } | |
101 | + } else { | |
102 | + break; | |
103 | + } | |
104 | + } | |
105 | + | |
106 | + if( ret ) { | |
107 | + iocpSession->mSession->setReading( 1 ); | |
108 | + | |
109 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
110 | + | |
111 | + if( eventArg->getTimeout() > 0 ) { | |
112 | + sp_gettimeofday( &( recvEvent->mTimeout ), NULL ); | |
113 | + recvEvent->mTimeout.tv_sec += eventArg->getTimeout(); | |
114 | + eventArg->getEventHeap()->push( recvEvent ); | |
115 | + } | |
116 | + } | |
117 | + } | |
118 | + | |
119 | + return ret; | |
120 | +} | |
121 | + | |
122 | +void SP_IocpEventCallback :: onRecv( SP_IocpSession_t * iocpSession ) | |
123 | +{ | |
124 | + SP_IocpEvent_t * recvEvent = &( iocpSession->mRecvEvent ); | |
125 | + SP_Session * session = iocpSession->mSession; | |
126 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
127 | + | |
128 | + SP_Sid_t sid = session->getSid(); | |
129 | + | |
130 | + eventArg->getEventHeap()->erase( recvEvent ); | |
131 | + | |
132 | + session->setReading( 0 ); | |
133 | + | |
134 | + int len = session->getIOChannel()->receive( session ); | |
135 | + | |
136 | + if( len > 0 ) { | |
137 | + session->addRead( len ); | |
138 | + if( 0 == session->getRunning() ) { | |
139 | + SP_IocpEventHelper::doDecodeForWork( session ); | |
140 | + } | |
141 | + if( ! addRecv( session ) ) { | |
142 | + if( 0 == session->getRunning() ) { | |
143 | + SP_IocpEventHelper::doError( session ); | |
144 | + } else { | |
145 | + sp_syslog( LOG_NOTICE, "session(%d.%d) busy, process session error later", | |
146 | + sid.mKey, sid.mSeq ); | |
147 | + } | |
148 | + } | |
149 | + } else if( 0 == len ) { | |
150 | + if( 0 == session->getRunning() ) { | |
151 | + SP_IocpEventHelper::doClose( session ); | |
152 | + } else { | |
153 | + sp_syslog( LOG_NOTICE, "session(%d.%d) busy, process session close later", | |
154 | + sid.mKey, sid.mSeq ); | |
155 | + } | |
156 | + } else { | |
157 | + int ret = -1, lastError = WSAGetLastError(); | |
158 | + | |
159 | + if( WSAEWOULDBLOCK == lastError && addRecv( session ) ) ret = 0; | |
160 | + | |
161 | + if( 0 != ret ) { | |
162 | + if( 0 == session->getRunning() ) { | |
163 | + sp_syslog( LOG_NOTICE, "session(%d.%d) read error, errno %d, status %d", | |
164 | + sid.mKey, sid.mSeq, lastError, session->getStatus() ); | |
165 | + SP_IocpEventHelper::doError( session ); | |
166 | + } else { | |
167 | + sp_syslog( LOG_NOTICE, "session(%d.%d) busy, process session error later", | |
168 | + sid.mKey, sid.mSeq ); | |
169 | + } | |
170 | + } | |
171 | + } | |
172 | +} | |
173 | + | |
174 | +BOOL SP_IocpEventCallback :: addSend( SP_Session * session ) | |
175 | +{ | |
176 | + BOOL ret = TRUE; | |
177 | + | |
178 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
179 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
180 | + SP_IocpEvent_t * sendEvent = &( iocpSession->mSendEvent ); | |
181 | + SP_Sid_t sid = session->getSid(); | |
182 | + | |
183 | + if( 0 == session->getRunning() ) { | |
184 | + SP_IocpEventHelper::doDecodeForWork( session ); | |
185 | + } | |
186 | + | |
187 | + if( 0 == session->getWriting() ) { | |
188 | + | |
189 | + const int SP_MAX_RETRY = 5; | |
190 | + | |
191 | + for( int retry = 0; retry < SP_MAX_RETRY; retry++ ) { | |
192 | + memset( &( sendEvent->mOverlapped ), 0, sizeof( OVERLAPPED ) ); | |
193 | + sendEvent->mType = SP_IocpEvent_t::eEventSend; | |
194 | + sendEvent->mWsaBuf.buf = NULL; | |
195 | + sendEvent->mWsaBuf.len = 0; | |
196 | + | |
197 | + DWORD sendBytes = 0; | |
198 | + | |
199 | + if( SOCKET_ERROR == WSASend( (SOCKET)iocpSession->mHandle, &( sendEvent->mWsaBuf ), 1, | |
200 | + &sendBytes, 0, &( sendEvent->mOverlapped ), NULL ) ) { | |
201 | + int lastError = WSAGetLastError(); | |
202 | + if( ERROR_IO_PENDING != lastError ) { | |
203 | + sp_syslog( LOG_ERR, "session(%d.%d) WSASend fail, errno %d, retry %d", | |
204 | + sid.mKey, sid.mSeq, lastError, retry ); | |
205 | + } | |
206 | + | |
207 | + if( WSAENOBUFS == lastError && retry < SP_MAX_RETRY - 1 ) { | |
208 | + Sleep( 50 * retry ); | |
209 | + continue; | |
210 | + } else { | |
211 | + if( ERROR_IO_PENDING != lastError ) ret = FALSE; | |
212 | + break; | |
213 | + } | |
214 | + } else { | |
215 | + break; | |
216 | + } | |
217 | + } | |
218 | + | |
219 | + if( ret ) { | |
220 | + if( eventArg->getTimeout() > 0 ) { | |
221 | + sp_gettimeofday( &( sendEvent->mTimeout ), NULL ); | |
222 | + sendEvent->mTimeout.tv_sec += eventArg->getTimeout(); | |
223 | + eventArg->getEventHeap()->push( sendEvent ); | |
224 | + } | |
225 | + | |
226 | + session->setWriting( 1 ); | |
227 | + } | |
228 | + } | |
229 | + | |
230 | + return ret; | |
231 | +} | |
232 | + | |
233 | +void SP_IocpEventCallback :: onSend( SP_IocpSession_t * iocpSession ) | |
234 | +{ | |
235 | + SP_IocpEvent_t * recvEvent = &( iocpSession->mRecvEvent ); | |
236 | + SP_Session * session = iocpSession->mSession; | |
237 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
238 | + | |
239 | + session->setWriting( 0 ); | |
240 | + | |
241 | + SP_Sid_t sid = session->getSid(); | |
242 | + | |
243 | + int ret = 0; | |
244 | + | |
245 | + if( session->getOutList()->getCount() > 0 ) { | |
246 | + int len = session->getIOChannel()->transmit( session ); | |
247 | + if( len > 0 ) { | |
248 | + session->addWrite( len ); | |
249 | + if( session->getOutList()->getCount() > 0 ) { | |
250 | + if( ! addSend( session ) ) { | |
251 | + if( 0 == session->getRunning() ) { | |
252 | + ret = -1; | |
253 | + SP_IocpEventHelper::doError( session ); | |
254 | + } | |
255 | + } | |
256 | + } | |
257 | + } else { | |
258 | + ret = -1; | |
259 | + | |
260 | + int lastError = WSAGetLastError(); | |
261 | + | |
262 | + if( WSAENOBUFS == lastError && addSend( session ) ) ret = 0; | |
263 | + | |
264 | + if( WSAEWOULDBLOCK == lastError && addSend( session ) ) ret = 0; | |
265 | + | |
266 | + if( 0 != ret ) { | |
267 | + if( 0 == session->getRunning() ) { | |
268 | + sp_syslog( LOG_NOTICE, "session(%d.%d) write error, errno %d, status %d, count %d", | |
269 | + sid.mKey, sid.mSeq, lastError, session->getStatus(), session->getOutList()->getCount() ); | |
270 | + SP_IocpEventHelper::doError( session ); | |
271 | + } else { | |
272 | + sp_syslog( LOG_NOTICE, "session(%d.%d) busy, process session error later, errno [%d]", | |
273 | + sid.mKey, sid.mSeq, errno ); | |
274 | + } | |
275 | + } | |
276 | + } | |
277 | + } | |
278 | + | |
279 | + if( 0 == ret && session->getOutList()->getCount() <= 0 ) { | |
280 | + if( SP_Session::eExit == session->getStatus() ) { | |
281 | + ret = -1; | |
282 | + if( 0 == session->getRunning() ) { | |
283 | + //sp_syslog( LOG_NOTICE, "session(%d.%d) normal exit", sid.mKey, sid.mSeq ); | |
284 | + SP_IocpEventHelper::doClose( session ); | |
285 | + } else { | |
286 | + sp_syslog( LOG_NOTICE, "session(%d.%d) busy, terminate session later", | |
287 | + sid.mKey, sid.mSeq ); | |
288 | + } | |
289 | + } | |
290 | + } | |
291 | + | |
292 | + if( 0 == ret && 0 == session->getRunning() ) { | |
293 | + SP_IocpEventHelper::doDecodeForWork( session ); | |
294 | + } | |
295 | +} | |
296 | + | |
297 | +BOOL SP_IocpEventCallback :: onAccept( SP_IocpAcceptArg_t * acceptArg ) | |
298 | +{ | |
299 | + SP_IocpEventArg * eventArg = acceptArg->mEventArg; | |
300 | + | |
301 | + SP_Sid_t sid; | |
302 | + sid.mKey = eventArg->getSessionManager()->allocKey( &sid.mSeq ); | |
303 | + assert( sid.mKey > 0 ); | |
304 | + | |
305 | + SP_Session * session = new SP_Session( sid ); | |
306 | + | |
307 | + int localLen = 0, remoteLen = 0; | |
308 | + struct sockaddr_in * localAddr = NULL, * remoteAddr = NULL; | |
309 | + | |
310 | + GetAcceptExSockaddrs( acceptArg->mBuffer, 0, | |
311 | + sizeof( sockaddr_in ) + 16, sizeof( sockaddr_in ) + 16, | |
312 | + (SOCKADDR**)&localAddr, &localLen, (SOCKADDR**)&remoteAddr, &remoteLen ); | |
313 | + | |
314 | + struct sockaddr_in clientAddr; | |
315 | + memcpy( &clientAddr, remoteAddr, sizeof( clientAddr ) ); | |
316 | + | |
317 | + char clientIP[ 32 ] = { 0 }; | |
318 | + SP_IOUtils::inetNtoa( &( clientAddr.sin_addr ), clientIP, sizeof( clientIP ) ); | |
319 | + session->getRequest()->setClientIP( clientIP ); | |
320 | + session->getRequest()->setClientPort( ntohs( clientAddr.sin_port ) ); | |
321 | + | |
322 | + session->setHandler( acceptArg->mHandlerFactory->create() ); | |
323 | + session->setIOChannel( acceptArg->mIOChannelFactory->create() ); | |
324 | + | |
325 | + if( addSession( eventArg, acceptArg->mClientSocket, session ) ) { | |
326 | + eventArg->getSessionManager()->put( sid.mKey, sid.mSeq, session ); | |
327 | + | |
328 | + if( eventArg->getSessionManager()->getCount() > acceptArg->mMaxConnections | |
329 | + || eventArg->getInputResultQueue()->getLength() >= acceptArg->mReqQueueSize ) { | |
330 | + | |
331 | + sp_syslog( LOG_WARNING, "System busy, session.count %d [%d], queue.length %d [%d]", | |
332 | + eventArg->getSessionManager()->getCount(), acceptArg->mMaxConnections, | |
333 | + eventArg->getInputResultQueue()->getLength(), acceptArg->mReqQueueSize ); | |
334 | + | |
335 | + SP_Message * msg = new SP_Message(); | |
336 | + msg->getMsg()->append( acceptArg->mRefusedMsg ); | |
337 | + msg->getMsg()->append( "\r\n" ); | |
338 | + session->getOutList()->append( msg ); | |
339 | + session->setStatus( SP_Session::eExit ); | |
340 | + | |
341 | + addSend( session ); | |
342 | + } else { | |
343 | + SP_IocpEventHelper::doStart( session ); | |
344 | + } | |
345 | + } else { | |
346 | + eventArg->getSessionManager()->remove( sid.mKey, sid.mSeq ); | |
347 | + delete session; | |
348 | + } | |
349 | + | |
350 | + // signal SP_IocpServer::acceptThread to post another AcceptEx | |
351 | + SetEvent( acceptArg->mAcceptEvent ); | |
352 | + | |
353 | + return TRUE; | |
354 | +} | |
355 | + | |
356 | +void SP_IocpEventCallback :: onResponse( void * queueData, void * arg ) | |
357 | +{ | |
358 | + SP_Response * response = (SP_Response*)queueData; | |
359 | + SP_IocpEventArg * eventArg = (SP_IocpEventArg*)arg; | |
360 | + SP_SessionManager * manager = eventArg->getSessionManager(); | |
361 | + | |
362 | + SP_Sid_t fromSid = response->getFromSid(); | |
363 | + uint16_t seq = 0; | |
364 | + | |
365 | + if( ! SP_IocpEventHelper::isSystemSid( &fromSid ) ) { | |
366 | + SP_Session * session = manager->get( fromSid.mKey, &seq ); | |
367 | + if( seq == fromSid.mSeq && NULL != session ) { | |
368 | + if( SP_Session::eWouldExit == session->getStatus() ) { | |
369 | + session->setStatus( SP_Session::eExit ); | |
370 | + } | |
371 | + | |
372 | + if( SP_Session::eNormal == session->getStatus() ) { | |
373 | + if( addRecv( session ) ) { | |
374 | + if( 0 == session->getRunning() ) { | |
375 | + SP_IocpEventHelper::doDecodeForWork( session ); | |
376 | + } | |
377 | + } else { | |
378 | + if( 0 == session->getRunning() ) { | |
379 | + SP_IocpEventHelper::doError( session ); | |
380 | + } | |
381 | + } | |
382 | + } | |
383 | + } else { | |
384 | + sp_syslog( LOG_WARNING, "session(%d.%d) invalid, unknown FROM", | |
385 | + fromSid.mKey, fromSid.mSeq ); | |
386 | + } | |
387 | + } | |
388 | + | |
389 | + for( SP_Message * msg = response->takeMessage(); | |
390 | + NULL != msg; msg = response->takeMessage() ) { | |
391 | + | |
392 | + SP_SidList * sidList = msg->getToList(); | |
393 | + | |
394 | + if( msg->getTotalSize() > 0 ) { | |
395 | + for( int i = sidList->getCount() - 1; i >= 0; i-- ) { | |
396 | + SP_Sid_t sid = sidList->get( i ); | |
397 | + SP_Session * session = manager->get( sid.mKey, &seq ); | |
398 | + if( seq == sid.mSeq && NULL != session ) { | |
399 | + if( 0 != memcmp( &fromSid, &sid, sizeof( sid ) ) | |
400 | + && SP_Session::eExit == session->getStatus() ) { | |
401 | + sidList->take( i ); | |
402 | + msg->getFailure()->add( sid ); | |
403 | + sp_syslog( LOG_WARNING, "session(%d.%d) would exit, invalid TO", sid.mKey, sid.mSeq ); | |
404 | + } else { | |
405 | + if( addSend( session ) ) { | |
406 | + session->getOutList()->append( msg ); | |
407 | + } else { | |
408 | + if( 0 == session->getRunning() ) { | |
409 | + SP_IocpEventHelper::doError( session ); | |
410 | + } | |
411 | + } | |
412 | + } | |
413 | + } else { | |
414 | + sidList->take( i ); | |
415 | + msg->getFailure()->add( sid ); | |
416 | + sp_syslog( LOG_WARNING, "session(%d.%d) invalid, unknown TO", sid.mKey, sid.mSeq ); | |
417 | + } | |
418 | + } | |
419 | + } else { | |
420 | + for( ; sidList->getCount() > 0; ) { | |
421 | + msg->getFailure()->add( sidList->take( SP_ArrayList::LAST_INDEX ) ); | |
422 | + } | |
423 | + } | |
424 | + | |
425 | + if( msg->getToList()->getCount() <= 0 ) { | |
426 | + SP_IocpEventHelper::doCompletion( eventArg, msg ); | |
427 | + } | |
428 | + } | |
429 | + | |
430 | + if( ! SP_IocpEventHelper::isSystemSid( &fromSid ) ) { | |
431 | + SP_Session * session = manager->get( fromSid.mKey, &seq ); | |
432 | + if( seq == fromSid.mSeq && NULL != session ) { | |
433 | + if( session->getOutList()->getCount() <= 0 && SP_Session::eExit == session->getStatus() ) { | |
434 | + if( 0 == session->getRunning() ) { | |
435 | + SP_IocpEventHelper::doClose( session ); | |
436 | + } else { | |
437 | + sp_syslog( LOG_NOTICE, "session(%d.%d) busy, terminate session later", | |
438 | + fromSid.mKey, fromSid.mSeq ); | |
439 | + } | |
440 | + } | |
441 | + } | |
442 | + } | |
443 | + | |
444 | + for( int i = 0; i < response->getToCloseList()->getCount(); i++ ) { | |
445 | + SP_Sid_t sid = response->getToCloseList()->get( i ); | |
446 | + SP_Session * session = manager->get( sid.mKey, &seq ); | |
447 | + if( seq == sid.mSeq && NULL != session ) { | |
448 | + session->setStatus( SP_Session::eExit ); | |
449 | + if( !addSend( session ) ) { | |
450 | + if( 0 == session->getRunning() ) { | |
451 | + SP_IocpEventHelper::doError( session ); | |
452 | + } | |
453 | + } | |
454 | + } else { | |
455 | + sp_syslog( LOG_WARNING, "session(%d.%d) invalid, unknown CLOSE", sid.mKey, sid.mSeq ); | |
456 | + } | |
457 | + } | |
458 | + | |
459 | + delete response; | |
460 | +} | |
461 | + | |
462 | +void SP_IocpEventCallback :: onTimeout( SP_IocpEventArg * eventArg ) | |
463 | +{ | |
464 | + SP_IocpEventHeap * eventHeap = eventArg->getEventHeap(); | |
465 | + | |
466 | + if( NULL == eventHeap->top() ) return; | |
467 | + | |
468 | + struct timeval curr; | |
469 | + sp_gettimeofday( &curr, NULL ); | |
470 | + | |
471 | + for( ; NULL != eventHeap->top(); ) { | |
472 | + SP_IocpEvent_t * event = eventHeap->top(); | |
473 | + struct timeval * first = &( event->mTimeout ); | |
474 | + | |
475 | + if( ( curr.tv_sec == first->tv_sec && curr.tv_usec >= first->tv_usec ) | |
476 | + ||( curr.tv_sec > first->tv_sec ) ) { | |
477 | + event = eventHeap->pop(); | |
478 | + | |
479 | + if( SP_IocpEvent_t::eEventTimer == event->mType ) { | |
480 | + event->mOnTimer( event ); | |
481 | + } else { | |
482 | + SP_IocpSession_t * iocpSession = NULL; | |
483 | + | |
484 | + if( SP_IocpEvent_t::eEventRecv == event->mType ) { | |
485 | + iocpSession = CONTAINING_RECORD( event, SP_IocpSession_t, mRecvEvent ); | |
486 | + } else if( SP_IocpEvent_t::eEventSend == event->mType ) { | |
487 | + iocpSession = CONTAINING_RECORD( event, SP_IocpSession_t, mSendEvent ); | |
488 | + } | |
489 | + | |
490 | + assert( NULL != iocpSession ); | |
491 | + | |
492 | + if( 0 == iocpSession->mSession->getRunning() ) { | |
493 | + SP_IocpEventHelper::doTimeout( iocpSession->mSession ); | |
494 | + } | |
495 | + } | |
496 | + } else { | |
497 | + break; | |
498 | + } | |
499 | + } | |
500 | +} | |
501 | + | |
502 | +BOOL SP_IocpEventCallback :: eventLoop( SP_IocpEventArg * eventArg, SP_IocpAcceptArg_t * acceptArg ) | |
503 | +{ | |
504 | + DWORD bytesTransferred = 0; | |
505 | + DWORD completionKey = 0; | |
506 | + OVERLAPPED * overlapped = NULL; | |
507 | + HANDLE completionPort = eventArg->getCompletionPort(); | |
508 | + DWORD timeout = SP_IocpEventHelper::timeoutNext( eventArg->getEventHeap() ); | |
509 | + | |
510 | + BOOL isSuccess = GetQueuedCompletionStatus( completionPort, &bytesTransferred, | |
511 | + &completionKey, &overlapped, timeout ); | |
512 | + DWORD lastError = WSAGetLastError(); | |
513 | + | |
514 | + SP_Sid_t sid; | |
515 | + memcpy( &sid, &completionKey, sizeof( completionKey ) ); | |
516 | + | |
517 | + SP_IocpSession_t * iocpSession = NULL; | |
518 | + if( completionKey > 0 ) { | |
519 | + uint16_t seq = 0; | |
520 | + SP_Session * session = eventArg->getSessionManager()->get( sid.mKey, &seq ); | |
521 | + if( NULL != session && sid.mSeq == seq ) { | |
522 | + iocpSession = (SP_IocpSession_t*)session->getArg(); | |
523 | + } | |
524 | + } | |
525 | + | |
526 | + if( ! isSuccess ) { | |
527 | + if( eKeyAccept == completionKey ) { | |
528 | + sp_syslog( LOG_ERR, "accept(%d) fail, errno %d", acceptArg->mClientSocket, lastError ); | |
529 | + sp_close( (SOCKET)acceptArg->mClientSocket ); | |
530 | + // signal SP_IocpServer::acceptThread to post another AcceptEx | |
531 | + SetEvent( acceptArg->mAcceptEvent ); | |
532 | + return TRUE; | |
533 | + } | |
534 | + | |
535 | + if( NULL != overlapped ) { | |
536 | + // process a failed completed I/O request | |
537 | + // lastError continas the reason for failure | |
538 | + | |
539 | + if( NULL != iocpSession ) { | |
540 | + if( 0 == iocpSession->mSession->getRunning() ) { | |
541 | + SP_IocpEventHelper::doClose( iocpSession->mSession ); | |
542 | + } | |
543 | + } | |
544 | + | |
545 | + if( ERROR_NETNAME_DELETED == lastError // client abort | |
546 | + || ERROR_OPERATION_ABORTED == lastError ) { | |
547 | + return TRUE; | |
548 | + } else { | |
549 | + char errmsg[ 512 ] = { 0 }; | |
550 | + spwin32_strerror( lastError, errmsg, sizeof( errmsg ) ); | |
551 | + sp_syslog( LOG_ERR, "GetQueuedCompletionStatus fail, errno %d, %s", | |
552 | + lastError, errmsg ); | |
553 | + return FALSE; | |
554 | + } | |
555 | + } else { | |
556 | + if( lastError == WAIT_TIMEOUT ) { | |
557 | + // time-out while waiting for completed I/O request | |
558 | + onTimeout( eventArg ); | |
559 | + } else { | |
560 | + // bad call to GQCS, lastError contains the reason for the bad call | |
561 | + } | |
562 | + } | |
563 | + | |
564 | + return FALSE; | |
565 | + } | |
566 | + | |
567 | + if( eKeyAccept == completionKey ) { | |
568 | + return onAccept( acceptArg ); | |
569 | + } else if( eKeyMsgQueue == completionKey ) { | |
570 | + SP_IocpMsgQueue * msgQueue = (SP_IocpMsgQueue*)overlapped; | |
571 | + msgQueue->process(); | |
572 | + return TRUE; | |
573 | + } else if( eKeyFree == completionKey ) { | |
574 | + assert( NULL == iocpSession ); | |
575 | + iocpSession = CONTAINING_RECORD( overlapped, SP_IocpSession_t, mFreeEvent ); | |
576 | + delete iocpSession->mSession; | |
577 | + free( iocpSession ); | |
578 | + return TRUE; | |
579 | + } else { | |
580 | + if( NULL == iocpSession ) return TRUE; | |
581 | + | |
582 | + SP_IocpEvent_t * iocpEvent = | |
583 | + CONTAINING_RECORD( overlapped, SP_IocpEvent_t, mOverlapped ); | |
584 | + | |
585 | + eventArg->getEventHeap()->erase( iocpEvent ); | |
586 | + | |
587 | + if( SP_IocpEvent_t::eEventRecv == iocpEvent->mType ) { | |
588 | + onRecv( iocpSession ); | |
589 | + return TRUE; | |
590 | + } | |
591 | + | |
592 | + if( SP_IocpEvent_t::eEventSend == iocpEvent->mType ) { | |
593 | + onSend( iocpSession ); | |
594 | + return TRUE; | |
595 | + } | |
596 | + } | |
597 | + | |
598 | + return TRUE; | |
599 | +} | |
600 | + | |
601 | +//=================================================================== | |
602 | + | |
603 | +int SP_IocpEventHelper :: isSystemSid( SP_Sid_t * sid ) | |
604 | +{ | |
605 | + return sid->mKey == SP_Sid_t::eTimerKey && sid->mSeq == SP_Sid_t::eTimerSeq; | |
606 | +} | |
607 | + | |
608 | +DWORD SP_IocpEventHelper :: timeoutNext( SP_IocpEventHeap * eventHeap ) | |
609 | +{ | |
610 | + SP_IocpEvent_t * event = eventHeap->top(); | |
611 | + | |
612 | + if( NULL == event ) return INFINITE; | |
613 | + | |
614 | + struct timeval curr; | |
615 | + sp_gettimeofday( &curr, NULL ); | |
616 | + | |
617 | + struct timeval * first = &( event->mTimeout ); | |
618 | + | |
619 | + DWORD ret = ( first->tv_sec - curr.tv_sec ) * 1000 | |
620 | + + ( first->tv_usec - curr.tv_usec ) / 1000; | |
621 | + | |
622 | + if( ret < 0 ) ret = 0; | |
623 | + | |
624 | + return ret; | |
625 | +} | |
626 | + | |
627 | +void SP_IocpEventHelper :: doDecodeForWork( SP_Session * session ) | |
628 | +{ | |
629 | + SP_MsgDecoder * decoder = session->getRequest()->getMsgDecoder(); | |
630 | + int ret = decoder->decode( session->getInBuffer() ); | |
631 | + if( SP_MsgDecoder::eOK == ret ) { | |
632 | + doWork( session ); | |
633 | + } else if( SP_MsgDecoder::eMoreData != ret ) { | |
634 | + doError( session ); | |
635 | + } else { | |
636 | + assert( ret == SP_MsgDecoder::eMoreData ); | |
637 | + } | |
638 | +} | |
639 | + | |
640 | +void SP_IocpEventHelper :: doWork( SP_Session * session ) | |
641 | +{ | |
642 | + if( SP_Session::eNormal == session->getStatus() ) { | |
643 | + session->setRunning( 1 ); | |
644 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
645 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
646 | + eventArg->getInputResultQueue()->push( new SP_SimpleTask( worker, session, 1 ) ); | |
647 | + } else { | |
648 | + SP_Sid_t sid = session->getSid(); | |
649 | + | |
650 | + char buffer[ 16 ] = { 0 }; | |
651 | + session->getInBuffer()->take( buffer, sizeof( buffer ) ); | |
652 | + sp_syslog( LOG_WARNING, "session(%d.%d) status is %d, ignore [%s...] (%dB)", | |
653 | + sid.mKey, sid.mSeq, session->getStatus(), buffer, session->getInBuffer()->getSize() ); | |
654 | + session->getInBuffer()->reset(); | |
655 | + } | |
656 | +} | |
657 | + | |
658 | +void SP_IocpEventHelper :: worker( void * arg ) | |
659 | +{ | |
660 | + SP_Session * session = (SP_Session*)arg; | |
661 | + SP_Handler * handler = session->getHandler(); | |
662 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
663 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
664 | + | |
665 | + SP_Response * response = new SP_Response( session->getSid() ); | |
666 | + if( 0 != handler->handle( session->getRequest(), response ) ) { | |
667 | + session->setStatus( SP_Session::eWouldExit ); | |
668 | + } | |
669 | + | |
670 | + session->setRunning( 0 ); | |
671 | + | |
672 | + eventArg->getResponseQueue()->push( response ); | |
673 | +} | |
674 | + | |
675 | +void SP_IocpEventHelper :: doClose( SP_Session * session ) | |
676 | +{ | |
677 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
678 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
679 | + | |
680 | + SP_Sid_t sid = session->getSid(); | |
681 | + | |
682 | + session->setRunning( 1 ); | |
683 | + | |
684 | + // remove session from SessionManager, the other threads will ignore this session | |
685 | + eventArg->getSessionManager()->remove( sid.mKey, sid.mSeq ); | |
686 | + | |
687 | + eventArg->getEventHeap()->erase( &( iocpSession->mRecvEvent ) ); | |
688 | + eventArg->getEventHeap()->erase( &( iocpSession->mSendEvent ) ); | |
689 | + | |
690 | + eventArg->getInputResultQueue()->push( new SP_SimpleTask( close, session, 1 ) ); | |
691 | +} | |
692 | + | |
693 | +void SP_IocpEventHelper :: close( void * arg ) | |
694 | +{ | |
695 | + SP_Session * session = (SP_Session*)arg; | |
696 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
697 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
698 | + | |
699 | + SP_Sid_t sid = session->getSid(); | |
700 | + | |
701 | + //sp_syslog( LOG_NOTICE, "session(%d.%d) close, disconnect", sid.mKey, sid.mSeq ); | |
702 | + | |
703 | + session->getHandler()->close(); | |
704 | + | |
705 | + sp_syslog( LOG_NOTICE, "session(%d.%d) close, r %d(%d), w %d(%d), i %d, o %d, s %d(%d), t %d", | |
706 | + sid.mKey, sid.mSeq, session->getTotalRead(), session->getReading(), | |
707 | + session->getTotalWrite(), session->getWriting(), | |
708 | + session->getInBuffer()->getSize(), session->getOutList()->getCount(), | |
709 | + eventArg->getSessionManager()->getCount(), eventArg->getSessionManager()->getFreeCount(), | |
710 | + eventArg->getEventHeap()->getCount() ); | |
711 | + | |
712 | + if( ! eventArg->disconnectEx( (SOCKET)iocpSession->mHandle, NULL, 0, 0 ) ) { | |
713 | + if( ERROR_IO_PENDING != WSAGetLastError () ) { | |
714 | + sp_syslog( LOG_ERR, "DisconnectEx(%d) fail, errno %d", sid.mKey, WSAGetLastError() ); | |
715 | + } | |
716 | + } | |
717 | + | |
718 | + if( 0 != sp_close( (SOCKET)iocpSession->mHandle ) ) { | |
719 | + sp_syslog( LOG_ERR, "close(%d) fail, errno %d", sid.mKey, WSAGetLastError() ); | |
720 | + } | |
721 | + | |
722 | + memset( &( iocpSession->mFreeEvent ), 0, sizeof( OVERLAPPED ) ); | |
723 | + PostQueuedCompletionStatus( eventArg->getCompletionPort(), 0, | |
724 | + SP_IocpEventCallback::eKeyFree, &( iocpSession->mFreeEvent ) ); | |
725 | +} | |
726 | + | |
727 | +void SP_IocpEventHelper :: doError( SP_Session * session ) | |
728 | +{ | |
729 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
730 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
731 | + SP_Sid_t sid = session->getSid(); | |
732 | + | |
733 | + sp_syslog( LOG_WARNING, "session(%d.%d) error, r %d(%d), w %d(%d), i %d, o %d, s %d(%d), t %d", | |
734 | + sid.mKey, sid.mSeq, session->getTotalRead(), session->getReading(), | |
735 | + session->getTotalWrite(), session->getWriting(), | |
736 | + session->getInBuffer()->getSize(), session->getOutList()->getCount(), | |
737 | + eventArg->getSessionManager()->getCount(), eventArg->getSessionManager()->getFreeCount(), | |
738 | + eventArg->getEventHeap()->getCount() ); | |
739 | + | |
740 | + session->setRunning( 1 ); | |
741 | + | |
742 | + SP_ArrayList * outList = session->getOutList(); | |
743 | + for( ; outList->getCount() > 0; ) { | |
744 | + SP_Message * msg = ( SP_Message * ) outList->takeItem( SP_ArrayList::LAST_INDEX ); | |
745 | + | |
746 | + int index = msg->getToList()->find( sid ); | |
747 | + if( index >= 0 ) msg->getToList()->take( index ); | |
748 | + msg->getFailure()->add( sid ); | |
749 | + | |
750 | + if( msg->getToList()->getCount() <= 0 ) { | |
751 | + doCompletion( eventArg, msg ); | |
752 | + } | |
753 | + } | |
754 | + | |
755 | + // remove session from SessionManager, so the other threads will ignore this session | |
756 | + eventArg->getSessionManager()->remove( sid.mKey, sid.mSeq ); | |
757 | + | |
758 | + eventArg->getEventHeap()->erase( &( iocpSession->mRecvEvent ) ); | |
759 | + eventArg->getEventHeap()->erase( &( iocpSession->mSendEvent ) ); | |
760 | + | |
761 | + eventArg->getInputResultQueue()->push( new SP_SimpleTask( error, session, 1 ) ); | |
762 | +} | |
763 | + | |
764 | +void SP_IocpEventHelper :: error( void * arg ) | |
765 | +{ | |
766 | + SP_Session * session = ( SP_Session * )arg; | |
767 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
768 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
769 | + | |
770 | + SP_Sid_t sid = session->getSid(); | |
771 | + | |
772 | + SP_Response * response = new SP_Response( sid ); | |
773 | + session->getHandler()->error( response ); | |
774 | + | |
775 | + eventArg->getResponseQueue()->push( response ); | |
776 | + | |
777 | + // the other threads will ignore this session, so it's safe to destroy session here | |
778 | + session->getHandler()->close(); | |
779 | + | |
780 | + if( ! eventArg->disconnectEx( (SOCKET)iocpSession->mHandle, NULL, 0, 0 ) ) { | |
781 | + if( ERROR_IO_PENDING != WSAGetLastError () ) { | |
782 | + sp_syslog( LOG_ERR, "DisconnectEx(%d) fail, errno %d", sid.mKey, WSAGetLastError() ); | |
783 | + } | |
784 | + } | |
785 | + | |
786 | + if( 0 != sp_close( (SOCKET)iocpSession->mHandle ) ) { | |
787 | + sp_syslog( LOG_ERR, "close(%d) fail, errno %d", sid.mKey, WSAGetLastError() ); | |
788 | + } | |
789 | + | |
790 | + memset( &( iocpSession->mFreeEvent ), 0, sizeof( OVERLAPPED ) ); | |
791 | + PostQueuedCompletionStatus( eventArg->getCompletionPort(), 0, | |
792 | + SP_IocpEventCallback::eKeyFree, &( iocpSession->mFreeEvent ) ); | |
793 | +} | |
794 | + | |
795 | +void SP_IocpEventHelper :: doTimeout( SP_Session * session ) | |
796 | +{ | |
797 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
798 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
799 | + SP_Sid_t sid = session->getSid(); | |
800 | + | |
801 | + sp_syslog( LOG_WARNING, "session(%d.%d) timeout, r %d(%d), w %d(%d), i %d, o %d, s %d(%d), t %d", | |
802 | + sid.mKey, sid.mSeq, session->getTotalRead(), session->getReading(), | |
803 | + session->getTotalWrite(), session->getWriting(), | |
804 | + session->getInBuffer()->getSize(), session->getOutList()->getCount(), | |
805 | + eventArg->getSessionManager()->getCount(), eventArg->getSessionManager()->getFreeCount(), | |
806 | + eventArg->getEventHeap()->getCount() ); | |
807 | + | |
808 | + session->setRunning( 1 ); | |
809 | + | |
810 | + SP_ArrayList * outList = session->getOutList(); | |
811 | + for( ; outList->getCount() > 0; ) { | |
812 | + SP_Message * msg = ( SP_Message * ) outList->takeItem( SP_ArrayList::LAST_INDEX ); | |
813 | + | |
814 | + int index = msg->getToList()->find( sid ); | |
815 | + if( index >= 0 ) msg->getToList()->take( index ); | |
816 | + msg->getFailure()->add( sid ); | |
817 | + | |
818 | + if( msg->getToList()->getCount() <= 0 ) { | |
819 | + doCompletion( eventArg, msg ); | |
820 | + } | |
821 | + } | |
822 | + | |
823 | + // remove session from SessionManager, the other threads will ignore this session | |
824 | + eventArg->getSessionManager()->remove( sid.mKey, sid.mSeq ); | |
825 | + | |
826 | + eventArg->getEventHeap()->erase( &( iocpSession->mRecvEvent ) ); | |
827 | + eventArg->getEventHeap()->erase( &( iocpSession->mSendEvent ) ); | |
828 | + | |
829 | + eventArg->getInputResultQueue()->push( new SP_SimpleTask( timeout, session, 1 ) ); | |
830 | +} | |
831 | + | |
832 | +void SP_IocpEventHelper :: timeout( void * arg ) | |
833 | +{ | |
834 | + SP_Session * session = ( SP_Session * )arg; | |
835 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
836 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
837 | + | |
838 | + SP_Sid_t sid = session->getSid(); | |
839 | + | |
840 | + SP_Response * response = new SP_Response( sid ); | |
841 | + session->getHandler()->timeout( response ); | |
842 | + | |
843 | + eventArg->getResponseQueue()->push( response ); | |
844 | + | |
845 | + // the other threads will ignore this session, so it's safe to destroy session here | |
846 | + session->getHandler()->close(); | |
847 | + | |
848 | + if( ! eventArg->disconnectEx( (SOCKET)iocpSession->mHandle, NULL, 0, 0 ) ) { | |
849 | + if( ERROR_IO_PENDING != WSAGetLastError () ) { | |
850 | + sp_syslog( LOG_ERR, "DisconnectEx(%d) fail, errno %d", sid.mKey, WSAGetLastError() ); | |
851 | + } | |
852 | + } | |
853 | + | |
854 | + if( 0 != sp_close( (SOCKET)iocpSession->mHandle ) ) { | |
855 | + sp_syslog( LOG_ERR, "close(%d) fail, errno %d", sid.mKey, WSAGetLastError() ); | |
856 | + } | |
857 | + | |
858 | + memset( &( iocpSession->mFreeEvent ), 0, sizeof( OVERLAPPED ) ); | |
859 | + PostQueuedCompletionStatus( eventArg->getCompletionPort(), 0, | |
860 | + SP_IocpEventCallback::eKeyFree, &( iocpSession->mFreeEvent ) ); | |
861 | +} | |
862 | + | |
863 | +void SP_IocpEventHelper :: doStart( SP_Session * session ) | |
864 | +{ | |
865 | + session->setRunning( 1 ); | |
866 | + | |
867 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
868 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
869 | + eventArg->getInputResultQueue()->push( new SP_SimpleTask( start, session, 1 ) ); | |
870 | +} | |
871 | + | |
872 | +void SP_IocpEventHelper :: start( void * arg ) | |
873 | +{ | |
874 | + SP_Session * session = ( SP_Session * )arg; | |
875 | + SP_IocpSession_t * iocpSession = (SP_IocpSession_t*)session->getArg(); | |
876 | + SP_IocpEventArg * eventArg = iocpSession->mEventArg; | |
877 | + | |
878 | + SP_IOChannel * ioChannel = session->getIOChannel(); | |
879 | + | |
880 | + int initRet = ioChannel->init( (int)iocpSession->mHandle ); | |
881 | + | |
882 | + SP_Response * response = new SP_Response( session->getSid() ); | |
883 | + int startRet = session->getHandler()->start( session->getRequest(), response ); | |
884 | + | |
885 | + int status = SP_Session::eWouldExit; | |
886 | + | |
887 | + if( 0 == initRet ) { | |
888 | + if( 0 == startRet ) status = SP_Session::eNormal; | |
889 | + } else { | |
890 | + delete response; | |
891 | + // make an empty response | |
892 | + response = new SP_Response( session->getSid() ); | |
893 | + } | |
894 | + | |
895 | + session->setStatus( status ); | |
896 | + session->setRunning( 0 ); | |
897 | + | |
898 | + eventArg->getResponseQueue()->push( response ); | |
899 | +} | |
900 | + | |
901 | +void SP_IocpEventHelper :: doCompletion( SP_IocpEventArg * eventArg, SP_Message * msg ) | |
902 | +{ | |
903 | + eventArg->getOutputResultQueue()->push( msg ); | |
904 | +} | ... | ... |
请
注册
或
登录
后发表评论