]> git.lizzy.rs Git - rudp.git/commitdiff
first commit
authorsongzc <evercomer@gmail.com>
Fri, 4 Sep 2015 14:18:02 +0000 (22:18 +0800)
committersongzc <evercomer@gmail.com>
Fri, 4 Sep 2015 14:18:02 +0000 (22:18 +0800)
26 files changed:
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
basetype.h [new file with mode: 0644]
crc32.c [new file with mode: 0644]
crc32.h [new file with mode: 0644]
linux_list.h [new file with mode: 0644]
nblk_svr.c [new file with mode: 0644]
platform_adpt.c [new file with mode: 0644]
platform_adpt.h [new file with mode: 0644]
rudp.c [new file with mode: 0644]
rudp.h [new file with mode: 0644]
rudp_imp.h [new file with mode: 0644]
rudp_punch.c [new file with mode: 0644]
rudp_punch.h [new file with mode: 0644]
rudpclt.c [new file with mode: 0644]
rudpsel.c [new file with mode: 0644]
rudpselc.c [new file with mode: 0644]
rudpsels.c [new file with mode: 0644]
rudpsvr.c [new file with mode: 0644]
simconn.c [new file with mode: 0644]
simulconn.c [new file with mode: 0644]
win32/simulconn/simulconn.vcproj [new file with mode: 0755]
win32/test_clt/test_clt.vcproj [new file with mode: 0755]
win32/win32.sln [new file with mode: 0755]
win32/win32.vcproj [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..669b2e4
--- /dev/null
@@ -0,0 +1,7 @@
+~.*
+*.~
+*.swp
+*.bak
+Debug
+Release
+*.suo
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..65aa54f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,77 @@
+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
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..828dc90
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+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
diff --git a/basetype.h b/basetype.h
new file mode 100644 (file)
index 0000000..d2d3d91
--- /dev/null
@@ -0,0 +1,108 @@
+#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
diff --git a/crc32.c b/crc32.c
new file mode 100644 (file)
index 0000000..86e24e9
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,93 @@
+#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
diff --git a/crc32.h b/crc32.h
new file mode 100644 (file)
index 0000000..31a83d5
--- /dev/null
+++ b/crc32.h
@@ -0,0 +1,17 @@
+#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
+
diff --git a/linux_list.h b/linux_list.h
new file mode 100644 (file)
index 0000000..8a85aab
--- /dev/null
@@ -0,0 +1,250 @@
+#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
diff --git a/nblk_svr.c b/nblk_svr.c
new file mode 100644 (file)
index 0000000..c681973
--- /dev/null
@@ -0,0 +1,100 @@
+#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;
+}
diff --git a/platform_adpt.c b/platform_adpt.c
new file mode 100644 (file)
index 0000000..27b5a17
--- /dev/null
@@ -0,0 +1,353 @@
+#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
diff --git a/platform_adpt.h b/platform_adpt.h
new file mode 100644 (file)
index 0000000..568df23
--- /dev/null
@@ -0,0 +1,524 @@
+#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__
diff --git a/rudp.c b/rudp.c
new file mode 100644 (file)
index 0000000..cb1c86a
--- /dev/null
+++ b/rudp.c
@@ -0,0 +1,3149 @@
+#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, &notify, 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;
+}
+
diff --git a/rudp.h b/rudp.h
new file mode 100644 (file)
index 0000000..fee886e
--- /dev/null
+++ b/rudp.h
@@ -0,0 +1,122 @@
+#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
+
diff --git a/rudp_imp.h b/rudp_imp.h
new file mode 100644 (file)
index 0000000..c917176
--- /dev/null
@@ -0,0 +1,290 @@
+#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
+
diff --git a/rudp_punch.c b/rudp_punch.c
new file mode 100644 (file)
index 0000000..3cb69ab
--- /dev/null
@@ -0,0 +1,176 @@
+#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;
+}
+
diff --git a/rudp_punch.h b/rudp_punch.h
new file mode 100644 (file)
index 0000000..b39b080
--- /dev/null
@@ -0,0 +1,55 @@
+#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
+
diff --git a/rudpclt.c b/rudpclt.c
new file mode 100644 (file)
index 0000000..60a61fb
--- /dev/null
+++ b/rudpclt.c
@@ -0,0 +1,228 @@
+#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;
+}
diff --git a/rudpsel.c b/rudpsel.c
new file mode 100644 (file)
index 0000000..fe15ed4
--- /dev/null
+++ b/rudpsel.c
@@ -0,0 +1,65 @@
+#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;
+}
diff --git a/rudpselc.c b/rudpselc.c
new file mode 100644 (file)
index 0000000..5a61a97
--- /dev/null
@@ -0,0 +1,174 @@
+#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;
+}
diff --git a/rudpsels.c b/rudpsels.c
new file mode 100644 (file)
index 0000000..fd0dd25
--- /dev/null
@@ -0,0 +1,173 @@
+#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;
+}
diff --git a/rudpsvr.c b/rudpsvr.c
new file mode 100644 (file)
index 0000000..190197e
--- /dev/null
+++ b/rudpsvr.c
@@ -0,0 +1,333 @@
+#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;
+}
diff --git a/simconn.c b/simconn.c
new file mode 100644 (file)
index 0000000..2e41445
--- /dev/null
+++ b/simconn.c
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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;
+}
+
diff --git a/simulconn.c b/simulconn.c
new file mode 100644 (file)
index 0000000..7b3a09d
--- /dev/null
@@ -0,0 +1,160 @@
+/* 
+ * 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;
+}
diff --git a/win32/simulconn/simulconn.vcproj b/win32/simulconn/simulconn.vcproj
new file mode 100755 (executable)
index 0000000..92e4f15
--- /dev/null
@@ -0,0 +1,204 @@
+<?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
diff --git a/win32/test_clt/test_clt.vcproj b/win32/test_clt/test_clt.vcproj
new file mode 100755 (executable)
index 0000000..004ff69
--- /dev/null
@@ -0,0 +1,203 @@
+<?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
diff --git a/win32/win32.sln b/win32/win32.sln
new file mode 100755 (executable)
index 0000000..aaa9432
--- /dev/null
@@ -0,0 +1,34 @@
+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
diff --git a/win32/win32.vcproj b/win32/win32.vcproj
new file mode 100755 (executable)
index 0000000..162fb65
--- /dev/null
@@ -0,0 +1,207 @@
+<?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