Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

SoundSrv.cc

Go to the documentation of this file.
00001 /*
00002 
00003     Sound card input server
00004     Copyright (C) 1999-2002 Jussi Laako
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 */
00021 
00022 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <limits.h>
00028 #include <errno.h>
00029 #include <signal.h>
00030 #include <time.h>
00031 #include <sched.h>
00032 #include <netdb.h>
00033 #include <sys/socket.h>
00034 #include <sys/types.h>
00035 //#include <sys/time.h>
00036 #include <sys/mman.h>
00037 #include <netinet/in.h>
00038 #include <netinet/ip.h>
00039 #include <netinet/tcp.h>
00040 #include <arpa/inet.h>
00041 #include <pth.h>
00042 
00043 #include "Config.h"
00044 #include "SoundSrv.hh"
00045 
00046 
00047 clSoundSrv *SoundSrv;
00048 
00049 
00050 void *Input(void *vpNone)
00051 {
00052     SoundSrv->InputExec();
00053     return NULL;
00054 }
00055 
00056 
00057 void *WaitConnect(void *vpNone)
00058 {
00059     SoundSrv->WaitConnectExec();
00060     return NULL;
00061 }
00062 
00063 
00064 void *ServeClient(void *vpHandle)
00065 {
00066     SoundSrv->ServeClientExec(vpHandle);
00067     return NULL;
00068 }
00069 
00070 
00071 int main(int argc, char *argv[])
00072 {
00073     bool bDaemon = false;
00074     int iArgCntr;
00075     char cpDevice[_POSIX_PATH_MAX + 1];
00076     #ifndef BSDSYS
00077     uid_t uidCurrent;
00078     struct sched_param sSchedParam;
00079     #endif
00080     
00081     signal(SIGPIPE, SIG_IGN);
00082     signal(SIGFPE, SIG_IGN);
00083     #ifndef BSDSYS
00084     uidCurrent = getuid();
00085     setuid(0);
00086     sSchedParam.sched_priority = SS_SCHED_PRIORITY;
00087     sched_setscheduler(0, SCHED_FIFO, &sSchedParam);
00088     setuid(uidCurrent);
00089     #endif
00090     if (pth_init() < 0)
00091     {
00092         fprintf(stderr, "fatal: pth_init() failed\n");
00093         exit(1);
00094     }
00095     strcpy(cpDevice, SS_SND_DEVICE);
00096     if (argc >= 2)
00097     {
00098         for (iArgCntr = 1; iArgCntr < argc; iArgCntr++)
00099         {
00100             if (strcmp(argv[iArgCntr], "-D") == 0)
00101             {
00102                 bDaemon = true;
00103             }
00104             else if (strcmp(argv[iArgCntr], "--version") == 0)
00105             {
00106                 printf("SoundSrv v%i.%i.%i\n", SS_VERSMAJ, SS_VERSMIN,
00107                     SS_VERSPL);
00108                 printf("Copyright (C) 1999-2001 Jussi Laako\n");
00109                 return 0;
00110             }
00111             else if (strcmp(argv[iArgCntr], "--help") == 0)
00112             {
00113                 printf("%s [-D|--version|--help|device]\n\n", argv[0]);
00114                 printf("-D         start as daemon\n");
00115                 printf("--version  display version information\n");
00116                 printf("--help     display this help\n");
00117                 printf("device     use device (eg. dsp0)\n");
00118                 return 0;
00119             }
00120             else
00121             {
00122                 strcpy(cpDevice, argv[iArgCntr]);
00123             }
00124         }
00125     }
00126     if (bDaemon)
00127     {
00128         if (fork() != 0)
00129         {
00130             exit(0);
00131         }
00132         setsid();
00133         freopen("/dev/null", "r+", stderr);
00134         freopen("/dev/null", "r+", stdin);
00135         freopen("/dev/null", "r+", stdout);
00136     }
00137     SoundSrv = new clSoundSrv(argv[0], cpDevice);
00138     SoundSrv->Exec();
00139     delete SoundSrv;
00140     pth_kill();
00141     return 0;
00142 }
00143 
00144 
00145 clSoundSrv::clSoundSrv(const char *cpName, const char *cpAudioDev)
00146 {
00147     int iBits;
00148     int iLoopCntr;
00149     int iOSSVersion;
00150     long lPthVersion;
00151     char cpCfgName[_POSIX_PATH_MAX + 1];
00152     char cpLogName[_POSIX_PATH_MAX + 1];
00153     char cpDevName[_POSIX_PATH_MAX + 1];
00154     char cpLogTxt[256];
00155     
00156     bRun = true;
00157     for (iLoopCntr = 0; iLoopCntr < SS_MAXCLIENTS; iLoopCntr++)
00158     {
00159         ipClientH[iLoopCntr] = -1;
00160     }
00161     strcpy(cpProgName, cpName);
00162     sprintf(cpCfgName, "soundsrv.%s.cfg", cpAudioDev);
00163     CfgFile = new clCfgFile(cpCfgName);
00164     sprintf(cpLogName, "%s.%s", SS_LOGFILE, cpAudioDev);
00165     LogFile = new clLogFile(cpLogName);
00166     LogFile->Add('*', "Starting");
00167     lPthVersion = pth_version();
00168     sprintf(cpLogTxt, "Pth version %lu.%lu.%lu (compiled with %u.%u.%u)",
00169         ((lPthVersion & 0xf00000) >> 20),
00170         ((lPthVersion & 0x0ff000) >> 12),
00171         (lPthVersion & 0x0000ff),
00172         SS_PTH_MAJ, SS_PTH_MIN, SS_PTH_PL);
00173     LogFile->Add(' ', cpLogTxt);
00174     sprintf(cpDevName, "/dev/%s", cpAudioDev);
00175     if (!CfgFile->GetInt("SampleRate", &iAudioSr))
00176     {
00177         iAudioSr = SS_SND_SAMPLERATE;
00178     }
00179     if (!CfgFile->GetInt("Channels", &iAudioCh))
00180     {
00181         iAudioCh = SS_SND_CHANNELS;
00182     }
00183     if (CfgFile->GetInt("Bits", &iBits))
00184     {
00185         switch (iBits)
00186         {
00187             case 8:
00188                 iAudioFrmt = AFMT_U8;
00189                 iAudioTypeSize = 1;
00190                 break;
00191             case 16:
00192                 iAudioFrmt = AFMT_S16_NE;
00193                 iAudioTypeSize = 2;
00194                 break;
00195             #ifndef USE_OSSLITE
00196             case 24:
00197             case 32:
00198                 iAudioFrmt = AFMT_S32_NE;
00199                 iAudioTypeSize = 4;
00200                 break;
00201             #endif
00202             default:
00203                 iAudioFrmt = SS_SND_FORMAT;
00204                 iAudioTypeSize = SS_SND_FORMAT_SIZE;
00205         }
00206     }
00207     else
00208     {
00209         iAudioFrmt = SS_SND_FORMAT;
00210         iAudioTypeSize = SS_SND_FORMAT_SIZE;
00211     }
00212     sprintf(cpLogTxt, "Request %s fs %i ch %i fmt %xh", cpAudioDev, 
00213         iAudioSr, iAudioCh, iAudioFrmt);
00214     LogFile->Add(' ', cpLogTxt);
00215     Audio = new clAudio(cpDevName, &iAudioFrmt, &iAudioSr, &iAudioCh,
00216         AUDIO_READ);
00217     sprintf(cpLogTxt, "Open %s fs %i ch %i fmt %xh", cpAudioDev, 
00218         iAudioSr, iAudioCh, iAudioFrmt);
00219     LogFile->Add(' ', cpLogTxt, Audio->GetError());
00220     iOSSVersion = Audio->GetVersion();
00221     sprintf(cpLogTxt, "OSS version %i.%i.%i (compiled with %i.%i.%i)",
00222         ((iOSSVersion >> 16) & 0xff), ((iOSSVersion >> 8) & 0xff),
00223         (iOSSVersion & 0xff),
00224         ((SOUND_VERSION >> 16) & 0xff), ((SOUND_VERSION >> 8) & 0xff),
00225         (SOUND_VERSION & 0xff));
00226     LogFile->Add(' ', cpLogTxt);
00227     sprintf(cpLogTxt, "Fragment size %i bytes", Audio->GetFragmentSize());
00228     LogFile->Add(' ', cpLogTxt);
00229     iSampleCount = Audio->GetFragmentSize() / iAudioTypeSize;
00230     iOutBufSize = iSampleCount * sizeof(GDT);
00231     cpOutBuf = (char *) malloc(iOutBufSize);
00232     if (cpOutBuf == NULL)
00233     {
00234         LogFile->Add('!', "OUT OF MEMORY");
00235         exit(1);
00236     }
00237     mlock(cpOutBuf, iOutBufSize);
00238 }
00239 
00240 
00241 clSoundSrv::~clSoundSrv()
00242 {
00243     delete Audio;
00244     LogFile->Add('*', "Shutdown");
00245     delete LogFile;
00246     delete CfgFile;
00247     munlock(cpOutBuf, iOutBufSize);
00248     if (cpOutBuf != NULL) free(cpOutBuf);
00249 }
00250 
00251 
00252 void clSoundSrv::Exec()
00253 {
00254     unsigned int iInputStackSize;
00255     int iSigNum;
00256     void *vpReturnValue;
00257     pth_attr_t pthaInput;
00258     pth_attr_t pthaWaitConnect;
00259     pth_event_t ptheInputDead;
00260     pth_event_t ptheWaitConnectDead;
00261     pth_event_t ptheThreadDead;
00262 
00263     sigemptyset(&sigsetQuit);
00264     sigaddset(&sigsetQuit, SIGINT);
00265     sigaddset(&sigsetQuit, SIGHUP);
00266     sigaddset(&sigsetQuit, SIGTERM);
00267     iInputStackSize = 1024 * 32;
00268     pthaInput = pth_attr_new();
00269     pth_attr_set(pthaInput, PTH_ATTR_NAME, "Input");
00270     pth_attr_set(pthaInput, PTH_ATTR_STACK_SIZE, iInputStackSize);
00271     tidInput = pth_spawn(pthaInput, Input, NULL);
00272     pthaWaitConnect = pth_attr_new();
00273     pth_attr_set(pthaWaitConnect, PTH_ATTR_NAME, "WaitConnect");
00274     tidWaitConnect = pth_spawn(PTH_ATTR_DEFAULT, WaitConnect, NULL);
00275     ptheInputDead = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tidInput);
00276     ptheWaitConnectDead = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD,
00277         tidWaitConnect);
00278     ptheThreadDead = pth_event_concat(ptheInputDead, ptheWaitConnectDead, 
00279         NULL);
00280     LogFile->Add(' ', "Running");
00281     pth_sigwait_ev(&sigsetQuit, &iSigNum, ptheThreadDead);
00282     if (pth_event_occurred(ptheThreadDead))
00283     {
00284         LogFile->Add('!', "Dead of thread detected");
00285         Quit();
00286     }
00287     else
00288     {
00289         Quit(iSigNum);
00290     }
00291     pth_cancel(tidInput);
00292     pth_join(tidInput, &vpReturnValue);
00293     pth_join(tidWaitConnect, &vpReturnValue);
00294     LogFile->Add(' ', "Stopping");
00295 }
00296 
00297 
00298 void clSoundSrv::Quit()
00299 {
00300     bRun = false;
00301 }
00302 
00303 
00304 void clSoundSrv::Quit(int iSigNum)
00305 {
00306     bRun = false;
00307     switch (iSigNum)
00308     {
00309         case SIGHUP:
00310             LogFile->Add(' ', "Received SIGHUP");
00311             break;
00312         case SIGINT:
00313             LogFile->Add(' ', "Received SIGINT");
00314             break;
00315         default:
00316             LogFile->Add('!', "Received unknown signal");
00317     }
00318 }
00319 
00320 
00321 void clSoundSrv::InputExec()
00322 {
00323     int iDevH;
00324     int iInBufSize;
00325     int iConvBufSize;
00326     int iBytesRead = 0;
00327     int iInputErrors = 0;
00328     void *pInBuf;
00329     GDT *pConvBuf;
00330 
00331     iInBufSize = iSampleCount * iAudioTypeSize;
00332     iConvBufSize = iSampleCount * sizeof(GDT);
00333     pInBuf = malloc(iInBufSize);
00334     pConvBuf = (GDT *) malloc(iConvBufSize);
00335     if (pInBuf == NULL || pConvBuf == NULL)
00336     {
00337         LogFile->Add('!', "OUT OF MEMORY!");
00338         return;
00339     }
00340     mlock(pInBuf, iInBufSize);
00341     mlock(pConvBuf, iConvBufSize);
00342     pth_cancel_state(PTH_CANCEL_DEFERRED, NULL);
00343     iDevH = SoundSrv->Audio->GetHandle();
00344     LogFile->Add(' ', "Input thread running");
00345     // We do one normal read to trigger input operation, this is trying to be
00346     // workaround for some buggy driver implementations...
00347     iBytesRead = read(iDevH, pInBuf, iInBufSize);
00348     while (bRun)
00349     {
00350         if (access(SS_SHUTDOWNFILE, F_OK) == 0)
00351         {
00352             unlink(SS_SHUTDOWNFILE);
00353             Quit();
00354             break;
00355         }
00356         iBytesRead += pth_read(iDevH, pInBuf, iInBufSize - iBytesRead);
00357         if (!bRun) break;
00358         if (iBytesRead == iInBufSize)
00359         {
00360             switch (iAudioTypeSize)
00361             {
00362                 case 1:
00363                     DSP.Convert(pConvBuf, (unsigned char *) pInBuf, 
00364                         iSampleCount);
00365                     break;
00366                 case 2:
00367                     DSP.Convert(pConvBuf, (signed short *) pInBuf,
00368                         iSampleCount, false);
00369                     break;
00370                 case 4:
00371                     DSP.Convert(pConvBuf, (signed int *) pInBuf,
00372                         iSampleCount, true);
00373                     break;
00374             }
00375             MutexThis.Wait();
00376             SoundMsg.SetData(cpOutBuf, pConvBuf, iSampleCount);
00377             CondDataAvail.Notify(TRUE);
00378             MutexThis.Release();
00379             iBytesRead = 0;
00380         }
00381         else if (iBytesRead > iInBufSize)
00382         {
00383             LogFile->Add('!', 
00384                 "pth_read() overflowed input buffer, process unstable");
00385             Quit();
00386         }
00387         else if (iBytesRead < iInBufSize && iBytesRead >= 0)
00388         {
00389             iInputErrors++;
00390             LogFile->Add('!', "pth_read() input buffer underrun");
00391         }
00392         else
00393         {
00394             iInputErrors++;
00395             LogFile->Add('!', "input device pth_read() error", errno);
00396         }
00397         if (iInputErrors >= SS_MAXERRORS)
00398         {
00399             LogFile->Add('!', "Too many errors on input device");
00400             Quit();
00401         }
00402     }
00403     munlock(pInBuf, iInBufSize);
00404     munlock(pConvBuf, iOutBufSize);
00405     free(pInBuf);
00406     free(pConvBuf);
00407     LogFile->Add(' ', "Input thread ending");
00408 }
00409 
00410 
00411 void clSoundSrv::WaitConnectExec()
00412 {
00413     int iLoopCntr;
00414     int iListenH;
00415     int iPort;
00416     socklen_t iAddrLen;
00417     char cpLogEntry[256];
00418     void *vpReturnValue;
00419     struct protoent *spProtocol = NULL;
00420     struct servent *spService = NULL;
00421     struct sockaddr_in sServAddr;
00422     struct sockaddr_in sClieAddr;
00423     pth_attr_t pthaServeClient;
00424     pth_event_t ptheInputDead;
00425 
00426     LogFile->Add(' ', "WaitConnect thread running");
00427     pthaServeClient = pth_attr_new();
00428     pth_attr_set(pthaServeClient, PTH_ATTR_NAME, "ServeClient");
00429     ptheInputDead = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tidInput);
00430     spProtocol = getprotobyname("tcp");
00431     if (spProtocol != NULL)
00432     {
00433         iListenH = socket(AF_INET, SOCK_STREAM, spProtocol->p_proto);
00434     }
00435     else
00436     {
00437         iListenH = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00438         LogFile->Add('#', 
00439             "Warning: no entry returned for TCP by getprotobyname()");
00440     }
00441     if (iListenH < 0)
00442     {
00443         LogFile->Add('!', "socket() failed for listening fd", errno);
00444         return;
00445     }
00446     memset(&sServAddr, 0x00, sizeof(sServAddr));
00447     sServAddr.sin_family = AF_INET;
00448     sServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00449     if (CfgFile->GetInt("Port", &iPort))
00450     {
00451         sServAddr.sin_port = htons(iPort);
00452     }
00453     else
00454     {
00455         spService = getservbyname(cpProgName, "tcp");
00456         if (spService != NULL)
00457         {
00458             sServAddr.sin_port = spService->s_port;
00459         }
00460         else
00461         {
00462             sServAddr.sin_port = htons(SS_DEFAULT_PORT);
00463         }
00464     }
00465     if (bind(iListenH, (struct sockaddr *) &sServAddr, sizeof(sServAddr)) < 0)
00466     {
00467         LogFile->Add('!', "bind() failed for listening fd", errno);
00468         close(iListenH);
00469         return;
00470     }
00471     if (listen(iListenH, SS_MAXCLIENTS) < 0)
00472     {
00473         LogFile->Add('!', "listen() failed for listening fd", errno);
00474         close(iListenH);
00475         return;
00476     }
00477     sprintf(cpLogEntry, "Listening for connections on port %i", 
00478         ntohs(sServAddr.sin_port));
00479     LogFile->Add(' ', cpLogEntry);
00480     while (bRun)
00481     {
00482         iClientIdx = FindFreeClient();
00483         memset(&sClieAddr, 0x00, sizeof(sClieAddr));
00484         iAddrLen = sizeof(sClieAddr);
00485         ipClientH[iClientIdx] = pth_accept_ev(iListenH, 
00486             (struct sockaddr *) &sClieAddr, &iAddrLen, ptheInputDead);
00487         if (!pth_event_occurred(ptheInputDead))
00488         {
00489             if (ipClientH[iClientIdx] >= 0)
00490             {
00491                 sprintf(cpLogEntry, "%s connected", 
00492                     inet_ntoa(sClieAddr.sin_addr));
00493                 LogFile->Add('+', cpLogEntry);
00494                 ptidServeClient[iClientIdx] =
00495                     pth_spawn(pthaServeClient, ServeClient, 
00496                         &ipClientH[iClientIdx]);
00497             }
00498         }
00499     }
00500     for (iLoopCntr = 0; iLoopCntr < SS_MAXCLIENTS; iLoopCntr++)
00501     {
00502         if (ipClientH[iLoopCntr] >= 0)
00503             pth_join(ptidServeClient[iLoopCntr], &vpReturnValue);
00504     }
00505     pth_event_free(ptheInputDead, PTH_FREE_THIS);
00506     LogFile->Add(' ', "WaitConnect thread ending");
00507 }
00508 
00509 
00510 void clSoundSrv::ServeClientExec(void *vpHandle)
00511 {
00512     bool bThreadRun = true;
00513     char cpFirstMsg[GLOBAL_HEADER_LEN];
00514     char *cpLocalOutBuf;
00515     int iHandleIdx;
00516     const int iSockH = *((int *) vpHandle);
00517     int iSockBufSize;
00518     //int iSockLowWater;
00519     int iSockNagle;
00520     int iSockTOS;
00521     int iBytesSent;
00522     int iLastRes;
00523     int iWriteErrno;
00524     socklen_t iSockOptLen;
00525     stSoundStart sSndStart;
00526     pth_event_t ptheInputDead;
00527 
00528     LogFile->Add(' ', "ServeClient thread running");
00529     iHandleIdx = FindThisHandle(iSockH);
00530     if (iHandleIdx < 0)
00531     {
00532         LogFile->Add('!', "FindThisHandle() returned error");
00533         return;
00534     }
00535     cpLocalOutBuf = (char *) malloc(iOutBufSize);
00536     if (cpLocalOutBuf == NULL)
00537     {
00538         LogFile->Add('!', "malloc() for local output buffer failed");
00539         return;
00540     }
00541     mlock(cpLocalOutBuf, iOutBufSize);
00542     ptheInputDead = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tidInput);
00543     sSndStart.iChannels = iAudioCh;
00544     sSndStart.dSampleRate = iAudioSr;
00545     sSndStart.iFragmentSize = iSampleCount;
00546     SoundMsg.SetStart(cpFirstMsg, &sSndStart);
00547     if (pth_write_ev(iSockH, cpFirstMsg, GLOBAL_HEADER_LEN, ptheInputDead) <
00548         GLOBAL_HEADER_LEN)
00549     {
00550         LogFile->Add('?', "Unable to send data header message to client",
00551             errno);
00552         close(iSockH);
00553         ipClientH[iHandleIdx] = -1;
00554         return;
00555     }
00556     iSockOptLen = sizeof(iSockBufSize);
00557     if (getsockopt(iSockH, SOL_SOCKET, SO_SNDBUF, &iSockBufSize, 
00558         &iSockOptLen) < 0)
00559     {
00560         LogFile->Add('!', "getsockopt() error getting send buffer size",
00561             errno);
00562     }
00563     if (iSockBufSize < (SS_SOCKET_BUF_FRAGS * iOutBufSize))
00564     {
00565         iSockBufSize = SS_SOCKET_BUF_FRAGS * iOutBufSize;
00566         if (setsockopt(iSockH, SOL_SOCKET, SO_SNDBUF, &iSockBufSize,
00567             sizeof(iSockBufSize)) < 0)
00568         {
00569             LogFile->Add('!', "setsockopt() error setting send buffer size",
00570                 errno);
00571         }
00572     }
00573     /*iSockOptLen = sizeof(iSockLowWater);
00574     if (getsockopt(iSockH, SOL_SOCKET, SO_SNDLOWAT, &iSockLowWater,
00575         &iSockOptLen) < 0)
00576     {
00577         LogFile->Add('!', "getsockopt() error getting send low water mark",
00578             errno);
00579     }
00580     if (iSockLowWater < iOutBufSize)
00581     {
00582         iSockLowWater = iOutBufSize;
00583         if (setsockopt(iSockH, SOL_SOCKET, SO_SNDLOWAT, &iSockLowWater,
00584             sizeof(iSockLowWater)) < 0)
00585         {
00586             LogFile->Add('!', "setsockopt() error setting send low water mark",
00587                 errno);
00588         }
00589     }*/
00590     iSockNagle = 1;
00591     if (setsockopt(iSockH, IPPROTO_TCP, TCP_NODELAY, &iSockNagle,
00592         sizeof(iSockNagle)) < 0)
00593     {
00594         LogFile->Add('!', "setsockopt() error disabling nagle algorithm",
00595             errno);
00596     }
00597     iSockTOS = IPTOS_LOWDELAY;
00598     if (setsockopt(iSockH, IPPROTO_IP, IP_TOS, &iSockTOS,
00599         sizeof(iSockTOS)) < 0)
00600     {
00601         LogFile->Add('!', "setsockopt() error setting TOS flag",
00602             errno);
00603     }
00604     while (bRun && bThreadRun)
00605     {
00606         MutexThis.Wait();
00607         CondDataAvail.Wait(MutexThis.GetPtr(), ptheInputDead);
00608         memcpy(cpLocalOutBuf, cpOutBuf, iOutBufSize);
00609         MutexThis.Release();
00610         if (!pth_event_occurred(ptheInputDead))
00611         {
00612             iBytesSent = 0;
00613             do {
00614                 iLastRes = pth_write_ev(iSockH, &cpLocalOutBuf[iBytesSent], 
00615                     iOutBufSize - iBytesSent, ptheInputDead);
00616                 iBytesSent += iLastRes;
00617                 if (pth_event_occurred(ptheInputDead)) 
00618                 {
00619                     bThreadRun = false;
00620                     break;
00621                 }
00622             } while (iBytesSent < iOutBufSize && iLastRes >= 0);
00623             if (!bThreadRun) break;
00624             iWriteErrno = (iLastRes < 0) ? errno : 0;
00625             if (iWriteErrno != 0)
00626             {
00627                 if (iWriteErrno == EPIPE)
00628                 {
00629                     LogFile->Add('-', "Client disconnect");
00630                 }
00631                 else
00632                 {
00633                     LogFile->Add('-', 
00634                         "pth_write() returned error on client socket",
00635                         iWriteErrno);
00636                 }
00637                 bThreadRun = false;
00638             }
00639         }
00640         else break;
00641     }
00642     close(iSockH);
00643     ipClientH[iHandleIdx] = -1;
00644     pth_event_free(ptheInputDead, PTH_FREE_THIS);
00645     munlock(cpLocalOutBuf, iOutBufSize);
00646     free(cpLocalOutBuf);
00647     LogFile->Add(' ', "ServeClient thread ending");
00648 }
00649 
00650 
00651 int inline clSoundSrv::FindFreeClient()
00652 {
00653     int iLoopCntr;
00654 
00655     for (iLoopCntr = 0; iLoopCntr < SS_MAXCLIENTS; iLoopCntr++)
00656     {
00657         if (ipClientH[iLoopCntr] < 0)
00658         {
00659             return iLoopCntr;
00660         }
00661     }
00662     return -1;
00663 }
00664 
00665 
00666 int inline clSoundSrv::FindThisHandle(int iFindH)
00667 {
00668     int iLoopCntr;
00669 
00670     for (iLoopCntr = 0; iLoopCntr < SS_MAXCLIENTS; iLoopCntr++)
00671     {
00672         if (ipClientH[iLoopCntr] == iFindH)
00673         {
00674             return iLoopCntr;
00675         }
00676     }
00677     return -1;
00678 }
00679 

Generated on Sun Oct 26 19:11:22 2003 for HASAS by doxygen 1.3.3