int loom_net_writeTCPSocket(loom_socketId_t s, void *buffer, int bytesToWrite) { #if LOOM_PLATFORM == LOOM_PLATFORM_WIN32 int winsockErrorCode; #endif int bytesLeft = bytesToWrite; for ( ; ; ) { int result = send((SOCKET)s, buffer, bytesLeft, MSG_NOSIGNAL); if (result >= 0) { bytesLeft -= result; if (bytesLeft != 0) { lmLogDebug(netLogGroup, "Partial write on socket %d, expected %d but wrote %d! Retrying...", s, bytesToWrite, result); // Set up to try again by advancing into the buffer. buffer = (void *)((char *)buffer + result); continue; } return bytesToWrite - bytesLeft; } #if LOOM_PLATFORM == LOOM_PLATFORM_WIN32 winsockErrorCode = WSAGetLastError(); if (winsockErrorCode != WSAEWOULDBLOCK) { break; } #else if (errno != EAGAIN) { break; } #endif if (loom_net_isSocketDead(s)) { break; } loom_thread_sleep(5); } return -1; }
void loom_net_enableSocketKeepalive(loom_socketId_t s) { int optVal = 1; socklen_t optLen = sizeof(optVal); if (loom_net_isSocketDead(s)) { lmLogError(netLogGroup, "Tried to set keepalive on dead socket."); return; } //lmLog(netLogGroup, "Setting keepalive with %d %d", optVal, optLen); if (setsockopt((int)s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, optLen) < 0) { // This failure when due to EINVAL (22 on darwin) on a freshly created // socket is often because the sockethas been shutdown asynchronously by the OS. lmLogError(netLogGroup, "Could not set SO_KEEPALIVE on socket %x due to %d", s, errno); return; } }
// Service our connection to the asset agent. static void loom_asset_serviceServer() { loom_mutex_lock(gAssetServerSocketLock); // Try to connect to the asset server if we aren't already, and it is set. if ((gAssetServerSocket == NULL) && ((ASSET_STREAM_HOST != NULL) && (strlen(ASSET_STREAM_HOST) > 0)) && ((platform_getMilliseconds() - gAssetServerLastConnectTryTime) > gAssetServerConnectTryInterval)) { lmLog(gAssetLogGroup, "Attempting to stream assets from %s:%d", ASSET_STREAM_HOST, ASSET_STREAM_PORT); gAssetServerLastConnectTryTime = platform_getMilliseconds(); gAssetServerSocket = loom_net_openTCPSocket(ASSET_STREAM_HOST, ASSET_STREAM_PORT, 0); gAssetConnectionOpen = false; loom_asset_notifyPendingCountChange(); loom_mutex_unlock(gAssetServerSocketLock); return; } if ((gAssetServerSocket != NULL) && (gAssetConnectionOpen == false)) { // We are waiting on the connection, see if it's writable... If not, return. if (loom_net_isSocketWritable(gAssetServerSocket) == 0) { loom_mutex_unlock(gAssetServerSocketLock); return; } if (loom_net_isSocketDead(gAssetServerSocket) == 1) { // Might be DOA, ie, connect failed. lmLog(gAssetLogGroup, "Failed to connect to asset server %s:%d", ASSET_STREAM_HOST, ASSET_STREAM_PORT); loom_net_closeTCPSocket(gAssetServerSocket); gAssetServerSocket = NULL; lmSafeDelete(NULL, gAssetProtocolHandler); gAssetConnectionOpen = false; loom_asset_notifyPendingCountChange(); loom_mutex_unlock(gAssetServerSocketLock); return; } lmLog(gAssetLogGroup, "Successfully connected to asset server %s:%d!", ASSET_STREAM_HOST, ASSET_STREAM_PORT); // Do this now to avoid clobbering error state and seeing the socket as // "open" when it is really dead. loom_net_enableSocketKeepalive(gAssetServerSocket); gAssetConnectionOpen = true; loom_asset_notifyPendingCountChange(); // Make sure we have a protocol handler. if (!gAssetProtocolHandler) { gAssetProtocolHandler = lmNew(NULL) AssetProtocolHandler(gAssetServerSocket); gAssetProtocolHandler->registerListener(lmNew(NULL) AssetProtocolFileMessageListener()); gAssetProtocolHandler->registerListener(lmNew(NULL) AssetProtocolCommandListener()); } loom_mutex_unlock(gAssetServerSocketLock); return; } // See if the socket is dead, and if so, clean up. if ((gAssetServerSocket != NULL) && (loom_net_isSocketDead(gAssetServerSocket) == 1)) { lmLog(gAssetLogGroup, "Lost connection to asset server."); loom_net_closeTCPSocket(gAssetServerSocket); gAssetServerSocket = NULL; lmSafeDelete(NULL, gAssetProtocolHandler); gAssetConnectionOpen = false; loom_asset_notifyPendingCountChange(); loom_mutex_unlock(gAssetServerSocketLock); return; } // Bail if we don't have a connection. if (!gAssetServerSocket || !gAssetConnectionOpen) { loom_mutex_unlock(gAssetServerSocketLock); return; } // Ping if we need to. if (platform_getMilliseconds() - gAssetServerLastPingTime > gAssetServerPingInterval) { gAssetProtocolHandler->sendPing(); gAssetServerLastPingTime = platform_getMilliseconds(); } // Service the asset server connection. gAssetProtocolHandler->process(); loom_mutex_unlock(gAssetServerSocketLock); }
void loom_net_readTCPSocket(loom_socketId_t s, void *buffer, int *bytesToRead, int peek /*= 0*/) { int errorCode; int waiting; int tmp = *bytesToRead; int bytesLeft; if (loom_net_isSocketDead(s)) { *bytesToRead = 0; return; } if (peek) { *bytesToRead = recv((SOCKET)s, buffer, tmp, MSG_PEEK); return; } bytesLeft = *bytesToRead; while (bytesLeft > 0) { int received = recv((SOCKET)s, buffer, bytesLeft, 0); if (received == -1) { waiting = 0; #if LOOM_PLATFORM == LOOM_PLATFORM_WIN32 errorCode = WSAGetLastError(); if (errorCode == WSAEWOULDBLOCK) { waiting = 1; } #else errorCode = errno; if (errorCode == EAGAIN) { waiting = 1; } #endif if (waiting) { // TODO figure out a better way to do this? //lmLogDebug(netLogGroup, "Waiting for receive buffer %d / %d", *bytesToRead - bytesLeft, *bytesToRead); loom_thread_sleep(5); continue; } else { lmLogError(netLogGroup, "Read socket error (%d)", errorCode); *bytesToRead = -1; return; } } bytesLeft -= received; buffer = (char*)buffer + received; } lmAssert(bytesLeft == 0, "Internal recv error, read too much data? %d", bytesLeft); }