IPSTACK * IPSGetIpStackFromAdaptor(const LLADP * pLLAdp, uint32_t type, IPSTATUS * pStatus) { uint8_t * pIpStackBuff = NULL; IPSTACK * pIpStack = NULL; if(pLLAdp == NULL) { AssignStatusSafely(pStatus, ipsAdaptorMustBeSpecified); return(NULL); } else if(pLLAdp->pNwAdp->hAdpHeap == NULL) { AssignStatusSafely(pStatus, ispOutOfMemory); return(NULL); } if((pIpStackBuff = (u8*)RRHPAlloc(pLLAdp->pNwAdp->hAdpHeap, IPStackEntrySize)) == NULL) { AssignStatusSafely(pStatus, ipsIpStackAllInUse); return(NULL); } if((pIpStack = IPSInitIpStack(pLLAdp, pIpStackBuff, type)) == NULL) { AssignStatusSafely(pStatus, ipsUnsupportedTransportProtocol); RRHPFree(pLLAdp->pNwAdp->hAdpHeap, pIpStackBuff); return(NULL); } AssignStatusSafely(pStatus, ipsSuccess); return(pIpStack); }
static bool DNSStartIPv4Request(const LLADP * pLLAdp, const uint8_t * pchDomainName, uint32_t cchDomanName, IPSTATUS * pStatus) { uint16_t cbMax = DNSCreateIPv4QueryCB(pLLAdp, pchDomainName, cchDomanName, &pLLAdp->pDNSMem->dnsDG); // start a new request. if(cbMax > 0) { // put in network order pLLAdp->pDNSMem->cbDNSDG = ExDNSDG(&pLLAdp->pDNSMem->dnsDG, cbMax); // Go into the state machine pLLAdp->pDNSMem->ip.ipv4.u32 = IPv4NONE.u32; pLLAdp->pDNSMem->dnsState = dnsSend; pLLAdp->pDNSMem->pchDomainName = pchDomainName; pLLAdp->pDNSMem->cchDomainName = cchDomanName; AssignStatusSafely(pStatus, ipsDNSIsResolving); return(true); } // else the name did not parse else { AssignStatusSafely(pStatus, ipsDNSInvalidName); return(false); } }
bool TCPServer::addSocket(TCPSocket& tcpSocket, IPSTATUS * pStatus) { // if we don't have a page manager, assign the default one if(tcpSocket._hPMGR == NULL) { tcpSocket._hPMGR = hNetworkPMGR; } if(tcpSocket._hPMGR == NULL) { AssignStatusSafely(pStatus, ipsNoPMGRGiven); return(false); } else if(_pDEIPcK == NULL) { AssignStatusSafely(pStatus, ipsNotInitialized); return(false); } else if(tcpSocket._pDEIPcK != NULL) { AssignStatusSafely(pStatus, ipsInUse); return(false); } // add it to the list of sockets to listen on FFInPacket(&_ffptSockets, &tcpSocket._ffptInfo); tcpSocket._pDEIPcK = _pDEIPcK; return(true); }
static uint32_t UDPPeekSMGR(UDPSOCKET * pSocket, HSMGR pSMGR, uint16_t index, uint8_t * pbRead, uint16_t cbRead, IPSTATUS * pStatus) { uint32_t cb = 0; if(pSocket == NULL) { AssignStatusSafely(pStatus, ipsSocketNULL); return(0); } else if(pbRead == NULL || cbRead == 0) { AssignStatusSafely(pStatus, ipsBufferNotDefined); return(0); } else if(pSocket->s.portRemote == portListen || pSocket->s.portRemote == portInvalid) { AssignStatusSafely(pStatus, ipsSocketNotResolved); return(0); } cb = min((pSocket->cbNextDataGram - index), cbRead); if(cb > 0 && SMGRRead((HSMGR) pSMGR, (sizeof(uint16_t) + index), pbRead, cb) == cb) { return(cb); } return(0); }
static bool IsInitNotLinked(IPSTATUS * pStatus) { if (wfmrf24.priv.fMRFBusy) { AssignStatusSafely(pStatus, ipsInUseW); return(false); } else if (wfmrf24.priv.connectionStatus != ForceIPStatus((InitMask | WF_EVENT_INITIALIZATION))) { AssignStatusSafely(pStatus, ipsInUse); return(false); } else if (!IsInitialized(pStatus)) { return(false); } // we are not busy and we are in the initialize state and we have // not connected. However, in the past, we may have attempted a disconnect while // during a reconnect, so lets just make sure we are disconnected Disconnect(); return(true); }
/***************************************************************************** Function: void TCPClose(SOCKET * pSocket, IPSTATUS * pStatus) Description: This politely closes a socket, making sure no data is lost Parameters: pSocket: The socket to close, it is always safe to close, closed sockets. pStatus: A pointer to a status variable to recieve the state of the socket as a status Returns: None ***************************************************************************/ void TCPClose(HSOCKET hSocket, IPSTATUS * pStatus) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; if(pSocket == NULL) { AssignStatusSafely(pStatus, ipsSocketNULL); return; } switch(TCPState(pSocket)) { case tcpListen: // closes, releases the socket so it can be used again pSocket->tcpState = tcpClosed; break; case tcpSynSent: // we do not update sndEND when we send a sndNXT, but we do update the sndNXT // this is because a syn is a phantom byte and we don't want to point beyond zero // in our output buffers and attempt to send a garbabe byte. // but in order to terminate properly we need sndNXT == sndEND or we will loop // attempting to send bytes from out buffer that we don't have to send pSocket->sndNXT = pSocket->sndEND; // we may have sent a syn and sndNXT > sndEND pSocket->tcpState = tcpWaitUserClose; break; case tcpSynReceived: case tcpSynReceivedWhileListening: pSocket->sndNXT = pSocket->sndEND; // we may have sent a syn and sndNXT > sndEND // fall thru case tcpEstablished: pSocket->tcpState = tcpFinWait1; break; case tcpFinWait1: case tcpFinWait2: case tcpCloseWait: case tcpClosing: case tcpLastAck: case tcpInvalid: case tcpUnassigned: case tcpAllocated: case tcpClosed: case tcpWaitUserClose: default: break; } pSocket->fSocketOpen = false; // get the status AssignStatusSafely(pStatus, IPStatusFromTCPState(pSocket->tcpState)); }
static bool Send(IPSTACK * pIpStack, IPSTATUS * pStatus) { AssignStatusSafely(pStatus, ipsSuccess); pIpStack->fOwnedByAdp = true; FFInPacket(&wfmrf24.priv.ffptWrite, pIpStack); return(true); }
/***************************************************************************** Function: uint32_t TCPPeekSMGR(TCPSOCKET * pSocket, HSMGR pSMGR, uint8_t * pbRead, uint16_t cbRead, IPSTATUS * pStatus) Description: Reads bytes out of the receive buffer but does not move the unread pointer, peek or receive will return the same data. Parameters: pSocket: The socket to read the bytes from pSMGR: pointer to an open stream pbRead: A buffer to receive the data cbRead: Max size of the buffer to receive the data pStatus: A pointer to a status variable to recieve the state of the socket as a status Returns: Number of bytes read ***************************************************************************/ static uint32_t TCPPeekSMGR(TCPSOCKET * pSocket, HSMGR pSMGR, uint16_t index, uint8_t * pbRead, uint16_t cbRead, IPSTATUS * pStatus) { int32_t cb = 0; IPSTATUS status = ipsSuccess; if(pSocket == NULL) { status = ipsSocketNULL; } else if(pbRead == NULL || cbRead == 0) { status = ipsBufferNotDefined; } else if(pSocket->s.portRemote == portListen || pSocket->s.portRemote == portInvalid) { status = ipsSocketNotResolved; } else if(pSMGR == NULL) { status = ipsNoSMGRGiven; } else { cb = SMGRRead((HSMGR) pSMGR, index, pbRead, min((SMGRcbStream(pSMGR) - index), cbRead)); } AssignStatusSafely(pStatus, status); return(cb); }
bool DEWFcK::wfConnect(SECURITY security, const char * szSsid, const byte * rgbKey, int iKey, IPSTATUS * pStatus) { IPSTATUS status = ipsFailed; deIPInit(); if(isWFInitialized(&status)) { switch(_wfState) { case idle: case scanReady: case keygenReady: case connecting: if(_pNwWF->Connect(security, (const uint8_t *) szSsid, rgbKey, iKey, true, &status)) { _wfState = connected; } else if(IsIPStatusAnError(status)) { _wfState = idle; } break; default: status = ipsInvalidOperation; break; } } AssignStatusSafely(pStatus, status); return(_wfState == connected); }
const NWADP * GetMRF24GAdaptor(MACADDR *pUseThisMac, HRRHEAP hAdpHeap, IPSTATUS * pStatus) { // get our pins set up WF_HIBERNATE_IO = 0; WF_HIBERNATE_TRIS = 0; WF_RESET_IO = 0; WF_RESET_TRIS = 0; // Enable the WiFi WF_CS_IO = 1; WF_CS_TRIS = 0; WF_INT_TRIS = 1; // register our interrupt vectors setIntVector(WF_INT_VEC, _WFInterrupt); setIntPriority(WF_INT_VEC, 3, 0); if (hAdpHeap == NULL) { AssignStatusSafely(pStatus, ipsNoHeapGiven); return(NULL); } AssignStatusSafely(pStatus, ipsSuccess); wfmrf24.priv.initStatus = ForceIPStatus((InitMask | WF_INIT_ERROR_SPI_NOT_CONNECTED)); wfmrf24.priv.connectionStatus = ForceIPStatus((InitMask | WF_EVENT_INITIALIZATION)); wfmrf24.priv.cScanResults = -1; wfmrf24.adpMRF24G.hAdpHeap = hAdpHeap; wfmrf24.priv.pIpStackBeingTx = NULL; memset(&wfmrf24.priv.ffptRead, 0, sizeof(FFPT)); memset(&wfmrf24.priv.ffptWrite, 0, sizeof(FFPT)); // save away our MAC if (pUseThisMac != NULL) { memcpy(&wfmrf24.adpMRF24G.mac, pUseThisMac, sizeof(MACADDR)); } else { memcpy(&wfmrf24.adpMRF24G.mac, &MACNONE, sizeof(MACADDR)); } WF_Init(); return(&wfmrf24.adpMRF24G); }
/***************************************************************************** Function: uint32_t TCPAvailable(SOCKET * pSocket, IPSTATUS * pStatus) Description: Returns the number of unread bytes in the socket receive buffer Parameters: pSocket: The socket to get the number of unread bytes pStatus: A pointer to a status variable to recieve the state of the socket as a status Returns: Number of unread bytes in the socket, or zero ***************************************************************************/ uint32_t TCPAvailable(HSOCKET hSocket, IPSTATUS * pStatus) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; uint32_t rcvNXT = 0; if(pSocket == NULL) { AssignStatusSafely(pStatus, ipsSocketNULL); return(0); } AssignStatusSafely(pStatus, IPStatusFromTCPState(pSocket->tcpState)); switch(TCPState(pSocket)) { // get rid of the FIN that is in the count case tcpEstablished: case tcpSynReceived: case tcpSynReceivedWhileListening: case tcpCloseWait: case tcpLastAck: case tcpWaitUserClose: case tcpFinWait1: case tcpFinWait2: case tcpClosing: rcvNXT = pSocket->rcvNXT; if(pSocket->fGotFin) { rcvNXT--; } break; case tcpListen: case tcpSynSent: case tcpInvalid: case tcpUnassigned: case tcpAllocated: case tcpClosed: default: return(0); break; } // how much can we read return(rcvNXT); }
/***************************************************************************** Function: bool TCPIsEstablished(SOCKET * pSocket, IPSTATUS * pStatus) Description: This is sort of like TCPIsConnected except it is for the established state. Think of being connected as being in the process of getting or closing a connection and being established. Established is a fully connected duplex condtion where both sides are ready to send and receive data. Parameters: pSocket: The socket to see if it is in the established state pStatus: A pointer to a status variable to recieve the status of the connection This may be NULL if you don't care about the status Returns: true if the connection is established and you can send/write data, false if the conneciton is not established ***************************************************************************/ bool TCPIsEstablished(HSOCKET hSocket, IPSTATUS * pStatus) { IPSTATUS status; TCPIsConnected(hSocket, &status); AssignStatusSafely(pStatus, status); return(status == IPStatusFromTCPState(tcpEstablished)); }
static bool StartScan(t_scanMode filter, IPSTATUS * pStatus) { if (IsInitialized(pStatus) && wfmrf24.priv.connectionStatus == ForceIPStatus((InitMask | WF_EVENT_INITIALIZATION))) { wfmrf24.priv.fMRFBusy = true; wfmrf24.priv.cScanResults = -1; WF_Scan(filter); AssignStatusSafely(pStatus, ipsPending); } return(true); }
static IPSTACK * Read(IPSTATUS * pStatus) { IPSTACK * pIpStack = FFOutPacket(&wfmrf24.priv.ffptRead); if (pIpStack != NULL) { pIpStack->fOwnedByAdp = false; } AssignStatusSafely(pStatus, ipsSuccess); return(pIpStack); }
/***************************************************************************** Function: bool DEWFcK::beginScan(void) bool DEWFcK::beginScan(WFSCAN scanType) bool DEWFcK::beginScan(int connectionID) bool DEWFcK::beginScan(int connectionID, WFSCAN scanType) Description: Scan for a WiFi SSID based on profile or connection ID. Parameters: connectionID - Scan for the network defined by the specifed profile, or all networks if 0/WF_SCAN_ALL is specified or omitted scanType - WF_ACTIVE_SCAN or WF_PASSIVE_SCAN or WF_PASSIVE_SCAN if omitted Returns: True if the the scan got started, false if not.. usually becasue an invalid connectionID was given. Remarks: We have to wait for a scan to finish before we can do any other hardware stuff, so this is a harsh call in that once connected this can cause problems or the connection can cause problem for this That is why once we are conneced, this call will fail, we can't run it. ***************************************************************************/ bool DEWFcK::wfScan(WFSCAN scanType, int * pcNetworks, IPSTATUS * pStatus) { // make sure we are initialized deIPInit(); if(isWFInitialized(pStatus)) { switch(_wfState) { case idle: case scanReady: case keygenReady: if(_pNwWF->StartScan(scanType, pStatus)) { _wfState = scanning; } break; case scanning: if(_pNwWF->IsScanDone((int32_t *) pcNetworks)) { AssignStatusSafely(pStatus, ipsSuccess); _wfState = scanReady; return(true); } else { AssignStatusSafely(pStatus, ipsScanning); } break; default: AssignStatusSafely(pStatus, ipsInvalidOperation); break; } } return(false); }
static bool IPSSetFrame(IPSTACK * pIpStack, IPSTATUS * pStatus) { if(pIpStack->cbFrame != sizeof(ETHERNETII_FRAME)) { AssignStatusSafely(pStatus, ipsInvalidFrameSize); return(false); } pIpStack->pFrameII->etherType = pIpStack->etherType; pIpStack->fIEEE802Frame = false; // put my MAC address in. memcpy(&pIpStack->pFrameII->macSrc, &pIpStack->pLLAdp->pNwAdp->mac, sizeof(MACADDR)); // put in the broadcast address, this will be filled in at the last min before // transmission when we do a ARP lookup for the IP memcpy(&pIpStack->pFrameII->macDest, &MACBROADCAST, sizeof(MACADDR)); AssignStatusSafely(pStatus, ipsSuccess); return(true); }
// does not calculate checksum; this is calculated when we got to network order static bool IPSSetHeader(IPSTACK * pIpStack, IPSTATUS * pStatus) { if(ILIsIPv6(pIpStack->pLLAdp)) { memset(pIpStack->pIPv6Hdr, 0, sizeof(IPv6HDR)); AssignStatusSafely(pStatus, ipsIpStackNotSupportedPkt); return(false); } else { if(pIpStack->cbIPHeader < sizeof(IPv4HDR)) { AssignStatusSafely(pStatus, ipsInvalidIPv4HedearSize); return(false);; } // Per RFC 791 pIpStack->cbIPHeader = sizeof(IPv4HDR); pIpStack->pIPv4Hdr->version = 4; pIpStack->pIPv4Hdr->cdwHeader = sizeof(IPv4HDR) / 4; pIpStack->pIPv4Hdr->cbTotal = sizeof(IPv4HDR) + pIpStack->cbTranportHeader + pIpStack->cbPayload; pIpStack->pIPv4Hdr->ident = 0; pIpStack->pIPv4Hdr->u16 = 0; pIpStack->pIPv4Hdr->timeToLive = TIME_TO_LIVE; pIpStack->pIPv4Hdr->protocol = pIpStack->protocol; // typically ippnICMP, ippnTCP, ippnUDP pIpStack->pIPv4Hdr->hdrChecksum = 0; // for calculations, this is set to 0, RFC 791 pIpStack->pIPv4Hdr->ipSrc.u32 = pIpStack->pLLAdp->ipMy.ipv4.u32; pIpStack->pIPv4Hdr->ipDest.u32 = IPv4BROADCAST.u32; // TODO: Process options pIpStack->fOptionPresent = false; return(true); } AssignStatusSafely(pStatus, ipsIpStackParsingError); return(false); }
static bool IsLinked(IPSTATUS * pStatus) { IPSTATUS status = wfmrf24.priv.connectionStatus; if (!IsInitialized(pStatus)) { return(false); } AssignStatusSafely(pStatus, status); // Alternative way, but slower than polling the event data // void WF_ConnectionStateGet(uint8_t *p_state); // This is faster and gives the same result return(status == ipsSuccess); }
IPSTACK * IPSRefresh(IPSTACK * pIpStack, const LLADP * pLLAdp, IPSTATUS * pStatus) { AssignStatusSafely(pStatus, ipsSuccess); if(pIpStack == NULL) { pIpStack = IPSGetIpStackFromAdaptor(pLLAdp, ippnTCP, pStatus); } else { pIpStack = IPSSwapSrcAndDest(pIpStack); } if(pIpStack != NULL) { // the payload may have a pointer in it that we are going to clear // that pointer may or may not be from the heap; but if it is not from // the heap, the pointer will be outside of the heap ranage and be ignored // by the heap manager with no damage. if(pIpStack->fFreePayloadToAdp) { RRHPFree(pIpStack->pLLAdp->pNwAdp->hAdpHeap, pIpStack->pPayload); } pIpStack->cbPayload = 0; pIpStack->pPayload = NULL; switch(pIpStack->protocol) { case ippnUDP: pIpStack->pUDPHdr->cbHdrData = sizeof(UDPHDR); pIpStack->pUDPHdr->checksum = 0; break; case ippnTCP: pIpStack->pTCPHdr->u16Flags = 0; pIpStack->pTCPHdr->dataOffset = sizeof(TCPHDR)/sizeof(uint32_t); pIpStack->pTCPHdr->urgentPtr = 0; pIpStack->pTCPHdr->checksum = 0; break; default: break; } } return(pIpStack); }
/***************************************************************************** Function: uint32_t TCPPeek(SOCKET * pSocket, void * pv, uint32_t cb, IPSTATUS * pStatus) Description: Reads bytes out of the receive buffer but does not move the unread pointer, peek or receive will return the same data. Parameters: hSocket: The socket to read the bytes from index: Number of bytes in to start the peek pbRead: A buffer to receive the data cbRead: Max size of the buffer to receive the data pStatus: A pointer to a status variable to recieve the state of the socket as a status Returns: Number of bytes read ***************************************************************************/ uint32_t TCPPeekIdx(HSOCKET hSocket, uint32_t index, void * pbRead, uint32_t cbRead, IPSTATUS * pStatus) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; IPSTATUS status = ipsSocketNULL; if(pSocket != NULL && pSocket->cbRxSMGR > 0) { SMGR * pSMGR = (SMGR*)alloca(pSocket->cbRxSMGR); if(SMGRRead((HSMGR) &pSocket->smgrRxTxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR) { // because we are only READing, no need to update the stream tables return(TCPPeekSMGR(pSocket, (HSMGR) pSMGR, (uint16_t) index, (u8*)pbRead, cbRead, pStatus)); } status = ipsFailedToReadStreamBuffer; } AssignStatusSafely(pStatus, status); return(0); }
/***************************************************************************** Function: uint32_t TCPRead(SOCKET * pSocket, void * pv, uint32_t cb, IPSTATUS * pStatus) Description: Reads bytes out of the receive buffer. We call this receive instead of read because RFC 793 calls it receive. Parameters: pSocket: The socket to read the bytes from pv: A buffer to receive the data cb: Max size of the buffer to receive the data pStatus: A pointer to a status variable to recieve the state of the socket as a status Returns: Number of bytes read ***************************************************************************/ uint32_t TCPRead(HSOCKET hSocket, void * pbRead, uint32_t cbRead, IPSTATUS * pStatus) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; IPSTATUS status = ipsSocketNULL; uint32_t cb = 0; if(pSocket != NULL && pSocket->cbRxSMGR > 0) { SMGR * pSMGR = (SMGR*)alloca(pSocket->cbRxSMGR); if(SMGRRead((HSMGR) &pSocket->smgrRxTxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR) { cb = TCPPeekSMGR(pSocket, (HSMGR) pSMGR, 0, (u8*)pbRead, cbRead, &status); if(cb > 0) { // move the begining to after what we read SMGRMoveEnd((HSMGR) pSMGR, cb, SMGRAtBegining); // apply the read bytes to our base pSocket->rcvIRS += cb; // and now fix up to the base pSocket->rcvNXT -= cb; pSocket->rcvUP -= cb; // pSocket->rcvSeqAhead -= cb; } // save away the table that is stored on the stack // this should not fail! It is a fixed size and already allocated SMGRWrite((HSMGR) &pSocket->smgrRxTxBuff, 0, pSMGR, pSocket->cbRxSMGR); } else { status = ipsFailedToReadStreamBuffer; } } AssignStatusSafely(pStatus, status); return(cb); }
static bool IsInitialized(IPSTATUS * pStatus) { // we ONLY DO THIS ONCE static bool fInitSetup = false; AssignStatusSafely(pStatus, wfmrf24.priv.initStatus); // Run the task because we might not be in the Adaptor yet WF_Task(); if (!fInitSetup && wfmrf24.priv.initStatus == (InitMask | WF_INIT_SUCCESSFUL)) { uint8_t channels[] = {}; t_scanContext scanContext = {WF_ACTIVE_SCAN, 1, 200, 400, 20}; WF_RegionalDomainSet(WF_DOMAIN_FCC); WF_NetworkTypeSet(WF_NETWORK_TYPE_INFRASTRUCTURE); WF_ChannelListSet(channels, sizeof(channels)); WF_ReconnectModeSet(3, WF_ATTEMPT_TO_RECONNECT, 40, WF_ATTEMPT_TO_RECONNECT); WF_ScanContextSet(&scanContext); // fixup the MAC if (memcmp(&wfmrf24.adpMRF24G.mac, &MACNONE, sizeof(MACADDR)) == 0) { WF_MacAddressGet((uint8_t *) &wfmrf24.adpMRF24G.mac); } else { WF_MacAddressSet((uint8_t *) &wfmrf24.adpMRF24G.mac); } // set up the hardware filters //WF_SetHwMultiCastFilter(WF_MULTICAST_FILTER_1, (uint8_t *) &wfmrf24.adpMRF24G.mac); WF_SetHwMultiCastFilter(WF_MULTICAST_FILTER_2, (uint8_t *) &MACNONE); // we are done fInitSetup = true; } return(wfmrf24.priv.initStatus == (InitMask | WF_INIT_SUCCESSFUL)); }
/***************************************************************************** Function: uint32_t TCPSend(SOCKET * pSocket, const void * pv, uint32_t cb, IPSTATUS * pStatus) Description: Stuff data into the socket to be sent on the next regularly scheduled send. Because of congestion control, this may take up to a fraction of a second to send. If you want it to go out immediately then call TCPFlush on the socket immediately after this call. Parameters: pSocket: The socket to send the data on pv: a pointer to a buffer of data to send cbReq: The number of bytes to send. pStatus: A pointer to a status variable to recieve the state of the send Returns: Number of bytes actually sent, could be less than requested if the socket is full. ***************************************************************************/ uint32_t TCPWrite(HSOCKET hSocket, const void * pv, uint32_t cbReq, IPSTATUS * pStatus) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; uint32_t cb = 0; if(pSocket == NULL) { AssignStatusSafely(pStatus, ipsSocketNULL); return(0); } // we can only write data if we are in the established state if(TCPIsEstablished(pSocket, pStatus)) { SMGR * pSMGR = (SMGR*)alloca(pSocket->cbTxSMGR); if(cbReq > 0 && pSMGR != NULL && (SMGRRead((HSMGR) &pSocket->smgrRxTxBuff, pSocket->cbRxSMGR, pSMGR, pSocket->cbTxSMGR) == pSocket->cbTxSMGR)) { // This may seem like an odd place to do this, but I will update the sndUNA pointers here // I do this here instead of in the ACK processing because I do not want to take the time to open up the // stream in the ACK process, I just want to update the sndUNA pointer and move on. The downside of this is that // we may hold some pages longer than we need, but before I take MORE memory in the write, I will free those pages // which is why I will do that here before we WRITE our data below. TCPScaleSndIndexes(pSocket, pSMGR); // after we have scaled our pointers and potentially released some memory, we can // write as much data as we can to the stream cb = SMGRWrite((HSMGR) pSMGR, SMGRcbStream(pSMGR), pv, cbReq); pSocket->sndEND += cb; // save away the table that is stored on the stack // this should not fail! It is a fixed size and already allocated SMGRWrite((HSMGR) &pSocket->smgrRxTxBuff, pSocket->cbRxSMGR, pSMGR, pSocket->cbTxSMGR); } } return(cb); }
/*** int TCPServer::availableClients(void) ** ** Synopsis: ** Checks to see how many pending clients are availabe to be accepted. ** ** Parameters: ** None ** ** Return Values: ** The number of waiting TCPSockets to be accepted. ** ** Errors: ** None ** ** Notes: ** ** This is the workhorse of the TCPServer Class ** It will update pending clients if a connection is detected ** It will attempt to start listening if a socket comes avalialbe for listening ** It will clean up disconnected clients */ int TCPServer::availableClients(int& cListening, int& cWaiting, IPSTATUS * pStatus) { int cAvailable = 0; cWaiting = 0; cListening = 0; FFLL * pffllSocket = NULL; if(_pDEIPcK == NULL) { AssignStatusSafely(pStatus, ipsNotInitialized); return(0); } if(ILIsIPNetworkReady(_pDEIPcK->_pLLAdp, pStatus)) { while((pffllSocket = (FFLL *) FFNext(&_ffptSockets, pffllSocket)) != NULL) { TCPSocket& tcpSocket = *((TCPSocket *) (pffllSocket->_this)); // for syntax sake if(TCPIsEstablished(&tcpSocket._socket, NULL)) { cAvailable++; } else if(TCPIsConnected(&tcpSocket._socket, NULL)) { cWaiting++; } else if(tcpSocket._socket.tcpState == tcpListen) { cListening++; } } } return(cAvailable); }
bool UDPSend(HSOCKET hSocket, const uint8_t * pbDatagram, uint16_t cbDatagram, IPSTATUS * pStatus) { UDPSOCKET * pSocket = (UDPSOCKET *) hSocket; IPSTACK * pIpStack = NULL; if(pSocket->s.portRemote == portListen || pSocket->s.portRemote == portInvalid) { AssignStatusSafely(pStatus, ipsSocketNotResolved); return(false); } else if((pIpStack = IPSGetIpStackFromAdaptor(pSocket->s.pLLAdp, ippnUDP, pStatus)) == NULL) { return(false); } else if(UDPRawSend(pSocket->s.pLLAdp, pIpStack, (void *) &pSocket->s.ipRemote, pSocket->s.portRemote, pSocket->s.portLocal, pbDatagram, cbDatagram, true, pStatus)) { return(true); } else { IPSRelease(pIpStack); return(false); } }
// this will free the socket if it can't open it TCPSOCKET * TCPInitSocket(const LLADP * pLLAdp, TCPSOCKET * pSocketOpen, HPMGR hPMGR, const void * pIPvXDest, uint16_t portRemote, uint16_t portLocal, IPSTATUS * pStatus) { IPSTATUS status = ipsSuccess; SMGR * pSMGR = NULL; uint32_t cb = 0; uint32_t cPages = 0; if(pSocketOpen == NULL) { AssignStatusSafely(pStatus, ipsSocketNULL); return(NULL); } else if(hPMGR == NULL) { AssignStatusSafely(pStatus, ipsNoPMGRGiven); } // find a port if(portLocal == portDynamicallyAssign) { portLocal = GetEphemeralPort(&g_ffptActiveTCPSockets, &g_nextTCPEphemeralPort); } // get the sequence number // we have to get this BEFORE we memset the socket // as the timewait may be the socket we are clearing. // also, if we are listening, we can only assign the sequence number // when we now our remote port and IP as to not duplicate and to watch seq numbers. if(portRemote != portListen) { SKTPORTPAIR portPair; // remote, local portPair.portRemote = portRemote; portPair.portLocal = portLocal; // worry about the 2MSL timewait issue, get an appropriate sequence number if(TCPIsInUse(pLLAdp, portPair.portPair, pIPvXDest)) { AssignStatusSafely(pStatus, ipsPortPairAndIPAlreadyActive); return(NULL); } } // build the stream manager to point to the page handler // first build the stream to the RxStream and TxStream // Rx is the 1st pSocketOpen->hPMGR = hPMGR; // calculate the size of the 2 embedded streams and how to partition the socket stream, stream // the Rx is the first indirect stream follwed by the Tx indirect stream in the socket stream cb = (1 << ((PMGR *) hPMGR)->pf2PerPage); cPages = ((PMGR *) hPMGR)->cPages; pSocketOpen->cbRxSMGR = GetSMGRSize(min(((cTCPRXPages * cb) - sizeof(SMGR)), cPages)); pSocketOpen->cbTxSMGR = GetSMGRSize(min(((cTCPTXPages * cb) - sizeof(SMGR)), cPages)); cb = pSocketOpen->cbRxSMGR + pSocketOpen->cbTxSMGR; if(SMGRInit(&pSocketOpen->smgrRxTxBuff, cbMAXTCPSreamRecord, hPMGR) != (HSMGR) &pSocketOpen->smgrRxTxBuff) { status = ispOutOfMemory; } else if((pSMGR = (SMGR*)alloca(cb)) == NULL) { status = ispOutOfMemory; } else if(SMGRInit(pSMGR, pSocketOpen->cbRxSMGR, hPMGR) == NULL || SMGRInit((SMGR *) (((uint8_t *) pSMGR) + pSocketOpen->cbRxSMGR), pSocketOpen->cbTxSMGR, hPMGR) == NULL) { status = ispOutOfMemory; } else if(SMGRWrite(&pSocketOpen->smgrRxTxBuff, 0, pSMGR, cb) != cb) { status = ispOutOfMemory; } AssignStatusSafely(pStatus, status); if(IsIPStatusAnError(status)) { SMGRFree((HSMGR) pSMGR); SMGRFree((HSMGR) (((uint8_t *) pSMGR) + pSocketOpen->cbRxSMGR)); SMGRFree((HSMGR) &pSocketOpen->smgrRxTxBuff); IPSReleaseSocket(pSocketOpen); return(NULL); } // make the socket pSocketOpen->tcpState = tcpAllocated; pSocketOpen->s.portLocal = portLocal; pSocketOpen->s.portRemote = portRemote; pSocketOpen->s.pLLAdp = pLLAdp; memcpy(&pSocketOpen->s.ipRemote, pIPvXDest, ILIPSize(pLLAdp)); // get a new seq nbr pSocketOpen->sndISS = TCPGetSeqNumber(pLLAdp); // max I will allow to come in. RFC 1122 4.2.2.6 pSocketOpen->cbLocalMSS = min((PMGRMaxAlloc(hPMGR) >> 2), (uint16_t) (LLGetMTUR(pLLAdp) - 20)); // Jacobson rule pSocketOpen->RTTsa = RTTsaINIT; pSocketOpen->RTTsv = RTTsvINIT; pSocketOpen->tRTO_SET = RTO(pSocketOpen); pSocketOpen->tRTOCur = pSocketOpen->tRTO_SET; return(pSocketOpen); }
/***************************************************************************** Function: bool TCPIsConnected(SOCKET * pSocket, IPSTATUS * pStatus) Description: This is sort of like TCPIsEstablished except it is for any connected state. Think of being connected as being in the process of getting or closing a connection and being established. Established is a fully connected duplex condtion where both sides are ready to send and receive data. Parameters: pSocket: The socket to see if it is in the established state pStatus: A pointer to a status variable to recieve the status of the connection This may be NULL if you don't care about the status Returns: true if the connection is in the process of connecting, half or full duplex connection, or in the process of closing but not yet closed. false if the conneciton is not in any kind of active condition. ***************************************************************************/ bool TCPIsConnected(HSOCKET hSocket, IPSTATUS * pStatus) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; IPSTATUS status = ipsUnknowTCPState; // check to see if we are even connected if(pSocket == NULL) { AssignStatusSafely(pStatus, ipsSocketNULL); return(false); } // Otherwise, what is our state? switch(pSocket->tcpState) { case tcpListen: case tcpSynSent: case tcpSynReceivedWhileListening: case tcpSynReceived: case tcpEstablished: case tcpFinWait1: case tcpFinWait2: case tcpCloseWait: case tcpClosing: case tcpLastAck: status = IPStatusFromTCPState(pSocket->tcpState); break; case tcpWaitUserClose: if(TCPAvailable(pSocket, NULL) > 0) { status = IPStatusFromTCPState(pSocket->tcpState); } else { status = IPErrorFromTCPState(pSocket->tcpState); } break; case tcpUnassigned: case tcpAllocated: case tcpInvalid: case tcpClosed: status = IPErrorFromTCPState(pSocket->tcpState); break; default: status = ipsUnknowTCPState; break; } AssignStatusSafely(pStatus, status); if(IsIPStatusAnError(status)) { return(false); } else if(!ILIsIPNetworkReady(pSocket->s.pLLAdp, &status)) { AssignStatusSafely(pStatus, status); return(false); } else if(pSocket->tcpState == tcpListen) { return(false); } return(true); }
/***************************************************************************** Function: SOCKET * TCPOpen(const LLADP * pLLAdp, const SOCKETPOOL * pSocketPool, void * pIPvXDest, uint16_t portRemote, uint16_t portLocal, IPSTATUS * pStatus) Summary: Opens a Socket for both Client and Server. If portRemote == 0 The socket is opened for listening. Description: Precondition: Parameters: pLLAdp - The adaptor to use pSocket - A pointer to the socket to use hPMGR - A handle to the page manager to create the socket stream. pIPvXDest - The Dest IP to connect to if a client, ignored for a server open and may be NULL portRemote - The remote port to connect to if Client, MUST be 0 if this is a server open for listen portLocal - Local port to use, one will be assigned if zero pStatus - A pointer to a status variable to recieve the status of the open, This may be NULL Returns: The Socket if opened, NULL on failure ***************************************************************************/ HSOCKET TCPOpenWithSocket(const LLADP * pLLAdp, TCPSOCKET * pSocket, HPMGR hPMGR, const void * pIPvXDest, uint16_t portRemote, uint16_t portLocal, IPSTATUS * pStatus) { IPSTATUS status = ipsSuccess; IPSTACK * pIpStack = NULL; uint32_t cbOptions = 0; // make sure pIPvXDest points to something if(portRemote == 0 || pIPvXDest == NULL) { pIPvXDest = &IPv6NONE; } if(pSocket == NULL) { AssignStatusSafely(pStatus, ipsNoSocketsAvailable); return(NULL); } else if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } // if this is a client open else if( (pSocket = TCPInitSocket(pLLAdp, pSocket, hPMGR, pIPvXDest, portRemote, portLocal, &status)) != NULL && portRemote != portListen && (pIpStack = TCPCreateSyn(pSocket, &cbOptions, &status)) != NULL) { pSocket->tcpState = tcpSynSent; pSocket->tLastAck = SYSGetMilliSecond(); // start the connection process TCPTransmit(pIpStack, pSocket, 1, cbOptions, false, SYSGetMilliSecond(), &status); } // else this is a server open / or an error getting the socket which we will abort below in the error check else if(pSocket != NULL) { pSocket->tcpState = tcpListen; } // we got an error somewhere; clean up if(IsIPStatusAnError(status)) { if(pSocket != NULL) { pSocket->tcpState = tcpUnassigned; TCPResetSocket(pSocket); } IPSRelease(pIpStack); pSocket = NULL; AssignStatusSafely(pStatus, status); return(NULL); } // put on the listening list. FFInPacket(&g_ffptActiveTCPSockets, pSocket); pSocket->fSocketOpen = true; AssignStatusSafely(pStatus, status); return((HSOCKET) pSocket); }
bool DNSInit(const LLADP * pLLAdp, void * rgbDNSMem, uint32_t cbDNSMem, HPMGR hPMGR, IPSTATUS * pStatus) { IPSTATUS status = ipsSuccess; DNSMEM * pDNSMem = (DNSMEM *) rgbDNSMem; uint32_t i = 0; if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } else if(hPMGR == NULL) { status = ipsNoPMGRGiven; } else if(rgbDNSMem == NULL) { status = ipsDNSMemIsNULL; } else if(cbDNSMem < sizeof(DNSMEM)) { status = ipsDNSNotEnoughMem; } else if(pLLAdp->pDNSMem != NULL) { status = ipsDNSAlreadyInitialized; } else if(ILIsIPv6(pLLAdp)) { status = ipsIPv6NotSupported; } if(IsIPStatusAnError(status)) { AssignStatusSafely(pStatus, status); return(false); } memset(pDNSMem, 0, cbDNSMem); if(&pDNSMem->socket != UDPOpenWithSocket(pLLAdp, &pDNSMem->socket, hPMGR, &IPv4BROADCAST, portDNSServer, portDynamicallyAssign, &status) || IsIPStatusAnError(status)) { UDPClose(&pDNSMem->socket); AssignStatusSafely(pStatus, status); return(false); } pDNSMem->dnsNSMax = (cbDNSMem - sizeof(DNSMEM)) / sizeof(IPv4or6); pDNSMem->cDhcpNS = 0; pDNSMem->iDNSCur = DNSiInvalid; pDNSMem->iDNSWorks = DNSiInvalid; pDNSMem->dnsState = dnsReady; pDNSMem->cTry = 0; ((LLADP *) pLLAdp)->pDNSMem = pDNSMem; // initialize them all to the Google NS // that way there is something in all of the slots // this will get over written if DHCP is used. for(i=0; i<pDNSMem->dnsNSMax; i++) { if((i % 2) == 0) { pDNSMem->dnsNS[i].ipv4.u32 = 0x04040808; // Google public DNS server } else { pDNSMem->dnsNS[i].ipv4.u32 = 0x08080808; // Google public DNS server } } AssignStatusSafely(pStatus, status); return(true); }
// 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); }