📄 netudp.c
字号:
/**
* UDP Protocol Support for uC/IP.
*
* Copyright (c) 2001 by Intelligent Systems Software (UK) Ltd. All rights reserved.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************
* REVISION HISTORY
*
* 02-02-2001 Craig Graham <c_graham@hinge.mistral.co.uk>,Intelligent Systems Software (UK) Ltd
* First Version. Not based on anything really except RFC 768 (and Guy Lancaster's TCP
* protocol implementation as a basis for the checksum stuff).
*(yyyy-mm-dd)
* 2001-06-27 Robert Dickenson <odin@pnc.com.au>, Cognizant Pty Ltd.
* Added support for static array of UDP_QUEUE* removing dependancy on
* malloc and free for all the usual reasons.
* 2001-09-10 Mads Lind Christiansen <mc@voxtream.com>, Partner Voxtream
* Fixed UDP checksum problems and more.
* The UDP module should now be up and running.
******************************************************************************
* NOTES
* This probably isn't very good, but it does work (at least well enough to support DNS lookups,
* which is what I wanted it for).
*
*/
#include <string.h>
#include "netconf.h"
#include "net.h"
#include "nettimer.h"
#include "netbuf.h"
#include "netrand.h"
#include "netip.h"
#include "netiphdr.h"
#include "netudp.h"
#include "neticmp.h"
#include "netdebug.h"
#include "os.h"
#include "devio.h"
/*#pragma warning (push)
#pragma warning (disable: 4761) // integral size mismatch in argument; conversion supplied
#pragma warning (disable: 4244) // 'function' : conversion from 'short ' to 'unsigned char ', possible loss of data
#pragma warning (disable: 4018) // signed/unsigned mismatch*/
////////////////////////////////////////////////////////////////////////////////
/** Maximum number of udp connections at one time */
#define MAXUDP 4
#define FUDP_OPEN 1
#define FUDP_CONNECTED 2
#define FUDP_LISTEN 4
#define MAXUDPQUEUES 20
/*
#ifdef DEBUG_UDP
#define UDPDEBUG(A) printf A
#else
#define UDPDEBUG(A)
#endif
*/
/** Dump an nBuf chain */
#define DUMPCHAIN(A) {\
NBuf* p;\
int i; \
for (p = (A); p; p = p->nextBuf) {\
for (i = 0; i < p->len; i++) {\
if ((i & 3)==0)\
UDPDEBUG(("\n[%d]:",i));\
UDPDEBUG(("%x,",p->data[i]));\
}\
}\
UDPDEBUG(("\n"));\
}
UDPCB udps[MAXUDP];
static UDP_QUEUE udpqs[MAXUDPQUEUES];
static UDP_QUEUE* udp_free_list;
/** Port number auto-assigned by udpConnect if you've not already bound the socket when you connect it */
static int randPort = 0x0507;
UDP_QUEUE* alloc_udp_q(void)
{
// return (UDP_QUEUE*)malloc(sizeof(UDP_QUEUE));
UDP_QUEUE* q = NULL;
if (udp_free_list != NULL) {
q = udp_free_list;
udp_free_list = udp_free_list->next;
}
return q;
}
void free_udp_q(UDP_QUEUE* q)
{
// free(q);
q->srcPort = 0;
q->next = udp_free_list;
udp_free_list = q;
}
void udpInit(void)
{
int i;
UDPDEBUG(("udpInit()\n"));
for (i = 0; i < MAXUDP; i++) {
udps[i].flags = 0;
udps[i].sem = OSSemCreate(0);
}
udp_free_list = NULL;
for (i = MAXUDPQUEUES; i--; ) {
free_udp_q(&udpqs[i]);
}
}
#if ONETASK_SUPPORT > 0
int udpOpen(void (*receiveEvent)(int ud, u_int16_t bytes))
#else
int udpOpen(void)
#endif
{
int i;
UDPDEBUG(("udpOpen()\n"));
OS_ENTER_CRITICAL();
for (i = 0; (i < MAXUDP) && (udps[i].flags & FUDP_OPEN); i++);
if (i == MAXUDP) {
OS_EXIT_CRITICAL();
return -1;
}
udps[i].flags |= FUDP_OPEN;
udps[i].ourPort = udps[i].theirPort = 0;
udps[i].theirAddr.s_addr = 0xffffffff;
udps[i].acceptFromAddr.s_addr = 0xffffffff; /* Default to not accepting any address stuff */
udps[i].head = udps[i].tail = NULL;
#if ONETASK_SUPPORT > 0
udps[i].receiveEvent = receiveEvent;
#endif
OS_EXIT_CRITICAL();
return i;
}
int udpClose(int ud)
{
if (!(udps[ud].flags & FUDP_OPEN)) return -1;
udps[ud].flags = 0;
return 0;
}
int udpConnect(u_int ud, const struct sockaddr_in *remoteAddr, u_char tos)
{
if (!(udps[ud].flags & FUDP_OPEN)) return -1;
udps[ud].acceptFromAddr = udps[ud].theirAddr = remoteAddr->sin_addr;
udps[ud].theirPort = htons(remoteAddr->sin_port);
udps[ud].tos = tos;
if (udps[ud].ourPort == 0)
udps[ud].ourPort = htons((unsigned short)(randPort++));
udps[ud].flags |= FUDP_CONNECTED;
return 0;
}
int udpListen(u_int ud, int backLog)
{
if (!(udps[ud].flags & FUDP_OPEN)) return -1;
udps[ud].flags |= FUDP_LISTEN;
return 0;
}
int udpBind(u_int ud, struct sockaddr_in* peerAddr)
{
UDPDEBUG(("udpBind(%d,%lx)\n",ud,peerAddr));
if (!(udps[ud].flags & FUDP_OPEN)) return -1;
udps[ud].acceptFromAddr.s_addr = peerAddr->sin_addr.s_addr;
udps[ud].acceptFromAddr.s_addr = 0xD34130B6UL;
//work out whether we should do the htons on the client ???
udps[ud].ourPort = peerAddr->sin_port;
udps[ud].ourPort = 0X1F90;
// udps[ud].ourPort = htons(peerAddr->sin_port);
return 0;
}
int udpRead(u_int ud, void* buf, long len)
{
unsigned char* d;
int rtn;
NBuf* b;
UDP_QUEUE* q;
struct in_addr fromAddr;
u_int8 err;
if (!(udps[ud].flags & FUDP_OPEN)) return -1;
d = (unsigned char*)buf;
rtn = 0;
//OSSemPend(udps[ud].sem, 0, &err);
OSSemPend(udps[ud].sem, 0, &err);
if (udps[ud].head == NULL) {
return -1;
}
fromAddr = udps[ud].theirAddr = udps[ud].head->srcAddr;
udps[ud].theirPort = udps[ud].head->srcPort;
UDPDEBUG(("fromAddr.s_addr = %08X, udps[ud].head->srcAddr.s_addr = %08X\n", fromAddr.s_addr, udps[ud].head->srcAddr.s_addr));
while ((udps[ud].head) && (len) && (fromAddr.s_addr == udps[ud].head->srcAddr.s_addr)) {
// Get next nBuf
b = udps[ud].head->nBuf;
// While we have more buffer to copy out to AND
// We have a queued nBuf
while ((len) && (b)) {
// While we have more buffer space to copy to AND
// nBuf is not empty
// while ((len) && (b->data != &b->body[b->len])) {
while ( (len) && (b->len) ) {
// Copy one byte
*d++ = *b->data++;
b->len--;
len--;
rtn++;
}
// If nBuf is empty
// if (b->data == &b->body[b->len]) {
if (!b->len) {
// Free it!
OS_ENTER_CRITICAL();
b = udps[ud].head->nBuf = nFree(b);
OS_EXIT_CRITICAL();
}
}
// If nBuf was freed (we need another one if any)
if (b == NULL) {
// Get next nBuf in queue
q = udps[ud].head;
OS_ENTER_CRITICAL();
udps[ud].head = q->next;
OS_EXIT_CRITICAL();
free_udp_q(q);
#if ONETASK_SUPPORT > 0
#else
if (udps[ud].head)
OSSemPend(udps[ud].sem, 0, &err);
#endif
} else {
#if ONETASK_SUPPORT > 0
// nBuf was not freed but we have filled our buffer (buf)
return rtn;
#else
OSSemPost(udps[ud].sem);
#endif
}
}
if (udps[ud].head == NULL)
udps[ud].tail = NULL;
return rtn;
}
#if 1
int udpWrite(u_int ud, const void* buf, long len)
{
NBuf* pNBuf;
IPHdr* ipHdr;
UDPHdr* udpHdr;
long rtn = 0;
long copied;
u_int mtu;
UDPDEBUG(("udpWrite()\n"));
if (!(udps[ud].flags & FUDP_OPEN)) return -1;
mtu = ipMTU(htonl(udps[ud].theirAddr.s_addr));
if (!mtu) {
UDPDEBUG(("no route to host\n"));
return -1;
}
while (len) {
pNBuf = NULL;
#if ONETASK_SUPPORT > 0
// We can't do a loop forever in a onetask OS
nGET(pNBuf);
// No more nBuf buffers available, should return what we have copied so far
if (!pNBuf) return rtn;
#else
// BUSY WAITING! (not nice)
do {
nGET(pNBuf);
} while (pNBuf == NULL);
#endif
// Reserve room for headers
pNBuf->len = pNBuf->chainLen = sizeof(IPHdr) + sizeof(UDPHdr);
// Add payload
copied = nAppend(pNBuf, &((unsigned char *)buf)[rtn], MIN(mtu - sizeof(IPHdr) - sizeof(UDPHdr), (unsigned)len));
if (copied && pNBuf) {
len -= copied;
rtn += copied;
// Setup IP header and prepare it so we can compute the UDP checksum
// Use the IP header as UDP pseudo header
ipHdr = nBUFTOPTR(pNBuf, IPHdr *);
ipHdr->ip_src.s_addr = htonl(localHost);
ipHdr->ip_dst.s_addr = udps[ud].theirAddr.s_addr;
ipHdr->ip_ttl = 0;
ipHdr->ip_p = IPPROTO_UDP;
ipHdr->ip_sum = htons((unsigned short)(copied + sizeof(UDPHdr)));
// Build the UDP header
udpHdr = (void *)(ipHdr + 1);
udpHdr->srcPort = udps[ud].ourPort;
udpHdr->dstPort = udps[ud].theirPort;
udpHdr->checksum = 0;
udpHdr->length = ipHdr->ip_sum;
// Compute UDP header checksum
udpHdr->checksum = inChkSum(pNBuf, (unsigned short)(pNBuf->chainLen - 8), 8);
// Build IP header
ipHdr->ip_v = 4;
ipHdr->ip_hl = sizeof(IPHdr) >> 2;
ipHdr->ip_tos =(unsigned char)(udps[ud].tos);
ipHdr->ip_len = copied + sizeof(IPHdr) + sizeof(UDPHdr);
ipHdr->ip_id = IPNEWID();
ipHdr->ip_off = 0;
ipHdr->ip_ttl = UDPTTL;
ipHdr->ip_sum = 0;
ipHdr->ip_sum = inChkSum(pNBuf, sizeof(IPHdr), 0);
} else {
// Nothing copied ?!? This can only happen if nBuf size is eq. to sizeof(IPHdr) + sizeof(UDPHdr)
// AND there are no more buffers free
// This situation isn't actually handled! But we will free nBuf anyway
nFreeChain(pNBuf);
}
UDPDEBUG(("-src=%s port %ld dest=%s port=%ld\n", \
ip_ntoa(/*htonl*/(ipHdr->ip_src.s_addr)), \
htons(udpHdr->srcPort), \
ip_ntoa2(/*htonl*/(ipHdr->ip_dst.s_addr)), \
htons(udpHdr->dstPort) \
));
// Pass the datagram to IP and we're done.
if (pNBuf) ipRawOut(pNBuf);
}
return rtn;
}
#else
int udpWrite(u_int ud, const void* buf, long len)
{
NBuf* pNBuf;
NBuf* pNBufTail;
IPHdr* ipHdr;
UDPHdr* udpHdr;
long rtn = len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -