1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18
19 #include "osclconfig_io.h"
20 #include "oscl_socket_tuneables.h"
21
22 #if(PV_SOCKET_SERVER)
23
24 #include "oscl_scheduler_ao.h"
25 #include "oscl_socket_method.h"
26 #include "oscl_socket_types.h"
27 #include "oscl_socket_serv_imp_pv.h"
28 #include "oscl_error.h"
29 #include "oscl_socket_imp.h"
30 #include "oscl_assert.h"
31
32 //Logger macro for socket server logging.
33 #if(PV_OSCL_SOCKET_SERVER_LOGGER_OUTPUT)
34 #include "pvlogger.h"
35 #define LOGSERV(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_DEBUG,m);
36 #else
37 #define LOGSERV(m)
38 #endif
39 /*
40 //disable this if it's too much
41 #undef LOGSERV
42 #define LOGSERV
43 */
44
45 //Macros for server stats logging for use with OsclSocketServI
46 #if (PV_OSCL_SOCKET_STATS_LOGGING)
47 #define ADD_STATS(x) iServStats.Add(x)
48 #define ADD_STATSP(x,y) iServStats.Add(x,y)
49 #define CONSTRUCT_STATS(x) iServStats.Construct(x)
50 #define DUMP_STATS iServStats.LogAndDump();
51 #else
52 #define ADD_STATS(x)
53 #define ADD_STATSP(x,y)
54 #define CONSTRUCT_STATS(x)
55 #define DUMP_STATS
56 #endif//PV_OSCL_SOCKET_STATS_LOGGING
57
58
59 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
60 //
61 //OsclSocketServI::LoopbackSocket
62 //
63
64 //Macros for server stats logging for use with OsclSocketServI::LoopbackSocket
65 #if (PV_OSCL_SOCKET_STATS_LOGGING)
66 #define ADD_LOOPSTATS(a,b) iStats.Add((TPVSocketFxn)0,a,b);
67 #define LOG_LOOPSTATS iStats.Log();
68 #define DUMP_LOOPSTATS iStats.Log();iStats.Clear((TPVSocketFxn)0);
69 #else
70 #define ADD_LOOPSTATS(a,b)
71 #define LOG_LOOPSTATS
72 #define DUMP_LOOPSTATS
73 #endif//PV_OSCL_SOCKET_STATS_LOGGING
74
Init(OsclSocketServI * aContainer)75 void OsclSocketServI::LoopbackSocket::Init(OsclSocketServI* aContainer)
76 //This will intialize the loopback socket that is used
77 //to wakeup a blocking select call.
78 {
79 iContainer = aContainer;
80 #if PV_OSCL_SOCKET_STATS_LOGGING
81 iStats.Construct(NULL, this);
82 #endif
83
84 //create the socket
85 bool ok;
86 int err;
87 OsclSocket(iSocket, OSCL_AF_INET, OSCL_SOCK_DATAGRAM, OSCL_IPPROTO_UDP, ok, err);
88 if (!ok)
89 {
90 ADD_LOOPSTATS(EOsclSocketServ_LoopsockError, err);
91 return ;
92 }
93
94 //set it to non-blocking mode
95 OsclSetNonBlocking(iSocket, ok, err);
96 if (!ok)
97 {//set non-blocking mode failed
98 ADD_LOOPSTATS(EOsclSocketServ_LoopsockError, err);
99 OsclCloseSocket(iSocket, ok, err);
100 return ;
101 }
102
103 //bind to any available port between 5000 and 10000.
104 OsclNetworkAddress myAddr("127.0.0.1", 5000);
105 while (myAddr.port < 10000)
106 {
107 OsclSocketI::MakeAddr(myAddr, iAddr);
108 OsclBind(iSocket, iAddr, ok, err);
109 if (!ok)
110 {
111 myAddr.port++;
112 }
113 else
114 {
115 break;//bind success!
116 }
117 }
118
119 if (!ok)
120 {//bind failed
121 ADD_LOOPSTATS(EOsclSocketServ_LoopsockError, err);
122 OsclCloseSocket(iSocket, ok, err);
123 return ;
124 }
125
126 //let's test a send & recv here just to be extra sure
127 //the loopsock is usable.
128 const char tmpBuf[2] = {0, 0};
129 int nbytes;
130 bool wouldblock;
131 wouldblock = false;
132 ok = false;
133 nbytes = 0;
134 OsclSendTo(iSocket, tmpBuf, 1, iAddr, ok, err, nbytes, wouldblock);
135 if (!ok)
136 {
137 if (wouldblock)
138 {
139 //just skip the test
140 ok = true;
141 }
142 else
143 {
144 //send failed.
145 ADD_LOOPSTATS(EOsclSocketServ_LoopsockError, err);
146 OsclCloseSocket(iSocket, ok, err);
147 return ;
148 }
149 }
150 else
151 {
152 //send ok-- now try a recv
153 TOsclSockAddr sourceaddr;
154 TOsclSockAddrLen sourceaddrlen = sizeof(sourceaddr);
155 ok = false;
156 nbytes = 0;
157 OsclRecvFrom(iSocket, tmpBuf, sizeof(tmpBuf),
158 &sourceaddr,
159 &sourceaddrlen,
160 ok,
161 err,
162 nbytes,
163 wouldblock);
164 if (!ok)
165 {
166 if (wouldblock)
167 {
168 //just skip the test
169 ok = true;
170 }
171 else
172 {//recv failed.
173 ADD_LOOPSTATS(EOsclSocketServ_LoopsockError, err);
174 OsclCloseSocket(iSocket, ok, err);
175 return ;
176 }
177 }
178 }
179
180 //loopsock is ready to use
181 ADD_LOOPSTATS(EOsclSocketServ_LoopsockOk, myAddr.port);
182 #if PV_OSCL_SOCKET_STATS_LOGGING
183 iStats.Construct((OsclAny*)iSocket, this);
184 #endif
185 iEnable = true;
186 }
187
Cleanup()188 void OsclSocketServI::LoopbackSocket::Cleanup()
189 //This will intialize the loopback socket that is used
190 //to wakeup a blocking select call.
191 {
192 if (iEnable)
193 {
194 //close the socket
195 bool ok;
196 int sockerr;
197 OsclCloseSocket(iSocket, ok, sockerr);
198 iEnable = false;
199 DUMP_LOOPSTATS;
200 }
201 }
202
Read()203 void OsclSocketServI::LoopbackSocket::Read()
204 {
205 if (!iEnable)
206 return;
207
208 //read all queued data on the socket
209 if (FD_ISSET(iSocket, &iContainer->iReadset))
210 {
211 char tmpBuf[2] = {0, 0};
212 int nbytes, err;
213 bool ok, wouldblock;
214 TOsclSockAddr sourceaddr;
215 TOsclSockAddrLen sourceaddrlen = sizeof(sourceaddr);
216
217 bool recv = true;
218 while (recv)
219 {
220 OsclRecvFrom(iSocket, tmpBuf, sizeof(tmpBuf),
221 &sourceaddr,
222 &sourceaddrlen,
223 ok,
224 err,
225 nbytes,
226 wouldblock);
227 recv = (ok && nbytes > 0);
228 }
229 }
230 }
231
ProcessSelect(TOsclSocket & maxsocket)232 void OsclSocketServI::LoopbackSocket::ProcessSelect(TOsclSocket& maxsocket)
233 //Do the necessary select loop processing to keep
234 //the loopback socket going.
235 {
236 if (!iEnable)
237 return;
238
239 //Monitor this socket whenever we will be doing a select.
240 if (maxsocket)
241 {
242 FD_SET(iSocket, &iContainer->iReadset);
243 if (iSocket > maxsocket)
244 maxsocket = iSocket;
245 }
246 }
247
Write()248 void OsclSocketServI::LoopbackSocket::Write()
249 //Write to the loopback socket
250 {
251 if (!iEnable)
252 return;
253
254 char tmpBuf[2] = {0, 0};
255 int nbytes, err;
256 bool wouldblock, ok;
257 OsclSendTo(iSocket, tmpBuf, 1, iAddr, ok, err, nbytes, wouldblock);
258
259 //if send failed, the select call will hang forever, so just go ahead and abort now.
260 OSCL_ASSERT(ok);
261 }
262 #endif //#if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
263
264 // Socket server stats for winmobile perf investigation.
265 #if (PV_SOCKET_SERVI_STATS)
266
267 //breakdown of time in the Session
268 enum TServiSessionStats
269 {
270 EServiSession_All
271 , EServiSession_Last
272 };
273
274 //breakdown of time in the Run() call
275 enum TServiRunStats
276 {
277 EServiRun_Proc = EServiSession_Last
278 , EServiRun_Select
279 , EServiRun_Reschedule
280 , EServiRun_Last
281 };
282 //breakdown of time in the ProcessSocketRequests call
283 enum TServiProcStats
284 {
285 EServiProc_Queue = EServiRun_Last
286 , EServiProc_Loop
287 , EServiProc_Fdset
288 , EServiProc_Last
289 };
290 //breakdown of time in the ProcessXXX calls in ProcessSocketRequests
291 enum TServiProcLoopStats
292 {
293 EServiProcLoop_Cancel = EServiProc_Last
294 , EServiProcLoop_Closed
295 , EServiProcLoop_Connect
296 , EServiProcLoop_Accept
297 , EServiProcLoop_Shutdown
298 , EServiProcLoop_Recv
299 , EServiProcLoop_Send
300 , EServiProcLoop_RecvFrom
301 , EServiProcLoop_SendTo
302 , EServiProcLoop_Last
303 };
304 static const char* const TServiStr[] =
305 {
306 "EServiSession_All"
307 , "EServiRun_Proc"
308 , "EServiRun_Select"
309 , "EServiRun_Reschedule"
310 , "EServiProc_Queue"
311 , "EServiProc_Loop"
312 , "EServiProc_Fdset"
313 , "EServiProcLoop_Cancel"
314 , "EServiProcLoop_Closed"
315 , "EServiProcLoop_Connect"
316 , "EServiProcLoop_Accept"
317 , "EServiProcLoop_Shutdown"
318 , "EServiProcLoop_Recv"
319 , "EServiProcLoop_Send"
320 , "EServiProcLoop_RecvFrom"
321 , "EServiProcLoop_SendTo"
322 };
323
324
325 #define PV_SERVI_STATS_SIZE (EServiProcLoop_Last)
326 #include "oscl_int64_utils.h"
327
328 class PVServiStats
329 {
330 public:
331 //use oscl tick count
332 typedef uint32 TPVTick;
Tickstr()333 const char* Tickstr()
334 {
335 return "Ticks";
336 }
settick(TPVTick & tick)337 void settick(TPVTick &tick)
338 {
339 tick = OsclTickCount::TickCount();
340 }
tickint(TPVTick & tick)341 int64 tickint(TPVTick& tick)
342 {
343 return tick;
344 }
345
PVServiStats()346 PVServiStats(): iCount(0), iRunningTotal(0)
347 {}
~PVServiStats()348 ~PVServiStats()
349 {}
350
351 uint32 iCount;
352 int64 iRunningTotal;
353
354 TPVTick _start;
355
356 //start an interval
Start()357 void Start()
358 {
359 settick(_start);
360 }
361
362 //end an interval
End()363 void End()
364 {
365 TPVTick now;
366 settick(now);
367 int32 delta = tickint(now) - tickint(_start);
368 //winmobile clock sometimes goes backward so treat any negative delta as zero.
369 if (delta > 0)
370 iRunningTotal += delta;
371 iCount++;
372 }
373 //end a long interval
LongEnd()374 void LongEnd()
375 {
376 TPVTick now;
377 settick(now);
378 int64 delta = tickint(now) - tickint(_start);
379 //winmobile clock sometimes goes backward so treat any negative delta as zero.
380 if (delta > 0)
381 iRunningTotal += delta;
382 iCount++;
383 }
384
Create()385 static PVServiStats* Create()
386 {
387 _OsclBasicAllocator alloc;
388 OsclAny* ptr = alloc.allocate(PV_SERVI_STATS_SIZE * sizeof(PVServiStats));
389 PVServiStats* ptr2 = (PVServiStats*)ptr;
390 for (uint32 i = 0; i < PV_SERVI_STATS_SIZE; i++)
391 {
392 new(ptr2++) PVServiStats();
393 }
394 return (PVServiStats*)ptr;
395 }
396
Destroy(PVServiStats * aStats)397 static void Destroy(PVServiStats* aStats)
398 {
399 if (aStats)
400 {
401 _OsclBasicAllocator alloc;
402 //don't bother with destructor since it's empty.
403 alloc.deallocate(aStats);
404 }
405 }
406
ShowStats(PVLogger * logger,int32 aIndex,PVServiStats & aInterval)407 void ShowStats(PVLogger* logger, int32 aIndex, PVServiStats& aInterval)
408 {
409 if (!iCount)
410 return;//don't print any that didn't run
411 if (aInterval.iRunningTotal == (int64)0)
412 return;//to avoid div by zero
413
414 float percent = 100.0 * iRunningTotal / aInterval.iRunningTotal;
415 int32 fraction = (int32)percent;
416 float decimal = percent - fraction;
417 decimal *= 100.0;
418
419 //print results
420 PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, logger, PVLOGMSG_INFO
421 , (0, " TIME PERCENT %d.%02d, Interval '%s', Count %d, TotalTicks Hi,Lo (0x%x,0x%08x)"
422 , (int32)percent, (int32)decimal
423 , TServiStr[aIndex]
424 , iCount
425 , Oscl_Int64_Utils::get_int64_upper32(iRunningTotal)
426 , Oscl_Int64_Utils::get_int64_lower32(iRunningTotal)
427 ));
428 }
429
ShowSummaryStats(PVServiStats * aArray)430 static void ShowSummaryStats(PVServiStats* aArray)
431 {
432 //lump this logging with Oscl scheduler perf logging.
433 uint32 index = 0;
434 PVLogger* logger = PVLogger::GetLoggerObject("OsclSchedulerPerfStats");
435
436 PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, logger, PVLOGMSG_INFO, (0, "Session Breakdown:"));
437 while (index < EServiSession_Last)
438 {
439 aArray[index].ShowStats(logger, index, aArray[EServiSession_All]);
440 index++;
441 }
442
443 PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, logger, PVLOGMSG_INFO, (0, "Run Breakdown:"));
444 while (index < EServiRun_Last)
445 {
446 aArray[index].ShowStats(logger, index, aArray[EServiSession_All]);
447 index++;
448 }
449
450 PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, logger, PVLOGMSG_INFO, (0, "ProcessRequests Breakdown:"));
451 while (index < EServiProc_Last)
452 {
453 aArray[index].ShowStats(logger, index, aArray[EServiSession_All]);
454 index++;
455 }
456
457 PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, logger, PVLOGMSG_INFO, (0, "ProcessRequests Loop Breakdown:"));
458 while (index < EServiProcLoop_Last)
459 {
460 aArray[index].ShowStats(logger, index, aArray[EServiSession_All]);
461 index++;
462 }
463 }
464 };
465 #define START_SERVI_STATS(x) iServiStats[x].Start()
466 #define END_SERVI_STATS(x) iServiStats[x].End()
467 #define LONG_END_SERVI_STATS(x) iServiStats[x].LongEnd()
468 //2nd level of detail-- switched off for now.
469 #define START_SERVI_STATS2(x) iServiStats[x].Start()
470 #define END_SERVI_STATS2(x) iServiStats[x].End()
471 #else
472 #define START_SERVI_STATS(x)
473 #define END_SERVI_STATS(x)
474 #define LONG_END_SERVI_STATS(x)
475 #define START_SERVI_STATS2(x)
476 #define END_SERVI_STATS2(x)
477 #endif //PV_SOCKET_SERVI_STATS
478
479 //
480 //OsclSocketServI-- PV implementation
481 //
482
483 #if(PV_SOCKET_SERVER_IS_THREAD)
OsclSocketServI(Oscl_DefAlloc & a)484 OsclSocketServI::OsclSocketServI(Oscl_DefAlloc &a)
485 : OsclSocketServIBase(a)
486 {
487 }
488 #else
OsclSocketServI(Oscl_DefAlloc & a)489 OsclSocketServI::OsclSocketServI(Oscl_DefAlloc &a)
490 : OsclTimerObject(PV_SOCKET_SERVER_AO_PRIORITY, "OsclSocketServI")
491 , OsclSocketServIBase(a)
492 {
493 }
494 #endif
495
~OsclSocketServI()496 OsclSocketServI::~OsclSocketServI()
497 {
498 Close(false);
499 CleanupServImp();
500 }
501
NewL(Oscl_DefAlloc & a)502 OsclSocketServI* OsclSocketServI::NewL(Oscl_DefAlloc &a)
503 {
504 OsclAny*p = a.ALLOCATE(sizeof(OsclSocketServI));
505 OsclError::LeaveIfNull(p);
506 OsclSocketServI *self = OSCL_PLACEMENT_NEW(p, OsclSocketServI(a));
507 OsclError::LeaveIfNull(self);
508 OsclError::PushL(self);
509 self->ConstructL();
510 OsclError::Pop();
511 return self;
512 }
513
ConstructL()514 void OsclSocketServI::ConstructL()
515 {
516 iSockServRequestList.iActiveRequests.reserve(6);
517 ConstructServImp();
518 CONSTRUCT_STATS(this);
519 }
520
Connect(uint32 aMessageSlots)521 int32 OsclSocketServI::Connect(uint32 aMessageSlots)
522 {
523 CONSTRUCT_STATS(this);
524
525 #if (PV_SOCKET_SERVI_STATS)
526 iServiStats = PVServiStats::Create();
527 START_SERVI_STATS(EServiSession_All);
528 #endif
529
530 //Connect to Oscl socket server
531
532 OSCL_UNUSED_ARG(aMessageSlots);
533
534 //should only connect once
535 if (iServState == ESocketServ_Connected)
536 {
537 return OsclErrGeneral;
538 }
539
540 #ifdef OsclSocketStartup
541 //startup the socket system.
542 bool ok;
543 OsclSocketStartup(ok);
544 if (!ok)
545 {
546 return OsclErrGeneral;
547 }
548 #endif//OsclSocketStartup
549
550 iServState = ESocketServ_Idle;
551
552 //Start the server thread or AO
553 int32 err = StartServImp();
554 if (err != OsclErrNone)
555 {
556 return err;
557 }
558
559 //check state.
560 if (iServState != ESocketServ_Connected)
561 {
562 //cleanup after a failure.
563 Close(false);
564 return OsclErrGeneral;
565 }
566 return OsclErrNone;
567 }
568
Close(bool aCleanup)569 void OsclSocketServI::Close(bool aCleanup)
570 {
571 //Close oscl socket server
572
573 if (iServState == ESocketServ_Connected)
574 {
575 StopServImp();
576 }
577
578 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
579 iLoopbackSocket.Cleanup();
580 #endif
581
582 #ifdef OsclSocketCleanup
583 //close the socket system
584 if (aCleanup)
585 {
586 bool ok;
587 OsclSocketCleanup(ok);
588 }
589 #endif//OsclSocketCleanup
590
591 DUMP_STATS;
592
593 #if (PV_SOCKET_SERVI_STATS)
594 if (iServiStats)
595 {
596 LONG_END_SERVI_STATS(EServiSession_All);
597 PVServiStats::ShowSummaryStats(iServiStats);
598 PVServiStats::Destroy(iServiStats);
599 iServiStats = NULL;
600 }
601 #endif
602 }
603
IsServerThread()604 bool OsclSocketServI::IsServerThread()
605 {
606 #if(PV_SOCKET_SERVER_IS_THREAD)
607 TOsclThreadId tid;
608 OsclThread::GetId(tid);
609 return tid == iThreadId;
610 #else
611 return true;
612 #endif
613 }
614
615 /**
616 * Process all active socket requests.
617 *
618 * This is called under the server thread or server AO.
619 *
620 * @param aNhandles(input/output): nHandles returned by last Select call.
621 * @param aNfds(output): Value = 1+maximum socket handle for all sockets
622 * that we are monitoring with the select call.
623 */
624 #if PV_SOCKET_SERVER_SELECT
ProcessSocketRequests(int & aNhandles,int & aNfds)625 void OsclSocketServI::ProcessSocketRequests(int& aNhandles, int &aNfds)
626 #else
627 void OsclSocketServI::ProcessSocketRequests()
628 #endif
629 {
630 //process all active requests
631
632 #if PV_SOCKET_SERVER_SELECT
633 //keep track of max socket handle to monitor.
634 TOsclSocket maxsocket = 0;
635 aNfds = (int)maxsocket + 1;
636
637 //save input handle count, then clear it until the next select operation.
638 int nhandles = aNhandles;
639 aNhandles = 0;
640 #endif
641
642 // Pick up new requests from the app thread.
643 START_SERVI_STATS2(EServiProc_Queue);
644 iSockServRequestList.Lock();
645 {
646 iSockServRequestList.GetNewRequests();
647
648 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
649 //flush any data on the loopback socket.
650 iLoopbackSocket.Read();
651 #endif
652 }
653 iSockServRequestList.Unlock();
654 END_SERVI_STATS2(EServiProc_Queue);
655
656 if (iSockServRequestList.iActiveRequests.empty())
657 {
658 //nothing to do!
659 return;
660 }
661
662 //Make a pass through the open request list and cancel or process each request.
663 START_SERVI_STATS2(EServiProc_Loop);
664 uint32 i;
665 for (i = 0; i < iSockServRequestList.iActiveRequests.size(); i++)
666 {
667 OsclSocketServRequestQElem* elem = &iSockServRequestList.iActiveRequests[i];
668
669 if (elem->iCancel)
670 {
671 //Request was canceled
672 START_SERVI_STATS2(EServiProcLoop_Cancel);
673 elem->iSocketRequest->Complete(elem, OSCL_REQUEST_ERR_CANCEL);
674 END_SERVI_STATS2(EServiProcLoop_Cancel);
675 }
676 else if (!IsServConnected())
677 {
678 //Server died or was closed.
679 START_SERVI_STATS2(EServiProcLoop_Closed);
680 elem->iSocketRequest->Complete(elem, OSCL_REQUEST_ERR_GENERAL
681 , (iServError) ? iServError : PVSOCK_ERR_SERV_NOT_CONNECTED);
682 END_SERVI_STATS2(EServiProcLoop_Closed);
683 }
684 #if PV_SOCKET_SERVER_SELECT
685 else if (nhandles == 0 && elem->iSelect)
686 {
687 //we're monitoring this socket but there is no current
688 //socket activity-- just keep waiting.
689 ;
690 }
691 #endif
692 else
693 {
694 //These routines will start the request, or else process
695 //the results of prior select call, and also set the select
696 //flags for the next call.
697
698 switch (elem->iSocketRequest->Fxn())
699 {
700 case EPVSocketShutdown:
701 START_SERVI_STATS2(EServiProcLoop_Shutdown);
702 elem->iSocketRequest->iSocketI->ProcessShutdown(elem);
703 END_SERVI_STATS2(EServiProcLoop_Shutdown);
704 break;
705
706 case EPVSocketConnect:
707 START_SERVI_STATS2(EServiProcLoop_Connect);
708 elem->iSocketRequest->iSocketI->ProcessConnect(elem);
709 END_SERVI_STATS2(EServiProcLoop_Connect);
710 break;
711
712 case EPVSocketAccept:
713 START_SERVI_STATS2(EServiProcLoop_Accept);
714 elem->iSocketRequest->iSocketI->ProcessAccept(elem);
715 END_SERVI_STATS2(EServiProcLoop_Accept);
716 break;
717
718 case EPVSocketSend:
719 START_SERVI_STATS2(EServiProcLoop_Send);
720 elem->iSocketRequest->iSocketI->ProcessSend(elem);
721 END_SERVI_STATS2(EServiProcLoop_Send);
722 break;
723
724 case EPVSocketSendTo:
725 START_SERVI_STATS2(EServiProcLoop_SendTo);
726 elem->iSocketRequest->iSocketI->ProcessSendTo(elem);
727 END_SERVI_STATS2(EServiProcLoop_SendTo);
728 break;
729
730 case EPVSocketRecv:
731 START_SERVI_STATS2(EServiProcLoop_Recv);
732 elem->iSocketRequest->iSocketI->ProcessRecv(elem);
733 END_SERVI_STATS2(EServiProcLoop_Recv);
734 break;
735
736 case EPVSocketRecvFrom:
737 START_SERVI_STATS2(EServiProcLoop_RecvFrom);
738 elem->iSocketRequest->iSocketI->ProcessRecvFrom(elem);
739 END_SERVI_STATS2(EServiProcLoop_RecvFrom);
740 break;
741
742 default:
743 OSCL_ASSERT(0);
744 break;
745 }
746 }
747 }
748 END_SERVI_STATS2(EServiProc_Loop);
749
750 //Zero out any old select set
751 START_SERVI_STATS2(EServiProc_Fdset);
752 #if PV_SOCKET_SERVER_SELECT
753 FD_ZERO(&iReadset);
754 FD_ZERO(&iWriteset);
755 FD_ZERO(&iExceptset);
756 #endif
757 LOGSERV((0, "OsclSocketServI::ProcessSocketRequests Clearing select set"));
758
759 //Now make a pass to either delete the request or collate the select flags.
760 for (i = 0; i < iSockServRequestList.iActiveRequests.size();)
761 {
762 OsclSocketServRequestQElem* elem = &iSockServRequestList.iActiveRequests[i];
763
764 if (elem->iSocketRequest)
765 {
766 //request is still active
767 i++;
768
769 #if PV_SOCKET_SERVER_SELECT
770 if (elem->iSelect > 0)
771 {
772 //Need to do a select call for this socket
773
774 TOsclSocket osock = elem->iSocketRequest->iSocketI->Socket();
775
776 if (osock > maxsocket)
777 {
778 LOGSERV((0, "OsclSocketServI::ProcessSocketRequests Setting Maxsocket to %d", osock));
779 maxsocket = osock;
780 }
781
782 //Add the socket to the select set. Keep in mind there can be multiple requests
783 //per socket, so check whether the socket is already added before adding.
784
785 if ((elem->iSelect & OSCL_READSET_FLAG) == OSCL_READSET_FLAG
786 && !(FD_ISSET(osock, &iReadset)))
787 {
788 FD_SET(osock, &iReadset);
789 LOGSERV((0, "OsclSocketServI::ProcessSocketRequests Setting Readset for %d", osock));
790 }
791
792 if ((elem->iSelect & OSCL_WRITESET_FLAG) == OSCL_WRITESET_FLAG
793 && !(FD_ISSET(osock, &iWriteset)))
794 {
795 FD_SET(osock, &iWriteset);
796 LOGSERV((0, "OsclSocketServI::ProcessSocketRequests Setting Writeset for %d", osock));
797 }
798
799 if ((elem->iSelect & OSCL_EXCEPTSET_FLAG) == OSCL_EXCEPTSET_FLAG
800 && !(FD_ISSET(osock, &iExceptset)))
801 {
802 FD_SET(osock, &iExceptset);
803 LOGSERV((0, "OsclSocketServI::ProcessSocketRequests Setting Exceptset for %d", osock));
804 }
805 }
806 #endif
807 }
808 else
809 {
810 //request is complete and can be deleted.
811 iSockServRequestList.iActiveRequests.erase(elem);
812 }
813 }
814 END_SERVI_STATS2(EServiProc_Fdset);
815
816 #if PV_SOCKET_SERVER_SELECT
817 if (maxsocket)
818 {
819 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
820 //also monitor the loopback socket if we're going to call select.
821 iLoopbackSocket.ProcessSelect(maxsocket);
822 #endif
823
824 //set Nfds to 1+maxsocket handle.
825 aNfds = (int)maxsocket + 1;
826 }
827
828 LOGSERV((0, "OsclSocketServI::ProcessSocketRequests NFDS %d", aNfds));
829 #endif
830
831 }
832
ServerEntry()833 void OsclSocketServI::ServerEntry()
834 //Server entry processing
835 {
836 iLogger = PVLogger::GetLoggerObject("osclsocket_serv");
837
838 iServError = 0;
839 iServState = OsclSocketServI::ESocketServ_Connected;
840
841 iSockServRequestList.Open(this);
842
843 #if PV_SOCKET_SERVER_SELECT
844 FD_ZERO(&iReadset);
845 FD_ZERO(&iWriteset);
846 FD_ZERO(&iExceptset);
847 #endif
848 }
849
ServerExit()850 void OsclSocketServI::ServerExit()
851 //Server exit processing
852 {
853 //change state if this was a normal exit.
854 if (iServState == OsclSocketServI::ESocketServ_Connected)
855 {
856 iServState = OsclSocketServI::ESocketServ_Idle;
857 }
858
859 //Go through the active requests one last time.
860 //All the requests will complete with errors
861 //since the server is no longer connected.
862 #if PV_SOCKET_SERVER_SELECT
863 int nfds;
864 int nhandles = 0;
865 ProcessSocketRequests(nhandles, nfds);
866 #else
867 ProcessSocketRequests();
868 #endif
869
870 iSockServRequestList.Close();
871
872 //make sure sets are clear so resources get cleaned up.
873 #if PV_SOCKET_SERVER_SELECT
874 FD_ZERO(&iReadset);
875 FD_ZERO(&iWriteset);
876 FD_ZERO(&iExceptset);
877 #endif
878 }
879
ConstructServImp()880 void OsclSocketServI::ConstructServImp()
881 {
882 #if(PV_SOCKET_SERVER_IS_THREAD)
883 iClose = false;
884 iStart.Create();
885 iExit.Create();
886 #endif
887 }
888
CleanupServImp()889 void OsclSocketServI::CleanupServImp()
890 {
891 #if(PV_SOCKET_SERVER_IS_THREAD)
892 iStart.Close();
893 iExit.Close();
894 #endif
895 }
896
897 #if(PV_SOCKET_SERVER_IS_THREAD)
898 //socket server thread routine
899 static TOsclThreadFuncRet OSCL_THREAD_DECL sockthreadmain(TOsclThreadFuncArg arg);
900 #endif
901
StartServImp()902 int32 OsclSocketServI::StartServImp()
903 {
904 #if(PV_SOCKET_SERVER_IS_THREAD)
905
906 //setup the loopback socket and/or polling interval.
907 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
908 iLoopbackSocket.iEnable = false;
909 #endif
910 iSelectPollIntervalMsec = 0;
911
912 //check the select timeout in the configuration.
913 int32 selectTimeoutMsec = PV_SOCKET_SERVER_SELECT_TIMEOUT_MSEC;
914 if (selectTimeoutMsec <= 0)
915 {
916 //non-polling option selected.
917 //create the select cancel pipe.
918 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
919 iLoopbackSocket.Init(this);
920
921 //if loopback socket isn't available, we must poll.
922 if (!iLoopbackSocket.iEnable)
923 #endif
924 {
925 iSelectPollIntervalMsec = 10;
926 }
927 }
928 else
929 {
930 //polling option selected.
931 iSelectPollIntervalMsec = selectTimeoutMsec;
932 #if(PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET)
933 //create the loopback socket.
934 iLoopbackSocket.Init(this);
935 #endif
936 }
937
938 //Start the server thread.
939 OsclThread thread;
940 OsclProcStatus::eOsclProcError err = thread.Create((TOsclThreadFuncPtr)sockthreadmain,
941 1024,
942 (TOsclThreadFuncArg)this);
943 if (err != OsclErrNone)
944 return OsclErrGeneral;
945
946 thread.SetPriority(PV_SOCKET_SERVER_THREAD_PRIORITY);
947
948 //wait til thread starts
949 iStart.Wait();
950
951 return OsclErrNone;
952
953 #else//PV_SOCKET_SERVER_IS_THREAD
954
955 //Socket server AO startup.
956
957 #if PV_SOCKET_SERVER_SELECT_LOOPBACK_SOCKET
958 iLoopbackSocket.iEnable = false;
959 #endif
960
961 ServerEntry();
962
963 if (!IsAdded())
964 {
965 #if PV_SOCKET_SERVER_SELECT
966 iNhandles = 0;
967 iNfds = 0;
968 #endif
969 AddToScheduler();
970 }
971 return OsclErrNone;
972
973 #endif //PV_SOCKET_SERVER_IS_THREAD
974 }
975
StopServImp()976 void OsclSocketServI::StopServImp()
977 {
978 #if(PV_SOCKET_SERVER_IS_THREAD)
979 //stop the thread.
980 iClose = true;
981 iSockServRequestList.Wakeup();//wake up the thread if needed.
982 WakeupBlockingSelect();
983 //wait til thread exits
984 iExit.Wait();
985
986 #else//PV_SOCKET_SERVER_IS_THREAD
987
988 //Socket server AO cleanup.
989 if (iServState != OsclSocketServI::ESocketServ_Connected)
990 {
991 return;
992 }
993
994 //cancel any active request.
995 if (IsAdded())
996 {
997 Cancel();
998 }
999
1000 ServerExit();
1001
1002 //remove AO from scheduler.
1003 if (IsAdded())
1004 {
1005 RemoveFromScheduler();
1006 }
1007 #endif//PV_SOCKET_SERVER_IS_THREAD
1008 }
1009
1010
1011 #if(PV_SOCKET_SERVER_IS_THREAD)
1012
InThread()1013 void OsclSocketServI::InThread()
1014 //Socket server thread implementation.
1015 {
1016 OsclThread::GetId(iThreadId);
1017
1018 iClose = false;
1019
1020 ServerEntry();
1021
1022 //Let server know thread is started and ready to
1023 //process requests.
1024 iStart.Signal();
1025
1026 //create select timeout structure
1027 timeval timeout;
1028
1029 bool ok;
1030 int nfds;
1031 int nhandles = 0;
1032
1033 while (!iClose)
1034 {
1035 //process new requests and new socket activity on existing requests.
1036 ProcessSocketRequests(nhandles, nfds);
1037
1038 //Make the select call if needed.
1039 if (nfds > 1)
1040 {
1041 //Set the fixed timeout. The select call may update this value
1042 //so it needs to be set on each call.
1043 timeout.tv_sec = 0;
1044
1045 if (iSelectPollIntervalMsec == 0)
1046 {
1047 //wait forever
1048 timeout.tv_usec = 0x1fffffff;
1049 }
1050 else
1051 {
1052 //poll
1053 timeout.tv_usec = iSelectPollIntervalMsec * 1000;
1054 }
1055
1056 LOGSERV((0, "OsclSocketServI::InThread Calling select, timeout %d", iSelectPollIntervalMsec));
1057 OsclSocketSelect(nfds, iReadset, iWriteset, iExceptset, timeout, ok, iServError, nhandles);
1058 LOGSERV((0, "OsclSocketServI::InThread Select call returned"));
1059 if (!ok)
1060 {
1061 //select error.
1062 iServState = OsclSocketServI::ESocketServ_Error;
1063 break;
1064 }
1065 if (nhandles)
1066 {
1067 ADD_STATS(EOsclSocketServ_SelectActivity);
1068 }
1069 else
1070 {
1071 ADD_STATS(EOsclSocketServ_SelectNoActivity);
1072 }
1073 }
1074 else
1075 {
1076 //wait on new requests from the app side.
1077 LOGSERV((0, "OsclSocketServI::InThread Waiting on requests"));
1078 iSockServRequestList.WaitOnRequests();
1079 LOGSERV((0, "OsclSocketServI::InThread Done Waiting on requests"));
1080 }
1081
1082 }//select loop
1083
1084 ServerExit();
1085
1086 //signal close complete to caller...
1087 if (iClose)
1088 {
1089 iClose = false;
1090 iExit.Signal();
1091 }
1092 }
1093
1094 static TOsclThreadFuncRet OSCL_THREAD_DECL sockthreadmain2(TOsclThreadFuncArg arg);
sockthreadmain(TOsclThreadFuncArg arg)1095 static TOsclThreadFuncRet OSCL_THREAD_DECL sockthreadmain(TOsclThreadFuncArg arg)
1096 //socket server thread.
1097 {
1098 OsclBase::Init();
1099 OsclErrorTrap::Init();
1100
1101 //once error trap is initialized, run everything else under a trap
1102 int32 err;
1103 OSCL_TRY(err,
1104
1105 OsclMem::Init();
1106 PVLogger::Init();
1107
1108 sockthreadmain2(arg);
1109
1110 PVLogger::Cleanup();
1111 OsclMem::Cleanup();
1112 );
1113
1114 OsclErrorTrap::Cleanup();
1115 OsclBase::Cleanup();
1116
1117 return 0;
1118 }
1119
1120
1121 #include "pvlogger.h"
1122
1123 #if(PV_OSCL_SOCKET_SERVER_LOGGER_OUTPUT)
1124 #include "pvlogger_time_and_id_layout.h"
1125 #include "pvlogger_file_appender.h"
1126 #include "pvlogger_stderr_appender.h"
1127
1128 #define LOGFILENAME _STRLIT_WCHAR("pvosclsocket_serv.log");
1129
1130 template<class DestructClass>
1131 class LogAppenderDestructDealloc : public OsclDestructDealloc
1132 {
1133 public:
destruct_and_dealloc(OsclAny * ptr)1134 void destruct_and_dealloc(OsclAny *ptr)
1135 {
1136 delete((DestructClass*)ptr);
1137 }
1138 };
1139 #endif//PV_OSCL_SOCKET_SERVER_LOGGER_OUTPUT
1140
1141
sockthreadmain2(TOsclThreadFuncArg arg)1142 static TOsclThreadFuncRet OSCL_THREAD_DECL sockthreadmain2(TOsclThreadFuncArg arg)
1143 {
1144 OSCL_ASSERT(arg);
1145 OsclSocketServI *serv = (OsclSocketServI*)arg;
1146
1147 #if(PV_OSCL_SOCKET_SERVER_LOGGER_OUTPUT)
1148 //create logger appenders.
1149 PVLoggerAppender* appender;
1150
1151 //File logger
1152 //find an unused filename so we don't over-write any prior logs
1153 Oscl_FileServer fs;
1154 Oscl_File file;
1155 fs.Connect();
1156 OSCL_wHeapString<OsclMemAllocator> filename;
1157 oscl_wchar fileid[2];
1158 fileid[1] = (oscl_wchar)'\0';
1159 for (char c = 'A'; c <= 'Z'; c++)
1160 {
1161 filename = LOGFILENAME;
1162 fileid[0] = (oscl_wchar)c;
1163 filename += fileid;
1164 filename += _STRLIT_WCHAR(".txt");
1165 if (file.Open((oscl_wchar*)filename.get_cstr(), Oscl_File::MODE_READ, fs) != 0)
1166 {
1167 break;//found a nonexistent file.
1168 }
1169 file.Close();
1170 }
1171 fs.Close();
1172 //create appender using the selected filename.
1173 appender = TextFileAppender<TimeAndIdLayout, 1024>::CreateAppender((OSCL_TCHAR*)filename.get_cstr());
1174 OsclRefCounterSA<LogAppenderDestructDealloc<TextFileAppender<TimeAndIdLayout, 1024> > > *appenderRefCounter =
1175 new OsclRefCounterSA<LogAppenderDestructDealloc<TextFileAppender<TimeAndIdLayout, 1024> > >(appender);
1176 //Set logging options.
1177 OsclSharedPtr<PVLoggerAppender> appenderPtr(appender, appenderRefCounter);
1178 PVLogger *rootnode = PVLogger::GetLoggerObject("");
1179 rootnode->AddAppender(appenderPtr);
1180 rootnode->SetLogLevel(PVLOGMSG_DEBUG);
1181 #endif //PV_OSCL_SOCKET_SERVER_LOGGER_OUTPUT
1182
1183 serv->InThread();
1184
1185 return 0;
1186 }
1187
1188
1189 #else//PV_SOCKET_SERVER_IS_THREAD
1190 //Non-threaded section
1191
Run()1192 void OsclSocketServI::Run()
1193 //Socket server AO
1194 {
1195 #if !PV_SOCKET_SERVER_SELECT
1196 //non-select-loop implementation.
1197
1198 //Process active requests.
1199 START_SERVI_STATS(EServiRun_Proc);
1200 ProcessSocketRequests();
1201 END_SERVI_STATS(EServiRun_Proc);
1202
1203 //Re-schedule
1204 START_SERVI_STATS(EServiRun_Reschedule);
1205 if (!iSockServRequestList.iActiveRequests.empty())
1206 {
1207 // Re-schedule after a delay for continued monitoring
1208 // of active requests.
1209 // Note: new requests will interrupt this polling interval
1210 // and schedule ASAP.
1211 ADD_STATS(EOsclSocketServ_SelectReschedulePoll);
1212 RunIfNotReady(1000*PV_SOCKET_SERVER_AO_INTERVAL_MSEC);
1213 }
1214 END_SERVI_STATS(EServiRun_Reschedule);
1215
1216 #else
1217 //select loop implementation.
1218
1219 //loop 2x so we can complete some requests in one call.
1220 for (uint32 i = 0; i < 2; i++)
1221 {
1222 //Process active requests.
1223 START_SERVI_STATS(EServiRun_Proc);
1224 ProcessSocketRequests(iNhandles, iNfds);
1225 END_SERVI_STATS(EServiRun_Proc);
1226
1227 //Make the select call if needed.
1228 if (iNfds > 1)
1229 {
1230 START_SERVI_STATS(EServiRun_Select);
1231 //use a delay of zero since we're essentially polling for socket activity.
1232 //note the select call may update this value so it must be set prior to each call.
1233 timeval timeout;
1234 timeout.tv_sec = 0;
1235 timeout.tv_usec = 0;
1236 bool ok;
1237 OsclSocketSelect(iNfds, iReadset, iWriteset, iExceptset, timeout, ok, iServError, iNhandles);
1238 END_SERVI_STATS(EServiRun_Select);
1239 if (!ok)
1240 {
1241 //a select error is fatal.
1242 StopServImp();//stop the AO
1243 iServState = OsclSocketServI::ESocketServ_Error;
1244 return;
1245 }
1246
1247 if (iNhandles)
1248 {
1249 ADD_STATS(EOsclSocketServ_SelectActivity);
1250 }
1251 else
1252 {
1253 ADD_STATS(EOsclSocketServ_SelectNoActivity);
1254 }
1255 }
1256 }
1257
1258 //Re-schedule
1259 START_SERVI_STATS(EServiRun_Reschedule);
1260 if (!iSockServRequestList.iActiveRequests.empty())
1261 {
1262 if (iNhandles)
1263 {
1264 // Re-schedule ASAP when we have socket activity.
1265 ADD_STATS(EOsclSocketServ_SelectRescheduleAsap);
1266 RunIfNotReady();
1267 }
1268 else
1269 {
1270 // Re-schedule after a delay for continued monitoring
1271 // of active requests.
1272 // Note: new requests will interrupt this polling interval
1273 // and schedule ASAP.
1274 ADD_STATS(EOsclSocketServ_SelectReschedulePoll);
1275 RunIfNotReady(1000*PV_SOCKET_SERVER_AO_INTERVAL_MSEC);
1276 }
1277 }
1278 END_SERVI_STATS(EServiRun_Reschedule);
1279
1280 #endif //PV_SOCKET_SERVER_SELECT
1281 }
1282
1283 //re-schedule the AO when a new request comes in.
WakeupAO()1284 void OsclSocketServI::WakeupAO()
1285 {
1286 if (IsAdded())
1287 {
1288 // To avoid waiting for the polling period to expire,
1289 // cancel and activate for immediate run
1290 if (IsBusy())
1291 Cancel();
1292
1293 RunIfNotReady();
1294 }
1295 }
1296
1297
1298 #endif//PV_SOCKET_SERVER_IS_THREAD
1299 #endif //PV_SOCKET_SERVER
1300
1301
1302
1303