//============================================================================ static void NotifyConnSocketConnectFailed (CliFileConn * conn) { s_critsect.Enter(); { conn->cancelId = 0; s_conns.Unlink(conn); if (conn == s_active) s_active = nil; } s_critsect.Leave(); // Cancel all transactions in progress on this connection. NetTransCancelByConnId(conn->seq, kNetErrTimeout); #ifndef SERVER // Client apps fail if unable to connect for a time if (++conn->numFailedConnects >= kMaxFailedConnects) { ReportNetError(kNetProtocolCli2File, kNetErrConnectFailed); } else #endif // ndef SERVER { // start reconnect, if we are doing that if (s_running && conn->AutoReconnectEnabled()) conn->StartAutoReconnect(); else conn->UnRef("Lifetime"); // if we are not reconnecting, this socket is done, so remove the lifetime ref } conn->UnRef("Connecting"); }
//============================================================================ static void AsyncLookupCallback ( void * param, const char name[], unsigned addrCount, const plNetAddress addrs[] ) { if (!addrCount) { ReportNetError(kNetProtocolCli2File, kNetErrNameLookupFailed); return; } for (unsigned i = 0; i < addrCount; ++i) { Connect(name, addrs[i]); } }
//============================================================================ static void NotifyConnSocketDisconnect (CliFileConn * conn) { conn->StopAutoPing(); s_critsect.Enter(); { conn->cancelId = 0; s_conns.Unlink(conn); if (conn == s_active) s_active = nil; } s_critsect.Leave(); // Cancel all transactions in progress on this connection. NetTransCancelByConnId(conn->seq, kNetErrTimeout); bool notify = false; #ifdef SERVER { if (hsTimer::GetMilliSeconds<uint32_t>() - conn->connectStartMs > kMinValidConnectionMs) conn->reconnectStartMs = 0; else conn->reconnectStartMs = GetNonZeroTimeMs() + kMaxReconnectIntervalMs; } #else { #ifndef LOAD_BALANCER_HARDWARE // If the connection to the remote server was open for longer than // kMinValidConnectionMs then assume that the connection was to // a valid server and try to perform reconnection immediately. If // less time elapsed then the connection was likely to a server // with an open port but with no notification procedure registered // for this type of communication channel. if (hsTimer::GetMilliSeconds<uint32_t>() - conn->connectStartMs > kMinValidConnectionMs) { conn->reconnectStartMs = 0; } else { if (++conn->numImmediateDisconnects < kMaxImmediateDisconnects) conn->reconnectStartMs = GetNonZeroTimeMs() + kMaxReconnectIntervalMs; else notify = true; } #else // File server is running behind a load-balancer, so the next connection may // send us to a new server, therefore attempt a reconnection to the same // address even if the disconnect was immediate. This is safe because the // file server is stateless with respect to clients. if (hsTimer::GetMilliSeconds<uint32_t>() - conn->connectStartMs <= kMinValidConnectionMs) { if (++conn->numImmediateDisconnects < kMaxImmediateDisconnects) conn->reconnectStartMs = GetNonZeroTimeMs() + kMaxReconnectIntervalMs; else notify = true; } else { // disconnect was not immediate. attempt a reconnect unless we're shutting down conn->numImmediateDisconnects = 0; conn->reconnectStartMs = 0; } #endif // LOAD_BALANCER } #endif // ndef SERVER if (notify) { ReportNetError(kNetProtocolCli2File, kNetErrDisconnected); } else { // clean up the socket and start reconnect, if we are doing that conn->Destroy(); if (conn->AutoReconnectEnabled()) conn->StartAutoReconnect(); else conn->UnRef("Lifetime"); // if we are not reconnecting, this socket is done, so remove the lifetime ref } conn->UnRef("Connected"); }
BOOL COXNetBrowseTree::CreateChildren(HTREEITEM hParentItem, NETRESOURCE* pParentNetResources) // --- In : hParentItem : Node of which the children nodes have to be created // pParentNetResources : Net resource of this parent node // --- Out : // --- Returns : // --- Effect : Computes the netresources of the children and creates the child nodes { HANDLE hEnum = NULL; DWORD dwScope = pParentNetResources == NULL ? m_nResourceScope : pParentNetResources->dwScope; DWORD nResult = WNetOpenEnum( dwScope, // scope of enumeration RESOURCETYPE_ANY, // resource types to list 0, // resource usage to list pParentNetResources, // pointer to resource structure &hEnum); // pointer to enumeration handle buffer if (nResult != NO_ERROR) { TRACE2("COXNetBrowseTree::CreateChildren : WNetOpenEnum failed with error code %i == 0x%X\n", nResult, nResult); ReportNetError(nResult, pParentNetResources == NULL ? NULL : pParentNetResources->lpRemoteName); return FALSE; } DWORD nCurrentCount(0); DWORD nCurrentSkipCount(0); /* =============================================================================== */ // The problem with the WNetEnumResoiurce fuction is that allthough you use // 0xFFFFFFFF as requested resource count (this means everything) the function // does NOT return ERROR_MORE_DATA if the buffer is too small. It only returns // this value if the buffer supplied is too small even for one value, in this // case the space needed to hold the first resource found in the enumeration // Normally the size of this resource should be sizeof(NETRESOURCE) which is // 32 bytes but experience learned that this fluctuates between 32 bytes and // more than 1000 bytes. This is probably due to the fact that WNetEnumResource // also needs allocated memory for the strings inside the NETRESOURCE struct. // This leads to the conclusion that we cannot calculate with certainty the size // of the buffer we need for a certain number of resources. The most robust // solution to this problem is to request a absolute number of resources, make // an serious and realistic estimation of the maximum amount of memory needed // to hold ALL requested resources and then test to see whether you have retrieved // all requested resources. If this is TRUE then again enumerate the resources // to determine whether there aren't any left and so on until the returned // number of resources is smaller than the requested number. This last remark // explains why we need to be sure that the requested number of resources // allways fit in the amount of memory we allocated for the buffer. We could // alocated a very big buffer but we prefer the loop. // Also note that we don't use NETRESOURCE* pRes = new NETRESOURCE[Count] // because the array allocated will be an array of structs of size sizeof(NETRESOURCE) // and that's just not correct to hold one netresource. That's why we use // GlobalAlloc. // USERS WHO WANT TO TUNE THE PERFORMANCE OF THIS FUNCTION CAN PLAY WITH THE // NUMBER OF NETRESOURCES VIA THE nCOUNT VARIABLE AND WITH THE SIZE OF THE // ALLOCATED BUFFER VIA THE nBUFFERSIZE VARIABLE BUT KEEP THE REMARKS ABOVE // IN MIND. /* =============================================================================== */ // Start with a reasonable buffer size DWORD nCount = 5; DWORD nBufferSize = 5000; LPNETRESOURCE rgpNetResources = (LPNETRESOURCE)GlobalAlloc(GPTR, nBufferSize); while (TRUE) { DWORD nTempCount = nCount; DWORD nTempBufferSize = nBufferSize; memset(rgpNetResources, 0, nBufferSize); DWORD nResult2 = WNetEnumResource( hEnum, // handle to enumeration &nTempCount, // pointer to entries to list (LPVOID)rgpNetResources, // pointer to buffer for results &nTempBufferSize); // pointer to buffer size variable TRACE2("COXNetBrowseTree::WNetEnumResource : Number of Netresources (%i), in buffersize (0x%X)\n", nTempCount, nTempBufferSize); if ((nResult2 != NO_ERROR) && (nResult2 != ERROR_NO_MORE_ITEMS) && (nResult2 != ERROR_MORE_DATA)) { TRACE2("COXNetBrowseTree::CreateChildren : WNetEnumResource failed with error code %i == 0x%X\n", nResult2, nResult2); ReportNetError(nResult2, pParentNetResources == NULL ? NULL : pParentNetResources->lpRemoteName); // ... Cleanup the handle and memeory allocated VERIFY(WNetCloseEnum(hEnum) == NO_ERROR); GlobalFree((HGLOBAL)rgpNetResources); return FALSE; } if (nResult2 == ERROR_NO_MORE_ITEMS) nTempCount = 0; // Loop the requested number of NetResources and make tree item nodes { HTREEITEM hNewItem; NETRESOURCE* pSourceNetResource = NULL; NETRESOURCE* pCopyNetResource = NULL; DWORD nIndex; DWORD nSkipCount = 0; for (nIndex = 0; nIndex < nTempCount; nIndex++) { pSourceNetResource = &rgpNetResources[nIndex]; // Check special case for disks and printers if ((pSourceNetResource->dwType == RESOURCETYPE_DISK) && !m_bShowDisks) { // Skip this item nSkipCount++; continue; } if ((pSourceNetResource->dwType == RESOURCETYPE_PRINT) && !m_bShowPrinters) { // Skip this item nSkipCount++; continue; } // ... Create a new item hNewItem = InsertResourceItem(pSourceNetResource, hParentItem); if (hNewItem == NULL) { TRACE0("COXNetBrowseTree::InsertResourceItem returned NULL\n"); // Skip this item nSkipCount++; continue; } // Add a copy to the map // ... Should not yet be in map #ifdef _DEBUG NETRESOURCE* pCheckNetResource = NULL; ASSERT(!m_resourceMap.Lookup(hNewItem, pCheckNetResource)); #endif // _DEBUG pCopyNetResource = new NETRESOURCE; // ... Copy the struct itself memcpy(pCopyNetResource, pSourceNetResource, sizeof(NETRESOURCE)); // ... Make a copy of all the string members if (pSourceNetResource->lpLocalName != NULL) { size_t len = _tcslen(pSourceNetResource->lpLocalName) + 1; pCopyNetResource->lpLocalName = new TCHAR[len]; UTBStr::tcscpy(pCopyNetResource->lpLocalName, len, pSourceNetResource->lpLocalName); } else { pCopyNetResource->lpLocalName = new TCHAR[1]; *pCopyNetResource->lpLocalName = _T('\0'); } if (pSourceNetResource->lpRemoteName != NULL) { size_t len = _tcslen(pSourceNetResource->lpRemoteName) + 1; pCopyNetResource->lpRemoteName = new TCHAR[len]; UTBStr::tcscpy(pCopyNetResource->lpRemoteName, len, pSourceNetResource->lpRemoteName); } else { pCopyNetResource->lpRemoteName = new TCHAR[1]; *pCopyNetResource->lpRemoteName = _T('\0'); } if (pSourceNetResource->lpComment != NULL) { size_t len = _tcslen(pSourceNetResource->lpComment) + 1; pCopyNetResource->lpComment = new TCHAR[len]; UTBStr::tcscpy(pCopyNetResource->lpComment, len, pSourceNetResource->lpComment); } else { pCopyNetResource->lpComment = new TCHAR[1]; *pCopyNetResource->lpComment = _T('\0'); } if (pSourceNetResource->lpProvider != NULL) { size_t len = _tcslen(pSourceNetResource->lpProvider) + 1; pCopyNetResource->lpProvider = new TCHAR[len]; UTBStr::tcscpy(pCopyNetResource->lpProvider, len, pSourceNetResource->lpProvider); } else { pCopyNetResource->lpProvider = new TCHAR[1]; *pCopyNetResource->lpProvider = _T('\0'); } // ... Add to map m_resourceMap.SetAt(hNewItem, pCopyNetResource); } // we need to keep track of the real number of nodes because we // need it to set the correct treeitem number for the parent node nCurrentCount += nTempCount; nCurrentSkipCount += nSkipCount; if (hParentItem != NULL) { // Mark the parent node as expanded at least once VERIFY(SetItemState(hParentItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE)); // Set the number of child items to the correct value TV_ITEM item; item.hItem = hParentItem; item.mask = TVIF_CHILDREN; ASSERT(nSkipCount <= nTempCount); item.cChildren = nCurrentCount - nCurrentSkipCount; VERIFY(SetItem(&item)); } } if (nResult2 == ERROR_MORE_DATA || nTempCount == nCount) // Possibly there is more data to retrieve { nTempCount = nCount; continue; } else // There was no error and there isn't anymore data to retrieve break; } // Cleanup the handle and allocated memory VERIFY(WNetCloseEnum(hEnum) == NO_ERROR); GlobalFree((HGLOBAL)rgpNetResources); return TRUE; }