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

SoundProxy.cc

Go to the documentation of this file.
00001 /*
00002 
00003     Sound service proxy
00004     Copyright (C) 2000-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 <pthread.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <signal.h>
00029 #include <sched.h>
00030 #include <sys/types.h>
00031 #include <sys/socket.h>
00032 #include <netinet/in.h>
00033 #include <arpa/inet.h>
00034 #include <glib.h>
00035 
00036 #include "SoundProxy.hh"
00037 
00038 
00039 static bool bDaemon;
00040 static bool bDebug;
00041 clSoundProxy *SoundProxy;
00042 
00043 
00044 int main (int argc, char *argv[])
00045 {
00046     int iRetVal;
00047 
00048     bDaemon = false;
00049     bDebug = false;
00050     signal(SIGPIPE, SIG_IGN);
00051     signal(SIGFPE, SIG_IGN);
00052     if (argc > 1)
00053     {
00054         if (strcmp(argv[1], "-D") == 0)
00055             bDaemon = true;
00056         if (strcmp(argv[1], "--debug") == 0)
00057             bDebug = true;
00058         if (strcmp(argv[1], "--version") == 0)
00059         {
00060             printf("SoundProxy v%i.%i.%i\n", 
00061                 SP_VERSMAJ, SP_VERSMIN, SP_VERSPL);
00062             printf("Copyright (C) 2000-2001 Jussi Laako\n\n");
00063         }
00064         if (strcmp(argv[1], "--help") == 0)
00065         {
00066             printf("%s [-D|--debug|--version|--help]\n", argv[0]);
00067         }
00068     }
00069     if (bDaemon)
00070     {
00071         if (fork() == 0)
00072         {
00073             setsid();
00074             freopen("/dev/null", "r", stdin);
00075             freopen("/dev/null", "a", stdout);
00076             freopen("/dev/null", "a", stderr);
00077         }
00078         else
00079         {
00080             return 0;
00081         }
00082     }
00083     SoundProxy = new clSoundProxy();
00084     iRetVal = SoundProxy->Exec();
00085     delete SoundProxy;
00086     return iRetVal;
00087 }
00088 
00089 
00090 void *WrapSoundInThread (void *vpData)
00091 {
00092     return SoundProxy->SoundInThread(vpData);
00093 }
00094 
00095 
00096 void *WrapWaitConnectThread (void *vpData)
00097 {
00098     return SoundProxy->WaitConnectThread(vpData);
00099 }
00100 
00101 
00102 void *WrapServeClientThread (void *vpData)
00103 {
00104     return SoundProxy->ServeClientThread(vpData);
00105 }
00106 
00107 
00108 inline void clSoundProxy::AddToLog (char cMark, const char *cpLogEntry)
00109 {
00110     MutexClass.Wait();
00111     Log.Add(cMark, cpLogEntry);
00112     MutexClass.Release();
00113 }
00114 
00115 
00116 inline void clSoundProxy::AddToLog (char cMark, const char *cpLogEntry, 
00117     int iErrno)
00118 {
00119     MutexClass.Wait();
00120     Log.Add(cMark, cpLogEntry, iErrno);
00121     MutexClass.Release();
00122 }
00123 
00124 
00125 int clSoundProxy::FindFreeSlot ()
00126 {
00127     int iResIdx = -1;
00128     int iLoopCntr;
00129 
00130     MutexClass.Wait();
00131     for (iLoopCntr = 0; iLoopCntr < SP_MAXCLIENTS; iLoopCntr++)
00132     {
00133         if (!bServeClient[iLoopCntr])
00134         {
00135             iResIdx = iLoopCntr;
00136             break;
00137         }
00138     }
00139     MutexClass.Release();
00140     return iResIdx;
00141 }
00142 
00143 
00144 clSoundProxy::clSoundProxy ()
00145 {
00146     int iLoopCntr;
00147 
00148     bRun = true;
00149     Cfg.SetFileName(SP_CFGFILE);
00150     if (!Cfg.GetStr("LogFile", cpLogFile))
00151         strcpy(cpLogFile, SP_DEF_LOGFILE);
00152     Cfg.GetStr("ServerHost", cpServerHost);
00153     Cfg.GetInt("ServerPort", &iServerPort);
00154     Cfg.GetInt("Port", &iServicePort);
00155     Log.Open(cpLogFile);
00156     cpFirstMsg = (char *) FirstMsg.Size(GLOBAL_HEADER_LEN);
00157     cpDataMsg = (char *) DataMsg.Size(SP_BUFFER_SIZE);
00158     DataMsg.Lock();
00159     for (iLoopCntr = 0; iLoopCntr < SP_MAXCLIENTS; iLoopCntr++)
00160         bServeClient[iLoopCntr] = false;
00161 }
00162 
00163 
00164 clSoundProxy::~clSoundProxy ()
00165 {
00166 }
00167 
00168 
00169 int clSoundProxy::Exec ()
00170 {
00171     int iSigNum;
00172     sigset_t ssSignals;
00173 
00174     sigemptyset(&ssSignals);
00175     sigaddset(&ssSignals, SIGHUP);
00176     sigaddset(&ssSignals, SIGINT);
00177     sigaddset(&ssSignals, SIGTERM);
00178     sigprocmask(SIG_BLOCK, &ssSignals, NULL);
00179     AddToLog('*', "Started");
00180     pthread_create(&ptidSoundIn, NULL, WrapSoundInThread, NULL);
00181     pthread_create(&ptidWaitConnect, NULL, WrapWaitConnectThread, NULL);
00182     sigwait(&ssSignals, &iSigNum);
00183     switch (iSigNum)
00184     {
00185         case SIGHUP:
00186             AddToLog(' ', "Received SIGHUP");
00187             break;
00188         case SIGINT:
00189             AddToLog(' ', "Received SIGINT");
00190             break;
00191         case SIGTERM:
00192             AddToLog(' ', "Received SIGTERM");
00193             break;
00194         default:
00195             AddToLog(' ', "Received unexpected signal");
00196             break;
00197     }
00198     Stop();
00199     pthread_join(ptidWaitConnect, NULL);
00200     pthread_join(ptidSoundIn, NULL);
00201     AddToLog('*', "Stopped");
00202     return 0;
00203 }
00204 
00205 
00206 void clSoundProxy::Stop ()
00207 {
00208     MutexClass.Wait();
00209     bRun = false;
00210     MutexClass.Release();
00211 }
00212 
00213 
00214 void *clSoundProxy::SoundInThread (void *vpData)
00215 {
00216     bool bLocalRun;
00217     int iSockH;
00218     char cpConvBuf[SP_CONV_BUF_LEN];
00219     char *cpMsgBuf;
00220     #ifndef BSDSYS
00221     uid_t uidCurrent;
00222     struct sched_param sSchedParam;
00223     #endif
00224     clAlloc MsgBuf;
00225     clSockClie SClient;
00226     clSockOp SOp;
00227 
00228     iSockH = SClient.Connect(cpServerHost, NULL, iServerPort);
00229     if (iSockH < 0)
00230     {
00231         g_snprintf(cpConvBuf, SP_CONV_BUF_LEN, 
00232             "Unable to connect to %s:%i", cpServerHost, iServerPort);
00233         AddToLog('!', cpConvBuf, SClient.GetErrno());
00234         Stop();
00235         return NULL;
00236     }
00237     SOp.SetHandle(iSockH);
00238     g_snprintf(cpConvBuf, SP_CONV_BUF_LEN, "Connected to %s:%i",
00239         cpServerHost, iServerPort);
00240     AddToLog('#', cpConvBuf);
00241     if (SOp.ReadSelect(SP_1ST_MSG_TIMEOUT))
00242     {
00243         MutexData.Wait();
00244         if (SOp.ReadN(cpFirstMsg, GLOBAL_HEADER_LEN) != GLOBAL_HEADER_LEN)
00245         {
00246             AddToLog('!', "Unable to get first message from server",
00247                 SOp.GetErrno());
00248             Stop();
00249         }
00250         MutexData.Release();
00251     }
00252     else
00253     {
00254         AddToLog('!', "Unable to get first message from server (timeout)");
00255         Stop();
00256     }
00257     cpMsgBuf = (char *) MsgBuf.Size(SP_BUFFER_SIZE);
00258     MsgBuf.Lock();
00259     AddToLog(' ', "SoundIn thread running");
00260     #ifndef BSDSYS
00261     uidCurrent = getuid();
00262     setuid(0);
00263     sSchedParam.sched_priority = sched_get_priority_min(SCHED_FIFO) + 
00264         SP_SCHED_PRIORITY;
00265     pthread_setschedparam(pthread_self(), SCHED_FIFO, &sSchedParam);
00266     setuid(uidCurrent);
00267     #endif
00268     SOp.DisableNagle();
00269     SOp.SetTypeOfService(IPTOS_LOWDELAY);
00270     MutexClass.Wait();
00271     bLocalRun = bRun;
00272     MutexClass.Release();
00273     while (bLocalRun)
00274     {
00275         if (SOp.ReadSelect(SP_MSG_TIMEOUT))
00276         {
00277             if (SOp.ReadN(cpMsgBuf, SP_BUFFER_SIZE) == SP_BUFFER_SIZE)
00278             {
00279                 MutexData.Wait();
00280                 memcpy(cpDataMsg, cpMsgBuf, SP_BUFFER_SIZE);
00281                 CondData.NotifyAll();
00282                 MutexData.Release();
00283             }
00284             else
00285             {
00286                 AddToLog('!', "Message receive error", SOp.GetErrno());
00287                 Stop();
00288             }
00289         }
00290         MutexClass.Wait();
00291         bLocalRun = bRun;
00292         MutexClass.Release();
00293     }
00294     SOp.Shutdown(2);
00295     SOp.Close();
00296     AddToLog(' ', "SoundIn thread ending");
00297     return NULL;
00298 }
00299 
00300 
00301 void *clSoundProxy::WaitConnectThread (void *vpData)
00302 {
00303     bool bLocalRun = true;
00304     int iSockH;
00305     int iSlotIdx;
00306     clSockServ SServer;
00307 
00308     AddToLog(' ', "WaitConnect thread running");
00309     SServer.Bind(iServicePort);
00310     while (bLocalRun)
00311     {
00312         iSlotIdx = FindFreeSlot();
00313         if (iSlotIdx >= 0)
00314         {
00315             iSockH = SServer.WaitForConnect(SP_WAIT_CONN_TIMEOUT);
00316             if (iSockH >= 0)
00317             {
00318                 MutexClass.Wait();
00319                 bServeClient[iSlotIdx] = true;
00320                 iClientSockH[iSlotIdx] = iSockH;
00321                 MutexClass.Release();
00322                 pthread_create(&ptidServeClient[iSlotIdx], NULL,
00323                     WrapServeClientThread, GINT_TO_POINTER(iSlotIdx));
00324             }
00325         }
00326         else
00327         {
00328             sched_yield();
00329         }
00330         MutexClass.Wait();
00331         bLocalRun = bRun;
00332         MutexClass.Release();
00333     }
00334     AddToLog(' ', "WaitConnect thread ending");
00335     return NULL;
00336 }
00337 
00338 
00339 void *clSoundProxy::ServeClientThread (void *vpData)
00340 {
00341     bool bLocalRun = true;
00342     int iThisIdx = GPOINTER_TO_INT(vpData);
00343     int iSockH;
00344     char *cpMsgBuf;
00345     char cpHdrBuf[GLOBAL_HEADER_LEN];
00346     char cpLogBuf[SP_CONV_BUF_LEN];
00347     socklen_t iPeerAddrLen;
00348     struct sockaddr_in sPeerAddr;
00349     #ifndef BSDSYS
00350     uid_t uidCurrent;
00351     struct sched_param sSchedParam;
00352     #endif
00353     clAlloc MsgBuf;
00354     clSockOp SOp;
00355 
00356     MutexClass.Wait();
00357     iSockH = iClientSockH[iThisIdx];
00358     MutexClass.Release();
00359     SOp.SetHandle(iSockH);
00360     //SOp.SetSendBufSize(SP_BUFFER_SIZE * 2);
00361     iPeerAddrLen = sizeof(sPeerAddr);
00362     SOp.GetPeerName((struct sockaddr *) &sPeerAddr, &iPeerAddrLen);
00363     g_snprintf(cpLogBuf, SP_CONV_BUF_LEN, "Client connected from %s:%i", 
00364         inet_ntoa(sPeerAddr.sin_addr), ntohs(sPeerAddr.sin_port));
00365     AddToLog('+', cpLogBuf);
00366     if (!SOp.DisableNagle())
00367     {
00368         AddToLog('#', "Unable to disable nagle algorithm", SOp.GetErrno());
00369     }
00370     if (!SOp.SetTypeOfService(IPTOS_LOWDELAY))
00371     {
00372         AddToLog('#', "Unable set type of service flag", SOp.GetErrno());
00373     }
00374     cpMsgBuf = (char *) MsgBuf.Size(SP_BUFFER_SIZE);
00375     MsgBuf.Lock();
00376     MutexData.Wait();
00377     memcpy(cpHdrBuf, cpFirstMsg, GLOBAL_HEADER_LEN);
00378     MutexData.Release();
00379     if (SOp.WriteSelect(SP_1ST_MSG_TIMEOUT))
00380     {
00381         if (SOp.WriteN(cpHdrBuf, GLOBAL_HEADER_LEN) != GLOBAL_HEADER_LEN)
00382         {
00383             AddToLog('!', "Unable to send first message", SOp.GetErrno());
00384             bLocalRun = false;
00385         }
00386     }
00387     else
00388     {
00389         AddToLog('!', "Unable to send first message (timeout)");
00390         bLocalRun = false;
00391     }
00392     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
00393     AddToLog(' ', "ServeClient thread running");
00394     #ifndef BSDSYS
00395     uidCurrent = getuid();
00396     setuid(0);
00397     sSchedParam.sched_priority = sched_get_priority_min(SCHED_FIFO) + 
00398         SP_SCHED_PRIORITY;
00399     pthread_setschedparam(pthread_self(), SCHED_FIFO, &sSchedParam);
00400     setuid(uidCurrent);
00401     #endif
00402     while (bLocalRun)
00403     {
00404         MutexData.Wait();
00405         CondData.Wait(MutexData.GetPtr());
00406         memcpy(cpMsgBuf, cpDataMsg, SP_BUFFER_SIZE);
00407         MutexData.Release();
00408         MutexClass.Wait();
00409         bLocalRun = bRun;
00410         MutexClass.Release();
00411         if (!bLocalRun) break;
00412         if (SOp.WriteSelect(SP_MSG_TIMEOUT))
00413         {
00414             if (SOp.WriteN(cpMsgBuf, SP_BUFFER_SIZE) != SP_BUFFER_SIZE)
00415             {
00416                 AddToLog('-', "Client disconnected?", SOp.GetErrno());
00417                 break;
00418             }
00419         }
00420     }
00421     SOp.Close();
00422     AddToLog(' ', "ServeClient thread ending");
00423     return NULL;
00424 }
00425 

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