/*** void UdpServer::resumeListening(void) ** ** Synopsis: ** Resumes listening on a UdpServer that did a StopListening ** ** Parameters: ** None ** ** Return Values: ** None ** ** Errors: ** None ** ** Notes: ** ** If StartListening was never called, this does nothing ** If it is already listening, it does nothing */ void UdpServer::resumeListening(void) { if(!_fStarted) { return; } // say we want to listen, may fail, but we will pick it up when we can. _fListening = true; // make sure we have room to to put our handle in if(_cPending >= _cPendingMax) { return; } // if we need to start listening on a socket if(_rghUDP[_cPending] >= INVALID_UDP_SOCKET) { // do not need to check to see if Ethernet is initialized because I can assign sockets before then _rghUDP[_cPending] = UDPOpen(_localPort, NULL, 0); if(_rghUDP[_cPending] < INVALID_UDP_SOCKET) { // As for the iBuff, when we get data on the socket, the last entry // will be where we put pending Client so just use this iBuff as the cache buffer ExchangeCacheBuffer(_rghUDP[_cPending], GetBufferLocation(_cPending), GetBufferSize()); } } }
bool UdpServer::acceptClient(UdpClient * pUdpClient, int index, DNETcK::STATUS * pStatus) { int cb = 0; // do not call AvailableClients here because that could shift the indexes around // and then we would not be returning the index that someone wants. if(pUdpClient == NULL) { if(pStatus != NULL) *pStatus = DNETcK::ClientPointerIsNULL; return(false); } else if(pUdpClient->_hUDP < INVALID_UDP_SOCKET) { if(pStatus != NULL) *pStatus = DNETcK::SocketAlreadyAssignedToClient; return(false); } else if(_cbCache < UdpClient::cbDatagramCacheMin) { if(pStatus != NULL) *pStatus = DNETcK::UDPCacheToSmall; return(false); } else if(index >= _cPending) { if(pStatus != NULL) *pStatus = DNETcK::IndexOutOfBounds; return(false); } // looks like we have a valid socket at our index // We are just making sure we have a properly initialized client pUdpClient->close(); pUdpClient->construct(pUdpClient->_rgbCache, pUdpClient->_cbCache, pUdpClient->_msARPWait, pUdpClient->_cARPRetries); // set the hUDP and get ready to complete making the UdpClient pUdpClient->_hUDP = _rghUDP[index]; pUdpClient->_classState = DNETcK::Finalizing; // about the only thing that can happen in finalize is that I can get an OutOfMemory error if(!pUdpClient->isEndPointResolved(DNETcK::msImmediate, pStatus)) { // we do not want to remove this from the pending list on error // maybe you can send me another UdpClient where you specify the // buffer and it won't fail. There is really nothing wrong with the socket return(false); } // at this point we want to copy the cache over to the UdpClient cache // right now we are using the servers cache, and we want to move that // to the UdpClient cache. // the ExchangeCacheBuffer will toss UPD datagrams that don't fit // in the new buffer. It is possible for the buffer to be empty if all // datagrams are too big to fit in the exchanged buffer ExchangeCacheBuffer( pUdpClient->_hUDP, pUdpClient->_rgbCache, pUdpClient->_cbCache); // We got the UdpClient, no remove this from our pending list // AvailableClient will do that if the socket is invalid _rghUDP[index] = INVALID_UDP_SOCKET; availableClients(); return(true); }
/*** void UdpClient::close(void) ** ** Synopsis: ** Closes the socket and clears the UdpClient instance; ** Returns the instance to a just constructed state releasing ** all resources except the user supplied datagram cache buffer ** which will be reused if SetEndPoint is called again. ** ** Parameters: ** None ** ** Return Values: ** None ** ** Errors: ** None ** ** Notes: ** ** Returns the UdpClient instance to ** a state just as if the instance had just been ** constructed. The user supplied datagram cache ** should still be kept valid. ** */ void UdpClient::close(void) { if(_hUDP < INVALID_UDP_SOCKET) { // remove from the UDP Cache ExchangeCacheBuffer(_hUDP, NULL, 0); // release MAL socket UDPClose(_hUDP); _hUDP = INVALID_UDP_SOCKET; } // initialize this instance of the class initUdpClient(); }
/*** void UdpServer::close(void) ** ** Synopsis: ** Stops Listening and closes all unaccepted sockets ** and clears everything back to it's originally constructed state. ** The datagram cache buffers remain in use as this is specified on the constuctor ** ** Parameters: ** None ** ** Return Values: ** None ** ** Errors: ** None ** ** Notes: ** ** Returns the UdpServer instance to ** a state just as if the instance had just been ** constructed. It also, Close all connections ** and releases all resources (sockets). ** */ void UdpServer::close(void) { stopListening(); for(int i = 0; i < _cMaxPendingAllowed; i++) { if(_rghUDP[i] < INVALID_UDP_SOCKET) { // clean out the buffer UDPIsGetReady(_rghUDP[i]); UDPDiscard(); UDPClose(_rghUDP[i]); ExchangeCacheBuffer(_rghUDP[i], NULL, 0); _rghUDP[i] = INVALID_UDP_SOCKET; } } clear(); }
/*** void UdpServer::stopListening(void) ** ** Synopsis: ** This stops listening on the server port, but does not shutdown UdpServer ** ** Parameters: ** None ** ** Return Values: ** None ** ** Errors: ** None ** ** Notes: ** To resume listening, just call ResumeListening ** This is a soft stop listening in that only the server stops listening on the port ** however the instance is still valid and you can continue to accept pending client. ** and you can resume the listening. ** */ void UdpServer::stopListening(void) { // DO NOT blow away pending clients. // that will be done on a close() // update the pending count so we have them all. availableClients(); // blow away any listening socket if(_cPending < _cPendingMax && _rghUDP[_cPending] < INVALID_UDP_SOCKET) { UDPIsGetReady(_rghUDP[_cPending]); UDPDiscard(); UDPClose(_rghUDP[_cPending]); ExchangeCacheBuffer(_rghUDP[_cPending], NULL, 0); _rghUDP[_cPending] = INVALID_UDP_SOCKET; } // no longer listening _fListening = false; }
bool UdpClient::isEndPointResolved(unsigned long msBlockMax, DNETcK::STATUS * pStatus) { unsigned long tStart = 0; DNETcK::STATUS statusT = DNETcK::None; // we want this to be PeriodicTasks and not StackTask because we // want to run all of the applications when IsDNETcK::EndPointResolved is called // because this is a common call and we want to keep all things running EthernetPeriodicTasks(); // nothing to do if we have already resolved it. if(_fEndPointsSetUp) { if(pStatus != NULL) *pStatus = DNETcK::EndPointResolved; return(true); } // make sure the network is initialized if(!DNETcK::isInitialzied(msBlockMax, pStatus)) { return(false); } // make sure the UDP cache is big enough if(_cbCache < UdpClient::cbDatagramCacheMin) { if(pStatus != NULL) *pStatus = DNETcK::UDPCacheToSmall; return(false); } // initialize our status to our current state if(pStatus != NULL) *pStatus = _classState; // return our current state, except if we are in the process of resolving if(DNETcK::isStatusAnError(_classState)) { return(false); } // continue with the resolve process tStart = millis(); do { // run the stack EthernetPeriodicTasks(); switch(_classState) { case DNETcK::DNSResolving: if(DNETcK::isDNSResolved(_szHostName, &_remoteEP.ip, DNETcK::msImmediate, &statusT)) { DNETcK::requestARPIpMacResolution(_remoteEP.ip); _classState = DNETcK::ARPResolving; _msARPtStart = millis(); } // stay at the resolving state until an error occurs // if an error, then we fail. else if(DNETcK::isStatusAnError(statusT)) { _classState = DNETcK::DNSResolutionFailed; } break; case DNETcK::ARPResolving: // see if we resolved the MAC address if(DNETcK::isARPIpMacResolved(_remoteEP.ip, &_remoteMAC, DNETcK::msImmediate)) { _classState = DNETcK::AcquiringSocket; _msARPtStart = 0; } // if the ARP timeout has occured; rmember, ARP really doesn't give us failues else if(hasTimeElapsed(_msARPtStart, _msARPWait, millis())) { // resend the ARP Request if(_cARPRetries > 0) { DNETcK::requestARPIpMacResolution(_remoteEP.ip); _msARPtStart = millis(); _cARPRetries--; } // otherwise we are done else { _classState = DNETcK::ARPResolutionFailed; _msARPtStart = 0; } } break; case DNETcK::AcquiringSocket: // set up the socket _hUDP = UdpClientSetEndPoint(_remoteEP.ip.rgbIP, _remoteMAC.rgbMAC, _remoteEP.port, _localPort); if(_hUDP >= INVALID_UDP_SOCKET) { _classState = DNETcK::SocketError; if(pStatus != NULL) *pStatus = _classState; break; } // fall right into finalize; we have finalize for the UdpServer to use case DNETcK::Finalizing: // assume the best that we will finish, unless something bad happens. _classState = DNETcK::EndPointResolved; // we just set up the socket, so all of the IP and port info should be correct // let's just update our code so we know we have what the MAL thinks. GetUdpSocketEndPoints(_hUDP, &_remoteEP.ip, &_remoteMAC, &_remoteEP.port, &_localPort); // see if a cache buffer came in. if(_rgbCache == NULL) { close(); _classState = DNETcK::UDPCacheToSmall; } // add it to the underlying caching engine else { ExchangeCacheBuffer(_hUDP, _rgbCache, _cbCache); } break; // if we got an error in the process, we are done. // this is how we get out of the do-while on an error default: if(pStatus != NULL) *pStatus = _classState; return(false); } } while(_classState != DNETcK::EndPointResolved && !hasTimeElapsed(tStart, msBlockMax, millis())); // not sure how we got out of the loop // but assign our state and only return true if we succeeded. if(pStatus != NULL) *pStatus = _classState; if(_classState == DNETcK::EndPointResolved) { _fEndPointsSetUp = true; return(true); } return(false); }