2
0

NetworkChannel.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EABase/eabase.h>
  5. #include <EAAssert/eaassert.h>
  6. #include <EAMain/internal/EAMainChannels.h>
  7. #if defined(EA_PLATFORM_IPHONE)
  8. #define EAMAIN_HAS_NETWORK_CHANNEL 1
  9. #define EAMAIN_FREOPEN_SUPPORTED 1
  10. #endif
  11. #if defined(EA_PLATFORM_WINRT)
  12. #define EAMAIN_HAS_NETWORK_CHANNEL 1
  13. #define EAMAIN_FREOPEN_SUPPORTED 0
  14. #endif
  15. #if defined(EA_PLATFORM_WINDOWS_PHONE) && !defined(EAMAIN_HAS_NETWORK_CHANNEL)
  16. #define EAMAIN_HAS_NETWORK_CHANNEL 1
  17. #define EAMAIN_FREOPEN_SUPPORTED 0
  18. #endif
  19. // winrt-arm configurations do not have winsock, so for these configurations
  20. // we disable the use of the network channel.
  21. #if defined(_MSC_VER) && !defined(EA_PLATFORM_WINDOWS_PHONE) && defined(EA_PROCESSOR_ARM) && defined(EAMAIN_HAS_NETWORK_CHANNEL)
  22. #undef EAMAIN_HAS_NETWORK_CHANNEL
  23. #endif
  24. #if defined(EA_PLATFORM_CAPILANO) && !defined(EAMAIN_HAS_NETWORK_CHANNEL)
  25. #define EAMAIN_HAS_NETWORK_CHANNEL 1
  26. #define EAMAIN_FREOPEN_SUPPORTED 1
  27. #endif
  28. #if !defined(EAMAIN_HAS_NETWORK_CHANNEL)
  29. #define EAMAIN_HAS_NETWORK_CHANNEL 0
  30. #endif
  31. #if !defined(EAMAIN_FREOPEN_SUPPORTED)
  32. #define EAMAIN_FREOPEN_SUPPORTED 0
  33. #endif
  34. #if EAMAIN_HAS_NETWORK_CHANNEL
  35. #if defined(_MSC_VER)
  36. EA_DISABLE_ALL_VC_WARNINGS()
  37. #if defined(WINAPI_FAMILY)
  38. #undef WINAPI_FAMILY
  39. #endif
  40. #define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
  41. #include <WinSock2.h>
  42. #include <ws2tcpip.h>
  43. #pragma comment(lib, "Ws2_32.lib")
  44. #if defined(EA_PLATFORM_WINDOWS_PHONE)
  45. #pragma warning(disable:4265)
  46. #include <thread>
  47. #else
  48. // Restoring VC warnings on Windows Phone causes some warnings to pop
  49. // up down below, emanating from std::thread. In order to have some
  50. // coverage of this code, warnings are re-enabled on other platforms.
  51. EA_RESTORE_ALL_VC_WARNINGS()
  52. #endif
  53. #define SocketGetLastError() WSAGetLastError()
  54. #define snprintf _snprintf
  55. #else
  56. #include <sys/types.h>
  57. #include <sys/socket.h>
  58. #include <errno.h>
  59. #if !defined(EA_PLATFORM_SONY)
  60. #include <netdb.h>
  61. #else
  62. #include <net.h>
  63. #endif
  64. #include <string.h>
  65. #include <unistd.h>
  66. typedef int SOCKET;
  67. const int INVALID_SOCKET = -1;
  68. const int SOCKET_ERROR = -1;
  69. #define SD_SEND SHUT_WR
  70. #define closesocket close
  71. #define WSAECONNREFUSED ECONNREFUSED
  72. #define WSAENETUNREACH ENETUNREACH
  73. #define SocketGetLastError() errno
  74. #endif
  75. #include <stdio.h>
  76. #include "eathread/eathread_thread.h"
  77. #include "EAStdC/EAMemory.h"
  78. #include "EAStdC/EAString.h"
  79. #include "EAStdC/EASprintf.h"
  80. namespace EA
  81. {
  82. namespace EAMain
  83. {
  84. namespace Internal
  85. {
  86. class NetworkChannel : public IChannel
  87. {
  88. SOCKET m_socket;
  89. char m_serverAddressStorage[128];
  90. char m_port[6];
  91. const char *m_serverAddress;
  92. static void SleepThread(int milliseconds);
  93. public:
  94. NetworkChannel();
  95. virtual ~NetworkChannel();
  96. virtual void Init();
  97. virtual void Send(const char8_t *data);
  98. virtual void Shutdown();
  99. void SetServerPort(const char *server, const char *port);
  100. bool Connect();
  101. };
  102. static NetworkChannel g_NetworkChannelInstance;
  103. void NetworkChannel::SleepThread(int milliseconds)
  104. {
  105. #if defined(_MSC_VER)
  106. #if defined(EA_PLATFORM_WINDOWS_PHONE)
  107. std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
  108. #else
  109. Sleep(milliseconds);
  110. #endif
  111. #else
  112. usleep(milliseconds * 1000);
  113. #endif
  114. }
  115. NetworkChannel::NetworkChannel()
  116. : m_socket(INVALID_SOCKET)
  117. , m_serverAddress(&m_serverAddressStorage[0])
  118. {
  119. EA::StdC::Memset8(m_serverAddressStorage, 0, sizeof m_serverAddressStorage);
  120. EA::StdC::Memset8(m_port, 0, sizeof m_port);
  121. #if defined(_MSC_VER)
  122. WSAData wsaData = {};
  123. WSAStartup(MAKEWORD(2, 2), &wsaData);
  124. #endif
  125. }
  126. static void LogNetworkError(const char *format, ...)
  127. {
  128. (void)format;
  129. }
  130. NetworkChannel::~NetworkChannel()
  131. {
  132. #if defined(_MSC_VER)
  133. WSACleanup();
  134. #endif
  135. }
  136. void NetworkChannel::Init()
  137. {
  138. }
  139. void NetworkChannel::Send(const char8_t *data)
  140. {
  141. char *buffer = const_cast<char *>(data);
  142. ssize_t bufferLength = static_cast<ssize_t>(strlen(buffer));
  143. ssize_t bytesSent = 0;
  144. while (bytesSent < bufferLength)
  145. {
  146. ssize_t result = send(m_socket, buffer + bytesSent, static_cast<int>(bufferLength - bytesSent), 0);
  147. if (result == SOCKET_ERROR)
  148. {
  149. bool reconnected = false;
  150. LogNetworkError("[NetworkChannel::Send] Reconnecting...");
  151. for (int i = 0; i < 20; ++i)
  152. {
  153. Shutdown();
  154. if (!Connect())
  155. {
  156. LogNetworkError("[NetworkChannel::Send] Send failed: %d", SocketGetLastError());
  157. }
  158. else
  159. {
  160. reconnected = true;
  161. break;
  162. }
  163. SleepThread(500);
  164. }
  165. if (!reconnected)
  166. {
  167. LogNetworkError("[NetworkChannel::Send] Unable to connect, aborting.");
  168. return;
  169. }
  170. }
  171. else
  172. {
  173. bytesSent += result;
  174. }
  175. }
  176. }
  177. void NetworkChannel::Shutdown()
  178. {
  179. // Closing the socket does not wait for pending data to be sent.
  180. // To ensure that all data has been sent, the write end of the
  181. // socket must first be shut down. This sends a FIN packet to
  182. // the receiver after all data has been sent and acknowledged
  183. // by the receiver. This must also be paired with a call to
  184. // recv to ensure that all pending readable data has been
  185. // read.
  186. shutdown(m_socket, SD_SEND);
  187. char buffer[128];
  188. for (;;)
  189. {
  190. ssize_t rv = recv(m_socket, buffer, (int)sizeof buffer, 0);
  191. if (rv <= 0)
  192. {
  193. // We can assume that a graceful shutdown has occurred
  194. // when rv == 0. If rv < 0 an error has occurred, but
  195. // we are not at a point where we can easily recover, so
  196. // this code will just shutdown the socket and exit the
  197. // program if an error happens here.
  198. break;
  199. }
  200. }
  201. closesocket(m_socket);
  202. m_socket = INVALID_SOCKET;
  203. }
  204. void NetworkChannel::SetServerPort(const char *server, const char *port)
  205. {
  206. using namespace EA::StdC;
  207. // If, somehow, the server name string is longer than the storge
  208. // allocated, allocate some space for it on the C-heap. Not ideal,
  209. // may actually fail some tests, but the alternative would be
  210. // no output from EAMain at all.
  211. if (Strlcpy(m_serverAddressStorage, server, sizeof m_serverAddressStorage) > (sizeof m_serverAddressStorage))
  212. {
  213. size_t serverNameLength = Strlen(server);
  214. char *ptr = static_cast<char *>(calloc(serverNameLength + 1, 1));
  215. Strlcpy(ptr, server, serverNameLength + 1);
  216. m_serverAddress = ptr;
  217. }
  218. // Valid port numbers are in the range [1, 65535] so will have
  219. // always 5 digits max.
  220. EA_ASSERT(sizeof m_port == 6);
  221. Strlcpy(m_port, port, sizeof m_port);
  222. }
  223. bool NetworkChannel::Connect()
  224. {
  225. EA_ASSERT(m_serverAddress != NULL);
  226. EA_ASSERT(m_port != NULL);
  227. bool result = false;
  228. SOCKET remoteSocket = INVALID_SOCKET;
  229. const int MAX_RETRIES = 250;
  230. #if !defined(EA_PLATFORM_SONY)
  231. struct addrinfo hints = {};
  232. hints.ai_socktype = SOCK_STREAM;
  233. addrinfo *p = NULL;
  234. if (getaddrinfo(m_serverAddress, m_port, &hints, &p) != 0)
  235. {
  236. LogNetworkError("[NetworkChannel::Connect] Cannot connect to %s:%s", m_serverAddress, m_port);
  237. goto ErrorReturn;
  238. }
  239. for (struct addrinfo *endpoint = p; endpoint != NULL; endpoint = endpoint->ai_next)
  240. #endif
  241. {
  242. #if !defined(EA_PLATFORM_SONY)
  243. remoteSocket = socket(endpoint->ai_family, endpoint->ai_socktype, endpoint->ai_protocol);
  244. #else
  245. remoteSocket = sceNetSocket("EAMain Socket", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0);
  246. #endif
  247. if (remoteSocket == INVALID_SOCKET)
  248. {
  249. LogNetworkError("[NetworkChannel::Connect] Cannot create socket");
  250. goto ErrorReturn;
  251. }
  252. #if defined(_MSC_VER)
  253. if (endpoint->ai_family == AF_INET6)
  254. {
  255. DWORD v6only = 0;
  256. setsockopt(remoteSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof v6only);
  257. }
  258. #endif
  259. for (int i = 0; i < MAX_RETRIES; ++i)
  260. {
  261. #if !defined(EA_PLATFORM_SONY)
  262. int connectResult = connect(remoteSocket, endpoint->ai_addr, (int)endpoint->ai_addrlen);
  263. #else
  264. char *p;
  265. SceNetInPort_t port = strtol(m_port, &p, 10);
  266. SceNetSockaddrIn sin;
  267. EA::StdC::Memset8(&sin, 0, sizeof sin);
  268. sin.sin_len = sizeof(sin);
  269. sin.sin_family = SCE_NET_AF_INET;
  270. if (sceNetInetPton(SCE_NET_AF_INET, m_serverAddress, &sin.sin_addr) <= 0)
  271. {
  272. LogNetworkError("[NetworkChannel::Connect] Cannot connect to %s:%s", m_serverAddress, m_port);
  273. goto ErrorReturn;
  274. }
  275. sin.sin_port = sceNetHtons(port);
  276. sin.sin_vport = sceNetHtons(SCE_NET_ADHOC_PORT);
  277. int connectResult = sceNetConnect(remoteSocket, (SceNetSockaddr *)&sin, sizeof(sin));
  278. #endif
  279. if (connectResult == 0)
  280. {
  281. result = true;
  282. m_socket = remoteSocket;
  283. goto SuccessReturn;
  284. }
  285. switch (SocketGetLastError())
  286. {
  287. case WSAENETUNREACH:
  288. SleepThread(20);
  289. continue;
  290. default:
  291. LogNetworkError("[NetworkChannel::Connect] Cannot connect to socket");
  292. goto ErrorReturn;
  293. }
  294. }
  295. }
  296. ErrorReturn:
  297. if (remoteSocket != INVALID_SOCKET)
  298. {
  299. LogNetworkError("[NetworkChannel::Connect] FAILED");
  300. closesocket(remoteSocket);
  301. }
  302. SuccessReturn:
  303. #if !defined(EA_PLATFORM_SONY)
  304. if (p)
  305. {
  306. freeaddrinfo(p);
  307. }
  308. #endif
  309. return result;
  310. }
  311. static IChannel *CreateNetworkChannelImpl(const char *server, int port)
  312. {
  313. char portString[6];
  314. if (port > 65536 || port < 0)
  315. {
  316. return NULL;
  317. }
  318. snprintf(portString, sizeof portString, "%d", port);
  319. portString[5] = 0;
  320. g_NetworkChannelInstance.SetServerPort(server, portString);
  321. if (g_NetworkChannelInstance.Connect())
  322. {
  323. return &g_NetworkChannelInstance;
  324. }
  325. return NULL;
  326. }
  327. #if !EAMAIN_FREOPEN_SUPPORTED
  328. IChannel *CreateNetworkChannel(const char *server, int port)
  329. {
  330. // On platforms where we do not support freopen on standard
  331. // IO streams, we create a raw network channel.
  332. return CreateNetworkChannelImpl(server, port);
  333. }
  334. #else
  335. static EA::Thread::Thread g_PrintThread;
  336. static volatile bool g_PrintThreadDone;
  337. static FILE *g_RedirectedStdoutHandle;
  338. static FILE *g_RedirectedStderrHandle;
  339. class StdoutWrapperChannel : public IChannel
  340. {
  341. NetworkChannel &m_channel;
  342. bool m_shutdown;
  343. StdoutWrapperChannel& operator=(const StdoutWrapperChannel&);
  344. StdoutWrapperChannel(const StdoutWrapperChannel&);
  345. public:
  346. StdoutWrapperChannel(NetworkChannel &channel)
  347. : m_channel(channel)
  348. , m_shutdown(false)
  349. {
  350. }
  351. virtual ~StdoutWrapperChannel();
  352. virtual void Init()
  353. {
  354. }
  355. virtual void Send(const char8_t *data)
  356. {
  357. fputs(data, stdout);
  358. fflush(stdout);
  359. }
  360. virtual void Shutdown()
  361. {
  362. if (g_RedirectedStdoutHandle)
  363. {
  364. fclose(g_RedirectedStdoutHandle);
  365. }
  366. if (g_RedirectedStderrHandle)
  367. {
  368. fclose(g_RedirectedStderrHandle);
  369. }
  370. g_PrintThreadDone = true;
  371. if (g_PrintThread.GetStatus() == EA::Thread::Thread::kStatusRunning)
  372. {
  373. g_PrintThread.WaitForEnd();
  374. }
  375. m_channel.Shutdown();
  376. m_shutdown = true;
  377. }
  378. };
  379. StdoutWrapperChannel::~StdoutWrapperChannel()
  380. {
  381. if (!m_shutdown)
  382. {
  383. Shutdown();
  384. }
  385. }
  386. static bool ReadFromFile(FILE *file)
  387. {
  388. static const int BUFFER_SIZE = 1024;
  389. static char buffer[BUFFER_SIZE + 1];
  390. bool haveRead = false;
  391. // This is a tortuous way of checking to see if there is data
  392. // available but the goal here is to prevent this thread from
  393. // blocking if nothing is ready. Blocking could be desirable
  394. // if we were only reading from one stream but because this
  395. // code attempts to read from both stdout and stderr we do not
  396. // want it to block on reading one while the other is receiving
  397. // important information.
  398. // Another possibility would be to use non-blocking IO but this
  399. // would require different implementations for different
  400. // platforms.
  401. long currentPosition = ftell(file);
  402. fseek(file, 0, SEEK_END);
  403. long endPosition = ftell(file);
  404. if (endPosition > currentPosition)
  405. {
  406. size_t bytesAvailable = static_cast<size_t>(endPosition - currentPosition);
  407. fseek(file, currentPosition, SEEK_SET);
  408. while (bytesAvailable > 0)
  409. {
  410. size_t bytesToRead = (bytesAvailable > BUFFER_SIZE) ? BUFFER_SIZE : bytesAvailable;
  411. size_t bytesRead = fread(buffer, 1, bytesToRead, file);
  412. buffer[bytesRead] = 0;
  413. g_NetworkChannelInstance.Send(buffer);
  414. bytesAvailable -= bytesRead;
  415. }
  416. haveRead = true;
  417. }
  418. return haveRead;
  419. }
  420. static char g_StdoutLogPath[256];
  421. static char g_StderrLogPath[256];
  422. static intptr_t PrintFunction(void *)
  423. {
  424. FILE *stdoutLog = fopen(g_StdoutLogPath, "rb");
  425. FILE *stderrLog = fopen(g_StderrLogPath, "rb");
  426. while (!g_PrintThreadDone)
  427. {
  428. // It might look neater to combine these file reads into
  429. // the if statement but this was not done because the
  430. // shortcircuting of the left hand condition prevented
  431. // the right hand condition from being evaluated, but
  432. // every iteration should read from both sources.
  433. bool haveReadStdout = ReadFromFile(stdoutLog);
  434. bool haveReadStderr = ReadFromFile(stderrLog);
  435. if (!haveReadStdout && !haveReadStderr)
  436. {
  437. EA::Thread::ThreadSleep(50);
  438. }
  439. }
  440. fflush(stdout); ReadFromFile(stdoutLog); fclose(stdoutLog);
  441. fflush(stderr); ReadFromFile(stderrLog); fclose(stderrLog);
  442. return 0;
  443. }
  444. IChannel *CreateNetworkChannel(const char *server, int port)
  445. {
  446. #if defined(EA_PLATFORM_CAPILANO)
  447. if (IsDebuggerPresent())
  448. {
  449. return NULL;
  450. }
  451. #endif
  452. EA::Thread::ThreadParameters threadParameters;
  453. char *STDOUT_LOG_NAME = "stdout.log";
  454. const char *STDERR_LOG_NAME = "stderr.log";
  455. threadParameters.mnPriority = EA::Thread::kThreadPriorityMax;
  456. #if defined EA_PLATFORM_IPHONE
  457. char temporaryDirectory[256];
  458. confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryDirectory, sizeof temporaryDirectory);
  459. EA::StdC::Snprintf(g_StdoutLogPath, sizeof g_StdoutLogPath, "%s/%s", temporaryDirectory, STDOUT_LOG_NAME);
  460. EA::StdC::Snprintf(g_StderrLogPath, sizeof g_StderrLogPath, "%s/%s", temporaryDirectory, STDERR_LOG_NAME);
  461. #elif defined EA_PLATFORM_CAPILANO
  462. EA::StdC::Snprintf(g_StdoutLogPath, sizeof g_StdoutLogPath, "T:\\%s", STDOUT_LOG_NAME);
  463. EA::StdC::Snprintf(g_StderrLogPath, sizeof g_StderrLogPath, "T:\\%s", STDERR_LOG_NAME);
  464. #else
  465. EA::StdC::Strlcpy(g_StdoutLogPath, STDOUT_LOG_NAME, sizeof g_StdoutLogPath);
  466. EA::StdC::Strlcpy(g_StderrLogPath, STDERR_LOG_NAME, sizeof g_StderrLogPath);
  467. #endif
  468. fprintf(stdout, ""); fflush(stdout);
  469. fprintf(stderr, ""); fflush(stderr);
  470. g_RedirectedStdoutHandle = freopen(g_StdoutLogPath, "wb", stdout);
  471. setvbuf(stdout, NULL, _IONBF, 0);
  472. g_RedirectedStderrHandle = freopen(g_StderrLogPath, "wb", stderr);
  473. setvbuf(stderr, NULL, _IONBF, 0);
  474. if (CreateNetworkChannelImpl(server, port) != NULL)
  475. {
  476. g_PrintThread.Begin(PrintFunction, NULL, &threadParameters);
  477. }
  478. return new StdoutWrapperChannel(g_NetworkChannelInstance);
  479. }
  480. #endif
  481. }
  482. }
  483. }
  484. #else
  485. namespace EA
  486. {
  487. namespace EAMain
  488. {
  489. namespace Internal
  490. {
  491. IChannel *CreateNetworkChannel(const char *server, int port)
  492. {
  493. return NULL;
  494. }
  495. }
  496. }
  497. }
  498. #endif