GPU-SD  1.0.2
dns_sd/module.cpp
00001 
00002 /* Copyright (c) 2011, Stefan Eilemann <eile@eyescale.ch> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include "module.h"
00019 
00020 #include <gpusd/gpuInfo.h>
00021 #include <dns_sd.h>
00022 #include <algorithm>
00023 #include <cerrno>
00024 #include <cstring>
00025 #include <iostream>
00026 #include <sstream>
00027 #ifndef _WIN32
00028 #  include <arpa/inet.h>
00029 #  include <sys/time.h>
00030 #endif
00031 
00032 #define WAIT_TIME 500 // ms
00033 
00034 namespace gpusd
00035 {
00036 namespace dns_sd
00037 {
00038 namespace
00039 {
00040 
00041 Module* instance = 0;
00042 
00043 static bool handleEvent( DNSServiceRef service )
00044 {
00045     const int fd = DNSServiceRefSockFD( service );
00046     const int nfds = fd + 1;
00047 
00048     fd_set fdSet;
00049     FD_ZERO( &fdSet );
00050     FD_SET( fd, &fdSet );
00051 
00052     struct timeval tv;
00053     tv.tv_sec = 0;
00054     tv.tv_usec = WAIT_TIME * 1000;
00055 
00056     const int result = select( nfds, &fdSet, 0, 0, &tv );
00057     switch( result )
00058     {
00059       case 0: // timeout
00060           return false;
00061 
00062       default:
00063           DNSServiceProcessResult( service );
00064           return true;
00065 
00066       case -1:
00067           std::cerr << "Select error: " << strerror( errno ) << " (" 
00068                     << errno << ")" << std::endl;
00069           return false;
00070     }
00071 }
00072 
00073 template< class T >
00074 bool getTXTRecordValue( const uint16_t txtLen, const unsigned char* txt,
00075                         const std::string& name, T& result )
00076 {
00077     uint8_t len = 0;
00078     const char* data = (const char*)TXTRecordGetValuePtr( txtLen, txt,
00079                                                           name.c_str(), &len );
00080     if( !data || len == 0 )
00081         return false;
00082 
00083     std::istringstream in( std::string( data, len ));
00084     in >> result;
00085     return true;
00086 }
00087 
00088 
00089 static void resolveCallback( DNSServiceRef service, DNSServiceFlags flags,
00090                              uint32_t interfaceIdx, DNSServiceErrorType error,
00091                              const char* name, const char* host, uint16_t port,
00092                              uint16_t txtLen, const unsigned char* txt,
00093                              void* context )
00094 {
00095     if( error != kDNSServiceErr_NoError)
00096     {
00097         std::cerr << "Resolve callback error: " << error << std::endl;
00098         return;
00099     }
00100 
00101     unsigned nGPUs = 0;
00102     getTXTRecordValue( txtLen, txt, "GPU Count", nGPUs );
00103     if( !nGPUs )
00104         return;
00105 
00106     GPUInfos* result = reinterpret_cast< GPUInfos* >( context );
00107     for( unsigned i = 0; i < nGPUs; ++i )
00108     {
00109         std::ostringstream out;
00110         out << "GPU" << i << " ";
00111         const std::string& gpu = out.str();
00112 
00113         std::string type;
00114         if( !getTXTRecordValue( txtLen, txt, gpu + "Type", type ))
00115             continue;
00116 
00117         GPUInfo info( type );
00118         info.hostname = host;
00119         getTXTRecordValue( txtLen, txt, "Session", info.session );
00120         getTXTRecordValue( txtLen, txt, gpu + "Port", info.port );
00121         getTXTRecordValue( txtLen, txt, gpu + "Device", info.device );
00122         getTXTRecordValue( txtLen, txt, gpu + "X", info.pvp[0] );
00123         getTXTRecordValue( txtLen, txt, gpu + "Y", info.pvp[1] );
00124         getTXTRecordValue( txtLen, txt, gpu + "Width", info.pvp[2] );
00125         getTXTRecordValue( txtLen, txt, gpu + "Height", info.pvp[3] );
00126         result->push_back( info );
00127     }
00128 }
00129 
00130 
00131 static void browseCallback( DNSServiceRef service, DNSServiceFlags flags,
00132                             uint32_t interfaceIdx, DNSServiceErrorType error,
00133                             const char* name, const char* type,
00134                             const char* domain, void* context )
00135 {
00136     if( error != kDNSServiceErr_NoError)
00137     {
00138         std::cerr << "Browse callback error: " << error << std::endl;
00139         return;
00140     }
00141 
00142     if( !( flags & kDNSServiceFlagsAdd ))
00143         return;
00144 
00145     error = DNSServiceResolve( &service, 0, interfaceIdx, name, type, domain,
00146                                (DNSServiceResolveReply)resolveCallback,
00147                                context );
00148     if( error != kDNSServiceErr_NoError)
00149     {
00150         std::cerr << "DNSServiceResolve error: " << error << std::endl;
00151         return;
00152     }
00153 
00154     GPUInfos* result = reinterpret_cast< GPUInfos* >( context );
00155     const size_t old = result->size();
00156 
00157     while( old == result->size() && handleEvent( service ))
00158         /* nop */;
00159 }
00160 
00161 }
00162 
00163 void Module::use()
00164 {
00165     if( !instance )
00166         instance = new Module;
00167 }
00168 
00169 GPUInfos Module::discoverGPUs_() const
00170 {
00171     DNSServiceRef service;
00172 
00173     GPUInfos candidates[2];
00174     uint32_t interfaces[2] = { 0, kDNSServiceInterfaceIndexLocalOnly };
00175     for( unsigned i = 0; i < 2; ++i )
00176     {
00177         const DNSServiceErrorType error = DNSServiceBrowse( &service, 0,
00178                                                             interfaces[i],
00179                                                             "_gpu-sd._tcp", "",
00180                                      (DNSServiceBrowseReply)browseCallback,
00181                                                             &candidates[i] );
00182         if( error == kDNSServiceErr_NoError )
00183         {
00184             while( handleEvent( service ))
00185                 /* nop */;
00186             DNSServiceRefDeallocate( service );
00187         }
00188         else
00189             std::cerr << "DNSServiceDiscovery error: " << error << std::endl;
00190     }
00191 
00192     // set localhost records to localhost
00193     for( GPUInfosIter i = candidates[0].begin(); i != candidates[0].end(); ++i )
00194     {
00195         GPUInfo& info = *i;
00196         if( std::find( candidates[1].begin(), candidates[1].end(), info ) !=
00197             candidates[1].end( ))
00198         {
00199             info.hostname.clear();
00200         }
00201     }
00202     return candidates[0];
00203 }
00204 
00205 }
00206 }
Generated on Tue Dec 13 2011 17:52:00 for GPU-SD 1.0.2 by  doxygen 1.7.5.1