--- /dev/null
+~.*
+*.~
+*.swp
+*.bak
+Debug
+Release
+*.suo
--- /dev/null
+OUTDIR=rel
+CFLAGS=-D__LINUX__ -Wall
+LDFLAGS=-lpthread -lrt
+
+ifneq ($(strip $(rel)), 1)
+CFLAGS += -D_DEBUG -g
+#CFLAGS += -D_DEBUG_RUDP
+OUTDIR=dbg
+else
+CFLAGS += -O2
+endif
+
+ifeq ($(strip $(target)), android)
+CROSS=arm-linux-androideabi-
+OUTDIR := $(addsuffix -android, $(OUTDIR))
+LDFLAGS=-lm -c
+endif
+
+CC=$(CROSS)gcc
+AR=$(CROSS)ar
+LDFLAGS+= -L$(OUTDIR) -lrudp
+
+LIBSRC = rudp.c platform_adpt.c crc32.c rudp.h rudp_imp.h #rudp_timer.c
+LIBOBJS = $(patsubst %.c, $(OUTDIR)/%.o, $(filter %.c, $(LIBSRC)))
+
+TARGETS=*.o *.a rudpsvr rudpclt simulconn
+TARGETS := $(addprefix $(OUTDIR)/, $(TARGETS))
+
+.PHONY: clean chkdir
+
+all: chkdir $(OUTDIR)/librudp.a
+
+test: chkdir $(OUTDIR)/rudpsvr $(OUTDIR)/rudpclt $(OUTDIR)/simulconn $(OUTDIR)/nblk_svr \
+ $(OUTDIR)/rudpsels $(OUTDIR)/rudpselc $(OUTDIR)/rudpsel #$(OUTDIR)/simconn
+
+
+$(OUTDIR)/nblk_svr: $(OUTDIR)/librudp.a $(OUTDIR)/nblk_svr.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/rudpsvr: $(OUTDIR)/librudp.a $(OUTDIR)/rudpsvr.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/rudpclt: $(OUTDIR)/librudp.a $(OUTDIR)/rudpclt.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/simulconn: $(OUTDIR)/librudp.a $(OUTDIR)/simulconn.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/librudp.a: $(LIBOBJS)
+ $(AR) -r $@ $^
+
+$(OUTDIR)/simconn: $(OUTDIR)/librudp.a $(OUTDIR)/simconn.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/punch: $(OUTDIR)/librudp.a $(OUTDIR)/rudp_punch.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/rudpsels: $(OUTDIR)/librudp.a $(OUTDIR)/rudpsels.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/rudpsel: $(OUTDIR)/librudp.a $(OUTDIR)/rudpsel.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(OUTDIR)/rudpselc: $(OUTDIR)/librudp.a $(OUTDIR)/rudpselc.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+#$(LIBOBJS): $(LIBSRC)
+
+$(OUTDIR)/%.o: %.c
+ $(CC) -c -o $@ $^ $(CFLAGS)
+
+
+clean:
+ rm -f $(TARGETS)
+
+chkdir:
+ @if [ ! -d $(OUTDIR) ]; then mkdir $(OUTDIR); fi
--- /dev/null
+1. What's this ?
+
+A simple implementation of Reliable UDP.
+With similar calling-interface of socket.
+
+
+2. Compile
+
+1) Generate library:
+
+# make
+
+2) Generate test
+
+# make test
+
+3. Install
+
+You need to copy following header files to your project:
+
+ basetype.h
+ platform-adpt.h
+ rudp.h
+
+plus the library file:
+ XXX/librudp.a
--- /dev/null
+#ifndef __basetype_h__
+#define __basetype_h__
+
+#define IN
+#define OUT
+#define INOUT
+
+#ifdef WIN32
+
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#define __BEGIN_ALIGNMENT(x)__ __pragma(pack(push, x))
+#define __END_ALIGNMENT(x)__ __pragma(pack(pop))
+
+#define __BEGIN_PACKED__ __pragma(pack(push, 1))
+#define __END_PACKED__ __pragma(pack(pop))
+#define __PACKED__
+
+#define __STDCALL __stdcall
+#define INLINE __inline
+#define __LIKELY(x) x
+#define __UNLIKELY(x) x
+
+
+#elif defined(__LINUX__) || defined(__ANDROID__)
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned int UINT;
+typedef unsigned long ULONG;
+
+#include <stdint.h>
+
+typedef long LONG;
+
+typedef const char * LPCSTR;
+typedef char * LPSTR;
+
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+
+#define __BEGIN_ALIGNMENT__(x)
+#define __END_ALIGNMENT__(x)
+
+#define __BEGIN_PACKED__
+#define __END_PACKED__
+#define __PACKED__ __attribute__((__packed__))
+
+#define __STDCALL
+#define INLINE inline
+#define __LIKELY(x) __builtin_expect(!!(x), 1)
+#define __UNLIKELY(x) __builtin_expect(!!(x), 0)
+
+#elif defined(ARM_UCOS_LWIP)
+
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned int UINT;
+typedef unsigned long ULONG;
+
+
+#define __BEGIN_ALIGNMENT(x)__
+#define __END_ALIGNMENT(x)__
+
+#define __BEGIN_PACKED__
+#define __END_PACKED__
+#define __PACKED__ __attribute__((__packed__))
+
+#define __STDCALL
+#define INLINE __inline
+#define __LIKELY(x) x
+#define __UNLIKELY(x) x
+
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+
+
+#endif
+
+#endif
--- /dev/null
+#include "crc32.h"\r
+\r
+#if 0\r
+#define POLYNOMIAL 0xEDB88320\r
+static uint32_t crc32_table[256];\r
+\r
+void make_table()\r
+{\r
+ int i, j;\r
+ for (i = 0 ; i < 256 ; i++)\r
+ for (j = 0, crc32_table[i] = i ; j < 8 ; j++)\r
+ crc32_table[i] = (crc32_table[i]>>1)^((crc32_table[i]&1)?POLYNOMIAL:0) ;\r
+}\r
+#else\r
+/* CRC-32 Lookup Table */\r
+static uint32_t crc32_table[256] =\r
+{\r
+ /* 0 -- */ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, \r
+ /* 4 -- */ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, \r
+ /* 8 -- */ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, \r
+ /* 12 -- */ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, \r
+ /* 16 -- */ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, \r
+ /* 20 -- */ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, \r
+ /* 24 -- */ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, \r
+ /* 28 -- */ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, \r
+ /* 32 -- */ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, \r
+ /* 36 -- */ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, \r
+ /* 40 -- */ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, \r
+ /* 44 -- */ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, \r
+ /* 48 -- */ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, \r
+ /* 52 -- */ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, \r
+ /* 56 -- */ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, \r
+ /* 60 -- */ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, \r
+ /* 64 -- */ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, \r
+ /* 68 -- */ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, \r
+ /* 72 -- */ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, \r
+ /* 76 -- */ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, \r
+ /* 80 -- */ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, \r
+ /* 84 -- */ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, \r
+ /* 88 -- */ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, \r
+ /* 92 -- */ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, \r
+ /* 96 -- */ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, \r
+ /* 100 -- */ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, \r
+ /* 104 -- */ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, \r
+ /* 108 -- */ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, \r
+ /* 112 -- */ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, \r
+ /* 116 -- */ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, \r
+ /* 120 -- */ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, \r
+ /* 124 -- */ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, \r
+ /* 128 -- */ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, \r
+ /* 132 -- */ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, \r
+ /* 136 -- */ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, \r
+ /* 140 -- */ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, \r
+ /* 144 -- */ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, \r
+ /* 148 -- */ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, \r
+ /* 152 -- */ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, \r
+ /* 156 -- */ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, \r
+ /* 160 -- */ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, \r
+ /* 164 -- */ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, \r
+ /* 168 -- */ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, \r
+ /* 172 -- */ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, \r
+ /* 176 -- */ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, \r
+ /* 180 -- */ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, \r
+ /* 184 -- */ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, \r
+ /* 188 -- */ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, \r
+ /* 192 -- */ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, \r
+ /* 196 -- */ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, \r
+ /* 200 -- */ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, \r
+ /* 204 -- */ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, \r
+ /* 208 -- */ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, \r
+ /* 212 -- */ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, \r
+ /* 216 -- */ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, \r
+ /* 220 -- */ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, \r
+ /* 224 -- */ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, \r
+ /* 228 -- */ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, \r
+ /* 232 -- */ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, \r
+ /* 236 -- */ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, \r
+ /* 240 -- */ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, \r
+ /* 244 -- */ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, \r
+ /* 248 -- */ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, \r
+ /* 252 -- */ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\r
+};\r
+#endif\r
+\r
+uint32_t calc_crc32(uint32_t crc, char *buff, int len)\r
+{\r
+ //if (!have_table) make_table();\r
+ int i;\r
+ crc = ~crc;\r
+ for (i = 0; i < len; i++)\r
+ crc = (crc >> 8) ^ crc32_table[(crc ^ buff[i]) & 0xff];\r
+ return ~crc;\r
+}\r
--- /dev/null
+#ifndef __crc32_h__
+#define __crc32_h__
+
+#include "basetype.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint32_t calc_crc32(uint32_t crc, char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+#ifndef __LIST_H
+#define __LIST_H
+
+#if defined(WIN32)
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+/* This file is from Linux Kernel (include/linux/list.h)
+ * and modified by simply removing hardware prefetching of list items.
+ * Here by copyright, credits attributed to where ever they belong.
+ * Get from http://isis.poly.edu/kulesh/stuff/src/klist/
+ */
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a newl entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static INLINE void __list_add(struct list_head *newl,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ newl->next = next;
+ newl->prev = prev;
+ next->prev = newl;
+ prev->next = newl;
+}
+
+/**
+ * list_add - add a newl entry
+ * @newl: newl entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a newl entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static INLINE void list_add(struct list_head *newl, struct list_head *head)
+{
+ __list_add(newl, head, head->next);
+}
+
+/**
+ * list_add_tail - add a newl entry
+ * @newl: newl entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a newl entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static INLINE void list_add_tail(struct list_head *newl, struct list_head *head)
+{
+ __list_add(newl, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static INLINE void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static INLINE void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = NULL;
+ entry->prev = (struct list_head *) 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static INLINE void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static INLINE void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static INLINE void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static INLINE int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+static INLINE void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the newl list to add.
+ * @head: the place to add it in the first list.
+ */
+static INLINE void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the newl list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static INLINE void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+
+#endif
--- /dev/null
+#include "rudp.h"
+#include <string.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ RUDPSOCKET s;
+
+ RUDPStart();
+
+ s = RUDPSocket();
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = argc==2?inet_addr(argv[1]):htonl(INADDR_ANY);
+ sai.sin_port = htons(5001);
+ if(RUDPBind(s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ perror("bind");
+ return -1;
+ }
+
+ RUDPListen(s, 5);
+
+ int opt = 1, rlt = 0;
+ //RUDPSetSockOpt(s, OPT_NBLK, &opt, sizeof(opt));
+
+ while(1)
+ {
+ int r;
+ struct timeval tv = { 1, 0 };
+#if 0
+ r = RUDPSELECT_READABLE;
+ rlt = RUDPSelectSock(s, -1, &r, &tv);
+ if(rlt < 0)
+ {
+ printf("RUDPSelectSock: %d\n", rlt);
+ break;
+ }
+ if(rlt == 0)
+ {
+ printf("No incoming connection\n");
+ continue;
+ }
+#else
+ RUDPSOCKCHNO r_schs[2];
+ int n_schs = 0;
+ RUDP_SET(s, -1, r_schs, n_schs);
+ rlt = RUDPSelect(r_schs, &n_schs, NULL, 0, NULL, 0, &tv);
+ if(rlt < 0)
+ {
+ printf("RUDPSelect: %d\n", rlt);
+ break;
+ }
+ if(rlt == 0)
+ {
+ printf("No incoming connection\n");
+ continue;
+ }
+#endif
+ int sa_len = sizeof(sai);
+ RUDPSOCKET a;
+ if(RUDPAccept(s, &a, (struct sockaddr*)&sai, &sa_len) < 0)
+ {
+ printf("accept error\n");
+ }
+ else
+ {
+ char line[1100];
+ int len, chno;
+ tv.tv_sec = 1; tv.tv_usec = 0;
+ while(1)
+ {
+ r = RUDPSELECT_READABLE;
+ if( (r = RUDPSelectSock(a, -1, &r, &tv)) < 0 )
+ {
+ printf("RUDPSelectSock on accepted socket: %d\n", r);
+ break;
+ }
+ if(r == 0) { continue; }
+
+ if( (len = RUDPRecv(a, &chno, line, 1000, 0)) > 0)
+ {
+ line[len] = '\0';
+ //printf("%s\n", line);
+ if(line[0] == '\0') break;
+ }
+ }
+ printf("receiving finished.\n");
+ RUDPClose(a);
+ }
+ }
+
+ RUDPClose(s);
+
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+#include "platform_adpt.h"
+#include <stdlib.h>
+
+#ifdef WIN32
+
+void PA_NetLibInit()
+{
+ WSADATA wd;
+ WSAStartup(0x0202, &wd);
+}
+
+int PA_Write(PA_HFILE hFile, const void *pBuff, unsigned int size)
+{
+ DWORD dwWritten;
+ if( ! WriteFile(hFile, pBuff, size, &dwWritten, NULL) )
+ return -1;
+ return dwWritten;
+}
+int PA_Read(PA_HFILE hFile, void *pBuff, unsigned int size)
+{
+ DWORD dwReaden;
+ if( ! ReadFile(hFile, pBuff, size, &dwReaden, NULL) )
+ return -1;
+ return dwReaden;
+}
+
+PA_HTHREAD PA_ThreadCreate(PA_ThreadRoutine* routine, void* data)
+{
+ return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)routine, data, 0, NULL);
+}
+
+void *PA_ThreadWaitUntilTerminate(PA_HTHREAD hThread)
+{
+ DWORD dwExitCode;
+ WaitForSingleObject(hThread, INFINITE);
+ GetExitCodeThread(hThread, &dwExitCode);
+ return (void*)dwExitCode;
+}
+
+BOOL PA_PipeCreate(PA_PIPE *pHPipeRd, PA_PIPE *pHPipeWrt)
+{
+ return CreatePipe(pHPipeRd, pHPipeWrt, NULL, 0) == TRUE;
+}
+BOOL PA_PipeClose(PA_PIPE hPipe)
+{
+ return CloseHandle(hPipe);
+}
+
+int PA_SocketSetNBlk(PA_SOCKET s, BOOL b)
+{
+ return ioctlsocket(s, FIONBIO, (u_long*)&b);
+}
+
+/*****************************
+ * Read-Write Lock
+ *****************************/
+enum { LOCK_LEVEL_NONE, LOCK_LEVEL_READ, LOCK_LEVEL_WRITE };
+
+RWLOCK *RWLockCreate()
+{
+ RWLOCK *pLock = (RWLOCK*)malloc(sizeof(RWLOCK));
+ pLock->m_currentLevel = LOCK_LEVEL_NONE;
+ pLock->m_readerCount = pLock->m_writeCount = 0;
+ pLock->m_writerId = 0;
+ //pLock->m_unlockEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ pLock->m_unlockEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ pLock->m_accessMutex = CreateMutex( NULL, FALSE, NULL );
+ InitializeCriticalSection( &pLock->m_csStateChange );
+ return pLock;
+}
+
+BOOL RWLockDestroy(RWLOCK *pLock)
+{
+ DeleteCriticalSection( &pLock->m_csStateChange );
+ if ( pLock->m_accessMutex ) CloseHandle( pLock->m_accessMutex );
+ if ( pLock->m_unlockEvent ) CloseHandle( pLock->m_unlockEvent );
+ free(pLock);
+ return TRUE;
+}
+
+static BOOL _Lock(RWLOCK *pLock, int level, DWORD timeout)
+{
+ BOOL bresult = TRUE;
+ DWORD waitResult = 0;
+
+ waitResult = WaitForSingleObject( pLock->m_accessMutex, timeout );
+ if ( waitResult != WAIT_OBJECT_0 ) return FALSE;
+
+ if ( level == LOCK_LEVEL_READ && pLock->m_currentLevel != LOCK_LEVEL_WRITE )
+ {
+ EnterCriticalSection( &pLock->m_csStateChange );
+ pLock->m_currentLevel = level;
+ pLock->m_readerCount += 1;
+ ResetEvent( pLock->m_unlockEvent );
+ LeaveCriticalSection( &pLock->m_csStateChange );
+ }
+ else if ( level == LOCK_LEVEL_READ &&
+ pLock->m_currentLevel == LOCK_LEVEL_WRITE )
+ {
+ waitResult = WaitForSingleObject( pLock->m_unlockEvent, timeout );
+ if ( waitResult == WAIT_OBJECT_0 )
+ {
+ EnterCriticalSection( &pLock->m_csStateChange );
+ pLock->m_currentLevel = level;
+ pLock->m_readerCount += 1;
+ ResetEvent( pLock->m_unlockEvent );
+ LeaveCriticalSection( &pLock->m_csStateChange );
+ }
+ else bresult = FALSE;
+ }
+ else if ( level == LOCK_LEVEL_WRITE &&
+ pLock->m_currentLevel == LOCK_LEVEL_NONE )
+ {
+ EnterCriticalSection( &pLock->m_csStateChange );
+ pLock->m_currentLevel = level;
+ pLock->m_writerId = GetCurrentThreadId();
+ pLock->m_writeCount = 1;
+ ResetEvent( pLock->m_unlockEvent );
+ LeaveCriticalSection( &pLock->m_csStateChange );
+ }
+ else if ( level == LOCK_LEVEL_WRITE &&
+ pLock->m_currentLevel != LOCK_LEVEL_NONE )
+ {
+ DWORD id = GetCurrentThreadId();
+ if(id == pLock->m_writerId) pLock->m_writeCount++;
+ else
+ {
+ waitResult = WaitForSingleObject( pLock->m_unlockEvent, timeout );
+ if ( waitResult == WAIT_OBJECT_0 )
+ {
+ EnterCriticalSection( &pLock->m_csStateChange );
+ pLock->m_currentLevel = level;
+ pLock->m_writerId = GetCurrentThreadId();
+ pLock->m_writeCount = 1;
+ ResetEvent( pLock->m_unlockEvent );
+ LeaveCriticalSection( &pLock->m_csStateChange );
+ }
+ else bresult = FALSE;
+ }
+ }
+
+ ReleaseMutex( pLock->m_accessMutex );
+ return bresult;
+
+} // lock()
+
+BOOL RWLockLockR(RWLOCK *pLock, DWORD timeout)
+{
+ return _Lock(pLock, LOCK_LEVEL_READ, timeout);
+}
+
+BOOL RWLockLockW(RWLOCK *pLock, DWORD timeout)
+{
+ return _Lock(pLock, LOCK_LEVEL_WRITE, timeout);
+}
+
+void RWLockUnlock(RWLOCK *pLock)
+{
+ EnterCriticalSection( &pLock->m_csStateChange );
+ if ( pLock->m_currentLevel == LOCK_LEVEL_READ )
+ {
+ pLock->m_readerCount --;
+ if ( pLock->m_readerCount == 0 )
+ {
+ pLock->m_currentLevel = LOCK_LEVEL_NONE;
+ SetEvent (pLock->m_unlockEvent);
+ }
+ }
+ else if ( pLock->m_currentLevel == LOCK_LEVEL_WRITE )
+ {
+ pLock->m_writeCount--;
+ if(pLock->m_writeCount == 0)
+ {
+ pLock->m_currentLevel = LOCK_LEVEL_NONE;
+ pLock->m_writerId = 0;
+ SetEvent ( pLock->m_unlockEvent );
+ }
+ }
+ LeaveCriticalSection( &pLock->m_csStateChange );
+}
+
+
+/////////////////////////////////////////////////////////
+#elif defined(__LINUX__) || defined(__ANDROID__)
+
+BOOL PA_EventWaitTimed(PA_EVENT e, DWORD ms)
+{
+ struct timespec ts;
+
+#if 0
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ ts.tv_sec += ms/1000;
+ ts.tv_nsec += (ms%1000)*1000000;
+#else
+ gettimeofday((struct timeval*)&ts, NULL);
+ ts.tv_nsec *= 1000;
+ ts.tv_sec += ms/1000;
+ ts.tv_nsec += (ms%1000)*1000000;
+ if(ts.tv_nsec > 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec ++;
+ }
+#endif
+ return sem_timedwait(e, &ts) == 0;
+}
+
+PA_HTHREAD PA_ThreadCreate(PA_ThreadRoutine* routine, void* data)
+{
+ pthread_t thd;
+ if(pthread_create(&thd, NULL, routine, data) == 0)
+ return thd;
+ else
+ return 0;
+}
+
+void* PA_ThreadWaitUntilTerminate(PA_HTHREAD hThread)
+{
+ void *tmp;
+ pthread_join(hThread, &tmp); return tmp;
+}
+
+BOOL PA_PipeCreate(PA_PIPE *pHPipeRd, PA_PIPE *pHPipeWrt)
+{
+ PA_PIPE fds[2];
+ if(pipe(fds) < 0) return FALSE;
+ *pHPipeRd = fds[0];
+ *pHPipeWrt = fds[1];
+ return TRUE;
+}
+BOOL PA_PipeClose(PA_PIPE hPipe)
+{
+ return 0 == close(hPipe);
+}
+
+void PA_Sleep(UINT ms)
+{
+ struct timeval tv;
+ tv.tv_sec = ms/1000;
+ tv.tv_usec = (ms%1000)*1000;
+ select(0, NULL, NULL, NULL, &tv);
+}
+
+DWORD PA_GetTickCount()
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return 1000*ts.tv_sec + ts.tv_nsec/1000000;
+}
+
+BOOL PA_DeleteFile(const char *fn)
+{
+ return unlink(fn) == 0;
+}
+
+int PA_SocketSetNBlk(PA_SOCKET s, BOOL b)
+{
+ int opt = fcntl(s, F_GETFL, &opt, 0);
+ if(b) opt |= O_NONBLOCK;
+ else opt &= ~O_NONBLOCK;
+ return fcntl(s, F_SETFL, opt);
+}
+
+/***********************
+ * Read-Write Lock
+ ***********************/
+BOOL _RWLockLockR(pthread_rwlock_t *lock, DWORD timeout)
+{
+ if(timeout == INFINITE)
+ return pthread_rwlock_rdlock(lock) == 0;
+ else
+ {
+ while(!pthread_rwlock_tryrdlock(lock) && timeout > 0)
+ {
+ usleep(10000);
+ if(timeout > 10) timeout -= 10;
+ else return FALSE;
+ }
+ return TRUE;
+ }
+}
+BOOL _RWLockLockW(pthread_rwlock_t *lock, DWORD timeout)
+{
+ if(timeout == INFINITE)
+ return pthread_rwlock_wrlock(lock)==0;
+ else
+ {
+ while(!pthread_rwlock_trywrlock(lock) && timeout > 0)
+ {
+ usleep(10000);
+ if(timeout > 10) timeout -= 10;
+ else return FALSE;
+ }
+ return TRUE;
+ }
+}
+
+#elif defined(ARM_UCOS_LWIP)
+PA_HTHREAD PA_ThreadCreate(PA_ThreadRoutine* routine, void* data)
+{
+ //sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
+ return sys_thread_new(NULL, routine, data, 0, 10);
+}
+void* PA_ThreadWaitUntilTerminate(PA_HTHREAD hThread)
+{
+ return NULL;
+}
+
+int PA_SocketSetNBlk(PA_SOCKET s, BOOL b)
+{
+ return lwip_ioctl(s, FIONBIO, (void*)&b);
+}
+#endif //linux
+
+#ifdef __ANDROID__
+void android_log(int level, const char *tag, const char *sfmt, ...)
+{
+ va_list va;
+ char buf[1024];
+ va_start(va, sfmt);
+ vsnprintf(buf, sizeof(buf), sfmt, va);
+ va_end(va);
+ __android_log_write(level, tag, buf);
+}
+#endif
+
+int PA_SocketSetLinger(PA_SOCKET s, int onoff, int linger)
+{
+ struct linger opt = { onoff, linger };
+ return setsockopt(s, SOL_SOCKET, SO_LINGER,
+#ifdef WIN32
+ (const char*)&opt,
+#else
+ &opt,
+#endif
+ sizeof(opt));
+}
+
+#ifdef _DEBUG
+void dbg_bin(const char *title, const void *p, int size)
+{
+ int i;
+ unsigned char *byts = (unsigned char*)p;
+ printf(title);
+ for(i=0; i<size; i++)
+ {
+ printf("%02X ", byts[i]);
+ if(i>0 && (i&31) == 31) printf("\n");
+ }
+ printf("\n");
+}
+#else
+#define dbg_bin(x, y, z)
+#endif
--- /dev/null
+#ifndef __platform_adpt_h__
+#define __platform_adpt_h__
+
+#include "basetype.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifdef WIN32 //Windows
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#if defined(__cplusplus) && defined(USE_MFC)
+#include <afx.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SOCKET Functions
+ */
+void PA_NetLibInit();
+#define PA_NetLibUninit() WSACleanup()
+
+#define PA_IOVEC WSABUF
+#define PA_IoVecGetPtr(pvec) ((pvec)->buf)
+#define PA_IoVecGetLen(pvec) ((pvec)->len)
+#define PA_IoVecSetPtr(pvec, ptr) (pvec)->buf = (char*)(ptr)
+#define PA_IoVecSetLen(pvec, _len) (pvec)->len = _len
+
+#define PA_SocketClose closesocket
+#define CloseSocket closesocket
+#define PA_Send(s, p, len, f) send(s, (const char*)p, len, f)
+#define PA_SendTo(s, p, len, f, paddr, alen) sendto(s, (const char*)p, len, f, paddr, alen)
+#define PA_Recv(s, p, len, f) recv(s, (char*)p, len, f)
+#define PA_RecvFrom(s, p, len, f, paddr, palen) recvfrom(s, (char*)p, len, f, paddr, palen)
+#define PA_GetSockName(s, paddr, paddr_len) getsockname(s, paddr, (int*)paddr_len)
+#define PA_GetPeerName(s, paddr, paddr_len) getpeername(s, paddr, (int*)paddr_len)
+#define PA_Accept(s, paddr, paddr_len) accept(s, paddr, paddr_len)
+#define PA_GetSockOpt(s, level, optname, optval, optlen) getsockopt(s, level, optname, (char*)optval, (int*)optlen)
+#define PA_SetSockOpt(s, level, optname, optval, optlen) setsockopt(s, level, optname, (const char*)optval, optlen)
+
+#define PA_SOCKET SOCKET
+#define PA_SocketIsValid(s) (s!=INVALID_SOCKET)
+#define PA_SocketGetError() WSAGetLastError()
+#define PA_SOCKET_ERROR SOCKET_ERROR //return value of socket operations
+
+
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ENOTSOCK WSAENOTSOCK
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#define EMSGSIZE WSAEMSGSIZE
+#define EPROTOTYPE WSAEPROTOTYPE
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EADDRINUSE WSAEADDRINUSE
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ENETDOWN WSAENETDOWN
+#define ENETUNREACH WSAENETUNREACH
+#define ENETRESET WSAENETRESET
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET WSAECONNRESET
+#define ENOBUFS WSAENOBUFS
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#define ETIMEDOUT WSAETIMEDOUT
+#define ECONNREFUSED WSAECONNREFUSED
+#define ELOOP WSAELOOP
+#define EHOSTDOWN WSAEHOSTDOWN
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+
+
+
+/*
+ *
+ */
+#define PA_INVALID_HANDLE INVALID_HANDLE_VALUE
+#define PA_IsValidHandle(handle) (handle != INVALID_HANDLE_VALUE)
+
+/*
+ * Synchronous Objects
+ */
+#define PA_MUTEX HANDLE
+#define PA_EVENT HANDLE
+#define PA_COND HANDLE
+#define PA_SEM HANDLE //semaphore
+#define PA_PIPE HANDLE
+#define PA_SPIN CRITICAL_SECTION
+
+#define PA_DEFINEMUTEX(x) PA_MUTEX x = CreateMutex(NULL, FALSE, NULL)
+#define PA_MutexInit(x) x = CreateMutex(NULL, FALSE, NULL)
+#define PA_MutexUninit(x) CloseHandle(x)
+#define PA_MutexLock(x) WaitForSingleObject(x, INFINITE)
+#define PA_MutexUnlock(x) ReleaseMutex(x)
+#define PA_MutexTryLock(x) (WaitForSingleObject(x, 0) == WAIT_OBJECT_0)
+
+#define PA_SpinInit(x) InitializeCriticalSection(&x)
+#define PA_SpinUninit(x) DeleteCriticalSection(&x)
+#define PA_SpinLock(x) EnterCriticalSection(&x)
+#define PA_SpinTryLock(x) TryEnterCriticalSection(&x)
+#define PA_SpinUnlock(x) LeaveCriticalSection(&x)
+
+#define PA_EventInit(x) x = CreateEvent(NULL, FALSE, FALSE, NULL)
+#define PA_EventUninit(x) CloseHandle(x)
+#define PA_EventSet(x) SetEvent(x)
+//#define PA_ResetEvent(x) ResetEvent(x)
+#define PA_EventWait(x) WaitForSingleObject(x, INFINITE)
+#define PA_EventWaitTimed(e, ms) (WaitForSingleObject(e, ms)==WAIT_OBJECT_0)
+
+#define PA_SemInit(x, max_value) x = CreateSemaphore(NULL, 0, max_value, NULL)
+#define PA_SemUninit(x) CloseHandle(x)
+#define PA_SemWait(x) WaitForSingleObject(x, INFINITE)
+#define PA_SemPost(x) ReleaseSemaphore(x, 1, NULL)
+
+/*
+ * Threads
+ */
+#define PA_HTHREAD HANDLE
+#define PA_HTHREAD_NULL NULL
+#define PA_THREAD_RETTYPE DWORD
+typedef PA_THREAD_RETTYPE (__STDCALL PA_ThreadRoutine)(void*);
+#define PA_ThreadGetCurrentHandle() GetCurrentThread()
+#define PA_ThreadCloseHandle(hThread) CloseHandle(hThread)
+void *PA_ThreadWaitUntilTerminate(PA_HTHREAD hThread);
+
+#define PA_Sleep(ms) Sleep(ms)
+
+/*
+ * Read-Write Lock
+ */
+typedef struct ReadWriteLock
+{
+ int m_currentLevel;
+ int m_readerCount, m_writeCount;
+ DWORD m_writerId;
+ HANDLE m_unlockEvent;
+ HANDLE m_accessMutex;
+ CRITICAL_SECTION m_csStateChange;
+} RWLOCK, *LPRWLOCK;
+
+RWLOCK *RWLockCreate();
+BOOL RWLockDestroy(RWLOCK *pLock);
+BOOL RWLockLockR(RWLOCK *pLock, DWORD timeout);
+BOOL RWLockLockW(RWLOCK *pLock, DWORD timeout);
+void RWLockUnlock(RWLOCK *pLock);
+
+#define PA_RWLOCK LPRWLOCK
+#define PA_RWLockInit(x) x = RWLockCreate()
+#define PA_RWLockUninit(x) RWLockDestroy(x)
+#define PA_RWLockLockR(x) RWLockLockR(x, INFINITE)
+#define PA_RWLockLockW(x) RWLockLockW(x, INFINITE)
+#define PA_RWLockFailed(op) (op == FALSE)
+#define PA_RWLockLockRTimed(x, timeout) RWLockLockR(x, timeout)
+#define PA_RWLockLockWTimed(x, timeout) RWLockLockW(x, timeout)
+#define PA_RWLockUnlock(x) RWLockUnlock(x)
+
+
+/*
+ * String functions
+ */
+#define PA_StrCaseCmp stricmp
+#define PA_StrNCaseCmp strnicmp
+#define PA_StrNCmp strncmp
+
+/*
+ * File Operations
+ */
+#define PA_HFILE HANDLE
+int PA_Write(PA_HFILE hFile, const void *pBuff, unsigned int size);
+int PA_Read(PA_HFILE hFile, void *pBuff, unsigned int size);
+#define PA_FileClose(hf) CloseHandle(hf)
+#define PA_FileIsValid(h) (h!=INVALID_HANDLE_VALUE)
+#define PA_DeleteFile(f) DeleteFile(f)
+
+/*
+ * Time
+ */
+#define PA_GetTickCount() GetTickCount()
+
+#ifdef __cplusplus
+}
+#endif
+
+#elif defined(__LINUX__) || defined(__ANDROID__)
+//
+// OS: Linux
+//
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <semaphore.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SOCKET Functions
+ */
+#define PA_NetLibInit()
+#define PA_NetLibUninit()
+
+#define PA_IOVEC struct iovec
+#define PA_IoVecGetPtr(pvec) ((pvec)->iov_base)
+#define PA_IoVecGetLen(pvec) ((pvec)->iov_len)
+#define PA_IoVecSetPtr(pvec, ptr) (pvec)->iov_base = (void*)(ptr)
+#define PA_IoVecSetLen(pvec, len) (pvec)->iov_len = len
+
+#define PA_SocketClose close
+#define CloseSocket close
+#define PA_Send send
+#define PA_SendTo sendto
+#define PA_Recv recv
+#define PA_RecvFrom(s, buf, size, flags, paddr, paddr_len) recvfrom(s, buf, size, flags, paddr, (socklen_t*)paddr_len)
+#define PA_GetSockName(s, paddr, paddr_len) getsockname(s, paddr, (socklen_t*)paddr_len)
+#define PA_GetPeerName(s, paddr, paddr_len) getpeername(s, paddr, (socklen_t*)paddr_len)
+#define PA_Accept(s, paddr, paddr_len) accept(s, paddr, (socklen_t*)paddr_len)
+#define PA_GetSockOpt(s, level, optname, optval, optlen) getsockopt(s, level, optname, optval, (socklen_t*)optlen)
+#define PA_SetSockOpt setsockopt
+
+#define PA_SOCKET int
+#define INVALID_SOCKET -1
+#define PA_SocketIsValid(s) (s>=0)
+#define PA_SocketGetError() errno
+#define PA_SOCKET_ERROR -1 //return value of socket operations
+
+/*
+ *
+ */
+#define PA_IsValidHandle(fd) (fd>=0)
+#define PA_INVALID_HANDLE -1
+
+/*
+ * Synchronous Objects
+ */
+#define PA_MUTEX pthread_mutex_t
+#define PA_PIPE int
+
+#define PA_EVENT sem_t*
+#define PA_SEM sem_t
+
+#define PA_DEFINEMUTEX(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER
+#define PA_MutexInit(x) pthread_mutex_init(&x, NULL)
+#define PA_MutexUninit(x) pthread_mutex_destroy(&x)
+#define PA_MutexLock(x) pthread_mutex_lock(&x)
+#define PA_MutexUnlock(x) pthread_mutex_unlock(&x)
+#define PA_MutexTryLock(x) (pthread_mutex_trylock(&x) == 0)
+
+#ifdef HAVE_SPIN_T
+#define PA_SPIN pthread_spinlock_t
+#define PA_SpinInit(x) pthread_spin_init(&x, PTHREAD_PROCESS_PRIVATE)
+#define PA_SpinUninit(x) pthread_spin_destroy(&x)
+#define PA_SpinLock(x) pthread_spin_lock(&x)
+#define PA_SpinTryLock(x) pthread_spin_trylock(&x)
+#define PA_SpinUnlock(x) pthread_spin_unlock(&x)
+#else
+#define PA_SPIN pthread_mutex_t
+#define PA_SpinInit(x) pthread_mutex_init(&x, NULL)
+#define PA_SpinUninit(x) pthread_mutex_destroy(&x)
+#define PA_SpinLock(x) pthread_mutex_lock(&x)
+#define PA_SpinTryLock(x) pthread_mutex_trylock(&x)
+#define PA_SpinUnlock(x) pthread_mutex_unlock(&x)
+#endif
+
+#define PA_EventInit(x) do { x=(sem_t*)malloc(sizeof(sem_t)); sem_init(x, 0, 0); } while(0)
+#define PA_EventUninit(x) do { sem_destroy(x); free(x); } while(0)
+#define PA_EventSet(x) sem_post(x)
+#define PA_EventWait(x) sem_wait(x)
+BOOL PA_EventWaitTimed(PA_EVENT e, DWORD ms);
+
+#define PA_SemInit(x, max_value) do { x = (sem_t*)malloc(sizeof(sem_t)); sem_init(x, 0, max_value); } while(0)
+#define PA_SemUninit(x) CloseHandle(x) { sem_destroy(x); free(x); }
+#define PA_SemWait(x) sem_wait(x)
+#define PA_SemPost(x) sem_post(x)
+
+/*
+ * Threads
+ */
+#define PA_HTHREAD pthread_t
+#define PA_HTHREAD_NULL 0L
+#define PA_THREAD_RETTYPE void*
+typedef PA_THREAD_RETTYPE (__STDCALL PA_ThreadRoutine)(void*);
+#define PA_ThreadGetCurrentHandle() pthread_self()
+#define PA_ThreadCloseHandle(hThread) pthread_detach(hThread)
+void* PA_ThreadWaitUntilTerminate(PA_HTHREAD hThread);
+
+void PA_Sleep(UINT ms); //Milliseconds
+
+/*
+ * Read-Write Lock
+ */
+#define INFINITE 0xFFFFFFFF
+
+#define PA_RWLOCK pthread_rwlock_t
+#define PA_RWLockInit(x) pthread_rwlock_init(&x, NULL)
+#define PA_RWLockUninit(x) pthread_rwlock_destroy(&x)
+BOOL _RWLockLockR(PA_RWLOCK *x, DWORD timeout);
+BOOL _RWLockLockW(PA_RWLOCK *x, DWORD timeout);
+#define PA_RWLockLockR(x) pthread_rwlock_rdlock(&x)
+#define PA_RWLockLockW(x) pthread_rwlock_wrlock(&x)
+#define PA_RWLockFailed(op) (op != 0)
+#define PA_RWLockLockRTimed(x, timeout) _RWLockLockR(&x, timeout)
+#define PA_RWLockLockWTimed(x, timeout) _RWLockLockR(&x, timeout)
+#define PA_RWLockUnlock(x) pthread_rwlock_unlock(&x)
+
+/*
+ * String functions
+ */
+#define PA_StrCaseCmp strcasecmp
+#define PA_StrNCaseCmp strncasecmp
+#define PA_StrNCmp strncmp
+
+/*
+ * File Operations
+ */
+#define PA_HFILE int
+#define PA_Write write
+#define PA_Read read
+#define PA_FileIsValid(h) (h>=0)
+#define PA_FileClose(f) close(f)
+BOOL PA_DeleteFile(const char *fn);
+
+/*
+ * Time
+ */
+DWORD PA_GetTickCount();
+
+#ifdef __cplusplus
+}
+#endif
+/* End of __LINUX__ */
+
+#elif defined(ARM_UCOS_LWIP)
+
+#include <lwip/opt.h>
+#include <lwip/init.h>
+
+#include <lwip/mem.h>
+#include <lwip/memp.h>
+#include <lwip/sys.h>
+#include <lwip/stats.h>
+#include <lwip/netdb.h>
+#include <lwip/tcpip.h>
+#include <lwip/sockets.h>
+
+
+/*
+ * Synchronous Objects: Mutex
+ */
+#define PA_EVENT sys_sem_t
+#define PA_SEM sys_sem_t
+
+#define PA_EventInit(x) sys_sem_new(&(x), 0)
+#define PA_EventUninit(x) sys_sem_free(&(x))
+#define PA_EventSet(x) sys_sem_signal(&(x))
+//#define PA_ResetEvent(x) ResetEvent(x)
+#define PA_EventWait(x) sys_arch_sem_wait(&(x), 0)
+#define PA_EventWaitTimed(e, ms) (sys_arch_sem_wait(&(e), ms)!=SYS_ARCH_TIMEOUT)
+
+#define PA_MUTEX sys_sem_t
+#define PA_MutexInit(x) sys_sem_new(&(x), 1)
+#define PA_MutexUninit(x) sys_sem_free(&(x))
+#define PA_MutexLock(x) sys_arch_sem_wait(&(x), 0)
+#define PA_MutexUnlock(x) sys_sem_signal(&(x))
+
+#define PA_PIPE void*
+
+/*
+ * Thread
+ */
+#define PA_HTHREAD sys_thread_t
+#define PA_HTHREAD_NULL NULL
+#define PA_THREAD_RETTYPE void*
+typedef PA_THREAD_RETTYPE (PA_ThreadRoutine)(void*);
+void* PA_ThreadWaitUntilTerminate(PA_HTHREAD hThread);
+#define PA_ThreadCloseHandle(hThread)
+
+/*
+ * SOCKET Functions
+ */
+#define PA_NetLibInit() lwip_socket_init()
+#define PA_NetLibUninit()
+
+#define PA_SocketClose lwip_close
+#define CloseSocket iwip_close
+#define PA_Send lwip_send
+#define PA_SendTo lwip_sendto
+#define PA_Recv lwip_recv
+#define PA_RecvFrom(s, buf, size, flags, paddr, paddr_len) lwip_recvfrom(s, buf, size, flags, paddr, (socklen_t*)paddr_len)
+#define PA_GetSockName(s, paddr, paddr_len) lwip_getsockname(s, paddr, (socklen_t*)paddr_len)
+#define PA_GetPeerName(s, paddr, paddr_len) lwip_getpeername(s, paddr, (socklen_t*)paddr_len)
+#define PA_Accept(s, paddr, paddr_len) lwip_accept(s, paddr, (socklen_t*)paddr_len)
+#define PA_GetSockOpt(s, level, optname, optval, optlen) lwip_getsockopt(s, level, optname, optval, (socklen_t*)optlen)
+#define PA_SetSockOpt lwip_setsockopt
+
+#define PA_SOCKET int
+#define INVALID_SOCKET -1
+#define PA_SocketIsValid(s) (s>=0)
+#define PA_SocketGetError(s) get_socket(s)->err
+#define PA_SOCKET_ERROR -1 //return value of socket operations
+
+struct LwipIoVec {
+ void *iov_base;
+ int iov_len;
+};
+#define PA_IOVEC struct LwipIoVec
+#define PA_IoVecGetPtr(pvec) ((pvec)->iov_base)
+#define PA_IoVecGetLen(pvec) ((pvec)->iov_len)
+#define PA_IoVecSetPtr(pvec, ptr) (pvec)->iov_base = (void*)(ptr)
+#define PA_IoVecSetLen(pvec, len) (pvec)->iov_len = len
+
+/*
+ * Time
+ */
+#define PA_GetTickCount() sys_now()
+#define PA_Sleep(x) usleep(x/1000)
+
+#else
+
+#error "Platform must be specified !"
+
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Common Wrapper
+ */
+PA_HTHREAD PA_ThreadCreate(PA_ThreadRoutine* routine, void* data);
+int PA_SocketSetNBlk(PA_SOCKET s, BOOL b);
+int PA_SocketSetLinger(PA_SOCKET s, int onoff, int linger);
+
+/*
+ * Pipe functions
+ */
+BOOL PA_PipeCreate(PA_PIPE *pHPipeRd, PA_PIPE *pHPipeWrt);
+BOOL PA_PipeClose(PA_PIPE hPipe);
+
+/*
+ * Debug
+ */
+#ifdef _DEBUG
+ #if defined(WIN32) && defined(__cplusplus) && defined(_USE_MFC) && !defined(_CONSOLE)
+ #define dbg_msg TRACE
+ #define PRINTF TRACE
+ #else
+ #define dbg_msg printf
+ #define PRINTF printf
+ #endif
+void dbg_bin(const char *title, const void *p, int size);
+#else
+ #ifdef WIN32
+ #define dbg_msg(fmt, __VA_ARGS__)
+ #else
+ #define dbg_msg(fmt, args...)
+ #endif
+#define dbg_bin(x,y,z)
+#endif
+
+#ifdef __ANDROID__
+#include <android/log.h>
+void android_log(int level, const char *tag, const char *sfmt, ...);
+#define LOG(sfmt, args...) android_log(ANDROID_LOG_INFO, __FUNCTION__, sfmt, ##args)
+#define LOGW(sfmt, args...) android_log(ANDROID_LOG_WARN, __FUNCTION__, sfmt, ##args)
+#define LOGE(sfmt, args...) android_log(ANDROID_LOG_ERROR, __FUNCTION__, sfmt, ##args)
+
+#undef dbg_msg
+#define dbg_msg LOG
+
+#elif defined(__LINUX__)
+
+#define LOG(sfmt, args...) do { dbg_msg(sfmt, ##args); dbg_msg("\n"); } while(0)
+#define LOGW(sfmt, args...) do { dbg_msg(sfmt, ##args); dbg_msg("\n"); } while(0)
+#define LOGE(sfmt, args...) do { dbg_msg(sfmt, ##args); dbg_msg("\n"); } while(0)
+
+#elif defined(WIN32)
+
+#define LOG(sfmt, ...) do { dbg_msg(sfmt, __VA_ARGS__); dbg_msg("\n"); } while(0)
+#define LOGW(sfmt, ...) do { dbg_msg(sfmt, __VA_ARGS__); dbg_msg("\n"); } while(0)
+#define LOGE(sfmt, ...) do { dbg_msg(sfmt, __VA_ARGS__); dbg_msg("\n"); } while(0)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //#ifndef __dcs_platform_h__
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include "rudp_imp.h"
+#include "rudp.h"
+#include "crc32.h"
+
+#include <assert.h>
+
+#ifndef min
+#define min(x,y) ((x)<(y)?(x):(y))
+#endif
+#ifndef max
+#define max(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#ifndef offsetof
+#define offsetof(s, m) ((int)(&((s*)0)->m))
+#endif
+
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+#define SETEVENT(event) PA_SetEvent(event)
+#elif defined(__LINUX__) || defined(__ANDROID__)
+#define SETEVENT(event) pthread_cond_signal(&event)
+#endif
+#define SAFE_FREE(p) if(p) { free(p); p = NULL; }
+//---------------------------------------------------------
+PA_MUTEX mutex_sock_list;
+LIST_HEAD(sock_list);
+
+PA_HTHREAD hthd;
+static volatile int run = 1;
+
+static PA_MUTEX mutex_pkt_pool;
+static int n_free_pkt = 0;
+static struct rudp_pkt *free_pkt = NULL;
+
+//static int sockw_r = -1, sockw_s;
+struct output_notify {
+ struct rudp_socket *s;
+ int chno;
+};
+
+unsigned int rudp_now = 0;
+//==========================================================
+
+
+#define RO_NORMAL 0
+#define RO_FORCE 1
+#define RO_REXMT 2 //rexmt as RCT_REXMT timer
+#define RO_ONLYONE 3
+#define RO_REXMT_FAST 4 //rexmt as duplicated ack received
+
+#define INITIAL_SEQ_NO 0
+
+#define FASTRETRANS 0
+#define FASTRETRANS2 1 //multiple packet lost
+#define CONGESTED 2
+
+//value for should_ack
+#define ACKT_DELAYED 1
+#define ACKT_OPENWND 2
+
+#ifdef _DEBUG_RUDP
+static char* IP2STR(unsigned int ip, char ips[16])
+{
+ int len = sprintf(ips, "%d.", ip&0xFF);
+ len += sprintf(ips+len, "%d.", (ip>>8)&0xFF);
+ len += sprintf(ips+len, "%d.", (ip>>16)&0xFF);
+ len += sprintf(ips+len, "%d", (ip>>24)&0xFF);
+ return ips;
+}
+
+static void _printTime()
+{
+ char sf[16];
+#if defined(ARM_UCOS_LWIP)
+#elif defined(WIN32)
+ SYSTEMTIME t;
+ GetLocalTime(&t);
+ sprintf(sf, "%.06f", t.wMilliseconds/1000.0);
+ PRINTF("%02d:%02d:%02d.%s ", t.wHour, t.wMinute, t.wSecond, sf+2);
+#else
+ struct timeval tv;
+ struct tm _tm;
+ gettimeofday(&tv, NULL);
+ localtime_r(&tv.tv_sec, &_tm);
+ sprintf(sf, "%.06f", tv.tv_usec/1000000.0);
+ PRINTF("%02d:%02d:%02d.%s ", _tm.tm_hour, _tm.tm_min, _tm.tm_sec, sf+2);
+#endif
+}
+#define PHF_FROM 0x10000000
+#define PHF_DATA 0x20000000
+static void __printHdr(const struct rudp_pcb *pcb, const struct rudp_hdr *phdr, const struct sockaddr_in *pa, int phf, int data_len)
+{
+ char ip[16];
+ _printTime();
+ if(phf & PHF_FROM)
+ {
+ PRINTF("%s.%d > ", IP2STR(pa->sin_addr.s_addr, ip), (int)ntohs(pa->sin_port));
+ if(pcb) PRINTF("%s.%d ", IP2STR(pcb->local.sin_addr.s_addr, ip), (int)ntohs(pcb->local.sin_port));
+ }
+ else
+ {
+ if(pcb) PRINTF("%s.%d > ", IP2STR(pcb->local.sin_addr.s_addr, ip), (int)ntohs(pcb->local.sin_port));
+ PRINTF("%s.%d ", IP2STR(pa->sin_addr.s_addr, ip), (int)ntohs(pa->sin_port));
+ }
+ PRINTF("c:%d ", phdr->flags.chno);
+
+ if(data_len)
+ {
+ PRINTF("P s:%u(%d) ", ntohl(phdr->seqno), data_len);
+ }
+ else printf(". ");
+ if(phdr->flags.syn) PRINTF("syn ");
+ if(phdr->flags.ack) PRINTF("ack %u(%d) ", ntohl(phdr->ackno), phdr->flags.n_loss);
+ if(phdr->flags.rst) PRINTF("rst ");
+ if(phdr->flags.fin) PRINTF("fin ");
+ PRINTF("win %d ", (int)WINDOW_NTOH(phdr->flags.window));
+
+ if(pcb)
+ {
+ PRINTF("[rwnd %d cwnd %d ssth %d", pcb->channel[phdr->flags.chno].sbuf.rwnd, pcb->cwnd, pcb->ssthresh);
+ if(phdr->flags.ack && (phf&PHF_FROM))
+ {
+ PRINTF(" rto %d", pcb->rto);
+ PRINTF(" rtw %d", pcb->rtw_size);
+ if(phdr->flags.n_loss) PRINTF(" lost %d", phdr->flags.n_loss);
+ }
+ PRINTF(" una %d", pcb->channel[phdr->flags.chno].sbuf.n_unacked);
+ PRINTF("]");
+ }
+ PRINTF("\n");
+#if defined(WIN32)
+ fflush(stdout);
+#endif
+}
+static void _printHdr(const struct rudp_pcb *pcb, const struct rudp_hdr *phdr, const struct sockaddr_in *pa)
+{
+ __printHdr(pcb, phdr, pa, 0, 0);
+}
+static void _printPkt(const struct rudp_pcb *pcb, const struct rudp_pkt *pkt, int phf, const struct sockaddr_in *pa)
+{
+ if(pkt->len) { phf |= PHF_DATA; }
+ __printHdr(pcb, &pkt->hdr, pa, phf, pkt->len);
+}
+#else
+#define _printHdr(a,b,c)
+#define _printPkt(a,b,c,d)
+#define _printTime()
+#endif
+
+#define DELAY_ACK_MS 100
+#define RTT_UINT 200 //accuracy of RTT, ms
+#define RTT_MIN (1000/RTT_UINT) //count in 1 second.
+
+#define MAX_REXMT_ATTEMPT 6
+static int rudp_backoff[MAX_REXMT_ATTEMPT+1] = { 1, 2, 4, 8, 16, 32, 32/*, 64, 64, 64, 64, 64*/ };
+#define MAX_RECONN_ATTEMPT 5
+static int conn_backoff[MAX_RECONN_ATTEMPT+1] = { RTT_MIN, 1*RTT_MIN, 2*RTT_MIN, 2*RTT_MIN, 2*RTT_MIN, 2*RTT_MIN }; //s
+
+static struct rudp_pkt *_MBufGetPacket();
+static void _MBufPutPacket(struct rudp_pkt *pkt);
+static int _ProcessPacket(struct rudp_socket *s, struct rudp_pkt *pkt, const struct sockaddr *from, int from_len);
+int _DispatchPacket(struct rudp_socket *s, struct rudp_pkt *pkt, const struct sockaddr *from, int from_len);
+static INLINE void _sendPacket(struct rudp_socket *s, struct rudp_channel *pch, struct rudp_pkt *pkt, int opt);
+static void _sendReset(struct rudp_socket *s, const struct sockaddr *to);
+static /*INLINE */void _sendHeader(struct rudp_socket *s, struct rudp_hdr *phdr);
+static void _sendSyn(struct rudp_socket *s);
+static void _sendSynAck(struct rudp_socket *s);
+static void _sendAck(struct rudp_socket *s, int chno);
+static void _sendFin(struct rudp_socket *s);
+
+typedef void (*TimerHandler)(struct rudp_socket *s);
+static void _timerProc(TimerHandler handler);
+static void _handleTimer500ms(struct rudp_socket *s);
+static void _handleTimer200ms(struct rudp_socket *s);
+
+static struct rudp_pkt *_MBufGetPacket()
+{
+ struct rudp_pkt *p;
+
+ PA_MutexLock(mutex_pkt_pool);
+ if(free_pkt)
+ {
+ p = free_pkt;
+ free_pkt = free_pkt->next;
+ n_free_pkt --;
+ }
+ else
+ {
+ p = (struct rudp_pkt*)malloc(sizeof(struct rudp_pkt));
+ if(!p) {
+ PA_MutexUnlock(mutex_pkt_pool);
+ return NULL;
+ }
+ }
+ p->next = NULL;
+ p->hdr.u32_flags = 0;
+ p->hdr.flags.rudp = RUDP_HEADER_TAG;
+ p->len = 0;
+ p->trans = 0;
+ p->pdata = p->data;
+ PA_MutexUnlock(mutex_pkt_pool);
+
+ return p;
+}
+static void _MBufPutPacket(struct rudp_pkt *pkt)
+{
+ PA_MutexLock(mutex_pkt_pool);
+ if(n_free_pkt > 256)
+ {
+ free(pkt);
+ }
+ else
+ {
+ pkt->next = free_pkt;
+ free_pkt = pkt;
+ n_free_pkt++;
+ }
+ PA_MutexUnlock(mutex_pkt_pool);
+}
+
+static struct rudp_socket *_AllocRudpSocket()
+{
+ struct rudp_socket *sock = (struct rudp_socket*)calloc(sizeof(struct rudp_socket), 1);
+ sock->tag = RUDP_SOCKET_TAG;
+
+ sock->state = RS_CLOSED;
+ sock->rcvbuf_sz = DEFAULT_RCVBUF_SIZE;
+
+ PA_MutexInit(sock->mutex_r);
+ PA_MutexInit(sock->mutex_w);
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ PA_EventInit(sock->event_r);
+ PA_EventInit(sock->event_w);
+#else
+ pthread_cond_init(&sock->event_r, NULL);
+ pthread_cond_init(&sock->event_w, NULL);
+#endif
+
+ INIT_LIST_HEAD(&sock->inst_list);
+ INIT_LIST_HEAD(&sock->listen_queue);
+ INIT_LIST_HEAD(&sock->accepted_list);
+ return sock;
+}
+
+static struct rudp_pcb *_AllocRudpPcb(uint32_t rcvbuf_size, uint32_t initial_seqno, uint32_t peer_initial_seqno, int rawnd)
+{
+ struct rudp_pcb *pcb;
+ int i;
+ pcb = (struct rudp_pcb*)calloc(sizeof(struct rudp_pcb), 1);
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct sndbuf *psbuf;
+ struct rcvbuf *prbuf;
+
+ psbuf = &pcb->channel[i].sbuf;
+ psbuf->seqno = initial_seqno;
+ psbuf->max_pkts = DEFAULT_SNDBUF_SIZE;
+ psbuf->rwnd = psbuf->rawnd = rawnd;
+
+ prbuf = &pcb->channel[i].rbuf;
+ prbuf->expected_seqno = prbuf->first_seq = peer_initial_seqno;
+ prbuf->q_size = rcvbuf_size;;
+ prbuf->pkt_q = (struct rudp_pkt**)calloc(sizeof(void*), rcvbuf_size);
+ prbuf->win = prbuf->q_size - 1;
+ }
+ pcb->cwnd = 2;
+ pcb->rtw_size = rawnd/2;//8;
+ pcb->rwin_size = rawnd;
+ pcb->ssthresh = rawnd;
+
+ pcb->srtt = 0;
+ pcb->sdev = 3;
+ pcb->rto = 6; //As [Jacobson 1988] rto = srtt + 2*sdev, but it seems too large for us
+
+ return pcb;
+}
+
+static void _terminateSocketInternally(struct rudp_socket *s, int err)
+{
+ if(s->state == RS_DEAD) return;
+
+ PA_MutexLock(s->mutex_r);
+ PA_MutexLock(s->mutex_w);
+
+ s->state = RS_DEAD;
+ s->err = err;
+
+ if(s->pcb)
+ {
+ int i;
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct rudp_pkt *c;
+ struct rcvbuf *prb;
+
+ c = s->pcb->channel[i].sbuf.first;
+ while(c)
+ {
+ struct rudp_pkt *p = c;
+ c = c->next;
+ _MBufPutPacket(p);
+ }
+
+ prb = &s->pcb->channel[i].rbuf;
+ for(; prb->head != prb->tail; prb->head = (prb->head+1)%prb->q_size)
+ if(prb->pkt_q[prb->head])
+ _MBufPutPacket(prb->pkt_q[prb->head]);
+ free(prb->pkt_q);
+ }
+ free(s->pcb);
+ s->pcb = NULL;
+ }
+
+ SETEVENT(s->event_r);
+ SETEVENT(s->event_w);
+
+ PA_MutexUnlock(s->mutex_w);
+ PA_MutexUnlock(s->mutex_r);
+
+#if 0
+ //Still in listening queue
+ if(list_empty(&s->inst_list) && !list_empty(&s->listen_queue))
+ {
+ list_del(&s->listen_queue);
+ free(s);
+ }
+#endif
+ //dbg_msg("################## _terminateSocketInternally ##########\n");
+}
+
+/// \brief Should be called with "mutex_sock_list" hold
+// \param err error code for the reason to cleanup this socket
+static void _CleanupSocket(struct rudp_socket *s, int err)
+{
+ if(s->state == RS_DEAD) return;
+
+ _terminateSocketInternally(s, err);
+
+ PA_MutexUninit(s->mutex_r);
+ PA_MutexUninit(s->mutex_w);
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ PA_EventUninit(s->event_r);
+ PA_EventUninit(s->event_w);
+#else
+ pthread_cond_destroy(&s->event_r);
+ pthread_cond_destroy(&s->event_w);
+#endif
+
+ if(!list_empty(&s->listen_queue))
+ {
+ struct list_head *pp, *qq;
+ list_for_each_safe(pp, qq, &s->listen_queue)
+ {
+ struct rudp_socket *sl = list_entry(pp, struct rudp_socket, listen_queue);
+ _CleanupSocket(sl, 0);
+ list_del(pp);
+ free(sl);
+ }
+ }
+
+ s->state = RS_DEAD;
+ //s->tag = 0;
+}
+
+static void _CleanAndFreeSocket(struct rudp_socket *s)
+{
+ if(list_empty(&s->inst_list)) //accepted
+ {
+ list_del(&s->accepted_list);
+ }
+ else
+ {
+ list_del(&s->inst_list);
+ if(list_empty(&s->accepted_list))
+ PA_SocketClose(s->udp_sock);
+ else
+ {
+ struct rudp_socket *aa = list_entry(s->accepted_list.next, struct rudp_socket, accepted_list);
+ INIT_LIST_HEAD(&aa->inst_list);
+ list_add_tail(&aa->inst_list, &sock_list);
+ }
+ }
+
+ if(s->state != RS_DEAD) _CleanupSocket(s, 0);
+
+ free(s);
+}
+
+void _timerProc(TimerHandler handler)
+{
+ struct list_head *p, *q, *pp, *qq;
+ //PA_MutexLock(mutex_sock_list);
+ list_for_each_safe(p, q, &sock_list)
+ {
+ struct rudp_socket *s, *ss;
+ s = list_entry(p, struct rudp_socket, inst_list);
+
+ if(s->state == RS_DEAD) continue;
+
+ list_for_each_safe(pp, qq, &s->accepted_list)
+ {
+ ss = list_entry(pp, struct rudp_socket, accepted_list);
+ handler(ss);
+ }
+ list_for_each_safe(pp, qq, &s->listen_queue) //a socket in listen_queue may be removed due to timeout
+ {
+ ss = list_entry(pp, struct rudp_socket, listen_queue);
+ handler(ss);
+ }
+
+ handler(s);
+ }
+ //PA_MutexUnlock(mutex_sock_list);
+}
+
+static void _congestionAvoidance(struct rudp_socket *s)
+{
+ if(s->pcb->cwnd < s->pcb->ssthresh)
+ {//slow start
+ s->pcb->cwnd++;
+#if 1
+ s->pcb->ca_cnt++;
+ if(s->pcb->ca_cnt >= s->pcb->rwin_size)
+#endif
+ if(s->pcb->rtw_size < s->pcb->rwin_size)
+ s->pcb->rtw_size++;
+ }
+ else
+ {//congestion avoidance, increase cwnd slowly
+ s->pcb->ca_cnt++;
+ if(s->pcb->ca_cnt >= s->pcb->cwnd)
+ {
+ s->pcb->ca_cnt = 0;
+ if(s->pcb->cwnd < s->pcb->rwin_size)
+ {
+ s->pcb->cwnd++;
+ //s->pcb->ssthresh++; ???
+ }
+ if(s->pcb->rtw_size < s->pcb->rwin_size)
+ s->pcb->rtw_size++;
+ }
+ }
+}
+
+static void _congestionDetected(struct rudp_socket *s, int chno, int what)
+{
+ //int rawnd, i;
+ struct rudp_pcb *pcb;
+
+ //for(i=rawnd=0; i<MAX_CHANNELS; i++) rawnd += pcb->channel[chno].sbuf.rawnd;
+
+ pcb = s->pcb;
+ pcb->ssthresh = min(pcb->channel[chno].sbuf.rawnd, pcb->cwnd)/2;
+ if(pcb->ssthresh < 2) pcb->ssthresh = 2;
+
+ if(what == CONGESTED) pcb->cwnd = 1;
+ else pcb->cwnd = pcb->ssthresh + 3;
+
+ switch(what)
+ {
+ case CONGESTED:
+ case FASTRETRANS2:
+ pcb->rtw_size >>= 1;
+ if(pcb->rtw_size < 8) pcb->rtw_size = 8;
+ break;
+
+ case FASTRETRANS:
+ pcb->rtw_size -= pcb->rtw_size >> 2;
+ if(pcb->rtw_size < 8) pcb->rtw_size = 8;
+ break;
+ }
+}
+
+static INLINE unsigned int _calcCurWnd(struct rudp_socket *s, struct sndbuf *psbuf)
+{
+ //if receiver's rawnd is 0, still send one more packet then transmission can be
+ //started again by re-transfer timer, even when the receiver's OPENWND ACK(s) are lost
+ return min(s->pcb->cwnd, psbuf->rwnd);
+
+ //return min(min(s->pcb->cwnd, psbuf->rwnd),psbuf->rawnd);
+ //return psbuf->rwnd;
+}
+
+/** Output a packet
+ *
+ * mutex_w shall be hold before call _RudpOutput
+ *
+ * return: 1 - if a packet is sent; otherwise, no packet is sent
+ */
+static int _RudpOutput(struct rudp_socket *s, int chno, int opt)
+{
+ struct sndbuf *psbuf;
+ struct rcvbuf *prbuf;
+ struct rudp_channel *pch;
+
+ if(s->tag != RUDP_SOCKET_TAG) return -1;
+ if(s->state <= RS_CLOSED) return -1;
+
+ pch = &s->pcb->channel[chno];
+ psbuf = &pch->sbuf;
+ prbuf = &pch->rbuf;
+
+ //if(pch->congested && opt == RO_NORMAL) return;
+ if(opt == RO_REXMT || opt == RO_REXMT_FAST) //packets are queued before
+ {
+ struct rudp_pkt *pkt = opt == RO_REXMT_FAST ? psbuf->rexmt : psbuf->first;
+ if(!pkt) return 0;
+ if(prbuf->should_ack == ACKT_DELAYED)
+ {
+ prbuf->should_ack = 0;
+ pkt->hdr.flags.ack = 1;
+ pkt->hdr.ackno = ntohl(prbuf->expected_seqno);
+ pkt->hdr.flags.n_loss = prbuf->n_lost;
+ //if(psbuf->first->trans) psbuf->first->hdr.crc32 = calc_crc32(0, (char*)&psbuf->first->hdr, offsetof(struct rudp_hdr, crc32));
+ }
+ _sendPacket(s, pch, pkt, opt);
+ pkt->hdr.flags.ack = 0;
+ return 1;
+ }
+
+ if(((prbuf->should_ack == ACKT_DELAYED) && !psbuf->first) || prbuf->should_ack == ACKT_OPENWND)
+ {
+ _sendAck(s, chno);
+ prbuf->should_ack = 0;
+
+ return 0;
+ }
+
+ if(opt == 0 && pch->sbuf.rawnd == 0)
+ {
+ if(pch->timer[RCT_REXMT] == 0)
+ pch->timer[RCT_PERSIST] = s->pcb->rto * rudp_backoff[pch->sbuf.first?pch->sbuf.first->trans:0];
+ //signalOutput(s, chno);
+ }
+ else
+ {
+ struct rudp_pkt *p;
+
+ p = psbuf->not_sent;
+ pch->timer[RCT_PERSIST] = 0;
+ if(p && (opt == RO_FORCE /*|| prbuf->should_ack == ACKT_DELAYED */
+ || _calcCurWnd(s, psbuf) > psbuf->n_unacked
+ /* && psbuf->n_unacked < s->pcb->rtw_size*/))
+ //psbuf->n_unacked < psbuf->rawnd) )
+ {
+ if(prbuf->should_ack == ACKT_DELAYED)
+ {
+ prbuf->should_ack = 0;
+ p->hdr.flags.ack = 1;
+ p->hdr.ackno = ntohl(prbuf->expected_seqno);
+ p->hdr.flags.n_loss = prbuf->n_lost;
+ //if(p->trans) p->hdr.crc32 = calc_crc32(0, (char*)&p->hdr, offsetof(struct rudp_hdr, crc32));
+ }
+ //psbuf->n_unacked++;
+ _sendPacket(s, pch, p, opt);
+ p->hdr.flags.ack = 0;
+ p = p->next;
+ //psbuf->not_sent = p = p->next;
+ if(p && p->seqno < psbuf->not_sent->seqno)
+ {
+ dbg_msg("#####################################################\n");
+ }
+ psbuf->not_sent = p;
+
+ //if(psbuf->rwnd > 0)
+ psbuf->rwnd--;
+ return 1;
+ if(opt == RO_ONLYONE) return 1;
+
+ if(_calcCurWnd(s, psbuf) && p)
+ {
+ //signalOutput(s, chno);
+ //struct output_notify notify = { s, chno };
+ //PA_Send(sockw_s, ¬ify, sizeof(notify), 0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void _handleTimer500ms(struct rudp_socket *s)
+{
+ int i, j;
+ struct rudp_pcb *pcb;
+
+ if(s->state == RS_LISTEN || s->state == RS_DEAD) return;
+ pcb = s->pcb;
+ if(pcb)
+ {
+ int sbuf_is_empty = 1;
+ //rudp_now ++;
+
+ PA_MutexLock(s->mutex_w);
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct rudp_channel *pch = &pcb->channel[i];
+ if(pch->sbuf.first) sbuf_is_empty = 0;
+ for(j=0; j<RCT_CNT; j++)
+ {
+ if(pch->timer[j] == 0) continue;
+ pch->timer[j] --;
+ if(pch->timer[j] == 0)
+ {
+ switch(j)
+ {
+ case RCT_PERSIST:
+ dbg_msg("Persist timeout.\n");
+ _RudpOutput(s, i, RO_FORCE);
+ break;
+ case RCT_REXMT:
+ if(pch->sbuf.first)
+ {
+ if(pch->sbuf.first->trans >= MAX_REXMT_ATTEMPT)
+ {
+ PA_MutexUnlock(s->mutex_w);
+ _CleanupSocket(s, ERUDP_TIMEOUTED);
+ s->state = RS_DEAD;
+ s->err = ERUDP_TIMEOUTED;
+ return;
+ }
+ else if(pch->sbuf.first->trans)
+ {
+ _congestionDetected(s, i, CONGESTED);
+ _printTime(); dbg_msg("congested: cwnd=%d, ssthresh=%d\n", pcb->cwnd, pcb->ssthresh);
+ _congestionAvoidance(s);
+ _RudpOutput(s, i, RO_REXMT);
+ pch->congested = 1;
+ pch->sbuf.pkt_rttm_start = pch->sbuf.not_sent;
+ }
+ else
+ _RudpOutput(s, i, 0);
+ }
+ break;
+ }
+ }
+ }
+ }
+ if(sbuf_is_empty && s->state == RS_FIN_QUEUED)
+ {
+ _sendFin(s);
+ s->state = RS_FIN_WAIT_1;
+ s->timer[RT_KEEP] = RTT_MIN * RTV_KEEP_CLOSE;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ }
+
+ for(i=0; i<RT_CNT; i++)
+ {
+ if(s->timer[i] == 0) continue;
+
+ s->timer[i]--;
+ if(s->timer[i] == 0)
+ {
+ switch(i)
+ {
+ case RT_KEEP: //for connecting timeout
+ if(s->state == RS_SYN_RCVD || s->state == RS_SYN_SENT)
+ {
+ if(s->pcb->retr_cnt >= MAX_RECONN_ATTEMPT)
+ {
+ if(list_empty(&s->inst_list))
+ {
+ list_del(&s->listen_queue);
+ INIT_LIST_HEAD(&s->listen_queue);
+ _CleanupSocket(s, ERUDP_TIMEOUTED);
+ free(s);
+ }
+ else
+ {
+ //_CleanupSocket(s, ERUDP_TIMEOUTED);
+ s->err = ERUDP_TIMEOUTED;
+ s->state = RS_CLOSED;
+ SETEVENT(s->event_w);
+ }
+ return;
+ }
+ else
+ {
+ s->timer[RT_KEEP] = conn_backoff[++s->pcb->retr_cnt];
+ if(s->state == RS_SYN_SENT)
+ _sendSyn(s);
+ else
+ _sendSynAck(s);
+ }
+ }
+ else if(s->state >= RS_FIN_QUEUED)
+ {
+ dbg_msg("clean and free %p\n", s);
+ _CleanAndFreeSocket(s);
+ }
+ break;
+ case RT_2MSL:
+ break;
+ }
+ }
+ }
+}
+
+void _handleTimer200ms(struct rudp_socket *s)
+{
+ if(s->pcb)// && (s->pcb->r_flags & RUDPF_DELAYACK))
+ {
+ int i;
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct rcvbuf *prb = &s->pcb->channel[i].rbuf;
+ if(prb->should_ack)
+ {
+ //_printTime(); dbg_msg("delayed ack.\n");
+ PA_MutexLock(s->mutex_w);
+ _RudpOutput(s, i, 0);
+ //signalOutput(s, i);
+ PA_MutexUnlock(s->mutex_w);
+ }
+ }
+ }
+}
+void _sendHeader(struct rudp_socket *s, struct rudp_hdr *phdr)
+{
+ _printHdr(s->pcb, phdr, &s->pcb->peer);
+ phdr->crc32 = calc_crc32(0, (char*)phdr, offsetof(struct rudp_hdr, crc32));
+ PA_SendTo(s->udp_sock, phdr, sizeof(struct rudp_hdr), 0,
+ s->connected?NULL:(struct sockaddr*)&s->pcb->peer,
+ sizeof(struct sockaddr));
+}
+
+void _sendPacket(struct rudp_socket *s, struct rudp_channel *pch, struct rudp_pkt *pkt, int opt)
+{
+ if(pch->timer[RCT_REXMT] == 0)
+ pch->timer[RCT_REXMT] = s->pcb->rto * rudp_backoff[pkt->trans];
+ pkt->ts = rudp_now;
+ //dbg_msg("............. seq %u, ts %d...........", pkt->seqno, rudp_now);
+ pkt->hdr.flags.window = WINDOW_HTON(pch->rbuf.win);
+ if(opt != RO_REXMT_FAST)
+ {
+ if(!pkt->trans) pch->sbuf.n_unacked++;
+ pkt->trans ++;
+ if(pkt->trans >= MAX_REXMT_ATTEMPT) pkt->trans = MAX_REXMT_ATTEMPT;
+ }
+ pkt->hdr.crc32 = calc_crc32(0, (char*)&pkt->hdr, offsetof(struct rudp_hdr, crc32));
+
+ _printPkt(s->pcb, pkt, PHF_DATA|pch->sbuf.rwnd, &s->pcb->peer);
+ PA_SendTo(s->udp_sock, &pkt->hdr, sizeof(struct rudp_hdr) + pkt->len, 0,
+ s->connected?NULL:(struct sockaddr*)&s->pcb->peer,
+ sizeof(struct sockaddr));
+}
+void _sendSyn(struct rudp_socket *s)
+{
+ struct rudp_hdr hdr;
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.flags.syn = 1;
+ hdr.seqno = htonl(s->pcb->channel[0].sbuf.seqno);
+ hdr.ackno = 0;
+ hdr.flags.window = WINDOW_HTON(s->pcb->channel[0].rbuf.win);
+ _sendHeader(s, &hdr);
+}
+void _sendSynAck(struct rudp_socket *s)
+{
+ struct rudp_hdr hdr;
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.flags.syn = 1;
+ hdr.seqno = htonl(s->pcb->channel[0].sbuf.seqno);
+ hdr.flags.ack = 1;
+ hdr.ackno = htonl(s->pcb->channel[0].rbuf.expected_seqno);
+ hdr.flags.window = WINDOW_HTON(s->pcb->channel[0].rbuf.win);
+ _sendHeader(s, &hdr);
+}
+//only ack flag
+void _sendEmptyAck(struct rudp_socket *s, int chno)
+{
+ struct rudp_hdr hdr;
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.seqno = 0;
+ hdr.flags.chno = chno;
+ hdr.flags.ack = 1;
+ hdr.ackno = 0;
+ hdr.flags.window = 0;
+ _sendHeader(s, &hdr);
+}
+
+//ack without data
+void _sendAck(struct rudp_socket *s, int chno)
+{
+ struct rudp_hdr hdr;
+ struct rcvbuf *pr = &s->pcb->channel[chno].rbuf;
+
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.flags.ack = 1;
+ hdr.flags.chno = chno;
+ hdr.seqno = htonl(s->pcb->channel[chno].sbuf.seqno);
+ hdr.ackno = htonl(pr->expected_seqno);
+ hdr.flags.n_loss = pr->n_lost;
+ hdr.flags.window = WINDOW_HTON(pr->win);
+ _sendHeader(s, &hdr);
+
+ pr->acked_seqno = pr->expected_seqno;
+ pr->should_ack = 0;
+}
+void _sendFin(struct rudp_socket *s)
+{
+ struct rudp_hdr hdr;
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.flags.fin = 1;
+ hdr.seqno = 0;
+ hdr.ackno = 0;
+ hdr.flags.window = 0;
+ _sendHeader(s, &hdr);
+}
+
+
+void _updateRTO(struct rudp_socket *s, int rtt)
+{
+ int rto0 = s->pcb->rto;
+#if 0
+ /* [Jacobson 1988], refresh rto */
+ int drtt = rtt - s->pcb->srtt;
+ if(drtt > 0)
+ {
+ s->pcb->srtt += drtt >> 3;
+ if(drtt > s->pcb->sdev)
+ s->pcb->sdev += (drtt - s->pcb->sdev) >> 2;
+ else
+ s->pcb->sdev -= (s->pcb->sdev - drtt) >> 2;
+ }
+ else
+ {
+ drtt = -drtt;
+ s->pcb->srtt -= drtt >> 3;
+ if(drtt > s->pcb->sdev)
+ s->pcb->sdev += (drtt - s->pcb->sdev) >> 2;
+ else
+ s->pcb->sdev -= (s->pcb->sdev - drtt) >> 2;
+ }
+ s->pcb->rto = s->pcb->srtt + (s->pcb->sdev > 0) ?(s->pcb->sdev << 2):(-s->pcb->sdev << 2);
+ if(s->pcb->rto < 2) s->pcb->rto = 2;
+ dbg_msg("rtt = %d, rto = %d\n", rtt, s->pcb->rto);
+#else
+ if(rtt < RTT_MIN) rtt = RTT_MIN;
+ //if(rtt < 2) rtt = 2;
+ s->pcb->rto = rtt;
+#endif
+ if(s->pcb->rto - rto0 > 0)
+ {
+ s->pcb->cwnd -= s->pcb->cwnd >> 2;
+ //s->pcb->rtw_size -= s->pcb->rtw_size >> 2;
+ }
+}
+
+INLINE BOOL _isPacketValid(struct rudp_pkt *pkt)
+{
+#ifdef _DEBUG
+ return (calc_crc32(0, (char*)&pkt->hdr, offsetof(struct rudp_hdr, crc32)) == pkt->hdr.crc32)?TRUE:(printf("Invalid packet!\n"),FALSE);
+#else
+ return calc_crc32(0, (char*)&pkt->hdr, offsetof(struct rudp_hdr, crc32)) == pkt->hdr.crc32;
+#endif
+}
+
+int _DispatchPacket(struct rudp_socket *s, struct rudp_pkt *pkt, const struct sockaddr *from, int from_len)
+{
+ struct list_head *pp, *qq;
+ struct rudp_socket *sa;
+ struct sockaddr_in *sp, *sf;
+
+ sf = (struct sockaddr_in*)from;
+
+ /* We must search each queue to make sure there is no duplicated connection for a listening socket */
+
+ if(s->state == RS_LISTEN)
+ {
+ list_for_each_safe(pp, qq, &s->listen_queue)
+ {
+ sa = list_entry(pp, struct rudp_socket, listen_queue);
+ if(!sa->pcb) continue;
+ sp = (struct sockaddr_in*)&sa->pcb->peer;
+ if(sp->sin_addr.s_addr == sf->sin_addr.s_addr && sp->sin_port == sf->sin_port)
+ {
+ int check_again;
+ if(pkt->hdr.flags.rst)
+ {
+ list_del(&sa->listen_queue);
+ INIT_LIST_HEAD(&sa->listen_queue);
+ _CleanupSocket(sa, ERUDP_RESETED);
+ free(sa);
+ return 0;
+ }
+
+ check_again = 0;
+ if(pkt->hdr.flags.ack && sa->state == RS_SYN_RCVD)
+ check_again = 1;
+ if(_ProcessPacket(sa, pkt, from, from_len) < 0)
+ _MBufPutPacket(pkt);
+ if(check_again && sa->state == RS_ESTABLISHED)
+ SETEVENT(s->event_r);
+ return 0;
+ }
+ }
+ }
+
+ list_for_each(pp, &s->accepted_list)
+ {
+ sa = list_entry(pp, struct rudp_socket, accepted_list);
+ if(sa->state >= RS_ESTABLISHED)
+ {
+ sp = (struct sockaddr_in*)&sa->pcb->peer;
+ if(sp->sin_addr.s_addr == sf->sin_addr.s_addr && sp->sin_port == sf->sin_port)
+ {
+ if(_ProcessPacket(sa, pkt, from, from_len) < 0)
+ _MBufPutPacket(pkt);
+ return 0;
+ }
+ }
+ }
+
+ /* It's time to Me */
+ if(s->state == RS_LISTEN/*listening socket*/ ||
+ ( s->pcb && (s->connected/*client*/
+ || (((sp = (struct sockaddr_in*)&s->pcb->peer), sp->sin_addr.s_addr == sf->sin_addr.s_addr)
+ && (sp->sin_port == sf->sin_port)/*accepted(listening socket is closed)*/) )
+ )
+ )
+ {
+ if(_ProcessPacket(s, pkt, from, from_len) < 0)
+ _MBufPutPacket(pkt);
+ return 0;
+ }
+
+ /* Nobody want this packet */
+ if(!(pkt->hdr.flags.rst && s->state <= 0))
+ _sendReset(s, from);
+ _MBufPutPacket(pkt);
+ return 0;
+}
+
+static int _PPState_Established(struct rudp_socket *s, struct rudp_pkt *pkt, const struct sockaddr *from, int from_len)
+{
+ struct rudp_channel *pch;
+ struct sndbuf *psbuf;
+ struct rcvbuf *prbuf;
+ int old_rawnd;
+ int chno;
+
+ if(pkt->hdr.flags.syn)
+ {
+ if(pkt->hdr.flags.ack)
+ _sendAck(s, 0);
+ else
+ _sendReset(s, from);
+ return -1;
+ }
+ if(pkt->hdr.flags.fin)
+ {
+ int i, ii;
+ PA_MutexLock(s->mutex_w);
+ s->state = RS_CLOSE_WAIT;
+ _sendAck(s, 0);
+ s->timer[RT_KEEP] = RTT_MIN * RTV_KEEP_CLOSE;
+
+ //
+ // Cleanup sndbuf
+ //
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct sndbuf *psb = &s->pcb->channel[i].sbuf;
+ struct rudp_pkt *c = psb->first;
+ while(c)
+ {
+ struct rudp_pkt *p = c;
+ c = c->next;
+ _MBufPutPacket(p);
+ }
+ memset(psb, 0, sizeof(struct sndbuf));
+ for(ii=0; ii<RCT_CNT; ii++) s->pcb->channel[i].timer[ii] = 0;
+ }
+ for(i=0; i<RT_CNT; i++) s->timer[i] = 0;
+
+ PA_MutexUnlock(s->mutex_w);
+ goto _checkdata;
+ }
+
+ chno = pkt->hdr.flags.chno;
+ pch = &s->pcb->channel[chno];
+ psbuf = &pch->sbuf;
+ old_rawnd = psbuf->rawnd;
+ psbuf->rawnd = WINDOW_NTOH(pkt->hdr.flags.window);
+ //psbuf->rwnd += old_rawnd - psbuf->rawnd;
+ psbuf->rwnd = psbuf->rawnd - psbuf->n_unacked;
+ if(psbuf->rwnd < 0) psbuf->rwnd = 0;
+
+
+ if(pkt->hdr.flags.ack && psbuf->first)
+ {
+ uint32_t ackno = ntohl(pkt->hdr.ackno);
+
+ PA_MutexLock(s->mutex_w);
+ if(SEQ_LE(ackno, psbuf->first->seqno)/* && !pch->congested*/) //duplicated ACK
+ //if(ackno == psbuf->first->seqno) //duplicated ACK
+ {
+ if(old_rawnd == 0 && psbuf->rawnd > 0) //Recevier's window opened
+ {
+ _RudpOutput(s, pkt->hdr.flags.chno, RO_FORCE);
+ PA_MutexUnlock(s->mutex_w);
+ goto _checkdata;
+ }
+
+ psbuf->dup_ack++;
+ if(psbuf->dup_ack >= 3)
+ {
+ if(psbuf->dup_ack == 3)
+ {
+ psbuf->rlost = pkt->hdr.flags.n_loss;
+ if(psbuf->rlost == 0) psbuf->rlost = 1;
+ psbuf->rexmt = psbuf->first;
+ _congestionDetected(s, chno, psbuf->rlost>1?FASTRETRANS2:FASTRETRANS);
+ _printTime(); dbg_msg("duplicated ACKs(%d): rlost=%d, cwnd=%d, ssthresh=%d\n",
+ ackno, psbuf->rlost, s->pcb->cwnd, s->pcb->ssthresh);
+
+ pch->timer[RCT_REXMT] = s->pcb->rto * rudp_backoff[0] + 1;
+
+ psbuf->pkt_rttm_start = psbuf->not_sent;
+ psbuf->fastretr_end_seq = psbuf->first->seqno + psbuf->n_unacked - 1;
+ }
+
+ if(psbuf->rlost && psbuf->rexmt)
+ {
+ _RudpOutput(s, pkt->hdr.flags.chno, RO_REXMT_FAST);
+ psbuf->rexmt = psbuf->rexmt->next;
+ psbuf->rlost --; //if(psbuf->rlsot == 0) psbuf->rexmt = NULL;
+ }
+ else if(psbuf->dup_ack > 3)
+ {
+ s->pcb->cwnd ++;
+ // Send one new packet every two duplicated acks.
+ // Because each ack means a packet(very possible being valid) is received by peer,
+ // so we can inject new packet into network
+ if(psbuf->dup_ack & 1) _RudpOutput(s, pkt->hdr.flags.chno, RO_FORCE);
+
+ if(s->pcb->cwnd > s->pcb->ssthresh)
+ s->pcb->cwnd = s->pcb->ssthresh;
+ //psbuf->dup_ack = 0;
+ }
+ }
+ else
+ _RudpOutput(s, pkt->hdr.flags.chno, RO_ONLYONE);
+ }
+ else// if(SEQ_GT(ackno, psbuf->first->seqno))
+ {
+ struct rudp_pkt *p, *p2;
+ int fast_rxmt_end = 0; //fast retransmission
+
+ p = psbuf->first;
+ //while(p && p->seqno != ackno && psbuf->n_unacked)
+ while(p && p->seqno < ackno)
+ {//remove acked packets
+ if(psbuf->pkt_rttm_start == p)
+ psbuf->pkt_rttm_start = NULL;
+ if(p->trans == 1 && psbuf->pkt_rttm_start == NULL)
+ _updateRTO(s, rudp_now - p->ts);
+
+ if(p->seqno == psbuf->fastretr_end_seq && psbuf->dup_ack >= 3)
+ fast_rxmt_end = 1;
+ p2 = p;
+ p = p->next;
+ _MBufPutPacket(p2);
+ psbuf->n_unacked --;
+ assert(psbuf->n_unacked>=0);
+ psbuf->n_pkt --;
+ psbuf->rwnd ++;
+
+ // Slow start && congestion avoidance
+ _congestionAvoidance(s);
+
+ // If recovery from congestion, or, after a fast retransmission,
+ // there's another hole in the unacked queue, continue performing
+ // fast retransmission.
+ // Otherwise, stop fast recovery
+ if(psbuf->rlost && psbuf->rexmt)
+ {
+ _RudpOutput(s, pkt->hdr.flags.chno, RO_REXMT_FAST);
+ psbuf->rexmt = psbuf->rexmt->next;
+ psbuf->rlost --; //if(psbuf->rlsot == 0) psbuf->rexmt = NULL;
+ }
+ else if(pch->congested)
+ {
+ psbuf->dup_ack ++;
+ if(psbuf->dup_ack & 1) _RudpOutput(s, pkt->hdr.flags.chno, RO_FORCE);
+
+ if(s->pcb->cwnd > s->pcb->ssthresh)
+ {
+ s->pcb->cwnd = s->pcb->ssthresh;
+ pch->congested = 0;
+ }
+ }
+ else
+ {
+ psbuf->dup_ack = 0;
+ if(old_rawnd == 0 && psbuf->rawnd > 0) //Recevier's window opened
+ _RudpOutput(s, pkt->hdr.flags.chno, RO_FORCE);
+ else
+ while(_RudpOutput(s, pkt->hdr.flags.chno, 0));
+ }
+ }
+ psbuf->first = p;
+
+ if(!p)
+ {
+ psbuf->pkt_rttm_start = psbuf->not_sent = psbuf->last = NULL; //enable rtt measurement
+ pch->timer[RCT_REXMT] = 0;
+
+ assert(psbuf->n_pkt==0);
+ }
+ else
+ pch->timer[RCT_REXMT] = s->pcb->rto * rudp_backoff[pkt->trans];
+
+ //signalOutput(s, pkt->hdr.flags.chno);
+ SETEVENT(s->event_w);
+ }
+ PA_MutexUnlock(s->mutex_w);
+ }
+
+_checkdata:
+ if(pkt->len) //length of data > 0
+ {
+ uint32_t pos, seqno;
+ int delta;
+
+ PA_MutexLock(s->mutex_r);
+ seqno = ntohl(pkt->hdr.seqno);
+ prbuf = &pch->rbuf;
+
+ delta = (int)(seqno - prbuf->first_seq);
+ if(delta < 0) //old packet, just ignore it
+ {
+ //PA_MutexUnlock(s->mutex_r);
+ dbg_msg("packet %d is ignored, expected_seqno=%d\n", pkt->seqno, prbuf->expected_seqno);
+ goto _sendack_and_discard_pkt;
+ }
+ if(delta < prbuf->q_size-1) //in the buffer
+ {
+ pos = (prbuf->head + delta)%prbuf->q_size;
+ if(prbuf->pkt_q[pos]) //duplicated
+ {
+ dbg_msg("packet %d is duplicated.\n", pkt->seqno);
+ goto _sendack_and_discard_pkt;
+ }
+
+ prbuf->pkt_q[pos] = pkt;
+
+ //update pointers & window
+ if((prbuf->tail + prbuf->q_size - prbuf->head)%prbuf->q_size <=
+ (pos + prbuf->q_size - prbuf->head)%prbuf->q_size)
+ prbuf->tail = (pos+1)%prbuf->q_size;
+ prbuf->win = (prbuf->q_size + prbuf->head - prbuf->tail - 1)%prbuf->q_size;
+
+ if(prbuf->loss == pos) //just the one we expected
+ {
+ //move "loss" to next empty slot, if any
+ while(prbuf->loss != prbuf->tail && prbuf->pkt_q[prbuf->loss])
+ {
+ prbuf->loss = (prbuf->loss + 1) % prbuf->q_size;
+ prbuf->expected_seqno++;
+ }
+ prbuf->should_ack = ACKT_DELAYED;
+ SETEVENT(s->event_r);
+ }
+
+ //(re-)calculate the size of (next, or current) hole.
+ {
+ int loss = prbuf->loss, n_lost=0;
+ while(loss != prbuf->tail && !prbuf->pkt_q[loss] && n_lost < MAX_LOSS_REPORT)
+ {
+ loss = (loss + 1) % prbuf->q_size;
+ n_lost++;
+ }
+ prbuf->n_lost = n_lost;
+ if(n_lost) prbuf->should_ack = 0;
+ }
+
+ if(!prbuf->should_ack ||
+ ((prbuf->should_ack == ACKT_DELAYED) && ((prbuf->expected_seqno - prbuf->acked_seqno) >= 3))
+ )
+ {
+ _sendAck(s, pkt->hdr.flags.chno);
+ prbuf->should_ack = 0;
+ }
+
+ PA_MutexUnlock(s->mutex_r);
+ return 0;
+ }
+ else
+ dbg_msg("exceeds receiver's buffer: %d\n", pkt->seqno);
+_sendack_and_discard_pkt:
+ PA_MutexUnlock(s->mutex_r);
+ _sendAck(s, pkt->hdr.flags.chno);
+ return -1;
+ }
+ else if(!pkt->hdr.flags.ack) //What's this? fin?
+ {
+ if(s->state == RS_CLOSE_WAIT)
+ {
+ PA_MutexLock(s->mutex_r);
+ s->err = ERUDP_PEER_CLOSED;
+ SETEVENT(s->event_r);
+ PA_MutexUnlock(s->mutex_r);
+ }
+ else
+ {
+ PA_MutexLock(s->mutex_w);
+ _RudpOutput(s, pkt->hdr.flags.chno, 0);
+ PA_MutexUnlock(s->mutex_w);
+ }
+ return -1;
+ }
+
+ return -1;
+}
+
+
+/// \brief Process packet
+// @return -1 -- if the packet will be released
+int _ProcessPacket(struct rudp_socket *s, struct rudp_pkt *pkt, const struct sockaddr *from, int from_len)
+{
+ struct rudp_channel *pch;
+ struct sndbuf *psbuf;
+
+ if((pkt->hdr.flags.rst) && s->state != RS_LISTEN)
+ {
+ if(s->state == RS_SYN_SENT)
+ {//To support simultanous connection, ignore it
+ //s->state = RS_CLOSED;
+ //s->err = ERUDP_RESETED;
+ }
+ else
+ {
+ _terminateSocketInternally(s, ERUDP_RESETED);
+ return -1;
+ }
+ }
+
+ switch(s->state)
+ {
+ case RS_CLOSED:
+ if(s->err) return -1;
+ if((s->flags & RF_ADHOC) && !s->pcb && pkt->hdr.flags.fin)
+ {
+ return -1;
+ }
+ break;
+
+ case RS_LISTEN:
+ if(pkt->hdr.flags.syn && !pkt->hdr.flags.ack)
+ {
+ struct rudp_socket *ss;
+ int sa_len;
+
+ ss = _AllocRudpSocket();
+ ss->rcvbuf_sz = s->rcvbuf_sz;
+ ss->udp_sock = s->udp_sock;
+ ss->pcb = _AllocRudpPcb(ss->rcvbuf_sz, INITIAL_SEQ_NO, ntohl(pkt->hdr.seqno), WINDOW_NTOH(pkt->hdr.flags.window));
+ memcpy(&ss->pcb->peer, from, from_len);
+ sa_len = sizeof(struct sockaddr_in);
+ PA_GetSockName(s->udp_sock, (struct sockaddr*)&ss->pcb->local, &sa_len);
+
+ ss->state = RS_SYN_RCVD;
+ ss->timer[RT_KEEP] = conn_backoff[0];
+ list_add_tail(&ss->listen_queue, &s->listen_queue);
+
+ _sendSynAck(ss);
+
+ return -1;
+ }
+ break;
+
+ case RS_SYN_SENT:
+ if(pkt->hdr.flags.syn)
+ {
+ int i;
+ struct rudp_hdr hdr;
+
+ pch = &s->pcb->channel[0];
+ psbuf = &pch->sbuf;
+
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ pch[i].rbuf.expected_seqno = pch[i].rbuf.first_seq = ntohl(pkt->hdr.seqno);
+ s->pcb->rwin_size = pch[i].sbuf.rwnd = pch[i].sbuf.rawnd = WINDOW_NTOH(pkt->hdr.flags.window);
+ s->pcb->rtw_size = s->pcb->rwin_size/2;//8;
+ }
+ s->pcb->ssthresh = s->pcb->rwin_size; //s->pcb->rtw_size;
+
+ /* Send ACK for normal connection, finish handshake.
+ * or
+ * Send SYN & ACK for simultaneous open.
+ */
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.flags.ack = 1;
+ hdr.ackno = pkt->hdr.seqno;
+ hdr.flags.window = WINDOW_HTON(s->pcb->channel[0].rbuf.win);
+
+ PA_MutexLock(s->mutex_w);
+
+ if(pkt->hdr.flags.ack) //Normal open
+ {
+ _sendHeader(s, &hdr);
+ s->state = RS_ESTABLISHED;
+ SETEVENT(s->event_w);
+ }
+ else // Simultaneous open
+ {
+ //re-use packet
+ hdr.flags.syn = 1;
+ hdr.seqno = htonl(psbuf->seqno);
+ _sendHeader(s, &hdr);
+
+ s->state = RS_SYN_RCVD;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ return -1;
+ }
+ break;
+
+ case RS_SYN_RCVD:
+ if(pkt->hdr.flags.ack)// && pkt->hdr.ackno == s->pcb->channel[0].sbuf.seqno)
+ {
+ pch = &s->pcb->channel[0];
+ psbuf = &pch->sbuf;
+
+ /* Simultaneous open, wakeup thread wait on RUDPConnect(...) */
+ if(list_empty(&s->listen_queue))
+ {
+ PA_MutexLock(s->mutex_w);
+ s->state = RS_ESTABLISHED;
+ SETEVENT(s->event_w);
+ PA_MutexUnlock(s->mutex_w);
+ }
+ /* Accepted, wakeup thread wait on RUDPAccept(...) */
+ else
+ {
+ //waiting thread is wakedup in _DispatchPacket...
+ //since s is not returned by Accept yet, it's safe without lock
+ s->state = RS_ESTABLISHED;
+ }
+ return -1;
+ }
+ else if(pkt->hdr.flags.syn)
+ {
+ _sendSynAck(s);
+ return -1;
+ }
+ break;
+
+ case RS_ESTABLISHED:
+ return _PPState_Established(s, pkt, from, from_len);
+
+ case RS_FIN_QUEUED:
+ case RS_FIN_WAIT_1:
+ if(pkt->hdr.flags.ack)
+ {
+ if(pkt->hdr.flags.fin)
+ {
+ _sendEmptyAck(s, 0);
+ s->state = RS_TIME_WAIT;
+ }
+ else
+ s->state = RS_FIN_WAIT_2;
+ }
+ else if(pkt->hdr.flags.fin)
+ {
+ _sendEmptyAck(s, 0);
+ s->state = RS_CLOSING;
+ }
+ s->timer[RT_KEEP] = RTT_MIN * RTV_KEEP_CLOSE;
+ return -1;
+
+ case RS_FIN_WAIT_2:
+ if(pkt->hdr.flags.fin)
+ {
+ _sendAck(s, 0);
+ s->state = RS_TIME_WAIT;
+ }
+ return -1;
+
+ case RS_CLOSING:
+ case RS_TIME_WAIT:
+ case RS_CLOSE_WAIT:
+ break;
+ }
+ _sendReset(s, from);
+ return -1;
+}
+
+/* pcb might not be allocated, cann't replaced by _sendHeader */
+void _sendReset(struct rudp_socket *s, const struct sockaddr *to)
+{
+ struct rudp_hdr hdr;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.u32_flags = 0;
+ hdr.flags.rudp = RUDP_HEADER_TAG;
+ hdr.flags.rst = 1;
+ hdr.crc32 = calc_crc32(0, (char*)&hdr, offsetof(struct rudp_hdr, crc32));
+ _printHdr(s->pcb, &hdr, (struct sockaddr_in*)to);
+ PA_SendTo(s->udp_sock, &hdr, sizeof(struct rudp_hdr), 0,
+ s->connected?NULL:to,
+ sizeof(struct sockaddr));
+}
+
+PA_THREAD_RETTYPE __STDCALL _RUDPServiceThread(void *pdata)
+{
+ fd_set rfds;
+ struct timeval tv;
+ struct list_head *p;
+ int max_fd;
+ unsigned long t200, t500, tnow;
+
+ t200 = t500 = PA_GetTickCount();
+ while(run)
+ {
+ FD_ZERO(&rfds);
+ tv.tv_sec = 0; tv.tv_usec = 25*1000;
+ //FD_SET(sockw_r, &rfds);
+ //max_fd = sockw_r;
+ max_fd = -1;
+
+ PA_MutexLock(mutex_sock_list);
+ list_for_each(p, &sock_list)
+ {
+ struct rudp_socket *s = list_entry(p, struct rudp_socket, inst_list);
+ //accepted socket's peer reseted ???
+ if(1)//s->state != RS_DEAD || !list_empty(&s->accepted_list))
+ {
+ FD_SET(s->udp_sock, &rfds);
+ max_fd = max(max_fd, s->udp_sock);
+ }
+ }
+ PA_MutexUnlock(mutex_sock_list);
+
+ if(select(max_fd+1, &rfds, NULL, NULL, &tv) > 0)
+ {
+ PA_MutexLock(mutex_sock_list);
+ list_for_each(p, &sock_list)
+ {
+ struct rudp_socket *s = list_entry(p, struct rudp_socket, inst_list);
+ if(FD_ISSET(s->udp_sock, &rfds))
+ {
+ struct sockaddr from;
+ int len, from_len;
+ struct rudp_pkt *pkt;
+
+ while(1)
+ {
+ pkt = _MBufGetPacket();
+ from_len = sizeof(from);
+ if(pkt)
+ {
+ len = PA_RecvFrom(s->udp_sock, &pkt->hdr, MAX_PACKET_SIZE, 0, &from, &from_len);
+ if(len < 0 || len < sizeof(struct rudp_hdr) || pkt->hdr.flags.rudp != RUDP_HEADER_TAG ||
+ !_isPacketValid(pkt))
+ {
+ if(len < 0)
+ {
+#ifdef _DEBUG
+#if defined(WIN32)
+ int err = WSAGetLastError();
+ if(err != WSAEWOULDBLOCK)
+ dbg_msg("recvfrom error: %d\n", err);
+#elif defined(ARM_UCOS_LWIP)
+ int err = lwip_get_error(s->udp_sock);
+ if(err != EWOULDBLOCK)
+ dbg_msg("recvfrom: %s\n", lwip_strerr(err));
+#else
+ if(errno != EWOULDBLOCK)
+ dbg_msg("recvfrom: %s\n", strerror(errno));
+#endif
+#endif
+ //_terminateSocketInternally(s, ERUDP_RESETED);
+ }
+ else if(s->non_rudp_pkt_cb)
+ s->non_rudp_pkt_cb((const uint8_t*)&pkt->hdr, len, s->p_user);
+ _MBufPutPacket(pkt);
+ break;
+ }
+
+ pkt->len = len - sizeof(struct rudp_hdr);
+ pkt->seqno = ntohl(pkt->hdr.seqno);
+ _printPkt(s->pcb, pkt, PHF_FROM, (struct sockaddr_in*)&from);
+ _DispatchPacket(s, pkt, &from, from_len);
+ }
+ else
+ break;
+ }
+ }
+ }
+ PA_MutexUnlock(mutex_sock_list);
+ }
+
+ tnow = PA_GetTickCount();
+ PA_MutexLock(mutex_sock_list);
+ if(tnow - t200 >= DELAY_ACK_MS-4)
+ {
+ //t200 += DELAY_ACK_MS;
+ t200 = tnow;
+ _timerProc(_handleTimer200ms);
+ }
+ if(tnow - t500 >= RTT_UINT-4)
+ {
+ //t500 += RTT_UINT;
+ t500 = tnow;
+ rudp_now ++;
+ _timerProc(_handleTimer500ms);
+ }
+ PA_MutexUnlock(mutex_sock_list);
+ }
+
+
+ return (PA_THREAD_RETTYPE)(0);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////
+extern void initRudpTimer();
+extern void uninitRudpTimer();
+
+int RUDPStart()
+{
+/*
+ struct sockaddr_in sai;
+ int salen;
+
+ sockw_r = socket(AF_INET, SOCK_DGRAM, 0);
+ sockw_s = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = inet_addr("127.0.0.1");
+ bind(sockw_r, (struct sockaddr*)&sai, sizeof(sai));
+ salen = sizeof(sai);
+ PA_GetSockName(sockw_r, (struct sockaddr*)&sai, &salen);
+
+ if(connect(sockw_s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ perror("connect to output notification slot");
+ exit(-1);
+ }
+*/
+ PA_MutexInit(mutex_sock_list);
+ PA_MutexInit(mutex_pkt_pool);
+ free_pkt = NULL;
+
+ hthd = PA_ThreadCreate(_RUDPServiceThread, NULL);
+ //initRudpTimer();
+
+ return 0;
+}
+
+int RUDPCleanup()
+{
+ struct list_head *p, *q;
+
+ //uninitRudpTimer();
+
+ run = 0;
+ PA_ThreadWaitUntilTerminate(hthd);
+ PA_ThreadCloseHandle(hthd);
+ //PA_SocketClose(sockw_r);
+ //PA_SocketClose(sockw_s);
+
+ PA_MutexLock(mutex_sock_list);
+ list_for_each_safe(p, q, &sock_list)
+ {
+ struct rudp_socket *s = list_entry(p, struct rudp_socket, inst_list);
+ if(!list_empty(&s->listen_queue))
+ {
+ struct list_head *pp, *qq;
+ list_for_each_safe(pp, qq, &s->listen_queue)
+ {
+ struct rudp_socket *ss = list_entry(pp, struct rudp_socket, accepted_list);
+ _sendReset(ss, (struct sockaddr*)&ss->pcb->peer);
+ _CleanupSocket(ss, 0);
+ list_del(pp);
+ free(ss);
+ }
+ }
+ if(s->state == RS_ESTABLISHED)
+ _sendReset(s, (struct sockaddr*)&s->pcb->peer);
+ _CleanupSocket(s, 0);
+ list_del(p);
+ PA_SocketClose(s->udp_sock);
+ free(s);
+ }
+ PA_MutexUnlock(mutex_sock_list);
+
+ PA_MutexUninit(mutex_pkt_pool);
+ while(free_pkt)
+ {
+ struct rudp_pkt *p = free_pkt;
+ free_pkt = free_pkt->next;
+ free(p);
+ }
+
+ PA_MutexUninit(mutex_sock_list);
+
+ return 0;
+}
+
+RUDPSOCKET RUDPSocket()
+{
+ struct rudp_socket *sock = _AllocRudpSocket();
+ sock->udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ PA_SocketSetNBlk(sock->udp_sock, 1);
+ PA_MutexLock(mutex_sock_list);
+ list_add_tail(&sock->inst_list, &sock_list);
+ PA_MutexUnlock(mutex_sock_list);
+
+ return (RUDPSOCKET)sock;
+}
+
+RUDPSOCKET RUDPSocketFromUdp(int udpsock)
+{
+ struct rudp_socket *s = _AllocRudpSocket();
+ s->udp_sock = udpsock;
+ PA_SocketSetNBlk(udpsock, 1);
+ PA_MutexLock(mutex_sock_list);
+ list_add_tail(&s->inst_list, &sock_list);
+ PA_MutexUnlock(mutex_sock_list);
+
+ return (RUDPSOCKET)s;
+}
+
+int RUDPSetInvalidPacketCB(RUDPSOCKET sock, NONRUDPPACKETCB pkt_cb, void *p_user)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ s->non_rudp_pkt_cb = (_NONRUDPPACKETCB)pkt_cb;
+ s->p_user = p_user;
+ return 0;
+}
+
+int RUDPClose(RUDPSOCKET sock)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+ switch(s->state)
+ {
+ case RS_CLOSED:
+ break;
+ case RS_LISTEN:
+ {
+ struct list_head *p, *q;
+ PA_MutexLock(mutex_sock_list);
+ list_for_each_safe(p, q, &s->listen_queue)
+ {
+ struct rudp_socket *aa = list_entry(p, struct rudp_socket, accepted_list);
+ _sendReset(aa, (struct sockaddr*)&aa->pcb->peer);
+ _CleanupSocket(aa, 0);
+ list_del(p);
+ free(aa);
+ }
+ PA_MutexUnlock(mutex_sock_list);
+ }
+ break;
+ case RS_SYN_SENT:
+ case RS_SYN_RCVD:
+ _sendReset(s, (struct sockaddr*)&s->pcb->peer);
+ break;
+ case RS_ESTABLISHED:
+ {
+ int i, sb_is_empty = 1;
+ PA_MutexLock(s->mutex_w);
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct sndbuf *psb = &s->pcb->channel[i].sbuf;
+ struct rcvbuf *prb = &s->pcb->channel[i].rbuf;
+ if(psb->first != NULL) { sb_is_empty = 0; }
+
+ for(; prb->head != prb->tail; prb->head = (prb->head+1)%prb->q_size)
+ if(prb->pkt_q[prb->head])
+ {
+ _MBufPutPacket(prb->pkt_q[prb->head]);
+ prb->pkt_q[prb->head] = NULL;
+ }
+ }
+ if(sb_is_empty)
+ {
+ _sendFin(s);
+ s->state = RS_FIN_WAIT_1;
+ s->timer[RT_KEEP] = RTT_MIN * RTV_KEEP_CLOSE;
+ }
+ else
+ {
+ s->state = RS_FIN_QUEUED;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ }
+ break;
+ case RS_CLOSE_WAIT:
+ break;
+ case RS_FIN_QUEUED:
+ case RS_FIN_WAIT_1:
+ case RS_FIN_WAIT_2:
+ case RS_CLOSING:
+ case RS_TIME_WAIT:
+ return ERUDP_NOT_ALLOWED;
+ }
+
+ /* NOTE:
+ * Remove from inst_list first, then cleanup the resources.
+ * If we are managed to maintain the closing states in future, cleanup
+ * should be executed in timerProc()
+ */
+
+ if(1)//s->state < RS_ESTABLISHED)
+ {
+ PA_MutexLock(mutex_sock_list);
+ _CleanAndFreeSocket(s);
+ PA_MutexUnlock(mutex_sock_list);
+ }
+
+ return 0;
+}
+
+int RUDPListen(RUDPSOCKET sock, int n)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+ if(s->state != RS_CLOSED) return ERUDP_NOT_ALLOWED;
+ INIT_LIST_HEAD(&s->listen_queue);
+ s->state = RS_LISTEN;
+
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ {
+ int opt;
+ opt = 100*1024;//1500*s->pcb->channel[0].sbuf.rwin_size/2;
+ setsockopt(s->udp_sock, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(int));
+ //setsockopt(s->udp_sock, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(int));
+ }
+#endif
+
+ return 0;
+}
+
+int RUDPAccept(RUDPSOCKET sock, RUDPSOCKET *accepted, struct sockaddr *addr, int *addrlen)
+{
+ struct rudp_socket *s, *a;
+ struct list_head *p, *q;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+ *accepted = NULL;
+wait:
+ PA_MutexLock(s->mutex_r);
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ if(list_empty(&s->listen_queue))
+ {
+ PA_MutexUnlock(s->mutex_r);
+ PA_EventWait(s->event_r);
+ PA_MutexLock(s->mutex_r);
+ }
+#else
+ while(list_empty(&s->listen_queue))
+ pthread_cond_wait(&s->event_r, &s->mutex_r);
+#endif
+ PA_MutexUnlock(s->mutex_r);
+
+
+ PA_MutexLock(mutex_sock_list);
+
+ list_for_each_safe(p, q, &s->listen_queue)
+ {
+ a = list_entry(p, struct rudp_socket, listen_queue);
+ if(a->state == RS_ESTABLISHED)
+ {
+ list_del(p);
+
+ INIT_LIST_HEAD(&a->accepted_list);
+ list_add_tail(&a->accepted_list, &s->accepted_list);
+
+ INIT_LIST_HEAD(&a->listen_queue);
+ *accepted = (RUDPSOCKET)a;
+ memcpy(addr, &a->pcb->peer, sizeof(struct sockaddr));
+ *addrlen = sizeof(struct sockaddr);
+
+ break;
+ }
+ }
+
+ PA_MutexUnlock(mutex_sock_list);
+
+ if(!*accepted)
+ {
+ if(s->flags & RF_NBLK)
+ return ERUDP_AGAIN;
+ else goto wait;
+ }
+
+ return 0;
+}
+
+int RUDPBind(RUDPSOCKET sock, const struct sockaddr *addr, int addrlen)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+ if(bind(s->udp_sock, addr, addrlen) == 0) return 0;
+ return ERUDP_BIND;
+}
+
+
+/* For simultaneous open:
+ * 1. Call RUDPBind(...) to bind to a local port, call RUDPAccept(...) on NEITHER sides
+ * 2. Call RUDPConnect(...) on both sides
+ */
+int RUDPConnect(RUDPSOCKET sock, const struct sockaddr* addr, int addr_len)
+{
+ struct rudp_socket *s;
+ int sa_len;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->state == RS_ESTABLISHED) return ERUDP_CONNECTED;
+ if(s->state == RS_SYN_SENT) return ERUDP_IN_PROGRESS;
+ if(s->state != RS_CLOSED/* || s->pcb*/) return ERUDP_NOT_ALLOWED;
+
+
+ s->err = 0;
+ if(!s->pcb) s->pcb = _AllocRudpPcb(s->rcvbuf_sz, INITIAL_SEQ_NO, 0, 1);
+ memcpy(&s->pcb->peer, addr, sizeof(struct sockaddr));
+#if 0
+ if(connect(s->udp_sock, addr, addr_len) == 0)
+ s->connected = TRUE;
+ else
+ dbg_msg("call connect() failed.\n");
+#endif
+ sa_len = sizeof(struct sockaddr_in);
+ PA_GetSockName(s->udp_sock, (struct sockaddr*)&s->pcb->local, &sa_len);
+ s->state = RS_SYN_SENT;
+ s->timer[RT_KEEP] = conn_backoff[0];
+
+ //send initial SYN
+ _sendSyn(s);
+ s->pcb->retr_cnt = 0;
+
+ if(s->flags & RF_NBLK)
+ return ERUDP_AGAIN;
+
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ PA_EventWait(s->event_w);
+#else
+ PA_MutexLock(s->mutex_w);
+ while(s->state == RS_SYN_SENT)
+ pthread_cond_wait(&s->event_w, &s->mutex_w);
+ PA_MutexUnlock(s->mutex_w);
+#endif
+
+ if(s->state == RS_ESTABLISHED)
+ {
+#if 1
+ int opt = 0;
+ opt = 1500*128;
+ setsockopt(s->udp_sock, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(int));
+#endif
+
+ return 0;
+ }
+ else
+ return ERUDP_CONN_FAILED;
+}
+
+/** Set rudp socket to connected state(RS_ESTABLSHED) with default setting(receiver's buffer, ...)
+ */
+int RUDPConnected(RUDPSOCKET sock, const struct sockaddr* addr, int peer_rbuf_sz)
+{
+ struct rudp_socket *s;
+ int sa_len, opt;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->state == RS_ESTABLISHED) return ERUDP_CONNECTED;
+ if(s->state == RS_SYN_SENT) return ERUDP_IN_PROGRESS;
+ if(s->state != RS_CLOSED/* || s->pcb*/) return ERUDP_NOT_ALLOWED;
+
+
+ s->err = 0;
+ if(peer_rbuf_sz) s->rcvbuf_sz = peer_rbuf_sz;
+ if(!s->pcb) s->pcb = _AllocRudpPcb(s->rcvbuf_sz, INITIAL_SEQ_NO, 0, 1);
+ memcpy(&s->pcb->peer, addr, sizeof(struct sockaddr));
+#if 0
+ if(connect(s->udp_sock, addr, sizeof(struct sockaddr)) == 0)
+ s->connected = TRUE;
+ else
+ dbg_msg("call connect() failed.\n");
+#endif
+ sa_len = sizeof(struct sockaddr_in);
+ PA_GetSockName(s->udp_sock, (struct sockaddr*)&s->pcb->local, &sa_len);
+ //PA_MutexLock(s->mutex_w);
+ s->state = RS_ESTABLISHED;
+ SETEVENT(s->event_w);
+ //PA_MutexUnlock(s->mutex_w);
+#if 1
+ opt = 1500*128;
+ setsockopt(s->udp_sock, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(int));
+#endif
+ return 0;
+}
+
+//! \retval >=0 bytes sent
+//! \retval <0 error code
+int RUDPSendV(RUDPSOCKET sock, int chno, const PA_IOVEC *v, unsigned int size, int flags)
+{
+ struct rudp_socket *s;
+ struct sndbuf *ps;
+ unsigned int i, len, byt_sent;
+
+ len = byt_sent = 0;
+ for(i=0; i<size; i++) len += PA_IoVecGetLen(&v[i]);
+ if(len == 0) return 0;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->err) return s->err;
+ if(s->state != RS_ESTABLISHED) return ERUDP_NO_CONN;
+
+
+ ps = &s->pcb->channel[PHY_CHN(chno)].sbuf;
+ PA_MutexLock(s->mutex_w);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexLock(s->mutex_w);
+ return s->err;
+ }
+
+
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ if(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ PA_EventWait(s->event_w);
+ PA_MutexLock(s->mutex_w);
+ }
+#else
+ while(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ pthread_cond_wait(&s->event_w, &s->mutex_w);
+ }
+#endif
+ if(s->err == 0)
+ {
+ unsigned int t, copied = 0/*byte copied in an IOVEC*/;
+ struct rudp_pkt *last = ps->last;
+ i = 0;
+#if 1
+ //if last packet has the same chno, fill it
+ // <<<-- always has the same chno since we have sending-queue for each chno(20150203)
+ if(last && last->trans == 0 && last->hdr.flags.chno == chno)
+ {
+ for(; i<size && last->len < MAX_DATA_SIZE; i++)
+ {
+ t = min(PA_IoVecGetLen(&v[i]), MAX_DATA_SIZE - last->len);
+ memcpy(last->data + last->len, PA_IoVecGetPtr(&v[i]), t);
+ last->len += t;
+ byt_sent += t;
+ if(PA_IoVecGetLen(&v[i]) != t) //last packet is full, but there still are data in v[i]
+ {
+ copied = t;
+ break;
+ }
+ }
+ }
+#endif
+ while(i < size)
+ {
+ struct rudp_pkt *pkt;
+
+ pkt = _MBufGetPacket();
+ if(!pkt) break;
+
+ pkt->hdr.flags.chno = chno;
+
+ for(; i<size && pkt->len < MAX_DATA_SIZE; i++, copied = 0)
+ {
+ t = min(PA_IoVecGetLen(&v[i]) - copied, MAX_DATA_SIZE - pkt->len);
+ memcpy(pkt->data + pkt->len, (char*)PA_IoVecGetPtr(&v[i]) + copied, t);
+ pkt->len += t;
+ byt_sent += t;
+ if(PA_IoVecGetLen(&v[i]) - copied != t) //pkt is full
+ {
+ copied += t;
+ break;
+ }
+ }
+ if(pkt->len == 0)
+ {
+ _MBufPutPacket(pkt);
+ continue;
+ }
+
+ pkt->seqno = s->pcb->channel[PHY_CHN(chno)].sbuf.seqno++;
+ pkt->hdr.seqno = htonl(pkt->seqno);
+ if(ps->first)
+ {
+ ps->last->next = pkt;
+ ps->last = pkt;
+ //ps->last = ps->last->next = pkt;
+ if(!ps->not_sent) ps->not_sent = ps->last;
+ }
+ else
+ ps->first = ps->last = ps->not_sent = pkt;
+ pkt->next = NULL;
+
+ ps->n_pkt++;
+ }
+ //signalOutput(s, PHY_CHN(chno));
+ //_RudpOutput(s, PHY_CHN(chno), 0);
+ while(_RudpOutput(s, PHY_CHN(chno), 0) > 0);
+ }
+ else
+ byt_sent = s->err;
+
+ PA_MutexUnlock(s->mutex_w);
+
+ return byt_sent;
+}
+
+//! \param priority 0~15. Low value has a higher priority
+//! \retval >=0 bytes sent
+//! \retval <0 error code
+int RUDPSendVEx(RUDPSOCKET sock, int chno, int priority, const PA_IOVEC *v, unsigned int size, int flags)
+{
+ struct rudp_socket *s;
+ struct sndbuf *ps;
+ unsigned int i, len, byt_sent;
+
+ len = byt_sent = 0;
+ for(i=0; i<size; i++) len += PA_IoVecGetLen(&v[i]);
+ if(len == 0) return 0;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->err) return s->err;
+ if(s->state != RS_ESTABLISHED) return ERUDP_NO_CONN;
+
+
+ ps = &s->pcb->channel[PHY_CHN(chno)].sbuf;
+ PA_MutexLock(s->mutex_w);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexLock(s->mutex_w);
+ return s->err;
+ }
+
+
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ if(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ PA_EventWait(s->event_w);
+ PA_MutexLock(s->mutex_w);
+ }
+#else
+ while(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ pthread_cond_wait(&s->event_w, &s->mutex_w);
+ }
+#endif
+ if(s->err == 0)
+ {
+ unsigned int t, copied = 0/*byte copied in an IOVEC*/;
+ struct rudp_pkt *next_sav, *pos = ps->not_sent;
+
+ if(pos == NULL) pos = ps->last;
+ else
+ while(pos != ps->last && pos->priority <= priority)
+ pos = pos->next;
+
+ i = 0;
+ next_sav = pos->next;
+
+ //if the packet has the same priority, fill it.
+ if(pos && pos->trans == 0 && pos->hdr.flags.chno == chno && pos->priority == priority)
+ {
+ for(; i<size && pos->len < MAX_DATA_SIZE; i++)
+ {
+ t = min(PA_IoVecGetLen(&v[i]), MAX_DATA_SIZE - pos->len);
+ memcpy(pos->data + pos->len, PA_IoVecGetPtr(&v[i]), t);
+ pos->len += t;
+ byt_sent += t;
+ if(PA_IoVecGetLen(&v[i]) != t) //packet is full, but there still are data in v[i]
+ {
+ copied = t;
+ break;
+ }
+ }
+ }
+
+ while(i < size)
+ {
+ struct rudp_pkt *pkt;
+
+ pkt = _MBufGetPacket();
+ if(!pkt) break;
+
+ pkt->hdr.flags.chno = chno;
+
+ for(; i<size && pkt->len < MAX_DATA_SIZE; i++, copied = 0)
+ {
+ t = min(PA_IoVecGetLen(&v[i]) - copied, MAX_DATA_SIZE - pkt->len);
+ memcpy(pkt->data + pkt->len, (char*)PA_IoVecGetPtr(&v[i]) + copied, t);
+ pkt->len += t;
+ byt_sent += t;
+ if(PA_IoVecGetLen(&v[i]) - copied != t) //pkt is full
+ {
+ copied += t;
+ break;
+ }
+ }
+ if(pkt->len == 0)
+ {
+ _MBufPutPacket(pkt);
+ continue;
+ }
+
+ pkt->seqno = s->pcb->channel[PHY_CHN(chno)].sbuf.seqno++;
+ pkt->hdr.seqno = htonl(pkt->seqno);
+ if(ps->first)
+ {
+ pos->next = pkt;
+ pos = pkt;
+ if(!ps->not_sent) ps->not_sent = pos;
+ }
+ else
+ ps->first = ps->last = ps->not_sent = pkt;
+ pkt->next = NULL;
+
+ ps->n_pkt++;
+ }
+ pos->next = next_sav;
+
+ //signalOutput(s, PHY_CHN(chno));
+ //_RudpOutput(s, PHY_CHN(chno), 0);
+ while(_RudpOutput(s, PHY_CHN(chno), 0) > 0);
+ }
+ else
+ byt_sent = s->err;
+
+ PA_MutexUnlock(s->mutex_w);
+
+ return byt_sent;
+}
+
+int RUDPSend(RUDPSOCKET sock, int chno, const void *ptr, int len, int flags)
+{
+ struct rudp_socket *s;
+ struct sndbuf *ps;
+ int byt_sent = 0;
+
+ if(len == 0) return 0;
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->err) return s->err;
+ if(s->state != RS_ESTABLISHED) return ERUDP_NO_CONN;
+
+
+ ps = &s->pcb->channel[PHY_CHN(chno)].sbuf;
+ PA_MutexLock(s->mutex_w);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexLock(s->mutex_w);
+ return s->err;
+ }
+
+
+ /* Put a packet on the end of sending-queue then return.
+ * If the sending-queue is full, wait on this queue.
+ * The actual sending is done in the service thread.
+ */
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ while(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ PA_EventWait(s->event_w);
+ PA_MutexLock(s->mutex_w);
+ }
+#else
+ while(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ pthread_cond_wait(&s->event_w, &s->mutex_w);
+ }
+#endif
+
+ if(s->err == 0)
+ {
+ int t;
+ char *data;
+ struct rudp_pkt *last, *pkt;
+
+ data = (char*)ptr;
+ last = ps->last;
+
+ //Merge small packets with the same chno
+ if(last && last->trans == 0 && last->hdr.flags.chno == chno && last->len < MAX_DATA_SIZE)
+ {
+ t = min(len, MAX_DATA_SIZE - last->len);
+ memcpy(last->data + last->len, data, t);
+ last->len += t;
+ byt_sent += t;
+ data += t;
+ len -= t;
+ }
+
+ while(len)
+ {
+ pkt = _MBufGetPacket();
+ if(!pkt) break;
+
+ pkt->hdr.flags.chno = chno;
+
+ t = min(len, MAX_DATA_SIZE);
+ memcpy(pkt->data, data, t);
+ pkt->len = t;
+ pkt->trans = 0;
+ pkt->seqno = ps->seqno++;
+ pkt->hdr.seqno = htonl(pkt->seqno);
+ if(ps->first)
+ {
+ ps->last->next = pkt;
+ ps->last = pkt;
+ //ps->last = ps->last->next = pkt;
+ if(!ps->not_sent) ps->not_sent = ps->last;
+ }
+ else
+ ps->first = ps->last = ps->not_sent = pkt;
+ pkt->next = NULL;
+
+ ps->n_pkt++;
+ byt_sent += t;
+ len -= t;
+ }
+
+ //signalOutput(s, PHY_CHN(chno));
+ //_RudpOutput(s, PHY_CHN(chno), 0);
+ while(_RudpOutput(s, PHY_CHN(chno), 0) > 0);
+ }
+ else
+ byt_sent = s->err;
+
+ PA_MutexUnlock(s->mutex_w);
+
+ //_sendReset(s, &s->pcb->peer);
+ return byt_sent;
+}
+
+int RUDPSendEx(RUDPSOCKET sock, int chno, int priority, const void *ptr, int len, int flags)
+{
+ struct rudp_socket *s;
+ struct sndbuf *ps;
+ int byt_sent = 0;
+
+ if(len == 0) return 0;
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->err) return s->err;
+ if(s->state != RS_ESTABLISHED) return ERUDP_NO_CONN;
+
+
+ ps = &s->pcb->channel[PHY_CHN(chno)].sbuf;
+ PA_MutexLock(s->mutex_w);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexLock(s->mutex_w);
+ return s->err;
+ }
+
+
+ /* Put a packet on the end of sending-queue then return.
+ * If the sending-queue is full, wait on this queue.
+ * The actual sending is done in the service thread.
+ */
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ while(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ PA_MutexUnlock(s->mutex_w);
+ PA_EventWait(s->event_w);
+ PA_MutexLock(s->mutex_w);
+ }
+#else
+ while(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_w);
+ return ERUDP_AGAIN;
+ }
+ pthread_cond_wait(&s->event_w, &s->mutex_w);
+ }
+#endif
+
+ if(s->err == 0)
+ {
+ int t;
+ char *data;
+ struct rudp_pkt *pos, *pkt, *next_sav;
+
+ data = (char*)ptr;
+ pos = ps->not_sent;
+ while(pos && pos != ps->last && pos->priority <= priority)
+ pos = pos->next;
+
+ next_sav = pos->next;
+
+ //Merge small packets with the same chno
+ if(pos && pos->trans == 0 && pos->hdr.flags.chno == chno && pos->len < MAX_DATA_SIZE)
+ {
+ t = min(len, MAX_DATA_SIZE - pos->len);
+ memcpy(pos->data + pos->len, data, t);
+ pos->len += t;
+ byt_sent += t;
+ data += t;
+ }
+
+ while(byt_sent < len)
+ {
+ pkt = _MBufGetPacket();
+ if(!pkt) break;
+
+ pkt->hdr.flags.chno = chno;
+
+ t = min(len, MAX_DATA_SIZE);
+ memcpy(pkt->data, data, t);
+ pkt->len = t;
+ pkt->trans = 0;
+ pkt->seqno = ps->seqno++;
+ pkt->hdr.seqno = htonl(pkt->seqno);
+ if(ps->first)
+ {
+ pos->next = pkt;
+ pos = pkt;
+ if(!ps->not_sent) ps->not_sent = pos;
+ }
+ else
+ ps->first = ps->last = ps->not_sent = pkt;
+ pkt->next = NULL;
+
+ ps->n_pkt++;
+ byt_sent += t;
+ }
+
+ //signalOutput(s, PHY_CHN(chno));
+ //_RudpOutput(s, PHY_CHN(chno), 0);
+ while(_RudpOutput(s, PHY_CHN(chno), 0) > 0);
+ }
+ else
+ byt_sent = s->err;
+
+ PA_MutexUnlock(s->mutex_w);
+
+ //_sendReset(s, &s->pcb->peer);
+ return byt_sent;
+}
+/** Receive a packet
+ \param chno channel of packet[out]
+ \param flags ---
+ \return length of data received
+*/
+int RUDPRecv(RUDPSOCKET sock, int *chno, void *ptr, int len, int flags)
+{
+ struct rudp_socket *s;
+ struct rudp_pcb *pcb;
+ struct rcvbuf *prb;
+ int i, no_data;
+ int rlen;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->err && s->err != ERUDP_PEER_CLOSED) return s->err;
+ if(s->state != RS_ESTABLISHED && s->state != RS_CLOSE_WAIT) return ERUDP_NO_CONN;
+
+ pcb = s->pcb;
+ PA_MutexLock(s->mutex_r);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return s->err;
+ }
+wait_data:
+ no_data=1;
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ prb = &pcb->channel[i].rbuf;
+ if(prb->pkt_q[prb->head]) { no_data = 0; break; }
+ }
+ if(no_data)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ if(s->state == RS_CLOSE_WAIT) return 0;
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ return ERUDP_AGAIN;
+ PA_EventWait(s->event_r);
+ PA_MutexLock(s->mutex_r);
+ }
+#else
+ while(s->state == RS_ESTABLISHED)
+ {
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ prb = &pcb->channel[i].rbuf;
+ if(prb->pkt_q[prb->head]) { no_data = 0; break; }
+ }
+ if(!no_data) break;
+ if(s->state == RS_CLOSE_WAIT)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return 0;
+ }
+ if((flags & RUDPMSG_DONTWAIT) || (s->flags & RF_NBLK))
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return ERUDP_AGAIN;
+ }
+ pthread_cond_wait(&s->event_r, &s->mutex_r);
+ }
+#endif
+ if(s->err == 0)
+ {
+ rlen = 0;
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ struct rudp_pkt *pkt;
+
+ prb = &pcb->channel[i].rbuf;
+ pkt = prb->pkt_q[prb->head];
+ if(pkt)
+ {
+ if(pkt->len > len)
+ {
+ rlen = len;
+ memcpy(ptr, pkt->pdata, len);
+ pkt->len -= len;
+ pkt->pdata += len;
+ }
+ else
+ {
+ rlen = pkt->len;
+ memcpy(ptr, pkt->pdata, rlen);
+ *chno = pkt->hdr.flags.chno;
+
+ _MBufPutPacket(pkt);
+
+ prb->pkt_q[prb->head] = NULL;
+ /* "first_seq" always updates with "head",
+ * and is used to calculate the inserted posistion
+ * when a packet is received
+ */
+ prb->head = (prb->head+1)%prb->q_size;
+ prb->first_seq++;
+
+ prb->win++; /**/
+
+ if(prb->win == 1 && !prb->should_ack)
+ {
+ prb->should_ack = ACKT_OPENWND;
+ _RudpOutput(s, PHY_CHN(*chno), 0);
+ //signalOutput(s, *chno);
+ }
+ }
+ break;
+ }
+ }
+ if(rlen == 0)
+ {
+ if(s->flags & RF_NBLK)
+ rlen = -ERUDP_AGAIN;
+ else
+ goto wait_data;
+ }
+ }
+ else if(s->err == ERUDP_PEER_CLOSED)
+ rlen = 0;
+ else
+ rlen = s->err;
+ PA_MutexUnlock(s->mutex_r);
+
+ return rlen;
+}
+
+/** Receive a packet
+ \param chno channel of packet[out]
+ \param flags ---
+ \return length of data received
+*/
+int RUDPRecvChn(RUDPSOCKET sock, int *chno, void *ptr, int len, int flags)
+{
+ struct rudp_socket *s;
+ struct rudp_pcb *pcb;
+ struct rcvbuf *prb;
+ int rlen;
+
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+ if(s->err && s->err != ERUDP_PEER_CLOSED) return s->err;
+ if(s->state != RS_ESTABLISHED && s->state != RS_CLOSE_WAIT) return ERUDP_NO_CONN;
+
+ pcb = s->pcb;
+ PA_MutexLock(s->mutex_r);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return s->err;
+ }
+ prb = &pcb->channel[PHY_CHN(*chno)].rbuf;
+
+wait_data:
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ if(!prb->pkt_q[prb->head])
+ {
+ PA_MutexUnlock(s->mutex_r);
+ if(s->state == RS_CLOSE_WAIT) return 0;
+ if(s->flags & RF_NBLK) return ERUDP_AGAIN;
+ PA_EventWait(s->event_r);
+ PA_MutexLock(s->mutex_r);
+ }
+#else
+ while(s->state == RS_ESTABLISHED)
+ {
+ if(prb->pkt_q[prb->head]) break;
+
+ if(s->state == RS_CLOSE_WAIT)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return 0;
+ }
+ if(s->flags & RF_NBLK)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return ERUDP_AGAIN;
+ }
+ pthread_cond_wait(&s->event_r, &s->mutex_r);
+ }
+#endif
+ if(s->err == 0)
+ {
+ struct rudp_pkt *pkt;
+ rlen = 0;
+ pkt = prb->pkt_q[prb->head];
+ if(pkt)
+ {
+ if(pkt->len > len)
+ {
+ rlen = len;
+ memcpy(ptr, pkt->pdata, len);
+ *chno = pkt->hdr.flags.chno;
+
+ pkt->len -= len;
+ pkt->pdata += len;
+ }
+ else
+ {
+ rlen = pkt->len;
+ memcpy(ptr, pkt->pdata, rlen);
+ *chno = pkt->hdr.flags.chno;
+
+ _MBufPutPacket(pkt);
+
+ prb->pkt_q[prb->head] = NULL;
+ /* "first_seq" always updates with "head",
+ * and is used to calculate the inserted posistion
+ * when a packet is received
+ */
+ prb->head = (prb->head+1)%prb->q_size;
+ prb->first_seq++;
+
+ prb->win++; /**/
+
+ if(prb->win == 1 && !prb->should_ack)
+ {
+ prb->should_ack = ACKT_OPENWND;
+ _RudpOutput(s, PHY_CHN(*chno), 0);
+ //signalOutput(s, *chno);
+ }
+ }
+ }
+ else
+ {
+ if(s->flags & RF_NBLK)
+ rlen = -ERUDP_AGAIN;
+ else
+ goto wait_data;
+ }
+ }
+ else if(s->err == ERUDP_PEER_CLOSED)
+ rlen = 0;
+ else
+ rlen = s->err;
+ PA_MutexUnlock(s->mutex_r);
+
+ return rlen;
+}
+
+//return: <0 - failed
+// =0 - not ready
+// >0 - ready
+int RUDPSelectSock(RUDPSOCKET sock, int chno, int flag, const struct timeval *timeout)
+{
+ struct rudp_socket *s;
+#if defined(__LINUX__) || defined(__ANDROID__)
+ struct timespec ts;
+#endif
+ s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+
+#if defined(__LINUX__) || defined(__ANDROID__)
+ if(timeout)
+ {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += timeout->tv_sec;
+ ts.tv_nsec += 1000 * timeout->tv_usec;
+ if(ts.tv_nsec > 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec ++;
+ }
+ }
+#endif
+
+ if(flag == RUDPSELECT_READABLE)
+ {
+ struct rcvbuf *prb;
+ int no_data;
+ PA_MutexLock(s->mutex_r);
+ if(s->err == ERUDP_RESETED || s->err == ERUDP_PEER_CLOSED)
+ {
+ PA_MutexUnlock(s->mutex_r);
+ return 1;
+ }
+
+ no_data = 1;
+ if(no_data/* && s->state == RS_ESTABLISHED*/)
+ {
+ int i;
+ if(s->state == RS_LISTEN)
+ {
+ struct list_head *p;
+ list_for_each(p, &s->listen_queue)
+ {
+ struct rudp_socket *ss = list_entry(p, struct rudp_socket, listen_queue);
+ if(ss->state == RS_ESTABLISHED) //established socket, can be returned by RUDPAccept
+ {
+ no_data = 0;
+ break;
+ }
+ }
+ }
+ else if(s->state == RS_ESTABLISHED)
+ {
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ {
+ if(chno < 0 || chno == i)
+ {
+ prb = &s->pcb->channel[i].rbuf;
+ if(prb->pkt_q[prb->head]) { no_data = 0; break; }
+ }
+ }
+ }
+
+ if(no_data)
+ {
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ PA_MutexUnlock(s->mutex_r);
+ if(timeout)
+ no_data = !PA_EventWaitTimed(s->event_r, timeout->tv_sec*1000+timeout->tv_usec/1000);
+ else {
+ PA_EventWait(s->event_r);
+ no_data = 0;
+ }
+ PA_MutexLock(s->mutex_r);
+#else
+ if(timeout)
+ no_data = pthread_cond_timedwait(&s->event_r, &s->mutex_r, &ts) == ETIMEDOUT ? 1 : 0;
+ else
+ no_data = pthread_cond_wait(&s->event_r, &s->mutex_r) != 0;
+#endif
+ }
+ }
+
+ PA_MutexUnlock(s->mutex_r);
+ if(s->err) return s->err;
+ else return !no_data;
+ }
+
+
+ if(flag == RUDPSELECT_WRITABLE) do
+ {
+ struct sndbuf *ps;
+ int writable = 1;
+
+ if(chno < 0) return ERUDP_INVALID;
+ if(s->state != RS_ESTABLISHED) break;
+
+ PA_MutexLock(s->mutex_w);
+ if(s->state == RS_DEAD)
+ {
+ PA_MutexLock(s->mutex_w);
+ return s->err;
+ }
+
+ ps = &s->pcb->channel[chno].sbuf;
+ if(ps->n_pkt >= ps->max_pkts && s->state != RS_DEAD)
+ {
+#if defined(WIN32) || defined(ARM_UCOS_LWIP)
+ PA_MutexUnlock(s->mutex_w);
+ if(timeout)
+ writable = PA_EventWaitTimed(s->event_w, timeout->tv_sec*1000+timeout->tv_usec/1000);
+ else {
+ PA_EventWait(s->event_w);
+ writable = 1;
+ }
+ PA_MutexLock(s->mutex_w);
+#else
+ if(timeout)
+ writable = pthread_cond_timedwait(&s->event_w, &s->mutex_w, &ts) == ETIMEDOUT ? 0 : 1;
+ else
+ writable = pthread_cond_wait(&s->event_w, &s->mutex_w) == 0;
+#endif
+ }
+
+ PA_MutexUnlock(s->mutex_w);
+ if(s->err) return s->err;
+ else return writable;
+ } while(0);
+
+ return 0;
+}
+
+int RUDPSelect(RUDPSOCKCHNO *r_rscs, int *n_rrscs, RUDPSOCKCHNO *w_rscs, int *n_wrscs,
+ RUDPSOCKCHNO *e_rscs, int *n_erscs, const struct timeval *timeout)
+{
+ int i, ii, n;
+ int nr, nw, ne;
+ struct list_head *p;
+ struct rudp_socket *s, *ss;
+ unsigned int wait_ticks, t0;
+
+ struct timeval tv;
+ int _rfds[64], _wfds[64], _efds[64];
+ int _nr, _nw, _ne;
+ fd_set _rfds_, _wfds_, _efds_;
+ int max_fd = -1;
+
+ if(timeout)
+ wait_ticks = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+ else
+ wait_ticks = ~0UL;
+
+ /* Extract udp sockets */
+ _nr = _nw = _ne = 0;
+ if(r_rscs)
+ {
+ for(i=0; i<*n_rrscs; i++)
+ {
+ if(r_rscs[i].sock == NULL)
+ {
+ _rfds[_nr++] = r_rscs[i].chno;
+ max_fd = max(max_fd, r_rscs[i].chno);
+ }
+ }
+ }
+ if(w_rscs)
+ {
+ for(i=0; i<*n_wrscs; i++)
+ {
+ if(w_rscs[i].sock == NULL)
+ {
+ _wfds[_nw++] = w_rscs[i].chno;
+ max_fd = max(max_fd, w_rscs[i].chno);
+ }
+ }
+ }
+ if(e_rscs)
+ {
+ for(i=0; i<*n_erscs; i++)
+ {
+ if(e_rscs[i].sock == NULL)
+ {
+ _efds[_ne++] = e_rscs[i].chno;
+ max_fd = max(max_fd, e_rscs[i].chno);
+ }
+ }
+ }
+
+
+ nr = nw = ne = 0;
+ t0 = PA_GetTickCount();
+ do {
+ PA_MutexLock(mutex_sock_list);
+ if(r_rscs)
+ {
+ n = *n_rrscs;
+ for(i = 0; i < n; i++)
+ {
+ if(r_rscs[i].sock == NULL) continue;
+ s = (struct rudp_socket*)r_rscs[i].sock;
+ if(s->err == ERUDP_RESETED || s->err == ERUDP_PEER_CLOSED)
+ {
+ RUDP_SET(s, -1, r_rscs, nr);
+ }
+ else
+ {
+ if(s->state <= RS_CLOSED || s->state >= RS_FIN_QUEUED)
+ {
+ continue;
+ //PA_MutexUnlock(mutex_sock_list);
+ //return ERUDP_NOT_SOCKET;
+ }
+ PA_MutexLock(s->mutex_r);
+ if(s->state == RS_LISTEN)
+ {
+ list_for_each(p, &s->listen_queue)
+ {
+ ss = list_entry(p, struct rudp_socket, listen_queue);
+ if(ss->state == RS_ESTABLISHED) //established socket, can be returned by RUDPAccept
+ {
+ r_rscs[nr++].sock = s;
+ break;
+ }
+
+ }
+ }
+ else if(s->state == RS_CLOSE_WAIT)
+ {
+ RUDP_SET(s, -1, r_rscs, nr);
+ }
+ else
+ {
+ struct rcvbuf *prb;
+ for(ii=0; ii<MAX_PHY_CHANNELS; ii++)
+ {
+ if(r_rscs[i].chno < 0 || ii == r_rscs[i].chno)
+ {
+ prb = &s->pcb->channel[ii/*r_rscs[i].chno*/].rbuf;
+ if(prb->pkt_q[prb->head])
+ {
+ RUDP_SET(r_rscs[i].sock, ii, r_rscs, nr);
+ break;
+ }
+ }
+ }
+ }
+ PA_MutexUnlock(s->mutex_r);
+ }
+ }
+ if(nr) { *n_rrscs = nr; r_rscs[nr].sock = INVALID_RUDPSOCKET; }
+ }
+
+ if(w_rscs)
+ {
+ n = *n_wrscs;
+ for(i = 0; i < n; i++)
+ {
+ if(w_rscs[i].sock == NULL) continue;
+ s = (struct rudp_socket*)w_rscs[i].sock;
+ if(s->state <= RS_CLOSED || s->state >= RS_FIN_QUEUED)
+ {
+ //PA_MutexUnlock(mutex_sock_list);
+ //return ERUDP_NOT_SOCKET;
+ continue;
+ }
+ PA_MutexLock(s->mutex_w);
+ if(s->state == RS_ESTABLISHED)
+ {
+ for(ii=0; ii<MAX_PHY_CHANNELS; ii++)
+ {
+ if(w_rscs[i].chno < 0 || w_rscs[i].chno == ii)
+ {
+ struct sndbuf *psb = &s->pcb->channel[ii].sbuf;
+ if(psb->n_pkt < psb->max_pkts)
+ {
+ RUDP_SET(w_rscs[i].sock, ii, w_rscs, nw);
+ break;
+ }
+ }
+ }
+ }
+ else if(s->state == RS_CLOSE_WAIT)
+ {
+ RUDP_SET(w_rscs[i].sock, -1, w_rscs, nw);
+ }
+ PA_MutexUnlock(s->mutex_w);
+ }
+ if(nw) { *n_wrscs = nw; w_rscs[nw].sock = INVALID_RUDPSOCKET; }
+ }
+ if(e_rscs)
+ {
+ for(i=0; i<*n_erscs; i++)
+ {
+ if(e_rscs[i].sock == NULL) continue;
+ s = (struct rudp_socket*)e_rscs[i].sock;
+ if(s->err) RUDP_SET(s, -1, e_rscs, ne);
+ }
+ if(ne) { *n_erscs = ne; e_rscs[ne].sock = INVALID_RUDPSOCKET; }
+ }
+ PA_MutexUnlock(mutex_sock_list);
+
+ //if(nr || nw || ne) break; //normal socket will be starved
+ if(_nr || _nw || _ne)
+ {
+ tv.tv_sec = 0; tv.tv_usec = 0;
+ if(_nr) { FD_ZERO(&_rfds_); for(i=0; i<_nr; i++) FD_SET(_rfds[i], &_rfds_); }
+ if(_nw) { FD_ZERO(&_wfds_); for(i=0; i<_nw; i++) FD_SET(_wfds[i], &_wfds_); }
+ if(_ne) { FD_ZERO(&_efds_); for(i=0; i<_ne; i++) FD_SET(_efds[i], &_efds_); }
+ if(select(max_fd+1, _nr?&_rfds_:NULL, _nw?&_wfds_:NULL, _ne?&_efds_:NULL, &tv) > 0)
+ {
+ if(_nr) for(i=0; i<_nr; i++)
+ if(FD_ISSET(_rfds[i], &_rfds_))
+ {
+ r_rscs[nr].sock = NULL;
+ r_rscs[nr++].chno = _rfds[i];
+ }
+ if(_nw) for(i=0; i<_nw; i++)
+ if(FD_ISSET(_wfds[i], &_wfds_))
+ {
+ w_rscs[nw].sock = NULL;
+ w_rscs[nw++].chno = _wfds[i];
+ }
+ if(_ne) for(i=0; i<_ne; i++)
+ if(FD_ISSET(_efds[i], &_efds_))
+ {
+ e_rscs[ne].sock = NULL;
+ e_rscs[ne++].chno = _efds[i];
+ }
+ }
+ }
+
+ if(nr || nw || ne) break;
+ PA_Sleep(5);
+ } while(PA_GetTickCount() - t0 < wait_ticks);
+
+ if(n_erscs) *n_erscs = ne;
+ if(n_rrscs) *n_rrscs = nr;
+ if(n_wrscs) *n_wrscs = nw;
+
+ return nr + nw + ne;
+}
+
+int RUDP_FD_ISSET(int fd, const RUDPSOCKCHNO *prc, int size)
+{
+ int i;
+ if(fd < 0) return 0;
+ for(i=0; i<size; i++)
+ {
+ if(prc[i].sock == NULL && prc[i].chno == fd) return 1;
+ }
+ return 0;
+}
+
+int RUDP_ISSET(RUDPSOCKET s, const RUDPSOCKCHNO *prc, int size)
+{
+ int i;
+ if(s == INVALID_RUDPSOCKET) return 0;
+ for(i=0; i<size; i++)
+ {
+ if(prc[i].sock == s) return 1;
+ }
+ return 0;
+}
+
+int RUDPGetSockOpt(RUDPSOCKET sock, int opt, void *optval, int *optlen)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+ switch(opt)
+ {
+ case OPT_UDP_SNDBUF:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ PA_GetSockOpt(s->udp_sock, SOL_SOCKET, SO_SNDBUF, (char*)&opt, optlen);
+ return 0;
+ case OPT_UDP_RCVBUF:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ PA_GetSockOpt(s->udp_sock, SOL_SOCKET, SO_RCVBUF, (char*)&opt, optlen);
+ return 0;
+ case OPT_RUDP_SNDBUF:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ *((int*)optval) = s->pcb->channel[0].sbuf.max_pkts;
+ break;
+ case OPT_RUDP_RCVBUF:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ *((int*)optval) = s->pcb->channel[0].rbuf.q_size;
+ break;
+ case OPT_LINGER:
+ //case OPT_MSS:
+ case OPT_SNDTIMEO:
+ case OPT_RCVTIMEO:
+ break;
+ case OPT_ADHOC:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ *((int*)optval) = (s->flags & RF_ADHOC)?1:0;
+ break;
+
+ case OPT_NBLK:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ *((int*)optval) = (s->flags & RF_NBLK)?1:0;
+ break;
+
+ case OPT_REUSEADDR:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ PA_GetSockOpt(s->udp_sock, SOL_SOCKET, SO_REUSEADDR, (char*)optval, optlen);
+ break;
+ case OPT_ERR:
+ if(*optlen != sizeof(int)) return ERUDP_INVALID;
+ *((int*)optval) = s->err;
+
+ default:
+ return ERUDP_INVALID;
+ }
+ return 0;
+}
+
+int RUDPSetSockOpt(RUDPSOCKET sock, int opt, const void *optval, int optlen)
+{
+ int i, val;
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->tag != RUDP_SOCKET_TAG) return ERUDP_NOT_SOCKET;
+
+ switch(opt)
+ {
+ case OPT_UDP_SNDBUF:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ setsockopt(s->udp_sock, SOL_SOCKET, SO_SNDBUF, (char*)&opt, optlen);
+ break;
+ case OPT_UDP_RCVBUF:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ setsockopt(s->udp_sock, SOL_SOCKET, SO_RCVBUF, (char*)&opt, optlen);
+ break;
+ case OPT_RUDP_SNDBUF:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ if(s->pcb)
+ {
+ val = *((int*)optval);
+ if(val > MAX_WINDOW) val = MAX_WINDOW;
+ if(val < 64) val = 64;
+ for(i=0; i<MAX_PHY_CHANNELS; i++)
+ s->pcb->channel[i].sbuf.max_pkts = val;
+ }
+ break;
+ case OPT_RUDP_RCVBUF:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ if(!s->pcb && s->state == RS_CLOSED)
+ {
+ val = *((int*)optval);
+ if(val > MAX_WINDOW) val = MAX_WINDOW;
+ if(val < 64) val = 64;
+ s->rcvbuf_sz = val;
+ }
+ break;
+ case OPT_LINGER:
+ //case OPT_MSS:
+ case OPT_SNDTIMEO:
+ case OPT_RCVTIMEO:
+ break;
+ case OPT_ADHOC:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ if(s->state != RS_CLOSED || s->pcb) return ERUDP_NOT_ALLOWED;
+ if(*((int*)optval)) s->flags |= RF_ADHOC;
+ else s->flags &= ~RF_ADHOC;
+
+ case OPT_REUSEADDR:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ setsockopt(s->udp_sock, SOL_SOCKET, SO_REUSEADDR, (char*)optval, optlen);
+ break;
+
+ case OPT_NBLK:
+ if(optlen != sizeof(int)) return ERUDP_INVALID;
+ if(s->state < RS_CLOSED) return ERUDP_NOT_ALLOWED;
+ if(*((int*)optval)) s->flags |= RF_NBLK;
+ else s->flags &= ~RF_NBLK;
+ break;
+
+ default:
+ return ERUDP_INVALID;
+ }
+ return 0;
+}
+
+int RUDPGetSockName(RUDPSOCKET sock, struct sockaddr *name)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ socklen_t len = sizeof(struct sockaddr);
+ return getsockname(s->udp_sock, name, &len);
+}
+
+int RUDPGetPeerName(RUDPSOCKET sock, struct sockaddr *name)
+{
+ struct rudp_socket *s = (struct rudp_socket*)sock;
+ if(s->pcb)
+ {
+ memcpy(name, &s->pcb->peer, sizeof(struct sockaddr));
+ return 0;
+ }
+ memset(name, 0, sizeof(struct sockaddr));
+ return 0;
+}
+
--- /dev/null
+#ifndef __rudp_h__
+#define __rudp_h__
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+#include "platform_adpt.h"
+
+typedef void* RUDPSOCKET;
+#define INVALID_RUDPSOCKET NULL
+/*
+typedef struct _tagIOVEC {
+ void *iov_base;
+ unsigned int iov_len;
+} IOVEC;
+*/
+/*
+ * Errors
+ */
+#define ERUDP_FIRST -10000
+#define ERUDP_NOT_SOCKET (ERUDP_FIRST-1)
+#define ERUDP_NOT_ALLOWED (ERUDP_FIRST-2)
+#define ERUDP_CONN_FAILED (ERUDP_FIRST-3)
+#define ERUDP_CONNECTED (ERUDP_FIRST-4)
+#define ERUDP_IN_PROGRESS (ERUDP_FIRST-5)
+#define ERUDP_NO_CONN (ERUDP_FIRST-6)
+#define ERUDP_BIND (ERUDP_FIRST-7)
+#define ERUDP_RESETED (ERUDP_FIRST-8)
+#define ERUDP_TIMEOUTED (ERUDP_FIRST-9)
+#define ERUDP_INVALID (ERUDP_FIRST-10)
+#define ERUDP_PEER_CLOSED (ERUDP_FIRST-11) //normal close
+#define ERUDP_AGAIN (ERUDP_FIRST-12)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*NONRUDPPACKETCB)(const uint8_t *buff, int len, void *p_user);
+
+int RUDPStart();
+int RUDPCleanup();
+
+RUDPSOCKET RUDPSocket();
+RUDPSOCKET RUDPSocketFromUdp(int udpsock);
+int RUDPSetInvalidPacketCB(RUDPSOCKET, NONRUDPPACKETCB pkt_cb, void *p_user);
+int RUDPClose(RUDPSOCKET sock);
+
+int RUDPListen(RUDPSOCKET sock, int n);
+int RUDPAccept(RUDPSOCKET sock, /*OUT*/RUDPSOCKET *accepted, struct sockaddr *addr, int *addrlen);
+int RUDPBind(RUDPSOCKET sock, const struct sockaddr *addr, int addrlen);
+int RUDPConnect(RUDPSOCKET sock, const struct sockaddr* addr, int addr_len);
+
+// Set rudp socket to connected state(RS_ESTABLSHED) with default setting(receiver's buffer, ...)
+// peer_rbuf_sz: size of peer's rbuff
+int RUDPConnected(RUDPSOCKET sock, const struct sockaddr* addr, int peer_rbuf_sz);
+
+#define RUDPMSG_DONTWAIT 0x0001
+//flags: 0 or RUDPMSG_xxx
+int RUDPRecv(RUDPSOCKET sock, /*OUT*/int *chno, void *ptr, int len, int flags);
+int RUDPRecvChn(RUDPSOCKET sock, int *chno, void *ptr, int len, int flags);
+int RUDPSend(RUDPSOCKET sock, int chno, const void *ptr, int len, int flags);
+int RUDPSendEx(RUDPSOCKET sock, int chno, int priority, const void *ptr, int len, int flags);
+int RUDPSendV(RUDPSOCKET sock, int chno, const PA_IOVEC *v, unsigned int size, int flags);
+int RUDPSendVEx(RUDPSOCKET sock, int chno, int priority, const PA_IOVEC *v, unsigned int size, int flags);
+
+
+#define OPT_UDP_SNDBUF 1
+#define OPT_UDP_RCVBUF 2
+#define OPT_RUDP_SNDBUF 3 //called after connection
+#define OPT_RUDP_RCVBUF 4 //called before connection
+#define OPT_LINGER 5
+#define OPT_FC 6
+#define OPT_MSS 7
+#define OPT_SNDTIMEO 11
+#define OPT_RCVTIMEO 12
+#define OPT_REUSEADDR 13 //default: 1
+#define OPT_ADHOC 14 //simultaneously connect ?
+#define OPT_NBLK 15
+#define OPT_ERR 16 //get error
+int RUDPGetSockOpt(RUDPSOCKET sock, int opt, void *optval, int *optlen);
+int RUDPSetSockOpt(RUDPSOCKET sock, int opt, const void *optval, int optlen);
+
+#define RUDPSELECT_READABLE 0x01
+#define RUDPSELECT_WRITABLE 0x02
+//#define RUDPSELECT_ERROR 0x04
+int RUDPSelectSock(RUDPSOCKET sock, int chno, int flag/*one of RUDPSELECT_xxx*/, const struct timeval *timeout);
+//return: >0 - condition is yes
+// =0 - negative
+// <0 - error
+
+typedef
+struct _tagSelectChn {
+ RUDPSOCKET sock; //NULL for system socket
+ int chno; //system socket, or chno for rudp socket
+} RUDPSOCKCHNO;
+//All parameters except timeout are for INOUT
+int RUDPSelect(RUDPSOCKCHNO *r_rcs, int *n_rrc, RUDPSOCKCHNO *w_rcs, int *n_wrc, RUDPSOCKCHNO *e_rcs, int *n_erc, const struct timeval *timeout);
+
+#define RUDP_FD_SET(fd, prc, size) \
+ do { prc[size].sock = NULL; prc[size++].chno = fd; }while(0)
+#define RUDP_SET(s, chn, prc, size) \
+ do { prc[size].sock = s; prc[size++].chno = chn; }while(0)
+#define RUDP_CLR(s, chn, prc, size) \
+ do { int i; for(i=0; i<size; i++) \
+ if(prc[i].sock == s && prc[i].chno == chn) break; \
+ if(i < size) { while(i<size-1) prc[i] = prc[i+1]; size--; } \
+ } while(0)
+
+int RUDP_FD_ISSET(int fd, const RUDPSOCKCHNO *prc, int size);
+int RUDP_ISSET(RUDPSOCKET s, const RUDPSOCKCHNO *prc, int size);
+
+int RUDPGetSockName(RUDPSOCKET sock, struct sockaddr *name);
+int RUDPGetPeerName(RUDPSOCKET sock, struct sockaddr *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+#ifndef __rudp_imp_h__
+#define __rudp_imp_h__
+
+#include "basetype.h"
+#include "linux_list.h"
+#include "platform_adpt.h"
+
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#define RUDP_HEADER_TAG 3
+#define MAX_LOSS_REPORT 63 //6 bits
+#define MAX_WINDOW 4095 //12 bits
+
+//rudp packet header: 16 bytes
+struct rudp_hdr {
+ union {
+ uint32_t u32_flags;
+ /*
+ struct {
+ uint8_t tag;
+ uint8_t flags;
+ uint8_t window;
+ uint8_t chno;
+ } u8_flags;
+ */
+ struct {
+ //little endian
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t chno:8;
+ uint32_t window:12;
+ uint32_t n_loss:6; //number of lost packets from "ackno". all packets before ackno are confirmed
+ uint32_t ack:1; //0: no ack; 1: accumulated ack
+ uint32_t rst:1;
+ uint32_t fin:1;
+ uint32_t syn:1;
+ uint32_t rudp:2; //RUDP_HEADER_TAG
+#else
+ uint32_t rudp:2;
+ uint32_t syn:1;
+ uint32_t fin:1;
+ uint32_t rst:1;
+ uint32_t ack:1;
+ uint32_t n_loss:6;
+ uint32_t window:12; //counted by packages
+ uint32_t chno:8;
+#endif
+
+ } flags;
+ };
+
+ uint32_t seqno; //
+ uint32_t ackno; //Ackknowlage all packets BEFORE "ackno". !!!
+
+ uint32_t crc32; //crc32 for header
+};
+#define PHY_HDR_CHN(hdr) (hdr.flags.chno&1)
+#define PHY_CHN(chno) ((chno)&1)
+
+//for 8bits window value
+#define WINDOW_NTOH(window) window
+#define WINDOW_HTON(window) window
+//for 16bits window value
+//#define WINDOW_NTOH(window) ntohs(window)
+//#define WINDOW_HTON(window) htons(window)
+
+
+//1456 = 1492(IEEE802.2) - 20(Ethernet) - 8(UDP) - 8(PPPoE) - ?
+#define MAX_PACKET_SIZE 1448
+#define MAX_DATA_SIZE (MAX_PACKET_SIZE-sizeof(struct rudp_hdr))
+struct rudp_pkt {
+ struct rudp_pkt *next;
+
+ //data for sending
+ uint32_t seqno; //=ntohl(hdr.seqno), for quick reference
+ unsigned int ts; //timestamp when sending
+
+ int trans; //transmission count
+ int priority;
+
+ int len; //length of data, exclude hdr
+ unsigned char *pdata; //=data by default, move ahead when RUDPRecv is called and partial data in this packet are read out
+ //-----------------
+ struct rudp_hdr hdr;
+ unsigned char data[MAX_DATA_SIZE];
+};
+
+
+typedef enum {
+ RS_DEAD = -1, //all resources except the pointer to rudp_socket itself are freed, only RUDPClose() is allowed
+ RS_CLOSED = 0, //initally created or accepted
+ RS_LISTEN,
+ RS_SYN_SENT,
+ RS_SYN_RCVD,
+ RS_ESTABLISHED,
+ RS_CLOSE_WAIT,
+ RS_FIN_QUEUED,
+ RS_FIN_WAIT_1,
+ RS_FIN_WAIT_2,
+ RS_CLOSING,
+ RS_TIME_WAIT
+} RUDPSTATE;
+
+//----------------------------------------------
+//
+// 500ms TIMERs Used in RUDP PCB
+//
+// RT_xxx are for socket, RCT_xxx are for channel
+//
+#define RT_KEEP 0
+#define RT_2MSL 1
+#define RT_CNT 2
+
+#define RCT_PERSIST 0
+#define RCT_REXMT 1
+#define RCT_CNT 2
+
+#define RUDPT_RANGESET(tv, value, tvmin, tvmax) { \
+ (tv) = (value); \
+ if ((tv) < (tvmin)) \
+ (tv) = (tvmin); \
+ else if ((tv) > (tvmax)) \
+ (tv) = (tvmax); \
+}
+
+#define RTV_KEEP_INIT 15
+#define RTV_REXMTMIN 2
+#define RTV_REXMTMAX 128
+#define RTV_PERSMIN 10
+#define RTV_PERSMAX 120
+#define RTV_KEEP_CLOSE 5
+//----------------------------------------------
+
+
+#define SEQ_LT(a,b) ((int)((a) - (b)) < 0)
+#define SEQ_LE(a,b) ((int)((a) - (b)) <= 0)
+#define SEQ_GT(a,b) ((int)((a) - (b)) > 0)
+#define SEQ_GE(a,b) ((int)((a) - (b)) >= 0)
+
+
+/* Buffer size of RUDP.
+ *
+ * One have to respect to the UDP buffer
+ * size (SO_SNDBUF, SO_RCVBUF)
+ */
+#define DEFAULT_SNDBUF_SIZE 128
+#define DEFAULT_RCVBUF_SIZE 128
+struct sndbuf {
+ uint32_t seqno;
+ int max_pkts; //OPT_RCVBUF
+ int n_pkt; /*packets in queue*/
+ int n_unacked;
+ struct rudp_pkt *first, *last;
+ struct rudp_pkt *not_sent; //first unsent packet
+ struct rudp_pkt *rexmt; //fast retransmit
+
+
+ int rawnd; //receiver's advertised window in ack
+ int rwnd; //keeping counted receiver's window, updated as packet is sent or ack is received
+
+ int rlost; //receiver reports how many packets are expected to be re-transmitted
+
+
+ /* counter for continuously duplicated acks,
+ * fast-retransmission starts when reach 3
+ */
+ int dup_ack;
+ uint32_t fastretr_end_seq; //fast re-transmission stop untill this seqno
+
+ // RTT measurement
+ int stop_rttm; //stop rtt measurement
+ struct rudp_pkt *pkt_rttm_start; //rtt measurement resumes from pkt_rttm_start after any re-transmissions
+};
+
+struct rcvbuf {
+ uint32_t first_seq; //first seq in queue. this seq is pointed by "head"
+ uint32_t expected_seqno; //expected seqno
+ uint32_t acked_seqno; //ACK is sent when delay-time(DELAYED_MS) passed, or at most N(=3?) packets(or N*MSS bytes) received.
+ int should_ack; //new packet arrived, should send ack
+ int n_lost; //size of first gap(probably lost)
+
+ int q_size; //OPT_SNBUF
+ struct rudp_pkt **pkt_q; //size = q_size. A cycle buffer traced by head/tail
+ int head; //first packet or first lost packet in buffer
+ int loss; //first lost packet, or "tail"
+ int tail; //one after the packet with max seqno
+ int win; //receiver's window (q_size + head - tail - 1) % q_size, send in every output packet and ACK
+
+ /* queue for channels */
+};
+
+struct rudp_channel {
+ int timer[RCT_CNT];
+ int congested;
+ struct sndbuf sbuf;
+ struct rcvbuf rbuf;
+};
+
+
+#define MAX_PHY_CHANNELS 2
+#define MAX_LOG_CHANNELS 128
+struct rudp_pcb {
+ struct sockaddr_in local;
+ struct sockaddr_in peer;
+
+ /* Congestion Control */
+ /* ca_cnt: congestion avoidance counter.
+ * In the progress of congestion avoidance, plus 1
+ * when each ACK arrives, when "ca_cnt" reach "cwnd",
+ * reset "ca_cnt" and increase "cwnd" by one.
+ */
+ int ca_cnt;
+ int cwnd; //congestion window
+ int ssthresh; //slow start threshold
+
+
+ /* RTO */
+ int srtt; //smoothed RTT
+ int sdev; //smoothed deviation, or "rttvar"
+ int rto; //retransmission timeout
+
+
+ int rwin_size; //receiver's win size. keep unchanged after connection is established
+ int rtw_size; //receiver's realtime win size
+ struct rudp_channel channel[MAX_PHY_CHANNELS];
+
+
+ int retr_cnt; // Count of SYN or SYN&ACK sent when connection establishment
+};
+
+struct rudp_socket;
+typedef void (*_NONRUDPPACKETCB)(const uint8_t *buff, int len, void *p_user);
+
+#define RUDP_SOCKET_TAG 0x50445552 //'RUDP'
+#define RF_ADHOC 0x00000001
+#define RF_NBLK 0x00000002
+struct rudp_socket {
+ unsigned int tag; //'RUDP'
+
+ /* rudp_socket created by RUDPSocket/RUDPBindUdpSocket are
+ * linked with the inst_list chain(pointed by a global list header)
+ */
+ struct list_head inst_list;
+
+ /* rudp_socket return by RUDPAccept are linked to the listening socket's accepted_list.
+ *
+ * If the listening socket is closed, the first accepted socket take place of
+ * the listening socket(move into the inst_list chain).
+ *
+ * "udp_sock" is shared by the sockets in the accepted_list chain, it is closed
+ * only when accepted_list is empty.
+ */
+ struct list_head accepted_list;
+
+ /* sockets not accepted by RUDPAccept(...) are placed in a seperated chain,
+ * it's easy to be found when accepted and when the listening socket is closing
+ */
+ struct list_head listen_queue;
+
+
+ int udp_sock;
+ BOOL connected; //called connect() on udp socket(client socket only)
+
+ int state; //RUDPSTATE, refer to TCP's FSM
+ int timer[RT_CNT];
+
+ struct rudp_pcb *pcb; //for
+
+ PA_MUTEX mutex_r, mutex_w;
+#ifdef WIN32
+ HANDLE event_r, event_w;
+#else
+ pthread_cond_t event_r, event_w;
+#endif
+ int flags;
+
+ int rcvbuf_sz; //size of recv buffer, change before connection. OPT_RUDP_RCVBUF
+
+
+ int err;
+
+ //------------
+ _NONRUDPPACKETCB non_rudp_pkt_cb;
+ void *p_user;
+};
+
+#endif
+
--- /dev/null
+#include <string.h>
+#include "rudp_punch.h"
+
+/*
+ * \param local_port
+ * Local port the socket will bind to(but not listen on).
+ * \param listening_peer
+ * The address the other side listening on, may be NULL.
+ * \param candidate_peers, n_peer
+ * The possible addresses the other side can be reached by.
+ */
+RUDPSOCKET RUDPPunch(unsigned short local_port,
+ const struct sockaddr *listening_peer,
+ const struct sockaddr_in *candidate_peers, int n_peer,
+ CHECKCONNECTIONCB cb, void *cb_data)
+{
+#define MAX_CANDIDATES 10
+ RUDPSOCKET rsock_c = INVALID_RUDPSOCKET, rsocks[MAX_CANDIDATES];
+ RUDPSOCKCHNO rset[MAX_CANDIDATES], wset[MAX_CANDIDATES], eset[MAX_CANDIDATES];
+ int n_rset, n_wset, n_eset, nr, nw, ne;
+ struct timeval tv;
+ struct sockaddr_in sai;
+ int i, opt;
+
+ if(n_peer > 9) n_peer = 9;
+ if(listening_peer) n_peer++;
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(local_port);
+ opt = 1;
+ n_rset = n_wset = n_eset = 0;
+ for(i=0; i<n_peer; i++)
+ {
+ rsocks[i] = RUDPSocket();
+ RUDPSetSockOpt(rsocks[i], OPT_REUSEADDR, &opt, sizeof(int));
+ if(RUDPBind(rsocks[i], (struct sockaddr*)&sai, sizeof(sai)) != 0)
+ {
+ dbg_msg("RUDPBind failed.\n");
+ }
+ RUDPSetSockOpt(rsocks[i], OPT_NBLK, &opt, sizeof(int));
+ if(i==n_peer-1 && listening_peer)
+ {
+ RUDPConnect(rsocks[i], listening_peer, sizeof(struct sockaddr));
+ rsock_c = rsocks[i];
+ }
+ else
+ RUDPConnect(rsocks[i], (const struct sockaddr*)&candidate_peers[i], sizeof(struct sockaddr));
+
+ RUDP_SET(rsocks[i], -1, eset, n_eset);
+ RUDP_SET(rsocks[i], -1, rset, n_rset);
+ }
+
+
+ tv.tv_sec = 1; tv.tv_usec = 0;
+ time_t t0 = time(NULL);
+ do {
+
+ nr = n_rset; nw = n_wset; ne = n_eset;
+ if(RUDPSelect(rset, &nr, wset, &nw, eset, &ne, &tv) <= 0)
+ continue;
+
+ for(i=0; i<n_peer; i++)
+ if(rsocks[i] != INVALID_RUDPSOCKET && RUDP_ISSET(rsocks[i], rset, nr)) //data arrived
+ {
+ switch(cb(rsocks[i], CONNSTATUS_READABLE, cb_data))
+ {
+ case CHECKCONNECTION_OK:
+ rsock_c = rsocks[i];
+ rsocks[i] = INVALID_RUDPSOCKET;
+ goto out;
+
+ case CHECKCONNECTION_FAKE:
+ RUDPClose(rsocks[i]);
+ rsocks[i] = INVALID_RUDPSOCKET;
+ break;
+ }
+ }
+
+ for(i=0; i<n_peer; i++)
+ if(rsocks[i] != INVALID_RUDPSOCKET && RUDP_ISSET(rsocks[i], wset, nw)) //connected
+ {
+ switch(cb(rsocks[i], (i==n_peer-1)&&listening_peer?CONNSTATUS_ACCEPTED:CONNSTATUS_CONNECTED, cb_data))
+ {
+ case CHECKCONNECTION_OK:
+ rsock_c = rsocks[i];
+ rsocks[i] = INVALID_RUDPSOCKET;
+ goto out;
+
+ case CHECKCONNECTION_CONTINUE:
+ RUDP_SET(rsocks[i], 0, rset, n_rset);
+ RUDP_CLR(rsocks[i], 0, wset, n_wset);
+ break;
+
+ case CHECKCONNECTION_FAKE:
+ RUDPClose(rsocks[i]);
+ rsocks[i] = INVALID_RUDPSOCKET;
+ break;
+ }
+ }
+
+ for(i=0; i<n_peer; i++)
+ if(rsocks[i] != INVALID_RUDPSOCKET && RUDP_ISSET(rsocks[i], eset, ne))
+ {
+ if(i==n_peer-1 && listening_peer)
+ {
+ RUDPConnect(rsocks[i], listening_peer, sizeof(struct sockaddr));
+ }
+ else
+ RUDPConnect(rsocks[i], (const struct sockaddr*)&candidate_peers[i], sizeof(struct sockaddr));
+ }
+
+ } while(time(NULL) - t0 < 8);
+
+out:
+ for(i=0; i<n_peer; i++)
+ if(rsocks[i] != INVALID_RUDPSOCKET)
+ RUDPClose(rsocks[i]);
+ return rsock_c;
+}
+
+int _ClientPunchCb(RUDPSOCKET s, int status, void *data)
+{
+ int len, chno;
+ struct dcs_punch dp;
+
+ switch(status)
+ {
+ case CONNSTATUS_CONNECTED:
+ case CONNSTATUS_ACCEPTED:
+ if(RUDPSend(s, (char*)data, sizeof(struct dcs_header) + ntohl(((struct dcs_header*)data)->length), 0) < 0)
+ break;
+ return CHECKCONNECTION_CONTINUE;
+
+ case CONNSTATUS_READABLE:
+ len = RUDPRecv(s, &chno, &dp, sizeof(dp));
+ if(len >= sizeof(struct dcs_header) && check_dcs_header(&dp.dh) && dp.dh.cls == CLS_RESPONSE && dp.dh.st == ST_IPCAM)
+ return(dp.dh.status == 0)?CHECKCONNECTION_OK:-dp.dh.status;
+ else
+ return -1000;
+ break;
+ }
+
+ return CHECKCONNECTION_CONTINUE;
+}
+
+int _CameraPunchCb(RUDPSOCKET s, int status, void *data)
+{
+ int len;
+ struct dcs_punch dp;
+ switch(status)
+ {
+ case CONNSTATUS_CONNECTED:
+ ;//if this is client, send confirmation
+ break;
+ case CONNSTATUS_ACCEPTED:
+ ;//send confirmation
+ break;
+ case CONNSTATUS_READABLE:
+ len = RUDPRecv(s, &chno, &dp, sizeof(dp));
+ if(len >= sizeof(struct dcs_header) && check_dcs_header(&dp.dh) && dp.dh.cls == CLS_REQUEST && dp.dh.st == ST_CLT)
+ {
+ ;//check session and password
+ }
+ break;
+ }
+
+ return CHECKCONNECTION_CONTINUE;
+}
+
+
+int main()
+{
+ return 0;
+}
+
--- /dev/null
+#ifndef __rudp_punch_h__
+#define __rudp_punch_h__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rudp.h"
+#include "platform_adpt.h"
+
+#define CONNSTATUS_CONNECTED 1 //connection is established
+#define CONNSTATUS_ACCEPTED 2 //connection is accepted by server
+#define CONNSTATUS_READABLE 3 //data arrived from peer
+
+#define CHECKCONNECTION_OK 0
+#define CHECKCONNECTION_CONTINUE 1
+#define CHECKCONNECTION_FAKE 2
+#define CHECKCONNECTION_RESETED 3
+#define CHECKCONNECTION_
+typedef int (*CHECKCONNECTIONCB)(RUDPSOCKET sock, int status, void *data);
+
+/*
+ * \param local_port
+ * Local port the socket will bind to(but not listen on).
+ * \param listening_peer
+ * The address the other side listening on, may be NULL.
+ * \param candidate_peers, n_peer
+ * The possible addresses the other side can be reached by.
+ */
+//说明:
+// 连接建立时,以 ACCEPTED(连接为对方Listening状态的套接字接受) 或 CONNECTED(Simultaneous connection成功)
+// 为 status 参数调用cb。
+// 对ACCEPTED的连接,cb应向对端发送事务标识,以区分此连接所属的事务(或会话).当此连接绑定传话后,接下来进入连接确认阶段.
+// 对CONNECTED的连接,要进行连接确认。
+//
+// 因为穿透过程会同时发起多个连接,而最终只会选择一个成功连接。所以连接建立后要经双方确认, 然后才会关闭其它连接(过程),穿透过程中止。
+//
+// 确认阶段,其中一方选择一个(如最先建立的)连接,向另一方发送确认命令,确认后,双方关闭其它连接,使用确认的连接通信
+//
+// cb返回OK,则连接得到确认,函数返回该连接;返回CONTINUE,则继续确认过程;返回其他值该连接并关闭。
+// 当连接双方需要交换一些信息确认有效性时,cb向对端发送一些数据并返回 CHECKCONNECTION_CONTINUE。当对端应答到来时,
+// 用status=SOCK_STATUS_READABLE再次调用cb
+//
+RUDPSOCKET RUDPPunch(unsigned short local_port,
+ const struct sockaddr *listening_peer,
+ const struct sockaddr_in *candidate_peers, int n_peer,
+ CHECKCONNECTIONCB cb, void *cb_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+#include "rudp.h"
+#include "platform_adpt.h"
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+int g_quit = 0;
+int async = 0;
+void sig_handler(int sig)
+{
+ if(sig == SIGINT || sig == SIGTERM)
+ {
+ g_quit = 1;
+ }
+}
+
+int sendData(RUDPSOCKET s)
+{
+ char line[3000];
+ int i=0, rlt = 0;
+ memset(line, '1' + i%36, 3000);
+
+ time_t t0, t_prev, t;
+ unsigned long nTotal = 0, nByt = 0;
+ t0 = t_prev = time(NULL);
+ for(i=0; 0<50000 && !g_quit; i++)
+ {
+ PA_IOVEC v[3];
+ PA_IoVecSetPtr(&v[0], line);
+ PA_IoVecSetPtr(&v[1], line);
+ PA_IoVecSetPtr(&v[2], line);
+ PA_IoVecSetLen(&v[0], 230);
+ PA_IoVecSetLen(&v[1], 1100);
+ PA_IoVecSetLen(&v[2], 100);
+
+ if( (i % 100) == 0)
+ {
+ rlt = RUDPSendV(s, 0, v, 3, 0);
+ }
+ else
+ rlt = RUDPSendV(s, 0/*1*/, v, 3, 0);
+ if(rlt < 0)
+ {
+ if(rlt == ERUDP_AGAIN)
+ {
+ //usleep(10);
+ continue;
+ }
+ printf("RUDPSend error: %d\n", rlt);
+ break;
+ }
+
+ int onesent = PA_IoVecGetLen(&v[0]) + PA_IoVecGetLen(&v[1]) + PA_IoVecGetLen(&v[2]);
+ nTotal += onesent;
+ nByt += onesent;
+
+ time(&t);
+ if(t != t_prev)
+ {
+ fprintf(stderr, "rate: Avg.: %d B/s, Rt. %d B/s \r", nTotal/(t-t0), nByt);
+ fflush(stderr);
+ t_prev = t;
+ nByt = 0;
+ }
+ }
+
+ printf("***************************************\n");
+ if(rlt > 0)
+ {
+ line[0] = '\0';
+ RUDPSend(s, 0, line, 1, 0);
+ printf("all data sent.\n");
+ }
+ return 0;
+}
+
+void recvData(RUDPSOCKET a)
+{
+ int cnt = 0;
+ char line[2100];
+ int len, chno;
+ while( !g_quit )
+ {
+ struct timeval tv = { 0, 500000 };
+ int flag = RUDPSELECT_READABLE, rlt;
+ if( (rlt = RUDPSelectSock(a, -1, flag, &tv)) > 0)
+ {
+ if((len = RUDPRecv(a, &chno, line, 2000, 0)) > 0)
+ {
+ if(chno == 0)
+ {
+ //fprintf(stderr, "Packet %d from chn 0\n", cnt);
+ }
+ cnt++;
+ line[len] = '\0';
+ //printf("%s\n", line);
+ if(line[0] == '\0') break;
+ }
+ else if(len < 0)
+ {
+ if(len == ERUDP_AGAIN)
+ {
+ //usleep(10);
+ continue;
+ }
+ fprintf(stderr, "RUDPRecv: %d\n", len);
+ exit(-1);
+ }
+ }
+ else if(rlt < 0)
+ {
+ if(rlt == ERUDP_AGAIN)
+ {
+ //usleep(10);
+ continue;
+ }
+ printf("ERROR: RUDPSelectSock: %d\n", rlt);
+ exit(-1);
+ }
+ }
+ printf("receiving finished.\n");
+}
+void *threadSend(void *p)
+{
+ RUDPSOCKET a = (RUDPSOCKET*)p;
+ pthread_detach(pthread_self());
+
+ //recvData(a);
+ sendData(a);
+
+ RUDPClose(a);
+ sleep(5);
+ return NULL;
+}
+
+void* threadRecv(void *p)
+{
+ RUDPSOCKET a = (RUDPSOCKET*)p;
+ pthread_detach(pthread_self());
+
+ recvData(a);
+ //sendData(a);
+
+ RUDPClose(a);
+ sleep(5);
+ return NULL;
+}
+
+
+//Usage: rudpclt [-a] [server] [port]
+// ------- -a: asynchronous
+// ------- server: default is 127.0.0.1,
+// ------- port: 5001 by default
+#define SERVER_SEND 0x01
+#define SERVER_RECV 0x02
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ int sa_len;
+ int rlt, i;
+ RUDPSOCKET s;
+ char cmd = 3;
+
+
+ PA_NetLibInit();
+ RUDPStart();
+
+ s = RUDPSocket();
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = inet_addr("127.0.0.1");
+ sai.sin_port = htons(5001);
+ sa_len = sizeof(sai);
+
+ for(i=1; i<argc; i++)
+ {
+ if(argv[i][0] == '-')
+ {
+ if(strcmp("-a", argv[i]) == 0)
+ {
+ async = 1;
+ }
+ else if(strcmp("--recvonly", argv[i]) == 0)
+ cmd &= ~SERVER_RECV;
+ else if(strcmp("--sendonly", argv[i]) == 0)
+ cmd &= ~SERVER_SEND;
+ else if(strcmp("-?", argv[i]) == 0)
+ {
+ printf("Usage: rudpclt [-a] [server] [port]\n"
+ "\t-a: asynchronous\n"
+ "\tserver: default is 127.0.0.1\n"
+ "\tport: 5001 by default\n");
+ exit(0);
+ }
+
+ }
+ else if(strchr(argv[i], '.'))
+ sai.sin_addr.s_addr = inet_addr(argv[i]);
+ else
+ sai.sin_port = htons(atoi(argv[i]));
+ }
+
+ int opt;
+ //opt = 256; RUDPSetSockOpt(s, OPT_RUDP_RCVBUF, &opt, sizeof(int));
+ if( (rlt = RUDPConnect(s, (struct sockaddr*)&sai, sizeof(sai))) == 0)
+ {
+ opt = 256; RUDPSetSockOpt(s, OPT_RUDP_SNDBUF, &opt, sizeof(int));
+ if(async) RUDPSetSockOpt(s, OPT_NBLK, &async, sizeof(async));
+ pthread_t thd;
+ RUDPSend(s, 0, &cmd, 1, 0);
+ //sleep(5);
+ if(cmd & SERVER_RECV) pthread_create(&thd, NULL, threadSend, (void*)s);
+ recvData(s);
+ }
+ else if(rlt == -ERUDP_AGAIN)
+ {
+ RUDPClose(s);
+ s = NULL;
+ }
+
+ if(s) RUDPClose(s);
+
+ sleep(4);
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+#include "rudp.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+//===================================================================
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ RUDPSOCKET s;
+
+ RUDPStart();
+
+ s = RUDPSocket();
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = argc==2?inet_addr(argv[1]):htonl(INADDR_ANY);
+ sai.sin_port = htons(5001);
+ if(RUDPBind(s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ perror("bind");
+ return -1;
+ }
+
+ RUDPListen(s, 5);
+
+ int ic = 0;
+ char cBusy[] = "-\\|/";
+
+ while(1)
+ {
+ struct timeval tv = { 0, 500000 };
+ if(RUDPSelectSock(s, -1, RUDPSELECT_READABLE, &tv) > 0)
+ {
+ int sa_len = sizeof(sai);
+ RUDPSOCKET a;
+
+ if(RUDPAccept(s, &a, (struct sockaddr*)&sai, &sa_len) < 0)
+ {
+ printf("accept error\n");
+ }
+ else
+ RUDPClose(a);
+ }
+ else
+ {
+#if 0
+ printf("\r%c", cBusy[ic]); fflush(stdout);
+ ic = (ic+1)%4;
+#else
+ printf("\r%d", ic++); fflush(stdout);
+#endif
+ }
+ }
+
+ RUDPClose(s);
+
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+#include "rudp.h"
+#include "platform_adpt.h"
+#include <string.h>
+#include <stdio.h>
+
+int sendData(RUDPSOCKET s)
+{
+ char line[3000];
+ int i=0, rlt = 0;
+ memset(line, '1' + i%36, 3000);
+
+ time_t t0, t_prev, t;
+ unsigned long nTotal = 0, nByt = 0;
+ t0 = t_prev = time(NULL);
+ for(i=0; 0<50000; i++)
+ {
+ PA_IOVEC v[3];
+ v[0].iov_base = v[1].iov_base = v[2].iov_base = line;
+ v[0].iov_len = 230;
+ v[1].iov_len = 1100;
+ v[2].iov_len = 100;
+
+ int onesent = v[0].iov_len + v[1].iov_len + v[2].iov_len;
+ nTotal += onesent;
+ nByt += onesent;
+ if( (i % 4) == 0)
+ {
+ rlt = RUDPSendV(s, 1, v, 3, 0);
+ }
+ else
+ rlt = RUDPSendV(s, 0/*1*/, v, 3, 0);
+ if(rlt < 0)
+ {
+ printf("RUDPSend error: %d\n", rlt);
+ break;
+ }
+
+ time(&t);
+ if(t != t_prev)
+ {
+ fprintf(stderr, "rate: Avg.: %d B/s, Rt. %dB/s \r", nTotal/(t-t0), nByt);
+ fflush(stderr);
+ t_prev = t;
+ nByt = 0;
+ }
+ }
+
+ printf("***************************************\n");
+ if(rlt > 0)
+ {
+ line[0] = '\0';
+ RUDPSend(s, 0, line, 1, 0);
+ printf("all data sent.\n");
+ }
+ return 0;
+}
+
+void recvData(RUDPSOCKET a)
+{
+ int cnt = 0;
+ char line[2100];
+ int len, chno;
+ while( 1 )
+ {
+ struct timeval tv = { 0, 500000 };
+ int flag = RUDPSELECT_READABLE, rlt;
+ if( 1 )//(rlt = RUDPSelectSock(a, -1, flag, &tv)) > 0)
+ {
+ if((len = RUDPRecv(a, &chno, line, 2000, 0)) > 0)
+ {
+ if(chno == 0)
+ {
+ //fprintf(stderr, "Packet %d from chn 0\n", cnt);
+ }
+ cnt++;
+ line[len] = '\0';
+ //printf("%s\n", line);
+ if(line[0] == '\0') break;
+ }
+ else if(len < 0)
+ {
+ fprintf(stderr, "RUDPRecv: %d\n", len);
+ exit(-1);
+ }
+ } else if(rlt < 0)
+ {
+ printf("ERROR: RUDPSelectSock: %d\n", rlt);
+ exit(-1);
+ }
+ }
+ printf("receiving finished.\n");
+}
+void *threadSend(void *p)
+{
+ RUDPSOCKET a = (RUDPSOCKET*)p;
+ pthread_detach(pthread_self());
+
+ //recvData(a);
+ sendData(a);
+
+ RUDPClose(a);
+ sleep(5);
+ return NULL;
+}
+
+void* threadRecv(void *p)
+{
+ RUDPSOCKET a = (RUDPSOCKET*)p;
+ pthread_detach(pthread_self());
+
+ recvData(a);
+ //sendData(a);
+
+ RUDPClose(a);
+ sleep(5);
+ return NULL;
+}
+
+
+//Usage: rudpclt [-a] [server] [port]
+// ------- -a: asynchronous
+// ------- server: default is 127.0.0.1,
+// ------- port: 5001 by default
+#define SERVER_SEND 0x01
+#define SERVER_RECV 0x02
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ int sa_len;
+ int rlt, i, async = 0;
+ RUDPSOCKET s;
+ char cmd = 3;
+
+
+ PA_NetLibInit();
+ RUDPStart();
+
+ s = RUDPSocket();
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = inet_addr("127.0.0.1");
+ sai.sin_port = htons(5001);
+ sa_len = sizeof(sai);
+
+ for(i=1; i<argc; i++)
+ {
+ if(strchr(argv[i], '.'))
+ sai.sin_addr.s_addr = inet_addr(argv[i]);
+ else
+ sai.sin_port = htons(atoi(argv[i]));
+ }
+
+ int opt;
+ //opt = 256; RUDPSetSockOpt(s, OPT_RUDP_RCVBUF, &opt, sizeof(int));
+ if( (rlt = RUDPConnect(s, (struct sockaddr*)&sai, sizeof(sai))) == 0)
+ {
+ char line[1024];
+ int chn=0;
+ while(fgets(line, 1024, stdin))
+ {
+ if(strncmp(line, "quit", 4) == 0) break;
+ RUDPSend(s, chn, line, strlen(line)+1, 0);
+ chn = !chn;
+ }
+ }
+
+ if(s) RUDPClose(s);
+
+ sleep(4);
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+#include "rudp.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define SERVER_SEND 0x01
+#define SERVER_RECV 0x02
+
+//===================================================================
+int sendData(RUDPSOCKET sock)
+{
+ char line[3000];
+ int i=0, rlt = 0;
+
+ memset(line, '1' + i%36, 3000);
+
+ unsigned long n_byt;
+ for(i=0; 0<50000; i++)
+ {
+ struct timeval tv = { 0, 25000 };
+ int flag = RUDPSELECT_WRITABLE;
+ PA_IOVEC v[3];
+ v[0].iov_base = v[1].iov_base = v[2].iov_base = line;
+ v[0].iov_len = 230;
+ v[1].iov_len = 1100;
+ v[2].iov_len = 100;
+
+ n_byt = v[0].iov_len + v[1].iov_len + v[2].iov_len;
+ if(RUDPSelectSock(sock, 1, flag, &tv) > 0)
+ {
+ rlt = RUDPSendV(sock, 1, v, 3, 0);
+ if(rlt < 0)
+ {
+ printf("RUDPSend error: %d\n", rlt);
+ break;
+ }
+ else
+ {
+ }
+ }
+ }
+
+ printf("***************************************\n");
+ if(rlt > 0)
+ {
+ line[0] = '\0';
+ RUDPSend(sock, 0, line, 1, 0);
+ printf("all data sent.\n");
+ }
+ return 0;
+}
+
+void recvData(RUDPSOCKET sock)
+{
+ int cnt = 0;
+ char line[2100];
+ int len, chno;
+ int ic = 0;
+ char cBusy[] = "-\\|/";
+
+ while( 1 )
+ {
+ struct timeval tv = { 0, 500000 };
+ int flag = RUDPSELECT_READABLE, rlt;
+ if((rlt = RUDPSelectSock(sock, -1, flag, &tv)) > 0)
+ {
+ if((len = RUDPRecv(sock, &chno, line, 2000, 0)) > 0)
+ {
+ printf(line);
+ }
+ else if(len < 0)
+ {
+ fprintf(stderr, "RUDPRecv: %d\n", len);
+ exit(-1);
+ }
+ } else if(rlt < 0)
+ {
+ printf("ERROR: RUDPSelectSock: %d\n", rlt);
+ exit(-1);
+ }
+ else {
+ printf("\r%c", cBusy[ic]); fflush(stdout);
+ ic = (ic+1)%4;
+ }
+ }
+ printf("receiving finished.\n");
+}
+
+void *threadSend(void *p)
+{
+ RUDPSOCKET sock = (RUDPSOCKET)p;
+ pthread_detach(pthread_self());
+
+ //recvData(pcs);
+ sendData(sock);
+
+ RUDPClose(sock);
+ sleep(1);
+ return NULL;
+}
+
+void* threadRecv(void *p)
+{
+ RUDPSOCKET sock = (RUDPSOCKET)p;
+ pthread_detach(pthread_self());
+
+ recvData(sock);
+
+ RUDPClose(sock);
+ sleep(1);
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ RUDPSOCKET s;
+
+ RUDPStart();
+
+ s = RUDPSocket();
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = argc==2?inet_addr(argv[1]):htonl(INADDR_ANY);
+ sai.sin_port = htons(5001);
+ if(RUDPBind(s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ perror("bind");
+ return -1;
+ }
+
+ RUDPListen(s, 5);
+
+ int sa_len = sizeof(sai);
+ RUDPSOCKET a;
+ pthread_t thd;
+
+ while(1)
+ {
+ if(RUDPAccept(s, &a, (struct sockaddr*)&sai, &sa_len) < 0)
+ {
+ printf("accept error\n");
+ }
+ else
+ {
+#if 0
+ char cmd;
+ int chno, len;
+
+ while((len = RUDPRecv(a, &chno, &cmd, 1, 0)) > 0)
+ {
+ if( chno == 0 )
+ break;
+ }
+ if(cmd & SERVER_SEND)
+ pthread_create(&thd, NULL, threadSend, a);
+ if(cmd & SERVER_RECV)
+ pthread_create(&thd, NULL, threadRecv, a);
+#else
+ pthread_create(&thd, NULL, threadRecv, a);
+#endif
+ }
+ }
+
+ RUDPClose(s);
+
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+#include "rudp.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define SERVER_SEND 0x01
+#define SERVER_RECV 0x02
+struct comm_stat {
+ RUDPSOCKET sock;
+ float br_recv, br_send;
+ int cmd;
+};
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+volatile static struct comm_stat br_counter[10];
+
+//===================================================================
+int sendData(struct comm_stat *pcs)
+{
+ char line[3000];
+ int i=0, rlt = 0;
+ int total = 0;
+ struct timeval tv1, tv2;
+
+ gettimeofday(&tv1, NULL);
+ memset(line, '1' + i%36, 3000);
+
+ unsigned long n_byt;
+ for(i=0; 0<50000; i++)
+ {
+ struct timeval tv = { 0, 25000 };
+ int flag = RUDPSELECT_WRITABLE;
+ PA_IOVEC v[3];
+ PA_IoVecSetPtr(&v[0], line);
+ PA_IoVecSetPtr(&v[1], line);
+ PA_IoVecSetPtr(&v[2], line);
+ PA_IoVecSetLen(&v[0], 230);
+ PA_IoVecSetLen(&v[1], 1100);
+ PA_IoVecSetLen(&v[2], 100);
+
+ n_byt = PA_IoVecGetLen(&v[0]) + PA_IoVecGetLen(&v[1]) + PA_IoVecGetLen(&v[2]);
+ if(RUDPSelectSock(pcs->sock, 1, flag, &tv) > 0)
+ {
+ rlt = RUDPSendV(pcs->sock, 1, v, 3, 0);
+ if(rlt < 0)
+ {
+ printf("RUDPSend error: %d\n", rlt);
+ break;
+ }
+ else
+ {
+ total += n_byt;
+ }
+ }
+
+ gettimeofday(&tv2, NULL);
+ if(tv2.tv_sec - tv1.tv_sec >= 1)
+ {
+ float delta = (tv2.tv_sec - tv1.tv_sec) + ((int)(tv2.tv_usec/1000) - (int)(tv1.tv_usec/1000))/1000.0;
+ pcs->br_send = total/delta*8/1024/1024.0;
+ total = 0;
+ tv1 = tv2;
+ }
+ }
+
+ printf("***************************************\n");
+ if(rlt > 0)
+ {
+ line[0] = '\0';
+ RUDPSend(pcs->sock, 0, line, 1, 0);
+ printf("all data sent.\n");
+ }
+ return 0;
+}
+
+void recvData(struct comm_stat *pcs)
+{
+ int cnt = 0;
+ char line[2100];
+ int len, chno;
+ int total = 0;
+ struct timeval tv1, tv2;
+
+ gettimeofday(&tv1, NULL);
+ while( 1 )
+ {
+ struct timeval tv = { 0, 500000 };
+ int flag = RUDPSELECT_READABLE, rlt;
+ if(1)//(rlt = RUDPSelectSock(pcs->sock, -1, flag, &tv)) > 0)
+ {
+ if((len = RUDPRecv(pcs->sock, &chno, line, 2000, 0)) > 0)
+ {
+ if(chno == 0)
+ {
+ //fprintf(stderr, "\rPacket %d from chn 0", cnt); fflush(stderr);
+ }
+ cnt++;
+ line[len] = '\0';
+ if(line[0] == '\0') break;
+ //printf("%s\n", line);
+ total += len;
+ }
+ else if(len < 0)
+ {
+ fprintf(stderr, "RUDPRecv: %d\n", len);
+ exit(-1);
+ }
+ gettimeofday(&tv2, NULL);
+ if(tv2.tv_sec - tv1.tv_sec >= 1)
+ {
+ float delta = (tv2.tv_sec - tv1.tv_sec) + ((int)(tv2.tv_usec/1000) - (int)(tv1.tv_usec/1000))/1000.0;
+ pcs->br_recv= total/delta*8/1024/1024.0;
+ total = 0;
+ tv1 = tv2;
+ }
+ } else if(rlt < 0)
+ {
+ printf("ERROR: RUDPSelectSock: %d\n", rlt);
+ exit(-1);
+ }
+ }
+ printf("receiving finished.\n");
+}
+#if 0
+int sendRecvData(struct comm_stat *pcs)
+{
+ char line[3000];
+ int rlt = 0;
+ int totalr, totalw;
+ struct timeval tv1, tv2;
+
+ totalr = totalw = 0;
+ gettimeofday(&tv1, NULL);
+ memset(line, '1', 3000);
+
+ unsigned long n_byt;
+ while(1)
+ {
+ struct timeval tv = { 0, 50000 };
+ int flag = 0;
+ PA_IOVEC v[3];
+ v[0].iov_base = v[1].iov_base = v[2].iov_base = line;
+ v[0].iov_len = 230;
+ v[1].iov_len = 1100;
+ v[2].iov_len = 100;
+ n_byt = v[0].iov_len + v[1].iov_len + v[2].iov_len;
+
+ if(pcs->cmd & SERVER_SEND) flag |= RUDPSELECT_WRITABLE;
+ if(pcs->cmd & SERVER_RECV) flag |= RUDPSELECT_READABLE;
+ if(RUDPSelectSock(pcs->sock, 0, &flag, &tv) > 0) //Not supported
+ {
+ if(flag & RUDPSELECT_WRITABLE)
+ {
+ rlt = RUDPSendV(pcs->sock, 0, v, 3, 0);
+ if(rlt < 0)
+ {
+ printf("RUDPSend error: %d\n", rlt);
+ break;
+ }
+ else
+ {
+ totalw += n_byt;
+ }
+ }
+ if(flag & RUDPSELECT_READABLE)
+ {
+ int chno, len;
+ if((len = RUDPRecv(pcs->sock, &chno, line, 2000, 0)) > 0)
+ {
+ totalr += len;
+ }
+ else if(len < 0)
+ {
+ fprintf(stderr, "RUDPRecv: %d\n", len);
+ exit(-1);
+ }
+ }
+ }
+
+ gettimeofday(&tv2, NULL);
+ if(tv2.tv_sec - tv1.tv_sec >= 1)
+ {
+ float delta = (tv2.tv_sec - tv1.tv_sec) + ((int)(tv2.tv_usec/1000) - (int)(tv1.tv_usec/1000))/1000.0;
+ pcs->br_send = totalw/delta*8/1024/1024.0;
+ pcs->br_recv = totalr/delta*8/1024/1024.0;
+ totalr = totalw = 0;
+ tv1 = tv2;
+ }
+ }
+
+ printf("***************************************\n");
+ if(rlt > 0)
+ {
+ line[0] = '\0';
+ RUDPSend(pcs->sock, 0, line, 1, 0);
+ printf("all data sent.\n");
+ }
+ return 0;
+}
+
+void *threadSendRecv(void *p)
+{
+ struct comm_stat *pcs = (struct comm_stat*)p;
+ pthread_detach(pthread_self());
+
+ sendRecvData(pcs);
+
+ RUDPClose(pcs->sock);
+ memset(pcs, 0, sizeof(*pcs));
+ sleep(5);
+ return NULL;
+}
+
+#endif
+
+void *threadSend(void *p)
+{
+ struct comm_stat *pcs = (struct comm_stat*)p;
+ pthread_detach(pthread_self());
+
+ //recvData(pcs);
+ sendData(pcs);
+
+ RUDPClose(pcs->sock);
+ memset(pcs, 0, sizeof(*pcs));
+ sleep(5);
+ return NULL;
+}
+
+void* threadRecv(void *p)
+{
+ struct comm_stat *pcs = (struct comm_stat*)p;
+ pthread_detach(pthread_self());
+
+ recvData(pcs);
+ //sendData(pcs);
+
+ RUDPClose(pcs->sock);
+ memset(pcs, 0, sizeof(*pcs));
+ sleep(5);
+ return NULL;
+}
+
+void *threadPrint(void *p)
+{
+ int i, len;
+ char ss[128];
+
+ pthread_detach(pthread_self());
+ while(1)
+ {
+ sleep(1);
+ len = sprintf(ss, "Mbps recv|send::: ");
+ for(i=0; i<5; i++)
+ {
+ len += sprintf(ss+len, "%d: %.2f|%.2f; ", i, br_counter[i].br_recv, br_counter[i].br_send);
+ }
+ fprintf(stderr, "\r%s", ss); fflush(stderr);
+ }
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ RUDPSOCKET s;
+
+ RUDPStart();
+
+ s = RUDPSocket();
+
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_addr.s_addr = argc==2?inet_addr(argv[1]):htonl(INADDR_ANY);
+ sai.sin_port = htons(5001);
+ if(RUDPBind(s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ perror("bind");
+ return -1;
+ }
+
+ RUDPListen(s, 5);
+
+ int sa_len = sizeof(sai);
+ RUDPSOCKET a;
+ pthread_t thd;
+
+ pthread_create(&thd, NULL, threadPrint, NULL);
+ while(1)
+ {
+ if(RUDPAccept(s, &a, (struct sockaddr*)&sai, &sa_len) < 0)
+ {
+ printf("accept error\n");
+ }
+ else
+ {
+ int i;
+ for(i=0; i<10; i++)
+ {
+ if(br_counter[i].sock == NULL)
+ {
+ char cmd;
+ int chno, len;
+ br_counter[i].sock = a;
+
+ while((len = RUDPRecv(a, &chno, &cmd, 1, 0)) > 0)
+ {
+ if( chno == 0 )
+ break;
+ }
+ printf("client cmd: %d\n", cmd);
+ br_counter[i].cmd = cmd;
+#if 0
+ pthread_create(&thd, NULL, threadSendRecv, (void*)&br_counter);
+#else
+ if(cmd & SERVER_SEND)
+ pthread_create(&thd, NULL, threadSend, (void*)&br_counter[i]);
+ if(cmd & SERVER_RECV)
+ pthread_create(&thd, NULL, threadRecv, (void*)&br_counter[i]);
+#endif
+ break;
+ }
+ }
+ }
+ }
+
+ RUDPClose(s);
+
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+/*
+ *
+ * Demo for RUDPSimConnnect(...)
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rudp.h"
+#include "platform_adpt.h"
+
+RUDPSOCKET s;
+
+void *recv_thread(void *p)
+{
+ struct timeval tv = { 1, 0 };
+ RUDPSOCKCHNO rset[2];
+ int nr, rlt;
+ char line[1000];
+
+ while(1)
+ {
+ nr = 0;
+ RUDP_SET(s, 0, rset, nr);
+ if((rlt = RUDPSelect(rset, &nr, NULL, NULL, NULL, NULL, &tv)) > 0)
+ {
+ int chno, len, rudp;
+
+ if(RUDP_ISSET(s, rset, nr))
+ {
+ len = RUDPRecv(s, &chno, line, 1000, 0);
+ rudp = 1;
+ }
+ if(len > 0)
+ {
+ line[len] = '\0';
+ printf("%s: %s\n", rudp?"rudp":"udp", line);
+ }
+ else
+ {
+ printf("Recv Error %d\n", len);
+ break;
+ }
+ }
+ else if(rlt == 0)
+ {
+ printf(".");
+ fflush(stdout);
+ }
+ else
+ {
+ printf("RUDPSelect: %d\n", rlt);
+ break;
+ }
+ }
+ return NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ int i, connected = 0;
+
+ if(argc < 2) { printf("simconn remotehost [localport remoteport]\n"); return -1; }
+
+
+ PA_NetLibInit();
+ RUDPStart();
+
+ s = RUDPSocket();
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(argc>2?atoi(argv[2]):5001);
+ if(RUDPBind(s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ printf("bind to local port %d failed\n", ntohs(sai.sin_port));
+ RUDPCleanup();
+ return -1;
+ }
+ //i = 1;
+ //RUDPSetSockOpt(s, OPT_ADHOC, &i, sizeof(i));
+
+
+ if(argc > 3) sai.sin_port = htons(atoi(argv[3]));
+ sai.sin_addr.s_addr = inet_addr(argv[1]);
+ sleep(5);
+ printf("begin connection....\n");
+ if(RUDPSimConnect(s, (struct sockaddr*)&sai, 1, NULL, 0) == 0)
+ connected = 1;
+
+
+ char line[1000];
+ if(connected)
+ {
+ pthread_t thd;
+ pthread_create(&thd, NULL, recv_thread, NULL);
+ pthread_detach(thd);
+
+ while(fgets(line, 1000, stdin))
+ {
+ int rlt, flag = RUDPSELECT_WRITABLE;
+ struct timeval tv = { 0, 0 };
+ rlt = RUDPSelectSock(s, 0, flag, &tv);
+ if(rlt > 0)
+ {
+ if( (rlt = RUDPSend(s, 0, line, strlen(line), 0)) < 0)
+ {
+ printf("RUDPSend: %d\n", rlt);
+ break;
+ }
+ }
+ else
+ {
+ }
+ }
+ }
+ else
+ printf("connect to %s failed\n", argv[1]);
+
+ RUDPClose(s);
+
+ printf("press Enter to terminate.");
+ fgets(line, 1000, stdin);
+ RUDPCleanup();
+ return 0;
+}
+
--- /dev/null
+/*
+ * In this demo, two peers create(does not listen)
+ * a rudp socket and connect to each other, simultaneously.
+ *
+ */
+#include "rudp.h"
+#include <string.h>
+#include <stdio.h>
+#include "platform_adpt.h"
+
+RUDPSOCKET s;
+int udp_sock;
+
+PA_THREAD_RETTYPE __STDCALL recv_thread(void *p)
+{
+ struct timeval tv = { 1, 0 };
+ RUDPSOCKCHNO rset[2];
+ int nr, rlt;
+ char line[1000];
+
+ while(1)
+ {
+ nr = 0;
+ RUDP_FD_SET(udp_sock, rset, nr);
+ RUDP_SET(s, 0, rset, nr);
+ if((rlt = RUDPSelect(rset, &nr, NULL, NULL, NULL, NULL, &tv)) > 0)
+ {
+ int chno, len, rudp;
+
+ if(RUDP_ISSET(s, rset, nr))
+ {
+ len = RUDPRecv(s, &chno, line, 1000, 0);
+ rudp = 1;
+ }
+ else if(RUDP_FD_ISSET(udp_sock, rset, nr))
+ {
+ struct sockaddr sa;
+ int sa_len = sizeof(sa);
+ len = recvfrom(udp_sock, line, 1000, 0, &sa, &sa_len);
+ rudp = 0;
+ }
+ if(len > 0)
+ {
+ line[len] = '\0';
+ printf("%s: %s\n", rudp?"rudp":"udp", line);
+ }
+ else
+ {
+ printf("Recv Error %d\n", len);
+ break;
+ }
+ }
+ else if(rlt == 0)
+ {
+ printf(".");
+ fflush(stdout);
+ }
+ else
+ {
+ printf("RUDPSelect: %d\n", rlt);
+ break;
+ }
+ }
+ return (PA_THREAD_RETTYPE)0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in sai;
+ int i, connected = 0;
+ char line[1000];
+
+ if(argc < 2) { printf("simulconn remotehost [localport remoteport]\n"); return -1; }
+
+
+ PA_NetLibInit();
+ RUDPStart();
+
+ s = RUDPSocket();
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(argc>2?atoi(argv[2]):5001);
+ if(RUDPBind(s, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ printf("bind to local port %d failed\n", ntohs(sai.sin_port));
+ RUDPCleanup();
+ return -1;
+ }
+ i = 1;
+ //RUDPSetSockOpt(s, OPT_ADHOC, &i, sizeof(i));
+
+ sai.sin_port = htons(ntohs(sai.sin_port)+1);
+ udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if(bind(udp_sock, (struct sockaddr*)&sai, sizeof(sai)) < 0)
+ {
+ perror("bind udp");
+ RUDPCleanup();
+ return -1;
+ }
+
+
+ if(argc > 3) sai.sin_port = htons(atoi(argv[3]));
+ sai.sin_addr.s_addr = inet_addr(argv[1]);
+ PA_Sleep(5000);
+ printf("begin connection....\n");
+ for(i=0; i<3; i++)
+ {
+ if(RUDPConnect(s, (struct sockaddr*)&sai, sizeof(sai)) == 0)
+ {
+ connected = 1;
+ break;
+ }
+ else
+ {
+ printf("connection trying %d\n", i);
+ PA_Sleep(1000);
+ }
+ }
+
+ sai.sin_port = htons(ntohs(sai.sin_port)+1);
+
+ if(connected)
+ {
+ PA_HTHREAD thd;
+ thd = PA_ThreadCreate(recv_thread, NULL);
+
+ while(fgets(line, 1000, stdin))
+ {
+ int rlt, flag = RUDPSELECT_WRITABLE;
+ struct timeval tv = { 0, 0 };
+ rlt = RUDPSelectSock(s, 0, flag, &tv);
+ if(rlt > 0)
+ {
+ if(line[0] & 0x01)
+ {
+ if( (rlt = RUDPSend(s, 0, line, strlen(line), 0)) < 0)
+ {
+ printf("RUDPSend: %d\n", rlt);
+ break;
+ }
+ }
+ else
+ sendto(udp_sock, line, strlen(line), 0, (struct sockaddr*)&sai, sizeof(sai));
+ }
+ else
+ {
+ }
+ }
+ }
+ else
+ printf("connect to %s failed\n", argv[1]);
+
+ RUDPClose(s);
+
+ printf("press Enter to terminate.");
+ fgets(line, 1000, stdin);
+ RUDPCleanup();
+
+ return 0;
+}
--- /dev/null
+<?xml version="1.0" encoding="gb2312"?>\r
+<VisualStudioProject\r
+ ProjectType="Visual C++"\r
+ Version="9.00"\r
+ Name="simulconn"\r
+ ProjectGUID="{41513405-AEB2-4E74-BE17-7EE2EA8E9A62}"\r
+ RootNamespace="simulconn"\r
+ Keyword="Win32Proj"\r
+ TargetFrameworkVersion="131072"\r
+ >\r
+ <Platforms>\r
+ <Platform\r
+ Name="Win32"\r
+ />\r
+ </Platforms>\r
+ <ToolFiles>\r
+ </ToolFiles>\r
+ <Configurations>\r
+ <Configuration\r
+ Name="Debug|Win32"\r
+ OutputDirectory="Debug"\r
+ IntermediateDirectory="Debug"\r
+ ConfigurationType="1"\r
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+ CharacterSet="2"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ AdditionalIncludeDirectories="../.."\r
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+ MinimalRebuild="true"\r
+ BasicRuntimeChecks="3"\r
+ RuntimeLibrary="1"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="3"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="4"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ AdditionalDependencies="ws2_32.lib ../debug/rudpd.lib"\r
+ OutputFile="$(OutDir)/simulconn.exe"\r
+ LinkIncremental="2"\r
+ GenerateDebugInformation="true"\r
+ ProgramDatabaseFile="$(OutDir)/simulconn.pdb"\r
+ SubSystem="1"\r
+ RandomizedBaseAddress="1"\r
+ DataExecutionPrevention="0"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ <Configuration\r
+ Name="Release|Win32"\r
+ OutputDirectory="Release"\r
+ IntermediateDirectory="Release"\r
+ ConfigurationType="1"\r
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+ CharacterSet="2"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ AdditionalIncludeDirectories="../.."\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+ RuntimeLibrary="0"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="3"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="3"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ AdditionalDependencies="ws2_32.lib ../release/rudp.lib"\r
+ OutputFile="$(OutDir)/simulconn.exe"\r
+ LinkIncremental="1"\r
+ GenerateDebugInformation="true"\r
+ SubSystem="1"\r
+ OptimizeReferences="2"\r
+ EnableCOMDATFolding="2"\r
+ RandomizedBaseAddress="1"\r
+ DataExecutionPrevention="0"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ </Configurations>\r
+ <References>\r
+ </References>\r
+ <Files>\r
+ <Filter\r
+ Name="Ô´Îļþ"\r
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+ >\r
+ <File\r
+ RelativePath="..\..\simulconn.c"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Í·Îļþ"\r
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+ >\r
+ </Filter>\r
+ <Filter\r
+ Name="×ÊÔ´Îļþ"\r
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+ >\r
+ </Filter>\r
+ </Files>\r
+ <Globals>\r
+ </Globals>\r
+</VisualStudioProject>\r
--- /dev/null
+<?xml version="1.0" encoding="gb2312"?>\r
+<VisualStudioProject\r
+ ProjectType="Visual C++"\r
+ Version="9.00"\r
+ Name="test_clt"\r
+ ProjectGUID="{F43D9A26-2D21-467C-952D-64497339DFA9}"\r
+ Keyword="Win32Proj"\r
+ TargetFrameworkVersion="131072"\r
+ >\r
+ <Platforms>\r
+ <Platform\r
+ Name="Win32"\r
+ />\r
+ </Platforms>\r
+ <ToolFiles>\r
+ </ToolFiles>\r
+ <Configurations>\r
+ <Configuration\r
+ Name="Debug|Win32"\r
+ OutputDirectory="Debug"\r
+ IntermediateDirectory="Debug"\r
+ ConfigurationType="1"\r
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+ CharacterSet="2"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ AdditionalIncludeDirectories="../.."\r
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+ MinimalRebuild="true"\r
+ BasicRuntimeChecks="3"\r
+ RuntimeLibrary="1"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="3"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="4"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ AdditionalDependencies="ws2_32.lib ../debug/rudp.lib"\r
+ OutputFile="$(OutDir)/test_clt.exe"\r
+ LinkIncremental="2"\r
+ GenerateDebugInformation="true"\r
+ ProgramDatabaseFile="$(OutDir)/test_clt.pdb"\r
+ SubSystem="1"\r
+ RandomizedBaseAddress="1"\r
+ DataExecutionPrevention="0"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ <Configuration\r
+ Name="Release|Win32"\r
+ OutputDirectory="Release"\r
+ IntermediateDirectory="Release"\r
+ ConfigurationType="1"\r
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+ CharacterSet="2"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ AdditionalIncludeDirectories="../.."\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+ RuntimeLibrary="0"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="3"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="3"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ AdditionalDependencies="ws2_32.lib ../release/rudp.lib"\r
+ OutputFile="$(OutDir)/test_clt.exe"\r
+ LinkIncremental="1"\r
+ GenerateDebugInformation="true"\r
+ SubSystem="1"\r
+ OptimizeReferences="2"\r
+ EnableCOMDATFolding="2"\r
+ RandomizedBaseAddress="1"\r
+ DataExecutionPrevention="0"\r
+ TargetMachine="1"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCManifestTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCAppVerifierTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ </Configurations>\r
+ <References>\r
+ </References>\r
+ <Files>\r
+ <Filter\r
+ Name="Ô´Îļþ"\r
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+ >\r
+ <File\r
+ RelativePath="..\..\rudpclt.c"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Í·Îļþ"\r
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+ >\r
+ </Filter>\r
+ <Filter\r
+ Name="×ÊÔ´Îļþ"\r
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+ >\r
+ </Filter>\r
+ </Files>\r
+ <Globals>\r
+ </Globals>\r
+</VisualStudioProject>\r
--- /dev/null
+Microsoft Visual Studio Solution File, Format Version 10.00\r
+# Visual Studio 2008\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librudp", "win32.vcproj", "{0104ADF2-1925-41E9-A093-2868A43ECA1C}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_clt", "test_clt\test_clt.vcproj", "{F43D9A26-2D21-467C-952D-64497339DFA9}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simulconn", "simulconn\simulconn.vcproj", "{41513405-AEB2-4E74-BE17-7EE2EA8E9A62}"\r
+ ProjectSection(ProjectDependencies) = postProject\r
+ {0104ADF2-1925-41E9-A093-2868A43ECA1C} = {0104ADF2-1925-41E9-A093-2868A43ECA1C}\r
+ EndProjectSection\r
+EndProject\r
+Global\r
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+ Debug|Win32 = Debug|Win32\r
+ Release|Win32 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+ {0104ADF2-1925-41E9-A093-2868A43ECA1C}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {0104ADF2-1925-41E9-A093-2868A43ECA1C}.Debug|Win32.Build.0 = Debug|Win32\r
+ {0104ADF2-1925-41E9-A093-2868A43ECA1C}.Release|Win32.ActiveCfg = Release|Win32\r
+ {0104ADF2-1925-41E9-A093-2868A43ECA1C}.Release|Win32.Build.0 = Release|Win32\r
+ {F43D9A26-2D21-467C-952D-64497339DFA9}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {F43D9A26-2D21-467C-952D-64497339DFA9}.Debug|Win32.Build.0 = Debug|Win32\r
+ {F43D9A26-2D21-467C-952D-64497339DFA9}.Release|Win32.ActiveCfg = Release|Win32\r
+ {F43D9A26-2D21-467C-952D-64497339DFA9}.Release|Win32.Build.0 = Release|Win32\r
+ {41513405-AEB2-4E74-BE17-7EE2EA8E9A62}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {41513405-AEB2-4E74-BE17-7EE2EA8E9A62}.Debug|Win32.Build.0 = Debug|Win32\r
+ {41513405-AEB2-4E74-BE17-7EE2EA8E9A62}.Release|Win32.ActiveCfg = Release|Win32\r
+ {41513405-AEB2-4E74-BE17-7EE2EA8E9A62}.Release|Win32.Build.0 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(SolutionProperties) = preSolution\r
+ HideSolutionNode = FALSE\r
+ EndGlobalSection\r
+EndGlobal\r
--- /dev/null
+<?xml version="1.0" encoding="gb2312"?>\r
+<VisualStudioProject\r
+ ProjectType="Visual C++"\r
+ Version="9.00"\r
+ Name="librudp"\r
+ ProjectGUID="{0104ADF2-1925-41E9-A093-2868A43ECA1C}"\r
+ RootNamespace="librudp"\r
+ Keyword="Win32Proj"\r
+ TargetFrameworkVersion="131072"\r
+ >\r
+ <Platforms>\r
+ <Platform\r
+ Name="Win32"\r
+ />\r
+ </Platforms>\r
+ <ToolFiles>\r
+ </ToolFiles>\r
+ <Configurations>\r
+ <Configuration\r
+ Name="Debug|Win32"\r
+ OutputDirectory="Debug"\r
+ IntermediateDirectory="Debug"\r
+ ConfigurationType="4"\r
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+ CharacterSet="2"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ AdditionalIncludeDirectories=".."\r
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"\r
+ MinimalRebuild="true"\r
+ BasicRuntimeChecks="3"\r
+ RuntimeLibrary="1"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="3"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="4"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLibrarianTool"\r
+ OutputFile="$(OutDir)/rudpd.lib"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ <Configuration\r
+ Name="Release|Win32"\r
+ OutputDirectory="Release"\r
+ IntermediateDirectory="Release"\r
+ ConfigurationType="4"\r
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+ CharacterSet="2"\r
+ >\r
+ <Tool\r
+ Name="VCPreBuildEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ />\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"\r
+ />\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ />\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ AdditionalIncludeDirectories=".."\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"\r
+ RuntimeLibrary="0"\r
+ UsePrecompiledHeader="0"\r
+ WarningLevel="3"\r
+ Detect64BitPortabilityProblems="true"\r
+ DebugInformationFormat="3"\r
+ />\r
+ <Tool\r
+ Name="VCManagedResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ />\r
+ <Tool\r
+ Name="VCPreLinkEventTool"\r
+ />\r
+ <Tool\r
+ Name="VCLibrarianTool"\r
+ OutputFile="$(OutDir)/rudp.lib"\r
+ />\r
+ <Tool\r
+ Name="VCALinkTool"\r
+ />\r
+ <Tool\r
+ Name="VCXDCMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCBscMakeTool"\r
+ />\r
+ <Tool\r
+ Name="VCFxCopTool"\r
+ />\r
+ <Tool\r
+ Name="VCPostBuildEventTool"\r
+ />\r
+ </Configuration>\r
+ </Configurations>\r
+ <References>\r
+ </References>\r
+ <Files>\r
+ <Filter\r
+ Name="Ô´Îļþ"\r
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+ >\r
+ <File\r
+ RelativePath="..\basetype.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\crc32.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\crc32.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\platform_adpt.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\platform_adpt.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\rudp.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\rudp.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\rudp_imp.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Í·Îļþ"\r
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+ >\r
+ </Filter>\r
+ <Filter\r
+ Name="×ÊÔ´Îļþ"\r
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+ >\r
+ </Filter>\r
+ <File\r
+ RelativePath=".\ReadMe.txt"\r
+ >\r
+ </File>\r
+ </Files>\r
+ <Globals>\r
+ </Globals>\r
+</VisualStudioProject>\r