• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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