void TCPServer::periodicTask(void) { FFLL * pffllServer = NULL; // look at all of the server objects while((pffllServer = (FFLL *) FFNext(&_ffptPeriodTask, pffllServer)) != NULL) { FFLL * pffllSocket = NULL; TCPServer& tcpServer = *((TCPServer *) (pffllServer->_this)); // for syntax sake if(ILIsIPSetup(tcpServer._pDEIPcK->_pLLAdp, NULL)) { while((pffllSocket = (FFLL *) FFNext(&tcpServer._ffptSockets, pffllSocket)) != NULL) { TCPSocket& tcpSocket = *((TCPSocket *) (pffllSocket->_this)); // for syntax sake // start listening on available sockets if(tcpSocket._classState == ipsNotInitialized && tcpSocket._socket.tcpState < tcpInvalid) { // get this listening if(TCPOpenWithSocket(tcpSocket._pDEIPcK->_pLLAdp, &tcpSocket._socket, tcpSocket._hPMGR, &IPListen, portListen, tcpServer._listeningPort, NULL) == &tcpSocket._socket) { if(tcpSocket._socket.tcpState == tcpListen) { tcpSocket._classState = ipsListening; } } } } } } }
/*** bool TCPServer::getListeningEndPoint(IPEndPoint *pListeningEP) ** ** Synopsis: ** Gets the endpoint that the server is listening on. ** This is both the IP and port the server is on. ** ** Parameters: ** pLocalEP A pointer to an IPEndPoint to receive the local endpoint information. ** ** Return Values: ** true The local endpoint was returned. ** false The local endpoint is not known, usually because the connection was not set up yet. ** ** Errors: ** None ** ** Notes: ** ** If false is returned, then *pLocalEP will be garbage. ** */ bool TCPServer::getListeningEndPoint(IPEndPoint& epLocal) { if(_pDEIPcK != NULL && ILIsIPSetup(_pDEIPcK->_pLLAdp, NULL)) { ILGetMyIP(_pDEIPcK->_pLLAdp, &epLocal.ip); epLocal.port = _listeningPort; return(true); } return(false); }
// Notes on dnsNSMax and cDhcpNS. You would think that we should only cycle through cDhcpNS as this is the number // DNS servers given to us by DHCP, however, sometimes DHCP does not give us good DNS servers and for the // SNTP server to work, we need a good DNS server. So we continue to check the default, pre initialized google DNS // servers after the DHCP DNS servers are checked first. If we get a lot of DNS servers from DHCP, then ultimately // all of the pre installed google servers will be overwritten in the dnsNSMax list, but if we got a lot of DNS servers // the assumption is that they are good ones. In particular, I found that Verizon did not give me very good DNS servers, they // could not resolve the SNTP time servers. static void DNSStateMachine(const LLADP * pLLAdp) { IPSTATUS status = ipsSuccess; if(pLLAdp == NULL || pLLAdp->pDNSMem == NULL || !ILIsIPSetup(pLLAdp, NULL)) { return; } switch(pLLAdp->pDNSMem->dnsState) { case dnsSend: if(pLLAdp->pDNSMem->dnsNSMax == 0) { pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; break; } else if(pLLAdp->pDNSMem->cTry >= (pLLAdp->pDNSMem->dnsNSMax * DNSMINTRY)) { if(pLLAdp->pDNSMem->iDNSCur == pLLAdp->pDNSMem->iDNSWorks) { pLLAdp->pDNSMem->iDNSWorks = DNSiInvalid; } pLLAdp->pDNSMem->iDNSCur = DNSiInvalid; pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; break; } else if(pLLAdp->pDNSMem->iDNSWorks < pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSCur = pLLAdp->pDNSMem->iDNSWorks; } else if(pLLAdp->pDNSMem->iDNSCur >= pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSCur = 0; } else { pLLAdp->pDNSMem->iDNSCur = (pLLAdp->pDNSMem->iDNSCur + 1) % pLLAdp->pDNSMem->dnsNSMax; } // set this up for an attempt to get the IP address memcpy(&pLLAdp->pDNSMem->socket.s.ipRemote, &pLLAdp->pDNSMem->dnsNS[pLLAdp->pDNSMem->iDNSCur], ILIPSize(pLLAdp)); // fall thru on success case dnsReadySend: // clear the current IP address memset(&pLLAdp->pDNSMem->ip, 0, sizeof(IPv4or6)); // just make this unique for this pass pLLAdp->pDNSMem->dnsDG.dnsHdr.ID++; // set my timers and counts pLLAdp->pDNSMem->cTry++; pLLAdp->pDNSMem->tTimeout = dnsWaitForRetry; pLLAdp->pDNSMem->tStart = SYSGetMilliSecond(); // send out the DNS datagram UDPSend(&pLLAdp->pDNSMem->socket, (uint8_t *) &pLLAdp->pDNSMem->dnsDG, pLLAdp->pDNSMem->cbDNSDG, &status); // see if it went out. if(IsIPStatusAnError(status)) { pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; } else { pLLAdp->pDNSMem->dnsState = dnsWaiting; } break; case dnsWaiting: { uint16_t cbDG = UDPAvailable(&pLLAdp->pDNSMem->socket) ; IPSTATUS status; if(cbDG > sizeof(DNSHDR)) { // we need some space for the datagram uint8_t rgbDNSDG[DNSMAXUDPSIZE]; DNSDG * pDNSDG = (DNSDG *) rgbDNSDG; uint8_t * pEnd = NULL; uint8_t * pCName = NULL; DNSRR * pDNSRRA = NULL; // read the DNS datagram cbDG = UDPRead(&pLLAdp->pDNSMem->socket, rgbDNSDG, DNSMAXUDPSIZE, &status); // There are some servers setting this and they should not! RFC 6195 2.1 and I need to ignore it // Plus this is used internally to determine if we are in machine or network order. This is in network order right now. pDNSDG->dnsHdr.Z = 0; // now put in machine order. cbDG = ExDNSDG(pDNSDG, cbDG); pEnd = rgbDNSDG + cbDG; // if this is not a my response, keep waiting // remember the ID is not exchanged, so network and machine order will have the same ID if(!pDNSDG->dnsHdr.QR || pDNSDG->dnsHdr.ID != pLLAdp->pDNSMem->dnsDG.dnsHdr.ID) { break; } // ops and error occured, jump to finish with error // go to the error state with no address found if(pDNSDG->dnsHdr.RCODE != DNSRCODENoError) { // this is a failure case; go to the next DNS server pLLAdp->pDNSMem->dnsState = dnsSend; break; } // get the canonical name for what we are looking for // the first record is the question which has the name we used. // we need to use the one in this datagram because we do memory range // checking and if we use the QR we sent, it would be out of the memory range pCName = DNSFindCName(pDNSDG, DNSRRAN, pDNSDG->rrRecords, pEnd); // now find the A record pDNSRRA = DNSFindRR(pDNSDG, NULL, DNSRRAN, DNSTYPEA, DNSCLASSIN, pCName, pEnd); // if we got the A record we are done if( pDNSRRA != NULL && ((ILIsIPv6(pLLAdp) && pDNSRRA->RDLENGTH == sizeof(IPv6)) || (!ILIsIPv6(pLLAdp) && pDNSRRA->RDLENGTH == sizeof(IPv4)) ) ) { // copy in our result memcpy(&pLLAdp->pDNSMem->ip, pDNSRRA->RDATA, pDNSRRA->RDLENGTH); // say we are done pLLAdp->pDNSMem->dnsState = dnsReady; pLLAdp->pDNSMem->cTry = 0; // We got an IP so we know this DNS server can work, remember that if(pLLAdp->pDNSMem->iDNSCur < pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSWorks = pLLAdp->pDNSMem->iDNSCur; } // get out we found it and are done. break; } // by default we will go to the next well know sever unless we pick up a better NS to go to pLLAdp->pDNSMem->dnsState = dnsSend; // we did not find anything, so update our DNS request to use the new CName if(pCName != pDNSDG->rrRecords) { // make the new DNS packet with the CName instead of what we were using uint16_t cbMax = DNSCreateIPv4QueryDN(pLLAdp, rgbDNSDG, pCName, pEnd, &pLLAdp->pDNSMem->dnsDG); pLLAdp->pDNSMem->cbDNSDG = ExDNSDG(&pLLAdp->pDNSMem->dnsDG, cbMax); } // Didn't find an A record // But maybe there is a name server we should try. // If we asked for recursion and go it, no sense working the issue ourselves. // likewise if there are now NS with IP addresses, no sense working the issue if(!(pDNSDG->dnsHdr.RD && pDNSDG->dnsHdr.RA) && pDNSDG->dnsHdr.NSCOUNT > 0 && pDNSDG->dnsHdr.ARCOUNT > 0) { // this DNS server gave us something, so remember it if(pLLAdp->pDNSMem->iDNSCur < pLLAdp->pDNSMem->dnsNSMax) { pLLAdp->pDNSMem->iDNSWorks = pLLAdp->pDNSMem->iDNSCur; } pDNSRRA = DNSFindNSARR(pDNSDG, pCName, pEnd, DNSTYPEA); // if this looks like a good IP address to try, lets contact that name server if(pDNSRRA != NULL && pDNSRRA->RDLENGTH == sizeof(IPv4)) { // say were are not using one of our well known DNS servers pLLAdp->pDNSMem->iDNSCur = DNSiInvalid; // Put the IP in our socket memcpy(&pLLAdp->pDNSMem->socket.s.ipRemote, pDNSRRA->RDATA, pDNSRRA->RDLENGTH); pLLAdp->pDNSMem->dnsState = dnsReadySend; } } else if(pLLAdp->pDNSMem->iDNSWorks == pLLAdp->pDNSMem->iDNSCur) { pLLAdp->pDNSMem->iDNSWorks = DNSiInvalid; } } else if((SYSGetMilliSecond() - pLLAdp->pDNSMem->tStart) >= pLLAdp->pDNSMem->tTimeout) { pLLAdp->pDNSMem->dnsState = dnsWaitTry; } } break; case dnsWaitTry: if(pLLAdp->pDNSMem->iDNSWorks == pLLAdp->pDNSMem->iDNSCur) { pLLAdp->pDNSMem->iDNSWorks = DNSiInvalid; } if((pLLAdp->pDNSMem->cTry % DNSMINTRY) == 0) { pLLAdp->pDNSMem->dnsState = dnsSend; } else { pLLAdp->pDNSMem->dnsState = dnsReadySend; } break; case dnsReady: pLLAdp->pDNSMem->cTry = 0; break; // noting to do here, either we have something in the DNS memory IP or not. case dnsRedirect: case dnsUninit: default: break; } }
// This is not a URL, this must be a domain nume such as www.foo.bar.com with an optional . at the end. bool DNSResolve(const LLADP * pLLAdp, uint8_t const * const pchDomainName, uint32_t cchDomanName, void * pIPvX, IPSTATUS * pStatus) { IPSTATUS status = ipsSuccess; // see if we are initialized if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } else if( !ILIsIPSetup(pLLAdp, &status) ) { // do nothing, I got the status } else if(pLLAdp->pDNSMem == NULL || pLLAdp->pDNSMem->dnsState == dnsUninit) { status = ipsDNSIsNotInitialized; } else if(pchDomainName == NULL) { status = ipsDomainNameIsNULL; } else if(pIPvX == NULL) { status = ipsIPIsNULL; } // we are currently processing a DNS reqeust else if(pLLAdp->pDNSMem->dnsState != dnsReady) { // this is not the one we are working on! if(pLLAdp->pDNSMem->pchDomainName != pchDomainName) { status = ipsDNSIsInUse; } // this is the one we are working on, check to see if it is done. else { // go into the state machine. status = ipsDNSIsResolving; } } // we are done, see if we got it or not else if(pLLAdp->pDNSMem->pchDomainName == pchDomainName && pLLAdp->pDNSMem->cchDomainName == cchDomanName && strncmp((char *) pLLAdp->pDNSMem->pchDomainName, (char *) pchDomainName, cchDomanName) == 0) { if(ILIsIPv6(pLLAdp)) { // have no idea if(memcmp(&pLLAdp->pDNSMem->ip.ipv6, &IPv6NONE, sizeof(IPv6)) == 0) { status = ipsDNSFailedToResolve; } // got it else { memcpy(pIPvX, &pLLAdp->pDNSMem->ip.ipv6, sizeof(IPv6)); } } // IPv4 else { // have no idea if(pLLAdp->pDNSMem->ip.ipv4.u32 == IPv4NONE.u32) { status = ipsDNSFailedToResolve; } // got it else { memcpy(pIPvX, &pLLAdp->pDNSMem->ip.ipv4, sizeof(IPv4)); } } } // if we are ready, but he is asking for something else, start a new request. // check to see if the domain name starts with a number; as in IP address // TODO: IPv6 support else if(isdigit(*pchDomainName)) { uint32_t i = 0; uint32_t j = 0; uint32_t k = 0; uint8_t const * pch = pchDomainName; if(ILIsIPv6(pLLAdp)) { // TODO: do IPv6 support } else { for(i=0; i<4; i++) { for(j=0, k=0; j<3 && isdigit(*pch); j++, pch++) { k *= 10; k += (*pch - '0'); } if((i<3 && *pch == '.') || (i == 3 && (*pch == '/' || *pch == '\0'))) { ((IPv4 *) pIPvX)->u8[i] = (uint8_t) k; pch++; } // if is clearly not an IP address // try it as a domain name else { DNSStartIPv4Request(pLLAdp, pchDomainName, cchDomanName, &status); break; } } if(status == ipsSuccess) { // pretend we got the IP pLLAdp->pDNSMem->ip.ipv4.u32 = ((IPv4 *) pIPvX)->u32; pLLAdp->pDNSMem->pchDomainName = pchDomainName; pLLAdp->pDNSMem->cchDomainName = cchDomanName; } else { memcpy(pIPvX, &IPv4NONE, sizeof(IPv4)); } } } // otherwise we need to go look it up. else { DNSStartIPv4Request(pLLAdp, pchDomainName, cchDomanName, &status); } AssignStatusSafely(pStatus, status); return(status == ipsSuccess); }