Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
5.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // vmpi_launch.cpp : Defines the entry point for the console application.
  9. //
  10. #include "stdafx.h"
  11. #include "iphelpers.h"
  12. #include "bitbuf.h"
  13. #include "vmpi.h"
  14. bool g_bBroadcast = false;
  15. int PrintUsage()
  16. {
  17. printf( "vmpi_launch -machine <remote machine> -priority <priority> [-mpi_pw <password>] -command \"command line...\"\n" );
  18. printf( "-command must be the last switch..\n" );
  19. return 1;
  20. }
  21. int GetCurMicrosecondsAndSleep( int sleepLen )
  22. {
  23. Sleep( sleepLen );
  24. int retVal;
  25. __asm
  26. {
  27. rdtsc
  28. mov retVal, eax
  29. }
  30. return retVal;
  31. }
  32. const char* FindArg( int argc, char **argv, const char *pName, const char *pDefault )
  33. {
  34. for ( int i=0; i < argc; i++ )
  35. {
  36. if ( stricmp( argv[i], pName ) == 0 )
  37. {
  38. if ( (i+1) < argc )
  39. return argv[i+1];
  40. else
  41. return pDefault;
  42. }
  43. }
  44. return NULL;
  45. }
  46. int ParseArgs( int argc, char **argv, CIPAddr &remoteIP, int &iPriority, int &iFirstArg )
  47. {
  48. if ( FindArg( argc, argv, "-broadcast", "1" ) )
  49. g_bBroadcast = true;
  50. if ( g_bBroadcast == false )
  51. {
  52. const char *pRemoteIPStr = FindArg( argc, argv, "-machine", NULL );
  53. if ( !pRemoteIPStr || !ConvertStringToIPAddr( pRemoteIPStr, &remoteIP ) )
  54. {
  55. printf( "%s is not a valid machine name or IP address.\n", pRemoteIPStr );
  56. return PrintUsage();
  57. }
  58. }
  59. iPriority = 0;
  60. const char *pPriorityStr = FindArg( argc, argv, "-priority", NULL );
  61. if ( pPriorityStr )
  62. iPriority = atoi( pPriorityStr );
  63. if ( iPriority < 0 || iPriority > 1000 )
  64. {
  65. printf( "%s is not a valid priority.\n", pPriorityStr );
  66. return PrintUsage();
  67. }
  68. const char *pCommand = FindArg( argc, argv, "-command", NULL );
  69. if ( !pCommand )
  70. {
  71. return PrintUsage();
  72. }
  73. for ( iFirstArg=1; iFirstArg < argc; iFirstArg++ )
  74. {
  75. if ( argv[iFirstArg] == pCommand )
  76. break;
  77. }
  78. return 0;
  79. }
  80. void SendJobRequest(
  81. ISocket *pSocket,
  82. int argc,
  83. char **argv,
  84. CIPAddr &remoteIP,
  85. int &iPriority,
  86. int &iFirstArg,
  87. int jobID[4] )
  88. {
  89. // Build the packet to send out the job.
  90. char packetData[4096];
  91. bf_write packetBuf;
  92. // Come up with a unique job ID.
  93. jobID[0] = GetCurMicrosecondsAndSleep( 1 );
  94. jobID[1] = GetCurMicrosecondsAndSleep( 1 );
  95. jobID[2] = GetCurMicrosecondsAndSleep( 1 );
  96. jobID[3] = GetCurMicrosecondsAndSleep( 1 );
  97. // Broadcast out to tell all the machines we want workers.
  98. packetBuf.StartWriting( packetData, sizeof( packetData ) );
  99. packetBuf.WriteByte( VMPI_PROTOCOL_VERSION );
  100. const char *pPassword = FindArg( argc, argv, "-mpi_pw", "" );
  101. packetBuf.WriteString( pPassword );
  102. packetBuf.WriteByte( VMPI_LOOKING_FOR_WORKERS );
  103. packetBuf.WriteShort( 0 ); // Tell the port that we're listening on.
  104. // In this case, there is no VMPI master waiting for the app to connect, so
  105. // this parameter doesn't matter.
  106. packetBuf.WriteShort( iPriority );
  107. packetBuf.WriteLong( jobID[0] );
  108. packetBuf.WriteLong( jobID[1] );
  109. packetBuf.WriteLong( jobID[2] );
  110. packetBuf.WriteLong( jobID[3] );
  111. packetBuf.WriteWord( argc-iFirstArg ); // 1 command line argument..
  112. // Write the alternate exe name.
  113. for ( int iArg=iFirstArg; iArg < argc; iArg++ )
  114. packetBuf.WriteString( argv[iArg] );
  115. for ( int iBroadcastPort=VMPI_SERVICE_PORT; iBroadcastPort <= VMPI_LAST_SERVICE_PORT; iBroadcastPort++ )
  116. {
  117. remoteIP.port = iBroadcastPort;
  118. if ( g_bBroadcast == false )
  119. pSocket->SendTo( &remoteIP, packetBuf.GetBasePointer(), packetBuf.GetNumBytesWritten() );
  120. else
  121. pSocket->Broadcast( packetBuf.GetBasePointer(), packetBuf.GetNumBytesWritten(), iBroadcastPort );
  122. }
  123. if ( g_bBroadcast == false )
  124. printf( "Sent command, waiting for reply...\n" );
  125. else
  126. printf( "Sent command\n" );
  127. }
  128. bool WaitForJobStart( ISocket *pSocket, const CIPAddr &remoteIP, const int jobID[4] )
  129. {
  130. while ( 1 )
  131. {
  132. CIPAddr senderAddr;
  133. char data[4096];
  134. int len = -1;
  135. if ( g_bBroadcast == false )
  136. pSocket->RecvFrom( data, sizeof( data ), &senderAddr );
  137. else
  138. pSocket->RecvFrom( data, sizeof( data ), NULL );
  139. if ( len == 19 &&
  140. memcmp( senderAddr.ip, remoteIP.ip, sizeof( senderAddr.ip ) ) == 0 &&
  141. data[1] == VMPI_NOTIFY_START_STATUS &&
  142. memcmp( &data[2], jobID, 16 ) == 0 )
  143. {
  144. if ( data[18] == 0 )
  145. {
  146. // Wasn't able to run.
  147. printf( "Wasn't able to run on target machine.\n" );
  148. return false;
  149. }
  150. else
  151. {
  152. // Ok, the process is running now.
  153. printf( "Process running, waiting for completion...\n" );
  154. return true;
  155. }
  156. }
  157. Sleep( 100 );
  158. }
  159. }
  160. void WaitForJobEnd( ISocket *pSocket, const CIPAddr &remoteIP, const int jobID[4] )
  161. {
  162. while ( 1 )
  163. {
  164. CIPAddr senderAddr;
  165. char data[4096];
  166. int len = pSocket->RecvFrom( data, sizeof( data ), &senderAddr );
  167. if ( len == 18 &&
  168. memcmp( senderAddr.ip, remoteIP.ip, sizeof( senderAddr.ip ) ) == 0 &&
  169. data[1] == VMPI_NOTIFY_END_STATUS &&
  170. memcmp( &data[2], jobID, 16 ) == 0 )
  171. {
  172. int ret = *((int*)&data[2]);
  173. printf( "Finished [%d].\n", ret );
  174. break;
  175. }
  176. Sleep( 100 );
  177. }
  178. }
  179. int main(int argc, char* argv[])
  180. {
  181. if ( argc < 4 )
  182. {
  183. return PrintUsage();
  184. }
  185. // Parse the command line.
  186. CIPAddr remoteIP;
  187. int iFirstArg, iPriority;
  188. int jobID[4];
  189. int ret = ParseArgs( argc, argv, remoteIP, iPriority, iFirstArg );
  190. if ( ret != 0 )
  191. return ret;
  192. // Now send the command to the vmpi service on that machine.
  193. ISocket *pSocket = CreateIPSocket();
  194. if ( !pSocket->BindToAny( 0 ) )
  195. {
  196. printf( "Error binding a socket.\n" );
  197. return 1;
  198. }
  199. SendJobRequest( pSocket, argc, argv, remoteIP, iPriority, iFirstArg, jobID );
  200. // Wait for a reply, positive or negative.
  201. if ( g_bBroadcast == false )
  202. {
  203. if ( !WaitForJobStart( pSocket, remoteIP, jobID ) )
  204. return 2;
  205. WaitForJobEnd( pSocket, remoteIP, jobID );
  206. }
  207. pSocket->Release();
  208. return 0;
  209. }