⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netudp.c

📁 uC/IP Release Notes These release notes for uC/IP are divided into the following sections
💻 C
📖 第 1 页 / 共 2 页
字号:
/**
 * 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.
 ******************************************************************************
 * 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 "netconf.h"
#include <stdlib.h>
#include <string.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 <stdio.h>
#include "netdebug.h"
#include "netos.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"));\
    }

/**
 * Queue of incoming datagrams.
 * This maintains a list of nBuf chains, along with the source address and port they came from
 * to allow reponses to be sent to multiple peers from one unconnected socket
 */
typedef struct _udp_queue {
    /** Pointer to next chain */
    struct _udp_queue* next;
    /** Source address for this chain (machine byte order) */
    struct in_addr srcAddr;
    /** Source port for this chain (machine byte order) */
    u_int16_t srcPort;
    /** pointer to the head of the actual nBuf chain */
    NBuf* nBuf;
} UDP_QUEUE;

/**
 * UDP port control block
 */
typedef struct {
    unsigned long flags;
    /** incoming data semaphore (value is number of UDP_QUEUE's from head) */
    OS_EVENT* sem;
    /** accept address (network byte order) */
    struct in_addr acceptFromAddr;
    /** send to address (network byte order) */
    struct in_addr theirAddr;
    /** sendto/recvfrom port (network byte order) */
    u_int16_t theirPort;
    /** port number on local machine (network byte order) */
    u_int16_t ourPort;
    /** type of service */
    u_int16_t tos;
    /** Head of the queue of incoming datagrams */
    UDP_QUEUE* head;
    /** Last incoming datagram in the queue */
    UDP_QUEUE* tail;
} UDPCB;

static 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]);
    }
}


int udpOpen(void)
{
    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;
    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(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 = peerAddr->sin_addr;
    // TODO: work out whether we should do the htons or the client ???
    udps[ud].ourPort = peerAddr->sin_port;
//    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;
    UBYTE err;

    if (!(udps[ud].flags & FUDP_OPEN)) return -1;
    d = (unsigned char*)buf;
    rtn = 0;
    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;
    while ((udps[ud].head) && (len) && (fromAddr.s_addr == udps[ud].head->srcAddr.s_addr)) {
        b = udps[ud].head->nBuf;
        while ((len) && (b)) {
            while ((len) && (b->data != &b->body[b->len])) {
                *d++ = *b->data++;
                len--;
                rtn++;
            }
            if (b->data == &b->body[b->len]) {
                OS_ENTER_CRITICAL();
                b = udps[ud].head->nBuf = nFree(b);
                OS_EXIT_CRITICAL();
            }
        }
        if (b == NULL) {
            q = udps[ud].head;
            OS_ENTER_CRITICAL();
            udps[ud].head = q->next;
            OS_EXIT_CRITICAL();
            free_udp_q(q);
            if (udps[ud].head)
                OSSemPend(udps[ud].sem, 0, &err);
        } else {
            OSSemPost(udps[ud].sem);
        }
    }
    if (udps[ud].head == NULL)
        udps[ud].tail = NULL;
    return rtn;
}

int udpWrite(u_int ud, const void* buf, long len)
{
    NBuf* outHead;
    NBuf* outTail;
    IPHdr* ipHdr;
    UDPHdr* udpHdr;
    long rtn = len;
    long segLen;
    long packetLen;
    const unsigned char* d;
    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) {
        outHead = NULL;
        do {
            nGET(outHead);
        } while (outHead == NULL);
        outTail = outHead;
        packetLen = MIN(mtu, sizeof(IPHdr) + sizeof(UDPHdr) + len);

        /* build IP header */
        ipHdr = nBUFTOPTR(outTail, IPHdr*);
        ipHdr->ip_v = 4;
        ipHdr->ip_hl = sizeof(IPHdr) / 4;
        ipHdr->ip_tos = udps[ud].tos;
        ipHdr->ip_len = packetLen;
        ipHdr->ip_id = IPNEWID();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -