uint32_t UDPRead(HSOCKET hSocket, uint8_t * pbRead, uint16_t cbRead, IPSTATUS * pStatus) { UDPSOCKET * pSocket = (UDPSOCKET *) hSocket; uint32_t cb = 0; if(pSocket != NULL) { SMGR * pSMGR = alloca(pSocket->cbRxSMGR); if(pSMGR != NULL && (SMGRRead((HSMGR) &pSocket->smgrRxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR)) { cb = UDPPeekSMGR(pSocket, (HSMGR) pSMGR, 0, pbRead, cbRead, pStatus); // if this is the whole datagram // note, the > part should never happen, cb should always // be cb <= pSocket->cbNextDataGram and this condition // should be cb == pSocket->cbNextDataGram; but should somehow // > happen, this will offer some correction if(cb >= pSocket->cbNextDataGram) { // move the begining to the next datagram SMGRMoveEnd((HSMGR) pSMGR, cb + sizeof(uint16_t), SMGRAtBegining); // read the next 2 bytes for the datagarm size if it exists if(SMGRRead((HSMGR) pSMGR, 0, &pSocket->cbNextDataGram, sizeof(uint16_t)) != sizeof(uint16_t)) { pSocket->cbNextDataGram = 0; } } // otherwise it is a partial datagram read else { // move the begining to after what we read, but leave room to // write the remaining datagram size SMGRMoveEnd((HSMGR) pSMGR, cb, SMGRAtBegining); // update the remaining datagram size pSocket->cbNextDataGram -= cb; SMGRWrite((HSMGR) pSMGR, 0, &pSocket->cbNextDataGram, sizeof(uint16_t)); } // 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->smgrRxBuff, 0, pSMGR, pSocket->cbRxSMGR); } } return(cb); }
/***************************************************************************** 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); }
uint32_t TCPAddRxDataToSocket(TCPSOCKET * pSocket, uint32_t seqNbr, uint8_t * pb, uint32_t cb) { SMGR * pSMGR = (SMGR*)alloca(pSocket->cbRxSMGR); uint32_t rcvNXT = pSocket->rcvNXT + SEQBOUNDARY; // seqNbr is tricky, it has been normalized to rcvIRS // and may be very close to rcvUNR which is typically 0 // so if seqNbr is < rcvNXT it could be less than rcvUNR, or an unsigned less than 0 // or for an unsigned, very large; which would give us a false large seqNbr. // the MAX segment we can get is 64K, so as long as we scale this down so at least seqNbr + 64K < 2^^32, we can do a compare // and see if seqNbr < rcvNXT reliably. SEQBOUNDARY is 0x80000000 which is half way into the linear uint32_t range // scale seqNbr and rcvNXT and we can do a reliable < check. // Rip off data we have already received seqNbr += SEQBOUNDARY; if(seqNbr < rcvNXT) { pb += (rcvNXT - seqNbr); cb -= (rcvNXT - seqNbr); } // get our stream pointer if(cb > 0 && pSMGR != NULL && (SMGRRead((HSMGR) &pSocket->smgrRxTxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR)) { // write as much data as we can to the stream cb = SMGRWrite((HSMGR) pSMGR, SMGRcbStream(pSMGR), pb, cb); // add the bytes written to our rcvNXT pointer pSocket->rcvNXT += 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); return(cb); } return(0); }
static uint32_t UDPProcessRx(IPSTACK * pIpStack, UDPSOCKET * pSocket) { SMGR * pSMGR = alloca(pSocket->cbRxSMGR); uint32_t cbRet = 0; if(pIpStack->cbPayload > 0 && pSMGR != NULL && (SMGRRead((HSMGR) &pSocket->smgrRxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR)) { uint32_t iEnd = SMGRcbStream(pSMGR); // put in the size prefex uint32_t cbWritten = SMGRWrite((HSMGR) pSMGR, iEnd, &pIpStack->cbPayload, sizeof(uint16_t)); // put in the data cbWritten += SMGRWrite((HSMGR) pSMGR, iEnd + cbWritten, pIpStack->pPayload, pIpStack->cbPayload); // check to see that we wrote everything. if(cbWritten == (pIpStack->cbPayload + sizeof(uint16_t))) { if(pSocket->cbNextDataGram == 0) { pSocket->cbNextDataGram = pIpStack->cbPayload; } cbRet = pIpStack->cbPayload; } // we failed to save, so discard the datagram and put the stream back to where it was else { SMGRMoveEnd((HSMGR) pSMGR, iEnd, SMGRAtEnding); } // 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->smgrRxBuff, 0, pSMGR, pSocket->cbRxSMGR); } return(cbRet); }
void UDPDiscard(HSOCKET hSocket) { UDPSOCKET * pSocket = (UDPSOCKET *) hSocket; if(pSocket != NULL) { SMGR * pSMGR = alloca(pSocket->cbRxSMGR); if(pSMGR != NULL && (SMGRRead((HSMGR) &pSocket->smgrRxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR)) { uint32_t iEnd = SMGRcbStream(pSMGR); SMGRMoveEnd((HSMGR) pSMGR, iEnd, SMGRAtBegining); // 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->smgrRxBuff, 0, pSMGR, pSocket->cbRxSMGR); } } }
/***************************************************************************** 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); }
/***************************************************************************** Function: void TCPDiscard(SOCKET * pSocket) Description: Discards all unread bytes in the sockets receive buffer. Parameters: hSocket: The socket to clear the receive buffer from Returns: None ***************************************************************************/ void TCPDiscard(HSOCKET hSocket) { TCPSOCKET * pSocket = (TCPSOCKET *) hSocket; if(pSocket != NULL && pSocket->cbRxSMGR > 0) { SMGR * pSMGR = (SMGR*)alloca(pSocket->cbRxSMGR); if(SMGRRead((HSMGR) &pSocket->smgrRxTxBuff, 0, pSMGR, pSocket->cbRxSMGR) == pSocket->cbRxSMGR) { uint32_t iEnd = SMGRcbStream(pSMGR); // clear the stream by moving to the end SMGRMoveEnd((HSMGR) pSMGR, iEnd, SMGRAtBegining); // pretend like we read it // apply the read bytes to our base pSocket->rcvIRS += pSocket->rcvNXT; // and now fix up to the base pSocket->rcvNXT = 0; pSocket->rcvUP = 0; // if(pSocket->rcvSeqAhead >= pSocket->rcvNXT) // { // pSocket->rcvSeqAhead -= pSocket->rcvNXT; // } // else // { // pSocket->rcvSeqAhead = 0; // } // 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); } } }
// 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); }
HSOCKET UDPOpenWithSocket(const LLADP * pLLAdp, UDPSOCKET * pSocket, HPMGR hPMGR, const void * pIPvXDest, uint16_t portRemote, uint16_t portLocal, IPSTATUS * pStatus) { // uint32_t portPair = 0; IPSTATUS status = ipsSuccess; SMGR * pSMGR = NULL; uint32_t cb = 0; if(pLLAdp == NULL) { status = ipsAdaptorMustBeSpecified; } else if(pSocket == NULL) { status = ipsSocketNULL; } else if(hPMGR == NULL) { status = ipsNoPMGRGiven; } else if(pIPvXDest == NULL) { status = ipsIPAddressIsNull; } // get the local port else if(portLocal == portDynamicallyAssign) { portLocal = GetEphemeralPort(&g_ffptListeningUDPSockets, &g_nextUDPEphemeralPort); } AssignStatusSafely(pStatus, status); if(IsIPStatusAnError(status)) { return(NULL); } // build the stream manager to point to the page handler // first build the stream to the RxStream pSocket->hPMGR = hPMGR; if(SMGRInit(&pSocket->smgrRxBuff, cbMAXUDPSreamRecord, hPMGR) != (HSMGR) &pSocket->smgrRxBuff) { status = ispOutOfMemory; } else if((pSMGR = alloca((cb = GetSMGRSize(((PMGR *) hPMGR)->cPages)))) == NULL) { status = ispOutOfMemory; } else if(SMGRInit(pSMGR, cb, hPMGR) == NULL) { status = ispOutOfMemory; } else if(SMGRWrite(&pSocket->smgrRxBuff, 0, pSMGR, cb) != cb) { status = ispOutOfMemory; } AssignStatusSafely(pStatus, status); if(IsIPStatusAnError(status)) { SMGRFree((HSMGR) pSMGR); SMGRFree((HSMGR) &pSocket->smgrRxBuff); return(NULL); } pSocket->s.pLLAdp = pLLAdp; pSocket->s.portRemote = portRemote; pSocket->s.portLocal = portLocal; memcpy(&pSocket->s.ipRemote, pIPvXDest, ILIPSize(pLLAdp)); pSocket->cbRxSMGR = cb; // put on the listening list. FFInPacket(&g_ffptListeningUDPSockets, pSocket); // return the socket return(pSocket); }