Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/SoftEtherVPN/SoftEtherVPN_Stable.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordnobori <da.git@softether.co.jp>2014-01-04 17:00:08 +0400
committerdnobori <da.git@softether.co.jp>2014-01-04 17:00:08 +0400
commit749497dde0a1dd08c434a73b9d4e93dc3e3326d9 (patch)
tree7c83a55919c0f1aa1267c4dbcd008f1644f961ee /src/Cedar/Connection.c
parentd433e567a561f8ae094a535025b02c7dc47026c6 (diff)
v4.03-9408-rtm
Diffstat (limited to 'src/Cedar/Connection.c')
-rw-r--r--src/Cedar/Connection.c3457
1 files changed, 3457 insertions, 0 deletions
diff --git a/src/Cedar/Connection.c b/src/Cedar/Connection.c
new file mode 100644
index 00000000..5cc0296c
--- /dev/null
+++ b/src/Cedar/Connection.c
@@ -0,0 +1,3457 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Connection.c
+// Connection Manager
+
+#include "CedarPch.h"
+
+// Determine whether the socket is to use to send
+#define IS_SEND_TCP_SOCK(ts) \
+ ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode == false)))
+
+// Determine whether the socket is to use to receive
+#define IS_RECV_TCP_SOCK(ts) \
+ ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode == false)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode)))
+
+// Conversion of SECURE_SIGN
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(SECURE_SIGN));
+ PackGetStr(p, "SecurePublicCertName", t->SecurePublicCertName, sizeof(t->SecurePublicCertName));
+ PackGetStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName, sizeof(t->SecurePrivateKeyName));
+ t->ClientCert = PackGetX(p, "ClientCert");
+ PackGetData2(p, "Random", t->Random, sizeof(t->Random));
+ PackGetData2(p, "Signature", t->Signature, sizeof(t->Signature));
+ t->UseSecureDeviceId = PackGetInt(p, "UseSecureDeviceId");
+ t->BitmapId = PackGetInt(p, "BitmapId");
+}
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "SecurePublicCertName", t->SecurePublicCertName);
+ PackAddStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName);
+ PackAddX(p, "ClientCert", t->ClientCert);
+ PackAddData(p, "Random", t->Random, sizeof(t->Random));
+ PackAddData(p, "Signature", t->Signature, sizeof(t->Signature));
+ PackAddInt(p, "UseSecureDeviceId", t->UseSecureDeviceId);
+ PackAddInt(p, "BitmapId", t->BitmapId);
+}
+void FreeRpcSecureSign(SECURE_SIGN *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->ClientCert);
+}
+
+// Generate the next packet
+BUF *NewKeepPacket(bool server_mode)
+{
+ BUF *b = NewBuf();
+ char *string = KEEP_ALIVE_STRING;
+
+ WriteBuf(b, string, StrLen(string));
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// KEEP thread
+void KeepThread(THREAD *thread, void *param)
+{
+ KEEP *k = (KEEP *)param;
+ SOCK *s;
+ char server_name[MAX_HOST_NAME_LEN + 1];
+ UINT server_port;
+ bool udp_mode;
+ bool enabled;
+ // Validate arguments
+ if (thread == NULL || k == NULL)
+ {
+ return;
+ }
+
+WAIT_FOR_ENABLE:
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+
+ // Wait until it becomes enabled
+ while (true)
+ {
+ enabled = false;
+ Lock(k->lock);
+ {
+ if (k->Enable)
+ {
+ if (StrLen(k->ServerName) != 0 && k->ServerPort != 0 && k->Interval != 0)
+ {
+ StrCpy(server_name, sizeof(server_name), k->ServerName);
+ server_port = k->ServerPort;
+ udp_mode = k->UdpMode;
+ enabled = true;
+ }
+ }
+ }
+ Unlock(k->lock);
+ if (enabled)
+ {
+ break;
+ }
+ if (k->Halt)
+ {
+ return;
+ }
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+
+ if (udp_mode == false)
+ {
+ // TCP mode
+ // Try until a success to connection
+ while (true)
+ {
+ UINT64 connect_started_tick;
+ bool changed = false;
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ // Attempt to connect to the server
+ connect_started_tick = Tick64();
+ s = ConnectEx2(server_name, server_port, KEEP_TCP_TIMEOUT, (bool *)&k->Halt);
+ if (s != NULL)
+ {
+ // Successful connection
+ break;
+ }
+
+ // Connection failure: Wait until timeout or the setting is changed
+ while (true)
+ {
+ changed = false;
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+ {
+ break;
+ }
+
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+ }
+
+ // Success to connect the server
+ // Send and receive packet data periodically
+ if (s != NULL)
+ {
+ UINT64 last_packet_sent_time = 0;
+ while (true)
+ {
+ SOCKSET set;
+ UINT ret;
+ UCHAR buf[MAX_SIZE];
+ bool changed;
+
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+
+ Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+ ret = Recv(s, buf, sizeof(buf), false);
+ if (ret == 0)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+
+ if (s != NULL)
+ {
+ if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+ {
+ BUF *b;
+
+ // Send the next packet
+ last_packet_sent_time = Tick64();
+
+ b = NewKeepPacket(k->Server);
+
+ ret = Send(s, b->Buf, b->Size, false);
+ FreeBuf(b);
+
+ if (ret == 0)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ }
+ }
+
+ changed = false;
+
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed || s == NULL)
+ {
+ // Setting has been changed or disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ goto WAIT_FOR_ENABLE;
+ }
+ else
+ {
+ if (k->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ ReleaseSock(s);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ IP dest_ip;
+ // UDP mode
+ // Try to create socket until it successes
+ while (true)
+ {
+ UINT64 connect_started_tick;
+ bool changed = false;
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode == false)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ // Attempt to create a socket
+ connect_started_tick = Tick64();
+
+ // Attempt to resolve the name first
+ if (GetIP(&dest_ip, server_name))
+ {
+ // After successful name resolution, create a socket
+ s = NewUDP(0);
+ if (s != NULL)
+ {
+ // Creating success
+ break;
+ }
+ }
+
+ // Failure to create: wait until timeout or the setting is changed
+ while (true)
+ {
+ changed = false;
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+ {
+ break;
+ }
+
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+ }
+
+ // Send the packet data periodically
+ if (s != NULL)
+ {
+ UINT64 last_packet_sent_time = 0;
+ UINT num_ignore_errors = 0;
+ while (true)
+ {
+ SOCKSET set;
+ UINT ret;
+ UCHAR buf[MAX_SIZE];
+ bool changed;
+ IP src_ip;
+ UINT src_port;
+
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+
+ Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+ // Receive
+ ret = RecvFrom(s, &src_ip, &src_port, buf, sizeof(buf));
+ if (ret == 0)
+ {
+ if (s->IgnoreRecvErr == false)
+ {
+LABEL_DISCONNECTED:
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ else
+ {
+ if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS)
+ {
+ goto LABEL_DISCONNECTED;
+ }
+ }
+ }
+
+ if (s != NULL)
+ {
+ if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+ {
+ BUF *b;
+
+ // Send the next packet
+ last_packet_sent_time = Tick64();
+
+ b = NewKeepPacket(k->Server);
+
+ ret = SendTo(s, &dest_ip, server_port, b->Buf, b->Size);
+ FreeBuf(b);
+
+ if (ret == 0 && s->IgnoreSendErr == false)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ }
+ }
+
+ changed = false;
+
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode == false)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed || s == NULL)
+ {
+ // Setting has been changed or disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ goto WAIT_FOR_ENABLE;
+ }
+ else
+ {
+ if (k->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ ReleaseSock(s);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Stop the KEEP
+void StopKeep(KEEP *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ k->Halt = true;
+ Set(k->HaltEvent);
+ Cancel(k->Cancel);
+
+ WaitThread(k->Thread, INFINITE);
+ ReleaseThread(k->Thread);
+ DeleteLock(k->lock);
+
+ ReleaseCancel(k->Cancel);
+ ReleaseEvent(k->HaltEvent);
+
+ Free(k);
+}
+
+// Start the KEEP
+KEEP *StartKeep()
+{
+ KEEP *k = ZeroMalloc(sizeof(KEEP));
+
+ k->lock = NewLock();
+ k->HaltEvent = NewEvent();
+ k->Cancel = NewCancel();
+
+ // Thread start
+ k->Thread = NewThread(KeepThread, k);
+
+ return k;
+}
+
+// Copy the client authentication data
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a)
+{
+ CLIENT_AUTH *ret;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMallocEx(sizeof(CLIENT_AUTH), true);
+
+ ret->AuthType = a->AuthType;
+ StrCpy(ret->Username, sizeof(ret->Username), a->Username);
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ Copy(ret->HashedPassword, a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ StrCpy(ret->PlainPassword, sizeof(ret->PlainPassword), a->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication
+ ret->ClientX = CloneX(a->ClientX);
+ ret->ClientK = CloneK(a->ClientK);
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ // Secure device authentication
+ StrCpy(ret->SecurePublicCertName, sizeof(ret->SecurePublicCertName), a->SecurePublicCertName);
+ StrCpy(ret->SecurePrivateKeyName, sizeof(ret->SecurePrivateKeyName), a->SecurePrivateKeyName);
+ break;
+ }
+
+ return ret;
+}
+
+// Write data to the transmit FIFO (automatic encryption)
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL || ts == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (s->UseFastRC4)
+ {
+ Encrypt(ts->SendKey, data, data, size);
+ }
+
+ WriteFifo(ts->SendFifo, data, size);
+}
+
+// Write data to the reception FIFO (automatic deccyption)
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL || ts == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (s->UseFastRC4)
+ {
+ Encrypt(ts->RecvKey, data, data, size);
+ }
+
+ WriteFifo(ts->RecvFifo, data, size);
+}
+
+// TCP socket receive
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Receive
+ return Recv(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// TCP socket send
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Transmission
+ return Send(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// Send the data as UDP packet
+void SendDataWithUDP(SOCK *s, CONNECTION *c)
+{
+ UCHAR *buf;
+ BUF *b;
+ UINT64 dummy_64 = 0;
+ UCHAR dummy_buf[16];
+ UINT64 now = Tick64();
+ UINT ret;
+ bool force_flag = false;
+ bool packet_sent = false;
+ // Validate arguments
+ if (s == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Allocate the temporary buffer in heap
+ if (c->RecvBuf == NULL)
+ {
+ c->RecvBuf = Malloc(RECV_BUF_SIZE);
+ }
+ buf = c->RecvBuf;
+
+ if (c->Udp->NextKeepAliveTime == 0 || c->Udp->NextKeepAliveTime <= now)
+ {
+ force_flag = true;
+ }
+
+ // Creating a buffer
+ while ((c->SendBlocks->num_item > 0) || force_flag)
+ {
+ UINT *key32;
+ UINT64 *seq;
+ char *sign;
+
+ force_flag = false;
+
+ // Assemble a buffer from the current queue
+ b = NewBuf();
+
+ // Keep an area for packet header (16 bytes)
+ WriteBuf(b, dummy_buf, sizeof(dummy_buf));
+
+ // Pack the packets in transmission queue
+ LockQueue(c->SendBlocks);
+ {
+ while (true)
+ {
+ BLOCK *block;
+
+ if (b->Size > UDP_BUF_SIZE)
+ {
+ break;
+ }
+ block = GetNext(c->SendBlocks);
+ if (block == NULL)
+ {
+ break;
+ }
+
+ if (block->Size != 0)
+ {
+ WriteBufInt(b, block->Size);
+ WriteBuf(b, block->Buf, block->Size);
+
+ c->Session->TotalSendSize += (UINT64)block->SizeofData;
+ c->Session->TotalSendSizeReal += (UINT64)block->Size;
+ }
+
+ FreeBlock(block);
+ break;
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+
+ // Write sequence number and session key
+ sign = (char *)(((UCHAR *)b->Buf));
+ key32 = (UINT *)(((UCHAR *)b->Buf + 4));
+ seq = (UINT64 *)(((UCHAR *)b->Buf + 8));
+ Copy(sign, SE_UDP_SIGN, 4);
+ *key32 = Endian32(c->Session->SessionKey32);
+ *seq = Endian64(c->Udp->Seq++); // Increment the sequence number
+
+// InsertQueue(c->Udp->BufferQueue, b);
+
+ packet_sent = true;
+/* }
+
+ // Send a buffer
+ while (c->Udp->BufferQueue->num_item != 0)
+ {
+ FIFO *f = c->Udp->BufferQueue->fifo;
+ BUF **pb = (BUF**)(((UCHAR *)f->p) + f->pos);
+ BUF *b = *pb;
+
+*/ ret = SendTo(s, &c->Udp->ip, c->Udp->port, b->Buf, b->Size);
+ if (ret == SOCK_LATER)
+ {
+ // Blocking
+ Debug(".");
+// break;
+ }
+ if (ret != b->Size)
+ {
+ if (s->IgnoreSendErr == false)
+ {
+ // Error
+ Debug("******* SendTo Error !!!\n");
+ }
+ }
+
+ // Memory release
+ FreeBuf(b);
+// GetNext(c->Udp->BufferQueue);
+ }
+
+ if (packet_sent)
+ {
+ // KeepAlive time update
+ c->Udp->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+ }
+}
+
+// Write the data of the UDP packet to the connection
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size)
+{
+ BUF *b;
+ char sign[4];
+ // Validate arguments
+ if (c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Examine the protocol
+ if (c->Protocol != CONNECTION_UDP)
+ {
+ // UDP protocol is not used
+ return;
+ }
+
+ // Buffer configuration
+ b = NewBuf();
+ WriteBuf(b, data, size);
+
+ SeekBuf(b, 0, 0);
+ ReadBuf(b, sign, 4);
+
+ // Signature confirmation
+ if (Cmp(sign, SE_UDP_SIGN, 4) == 0)
+ {
+ UINT key32;
+
+ // Session key number
+ key32 = ReadBufInt(b);
+
+ if (c->Session->SessionKey32 == key32)
+ {
+ UINT64 seq;
+
+ // Read the Sequence number
+ ReadBuf(b, &seq, sizeof(seq));
+ seq = Endian64(seq);
+
+ if ((UINT)(seq - c->Udp->RecvSeq - (UINT64)1))
+ {
+ //Debug("** UDP Seq Lost %u\n", (UINT)(seq - c->Udp->RecvSeq - (UINT64)1));
+ }
+ c->Udp->RecvSeq = seq;
+
+ //Debug("SEQ: %I32u\n", seq);
+
+ while (true)
+ {
+ UINT size;
+
+ size = ReadBufInt(b);
+ if (size == 0)
+ {
+ break;
+ }
+ else if (size <= MAX_PACKET_SIZE)
+ {
+ void *tmp;
+ BLOCK *block;
+
+ tmp = Malloc(size);
+ if (ReadBuf(b, tmp, size) != size)
+ {
+ Free(tmp);
+ break;
+ }
+
+ // Block configuration
+ block = NewBlock(tmp, size, 0);
+
+ // Insert Block
+ InsertReveicedBlockToQueue(c, block);
+ }
+ }
+
+ // Update the last communication time
+ c->Session->LastCommTime = Tick64();
+ }
+ else
+ {
+ Debug("Invalid SessionKey: 0x%X\n", key32);
+ }
+ }
+
+ FreeBuf(b);
+}
+
+// Add a block to the receive queue
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block)
+{
+ SESSION *s;
+ // Validate arguments
+ if (c == NULL || block == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ s->TotalRecvSizeReal += block->SizeofData;
+ s->TotalRecvSize += block->Size;
+ }
+
+ LockQueue(c->ReceivedBlocks);
+ {
+ InsertQueue(c->ReceivedBlocks, block);
+ }
+ UnlockQueue(c->ReceivedBlocks);
+}
+
+// Generate the interval to the next Keep-Alive packet
+// (This should be a random number for the network load reduction)
+UINT GenNextKeepAliveSpan(CONNECTION *c)
+{
+ UINT a, b;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return INFINITE;
+ }
+
+ a = c->Session->Timeout;
+ b = rand() % (a / 2);
+ b = MAX(b, a / 5);
+
+ return b;
+}
+
+// send a Keep-Alive packet
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts)
+{
+ UINT size, i, num;
+ UINT size_be;
+ SESSION *s;
+ UCHAR *buf;
+ bool insert_natt_port = false;
+ // Validate arguments
+ if (c == NULL || ts == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+
+ size = rand() % MAX_KEEPALIVE_SIZE;
+ num = KEEP_ALIVE_MAGIC;
+
+ if (s != NULL && s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ if (s->UdpAccel->MyPortByNatTServer != 0)
+ {
+ size = MAX(size, (StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE) + sizeof(USHORT)));
+
+ insert_natt_port = true;
+ }
+ }
+
+ buf = MallocFast(size);
+
+ for (i = 0;i < size;i++)
+ {
+ buf[i] = rand();
+ }
+
+ if (insert_natt_port)
+ {
+ USHORT myport = Endian16((USHORT)s->UdpAccel->MyPortByNatTServer);
+
+ Copy(buf, UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE, StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE));
+ Copy(buf + StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE), &myport, sizeof(USHORT));
+ }
+
+ num = Endian32(num);
+ size_be = Endian32(size);
+ WriteSendFifo(c->Session, ts, &num, sizeof(UINT));
+ WriteSendFifo(c->Session, ts, &size_be, sizeof(UINT));
+ WriteSendFifo(c->Session, ts, buf, size);
+
+ c->Session->TotalSendSize += sizeof(UINT) * 2 + size;
+ c->Session->TotalSendSizeReal += sizeof(UINT) * 2 + size;
+
+ Free(buf);
+}
+
+// Transmission of block
+void ConnectionSend(CONNECTION *c)
+{
+ UINT i, num;
+ UINT64 now;
+ UINT min_count;
+ UINT64 max_recv_tick;
+ TCPSOCK **tcpsocks;
+ UINT size;
+ SESSION *s;
+ HUB *hub = NULL;
+ bool use_qos;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+ use_qos = s->QoS;
+
+ if (s != NULL)
+ {
+ hub = s->Hub;
+ }
+
+ now = Tick64();
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ TCP *tcp = c->Tcp;
+ TCPSOCK *ts;
+ TCPSOCK *ts_hp;
+ UINT num_available;
+ bool is_rudp = false;
+ LockList(tcp->TcpSockList);
+ {
+ num = LIST_NUM(tcp->TcpSockList);
+ tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ if (s != NULL)
+ {
+ is_rudp = s->IsRUDPSession;
+ }
+
+ // Select the socket that will be used to send
+ // Select a socket which have least delay count
+ min_count = INFINITE;
+ max_recv_tick = 0;
+ ts = NULL;
+ ts_hp = NULL;
+
+ num_available = 0;
+
+ if (c->IsInProc == false)
+ {
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *tcpsock = tcpsocks[i];
+ if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+ IS_SEND_TCP_SOCK(tcpsock))
+ {
+ // Processing of KeepAlive
+ if (now >= tcpsock->NextKeepAliveTime || tcpsock->NextKeepAliveTime == 0 ||
+ (s != NULL && s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->MyPortByNatTServerChanged))
+ {
+ // Send the KeepAlive
+ SendKeepAlive(c, tcpsock);
+ tcpsock->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ s->UdpAccel->MyPortByNatTServerChanged = false;
+ }
+ }
+
+ // Count the number of available sockets to send
+ num_available++;
+
+ ts_hp = tcpsock;
+ }
+ }
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *tcpsock = tcpsocks[i];
+ if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+ IS_SEND_TCP_SOCK(tcpsock))
+ {
+ // Selection of the socket
+ bool b = false;
+
+ if (use_qos == false)
+ {
+ b = true;
+ }
+ else if (num_available < 2)
+ {
+ b = true;
+ }
+ else if (tcpsock != ts_hp)
+ {
+ b = true;
+ }
+
+ if (b)
+ {
+ if (is_rudp == false)
+ {
+ // Use a socket which have minimum delay occurrences in the case of such as a TCP socket
+ if (tcpsock->LateCount <= min_count)
+ {
+ min_count = tcpsock->LateCount;
+ ts = tcpsock;
+ }
+ }
+ else
+ {
+ // Use socket which have the largest last received time in the case of R-UDP socket
+ if (tcpsock->LastRecvTime >= max_recv_tick)
+ {
+ max_recv_tick = tcpsock->LastRecvTime;
+ ts = tcpsock;
+ }
+ }
+ }
+ }
+ }
+
+ if (ts_hp == NULL)
+ {
+ ts_hp = ts;
+ }
+
+ if (use_qos == false)
+ {
+ ts_hp = ts;
+ }
+
+ if (ts == NULL || ts_hp == NULL)
+ {
+ // The socket available to send doesn't currently exist
+ }
+ else
+ {
+ TCPSOCK *tss;
+ UINT j;
+ QUEUE *q;
+
+ if (s->UdpAccel != NULL)
+ {
+ UdpAccelSetTick(s->UdpAccel, now);
+ }
+
+ for (j = 0;j < 2;j++)
+ {
+ if (j == 0)
+ {
+ q = c->SendBlocks2;
+ tss = ts_hp;
+ }
+ else
+ {
+ q = c->SendBlocks;
+ tss = ts;
+ }
+ // I reserve the data to send on the selected socket ts
+ LockQueue(c->SendBlocks);
+ if (q->num_item != 0)
+ {
+ UINT num_data;
+ BLOCK *b;
+
+ if (tss->SendFifo->size >= MAX((MAX_SEND_SOCKET_QUEUE_SIZE / s->MaxConnection), MIN_SEND_SOCKET_QUEUE_SIZE))
+ {
+ // The size of the socket send queue is exceeded
+ // Unable to send
+ while (b = GetNext(q))
+ {
+ if (b != NULL)
+ {
+ c->CurrentSendQueueSize -= b->Size;
+ FreeBlock(b);
+ }
+ }
+ }
+ else
+ {
+ if (c->IsInProc == false)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && UdpAccelIsSendReady(s->UdpAccel, true))
+ {
+ // UDP acceleration mode
+ while (b = GetNext(q))
+ {
+ UdpAccelSendBlock(s->UdpAccel, b);
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ FreeBlock(b);
+ }
+ }
+ else if (s->IsRUDPSession && s->EnableBulkOnRUDP && ts->Sock != NULL && ts->Sock->BulkSendTube != NULL)
+ {
+ // R-UDP bulk transfer
+ TUBE *t = ts->Sock->BulkSendTube;
+ bool flush = false;
+ TCP_PAIR_HEADER h;
+
+ Zero(&h, sizeof(h));
+ h.EnableHMac = s->EnableHMacOnBulkOfRUDP;
+
+ while (b = GetNext(q))
+ {
+ if (b->Compressed == false)
+ {
+ // Uncompressed
+ TubeSendEx(t, b->Buf, b->Size, &h, true);
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+ }
+ else
+ {
+ // Compressed
+ UCHAR *new_buf = Malloc(b->Size + sizeof(UINT64));
+
+ WRITE_UINT64(new_buf, CONNECTION_BULK_COMPRESS_SIGNATURE);
+
+ Copy(new_buf + sizeof(UINT64), b->Buf, b->Size);
+
+ TubeSendEx(t, new_buf, b->Size + sizeof(UINT64), &h, true);
+
+ s->TotalSendSize += b->SizeofData;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+ }
+
+ FreeBlock(b);
+
+ flush = true;
+ }
+
+ if (flush)
+ {
+ TubeFlush(t);
+ }
+ }
+ else
+ {
+ // TCP/IP socket
+ bool update_keepalive_timer = false;
+ // Number of data
+ num_data = Endian32(q->num_item);
+ PROBE_DATA2("WriteSendFifo num", &num_data, sizeof(UINT));
+ WriteSendFifo(s, tss, &num_data, sizeof(UINT));
+
+ s->TotalSendSize += sizeof(UINT);
+ s->TotalSendSizeReal += sizeof(UINT);
+
+ while (b = GetNext(q))
+ {
+ // Size data
+ UINT size_data;
+ size_data = Endian32(b->Size);
+ PROBE_DATA2("WriteSendFifo size", &size_data, sizeof(UINT));
+ WriteSendFifo(s, tss, &size_data, sizeof(UINT));
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ s->TotalSendSize += sizeof(UINT);
+ s->TotalSendSizeReal += sizeof(UINT);
+
+ // Data body
+ PROBE_DATA2("WriteSendFifo data", b->Buf, b->Size);
+ WriteSendFifo(s, tss, b->Buf, b->Size);
+
+ s->TotalSendSize += b->SizeofData;
+ s->TotalSendSizeReal += b->Size;
+
+ update_keepalive_timer = true;
+
+ // Block release
+ FreeBlock(b);
+ }
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && UdpAccelIsSendReady(s->UdpAccel, false))
+ {
+ update_keepalive_timer = false;
+ }
+
+ if (update_keepalive_timer)
+ {
+ // Increase the KeepAlive timer
+ tss->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+ }
+ }
+ }
+ else
+ {
+ bool flush = false;
+ // In-process socket
+ while (b = GetNext(q))
+ {
+ TubeSendEx(ts->Sock->SendTube, b->Buf, b->Size, NULL, true);
+ flush = true;
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ FreeBlock(b);
+ }
+
+ if (flush)
+ {
+ TubeFlush(ts->Sock->SendTube);
+ }
+ }
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+
+ // Send the reserved data to send registered in each socket now
+ if (c->IsInProc == false)
+ {
+ for (i = 0;i < num;i++)
+ {
+ ts = tcpsocks[i];
+
+SEND_START:
+ if (ts->Sock->Connected == false)
+ {
+ s->LastTryAddConnectTime = Tick64();
+ // Communication is disconnected
+ LockList(tcp->TcpSockList);
+ {
+ // Remove the socket from socket list
+ Delete(tcp->TcpSockList, ts);
+ // Release of TCPSOCK
+ FreeTcpSock(ts);
+ // Decrement the count
+ Dec(c->CurrentNumConnection);
+ Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+ Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+ }
+ UnlockList(tcp->TcpSockList);
+
+ continue;
+ }
+
+ // Get Fifo size
+ if (ts->SendFifo->size != 0)
+ {
+ UCHAR *buf;
+ UINT want_send_size;
+ // Send only if the data to send exists by 1 byte or more
+ // Get the pointer to the buffer
+ buf = (UCHAR *)ts->SendFifo->p + ts->SendFifo->pos;
+ want_send_size = ts->SendFifo->size;
+
+ PROBE_DATA2("TcpSockSend", buf, want_send_size);
+ size = TcpSockSend(s, ts, buf, want_send_size);
+
+ if (size == 0)
+ {
+ // Disconnected
+ continue;
+ }
+ else if (size == SOCK_LATER)
+ {
+ // Packet is jammed
+ ts->LateCount++; // Increment of the delay counter
+ PROBE_STR("ts->LateCount++;");
+ }
+ else
+ {
+ // Packet is sent only by 'size'
+ // Advance FIFO
+ ReadFifo(ts->SendFifo, NULL, size);
+ if (size < want_send_size)
+ {
+ // Fail to transmit all of the data that has been scheduled
+#ifdef USE_PROBE
+ {
+ char tmp[MAX_SIZE];
+
+ snprintf(tmp, sizeof(tmp), "size < want_send_size: %u < %u",
+ size, want_send_size);
+
+ PROBE_STR(tmp);
+ }
+#endif // USE_PROBE
+ }
+ else
+ {
+ // Because sending all the packets is completed
+ // (The queue is exhausted), reset the delay counter
+ ts->LateCount = 0;
+
+ PROBE_STR("TcpSockSend All Completed");
+ }
+ // Updated the last communication date and time
+ c->Session->LastCommTime = now;
+
+ goto SEND_START;
+ }
+ }
+ }
+ }
+
+ Free(tcpsocks);
+ }
+ else if (c->Protocol == CONNECTION_UDP)
+ {
+ // UDP
+ UDP *udp = c->Udp;
+ SOCK *sock = NULL;
+
+ Lock(c->lock);
+ {
+ sock = udp->s;
+ if (sock != NULL)
+ {
+ AddRef(sock->ref);
+ }
+ }
+ Unlock(c->lock);
+
+ if (sock != NULL)
+ {
+ // Send with UDP
+
+ // KeepAlive sending
+ if ((udp->NextKeepAliveTime == 0 || udp->NextKeepAliveTime <= now) ||
+ (c->SendBlocks->num_item != 0) || (udp->BufferQueue->num_item != 0))
+ {
+ // Send the current queue with UDP
+ SendDataWithUDP(sock, c);
+ }
+ }
+
+ if (sock != NULL)
+ {
+ ReleaseSock(sock);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+ {
+ // SecureNAT session
+ SNAT *snat = s->SecureNAT;
+ VH *v = snat->Nat->Virtual;
+
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = 0;
+
+ if (hub != NULL)
+ {
+ NatSetHubOption(v, hub->Option);
+ }
+
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_packet++;
+ c->CurrentSendQueueSize -= block->Size;
+ VirtualPutPacket(v, block->Buf, block->Size);
+ Free(block);
+ }
+
+ if (num_packet != 0)
+ {
+ VirtualPutPacket(v, NULL, 0);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ else if (c->Protocol == CONNECTION_HUB_LAYER3)
+ {
+ // Layer-3 session
+ L3IF *f = s->L3If;
+
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = 0;
+
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_packet++;
+ c->CurrentSendQueueSize -= block->Size;
+ L3PutPacket(f, block->Buf, block->Size);
+ Free(block);
+ }
+
+ if (num_packet != 0)
+ {
+ L3PutPacket(f, NULL, 0);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+ {
+ // HUB Link
+ LINK *k = (LINK *)s->Link;
+
+ if (k != NULL)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ UINT num_blocks = 0;
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block;
+
+ // Transfer the packet queue to the client thread
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_blocks++;
+ c->CurrentSendQueueSize -= block->Size;
+ InsertQueue(k->SendPacketQueue, block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ if (num_blocks != 0)
+ {
+ // Issue of cancellation
+ Cancel(k->ClientSession->Cancel1);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+ {
+ // Local bridge
+ BRIDGE *b = s->Bridge;
+
+ if (b != NULL)
+ {
+ if (b->Active)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = c->SendBlocks->num_item; // Packet count
+
+ if (num_packet != 0)
+ {
+ // Packet data array
+ void **datas = MallocFast(sizeof(void *) * num_packet);
+ UINT *sizes = MallocFast(sizeof(UINT *) * num_packet);
+ UINT i;
+
+ i = 0;
+ while (block = GetNext(c->SendBlocks))
+ {
+ if (hub != NULL && hub->Option != NULL && hub->Option->DisableUdpFilterForLocalBridgeNic == false &&
+ b->Eth != NULL && IsDhcpPacketForSpecificMac(block->Buf, block->Size, b->Eth->MacAddress))
+ {
+ // DHCP Packet is filtered
+ datas[i] = NULL;
+ sizes[i] = 0;
+
+ Free(block->Buf);
+ }
+ else
+ {
+ datas[i] = block->Buf;
+ sizes[i] = block->Size;
+
+ if (block->Size > 1514)
+ {
+ NormalizeEthMtu(b, c, block->Size);
+ }
+ }
+
+ c->CurrentSendQueueSize -= block->Size;
+ Free(block);
+ i++;
+ }
+
+ // Write the packet
+ EthPutPackets(b->Eth, num_packet, datas, sizes);
+
+ Free(datas);
+ Free(sizes);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+ }
+}
+
+// Reception of the block
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2)
+{
+ UINT i, num;
+ SOCKSET set;
+ SESSION *s;
+ TCPSOCK **tcpsocks;
+ UCHAR *buf;
+ UINT size;
+ UINT64 now;
+ UINT time;
+ UINT num_delayed = 0;
+ bool no_spinlock_for_delay = false;
+ HUB *hub = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ PROBE_STR("ConnectionReceive");
+
+ s = c->Session;
+
+ if (s != NULL)
+ {
+ hub = s->Hub;
+ }
+
+ if (hub != NULL)
+ {
+ no_spinlock_for_delay = hub->Option->NoSpinLockForPacketDelay;
+ }
+
+ now = Tick64();
+
+ if (c->RecvBuf == NULL)
+ {
+ c->RecvBuf = Malloc(RECV_BUF_SIZE);
+ }
+ buf = c->RecvBuf;
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ TCP *tcp = c->Tcp;
+ UINT next_delay_packet_diff = 0;
+
+ // Disconnect if disconnection interval is specified
+ if (s->ServerMode == false)
+ {
+ if (s->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ LockList(tcp->TcpSockList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(tcp->TcpSockList);i++)
+ {
+ TCPSOCK *ts = LIST_DATA(tcp->TcpSockList, i);
+ if (ts->DisconnectTick != 0 &&
+ ts->DisconnectTick <= now)
+ {
+ Debug("ts->DisconnectTick <= now\n");
+ Disconnect(ts->Sock);
+ }
+ }
+ }
+ UnlockList(tcp->TcpSockList);
+ }
+ }
+
+ if (s->HalfConnection && (s->ServerMode == false))
+ {
+ // Check the direction of the current TCP connections.
+ // Disconnect one if the number of connections reaches
+ // the limit and has only one direction
+ LockList(tcp->TcpSockList);
+ {
+ UINT i, num;
+ UINT c2s, s2c;
+ c2s = s2c = 0;
+ num = LIST_NUM(tcp->TcpSockList);
+ if (num >= s->MaxConnection)
+ {
+ TCPSOCK *ts;
+ for (i = 0;i < num;i++)
+ {
+ ts = LIST_DATA(tcp->TcpSockList, i);
+ if (ts->Direction == TCP_SERVER_TO_CLIENT)
+ {
+ s2c++;
+ }
+ else
+ {
+ c2s++;
+ }
+ }
+ if (s2c == 0 || c2s == 0)
+ {
+ // Disconnect the last socket
+ Disconnect(ts->Sock);
+ Debug("Disconnect (s2c=%u, c2s=%u)\n", s2c, c2s);
+ }
+ }
+ }
+ UnlockList(tcp->TcpSockList);
+ }
+
+ // Initializing the socket set
+ InitSockSet(&set);
+ LockList(tcp->TcpSockList);
+ {
+ num = LIST_NUM(tcp->TcpSockList);
+ tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ for (i = 0;i < num;i++)
+ {
+ AddSockSet(&set, tcpsocks[i]->Sock);
+ }
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ if (s->UdpAccel->UdpSock != NULL)
+ {
+ AddSockSet(&set, s->UdpAccel->UdpSock);
+ }
+ }
+
+ // Select
+ time = SELECT_TIME;
+ if (s->VirtualHost)
+ {
+ time = MIN(time, SELECT_TIME_FOR_NAT);
+ }
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ PROBE_STR("ConnectionReceive: Select 0");
+
+ if (s->Flag1 != set.NumSocket)
+ {
+ Select(&set, (num_delayed == 0 ? time : 1), c1, c2);
+ s->Flag1 = set.NumSocket;
+ }
+ else
+ {
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(&set, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ s->Flag1 = set.NumSocket;
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+
+ PROBE_STR("ConnectionReceive: Select 1");
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ // Read the data received by the UDP If using the UDP acceleration mode
+ UdpAccelSetTick(s->UdpAccel, now);
+ UdpAccelPoll(s->UdpAccel);
+
+ if (s->UdpAccelMss == 0)
+ {
+ s->UdpAccelMss = UdpAccelCalcMss(s->UdpAccel);
+ }
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->UdpAccel->RecvBlockQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (b->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(b);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, b);
+ }
+ }
+ }
+
+ {
+ bool new_status = UdpAccelIsSendReady(s->UdpAccel, true);
+
+ if (s->IsUsingUdpAcceleration != new_status)
+ {
+ Debug("UDP Status Changed: %u\n", new_status);
+ }
+
+ s->IsUsingUdpAcceleration = new_status;
+ }
+
+ // Read all the data that has arrived to the TCP socket
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *ts = tcpsocks[i];
+ SOCK *sock = ts->Sock;
+
+ if (s->IsRUDPSession)
+ {
+ TUBE *t = sock->BulkRecvTube;
+
+ if (s->EnableBulkOnRUDP)
+ {
+ // R-UDP bulk transfer data reception
+ if (t != NULL && IsTubeConnected(t))
+ {
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(t);
+ BLOCK *block;
+ if (d == NULL)
+ {
+ // All reception complete
+ break;
+ }
+
+ if (d->DataSize > sizeof(UINT64) && READ_UINT64(d->Data) == CONNECTION_BULK_COMPRESS_SIGNATURE)
+ {
+ // Compression
+ block = NewBlock(Clone(((UCHAR *)d->Data) + sizeof(UINT64),
+ d->DataSize - sizeof(UINT64)),
+ d->DataSize - sizeof(UINT64),
+ -1);
+ }
+ else
+ {
+ // Uncompressed
+ block = NewBlock(Clone(d->Data, d->DataSize), d->DataSize, 0);
+ }
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ FreeTubeData(d);
+
+ ts->LastCommTime = now;
+ ts->LastRecvTime = now;
+ c->Session->LastCommTime = now;
+ }
+ }
+ }
+ }
+
+ if (c->IsInProc)
+ {
+ TUBEDATA *d;
+ // Socket for in-process connection
+ if (IsTubeConnected(sock->RecvTube) == false)
+ {
+ // Communication is disconnected
+ goto DISCONNECT_THIS_TCP;
+ }
+
+ while (true)
+ {
+ BLOCK *block;
+ // Get the packet data from the tube
+ d = TubeRecvAsync(sock->RecvTube);
+ if (d == NULL)
+ {
+ // All acquisition completed
+ break;
+ }
+
+ block = NewBlock(Clone(d->Data, d->DataSize), d->DataSize, 0);
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ FreeTubeData(d);
+ }
+
+ c->Session->LastCommTime = now;
+ }
+ else
+ {
+ // A normal socket (Not in-process)
+ if (ts->WantSize == 0)
+ {
+ // Read for sizeof(UINT) first
+ ts->WantSize = sizeof(UINT);
+ }
+
+RECV_START:
+ // Receive
+ size = TcpSockRecv(s, ts, buf, RECV_BUF_SIZE);
+/*
+ // Experiment
+ if (c->ServerMode)
+ {
+ if ((ts->EstablishedTick + (UINT64)3000) <= now)
+ {
+ size = 0;
+ WHERE;
+ }
+ }*/
+
+ if (size == 0)
+ {
+DISCONNECT_THIS_TCP:
+ s->LastTryAddConnectTime = Tick64();
+ s->NumDisconnected++;
+ // Communication is disconnected
+ LockList(tcp->TcpSockList);
+ {
+ // Remove the socket from socket list
+ Delete(tcp->TcpSockList, ts);
+ // Release of TCPSOCK
+ FreeTcpSock(ts);
+ // Decrement
+ Dec(c->CurrentNumConnection);
+ Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+ Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+ }
+ UnlockList(tcp->TcpSockList);
+
+ continue;
+ }
+ else if (size == SOCK_LATER)
+ {
+ // State of waiting reception : don't do anything
+ if (IS_RECV_TCP_SOCK(ts))
+ {
+ if ((now > ts->LastCommTime) && ((now - ts->LastCommTime) >= ((UINT64)s->Timeout)))
+ {
+ // The connection has timed out
+ Debug("Connection %u Timeouted.\n", i);
+ goto DISCONNECT_THIS_TCP;
+ }
+ }
+ }
+ else
+ {
+ // Update the last communication time
+ ts->LastCommTime = now;
+ c->Session->LastCommTime = now;
+ ts->LastRecvTime = now;
+
+ // Write the received data into the FIFO
+ PROBE_DATA2("WriteRecvFifo", buf, size);
+ WriteRecvFifo(s, ts, buf, size);
+
+ // Stop receiving when the receive buffer is full
+ if (ts->RecvFifo->size < MAX_SEND_SOCKET_QUEUE_SIZE)
+ {
+ goto RECV_START;
+ }
+ }
+
+ // process the data written to FIFO
+ while (ts->RecvFifo->size >= ts->WantSize)
+ {
+ UCHAR *buf;
+ void *data;
+ BLOCK *block;
+ UINT sz;
+ // A sufficient amount of data is already stored
+ // Get the pointer of the data
+ buf = (UCHAR *)ts->RecvFifo->p + ts->RecvFifo->pos;
+
+ switch (ts->Mode)
+ {
+ case 0:
+ // The number of Data blocks
+ ts->WantSize = sizeof(UINT);
+ Copy(&sz, buf, sizeof(UINT));
+ PROBE_DATA2("ReadFifo 0", buf, sizeof(UINT));
+ sz = Endian32(sz);
+ ts->NextBlockNum = sz;
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->CurrentPacketNum = 0;
+ if (ts->NextBlockNum != 0)
+ {
+ if (ts->NextBlockNum == KEEP_ALIVE_MAGIC)
+ {
+ ts->Mode = 3;
+ }
+ else
+ {
+ ts->Mode = 1;
+ }
+ }
+ break;
+
+ case 1:
+ // Data block size
+ Copy(&sz, buf, sizeof(UINT));
+ sz = Endian32(sz);
+ PROBE_DATA2("ReadFifo 1", buf, sizeof(UINT));
+ if (sz > (MAX_PACKET_SIZE * 2))
+ {
+ // received a strange data size
+ // TCP/IP Error?
+ Debug("%s %u sz > (MAX_PACKET_SIZE * 2)\n", __FILE__, __LINE__);
+ Disconnect(ts->Sock);
+ }
+ ts->NextBlockSize = MIN(sz, MAX_PACKET_SIZE * 2);
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->WantSize = ts->NextBlockSize;
+ if (ts->WantSize != 0)
+ {
+ ts->Mode = 2;
+ }
+ else
+ {
+ ts->Mode = 1;
+ ts->WantSize = sizeof(UINT);
+ ts->CurrentPacketNum++;
+ if (ts->CurrentPacketNum >= ts->NextBlockNum)
+ {
+ ts->Mode = 0;
+ }
+ }
+ break;
+
+ case 2:
+ // Data block body
+ ts->WantSize = sizeof(UINT);
+ ts->CurrentPacketNum++;
+ data = MallocFast(ts->NextBlockSize);
+ Copy(data, buf, ts->NextBlockSize);
+ PROBE_DATA2("ReadFifo 2", buf, ts->NextBlockSize);
+ ReadFifo(ts->RecvFifo, NULL, ts->NextBlockSize);
+ block = NewBlock(data, ts->NextBlockSize, s->UseCompress ? -1 : 0);
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ if (ts->CurrentPacketNum >= ts->NextBlockNum)
+ {
+ // Reception of all the data blocks completed
+ ts->Mode = 0;
+ }
+ else
+ {
+ // Receive next data block size
+ ts->Mode = 1;
+ }
+ break;
+
+ case 3:
+ // Keep-Alive packet size
+ ts->Mode = 4;
+ Copy(&sz, buf, sizeof(UINT));
+ PROBE_DATA2("ReadFifo 3", buf, sizeof(UINT));
+ sz = Endian32(sz);
+ if (sz > MAX_KEEPALIVE_SIZE)
+ {
+ // received a strange data size
+ // TCP/IP Error?
+ Debug("%s %u sz > MAX_KEEPALIVE_SIZE\n", __FILE__, __LINE__);
+ Disconnect(ts->Sock);
+ }
+ ts->NextBlockSize = MIN(sz, MAX_KEEPALIVE_SIZE);
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->WantSize = sz;
+ break;
+
+ case 4:
+ // Keep-Alive packet body
+ //Debug("KeepAlive Recved.\n");
+ ts->Mode = 0;
+ sz = ts->NextBlockSize;
+
+ if (sz >= (StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE) + sizeof(USHORT)))
+ {
+ UCHAR *keep_alive_buffer = FifoPtr(ts->RecvFifo);
+
+ if (Cmp(keep_alive_buffer, UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE, StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE)) == 0)
+ {
+ USHORT us = READ_USHORT(keep_alive_buffer + StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE));
+
+ if (us != 0)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ UINT port = (UINT)us;
+
+ if (s->UdpAccel->YourPortByNatTServer != port)
+ {
+ s->UdpAccel->YourPortByNatTServer = port;
+ s->UdpAccel->YourPortByNatTServerChanged = true;
+
+ Debug("s->UdpAccel->YourPortByNatTServer: %u\n",
+ s->UdpAccel->YourPortByNatTServer);
+ }
+ }
+ }
+ }
+ }
+
+ PROBE_DATA2("ReadFifo 4", NULL, 0);
+ ReadFifo(ts->RecvFifo, NULL, sz);
+
+ s->TotalRecvSize += sz;
+ s->TotalRecvSizeReal += sz;
+
+ ts->WantSize = sizeof(UINT);
+ break;
+ }
+ }
+ }
+ }
+
+ Free(tcpsocks);
+ }
+ else if (c->Protocol == CONNECTION_UDP)
+ {
+ // UDP
+ UDP *udp = c->Udp;
+ SOCK *sock = NULL;
+
+ if (s->ServerMode == false)
+ {
+ Lock(c->lock);
+ {
+ if (c->Udp->s != NULL)
+ {
+ sock = c->Udp->s;
+ if (sock != NULL)
+ {
+ AddRef(sock->ref);
+ }
+ }
+ }
+ Unlock(c->lock);
+
+ InitSockSet(&set);
+
+ if (sock != NULL)
+ {
+ AddSockSet(&set, sock);
+ }
+
+ Select(&set, SELECT_TIME, c1, c2);
+
+ if (sock != NULL)
+ {
+ IP ip;
+ UINT port;
+ UCHAR *buf;
+ UINT size;
+
+ while (true)
+ {
+ buf = c->RecvBuf;
+ size = RecvFrom(sock, &ip, &port, buf, RECV_BUF_SIZE);
+ if (size == 0 && sock->IgnoreRecvErr == false)
+ {
+ Debug("UDP Socket Disconnected.\n");
+ Lock(c->lock);
+ {
+ ReleaseSock(udp->s);
+ udp->s = NULL;
+ }
+ Unlock(c->lock);
+ break;
+ }
+ else if (size == SOCK_LATER)
+ {
+ break;
+ }
+ else
+ {
+ if (size)
+ {
+ PutUDPPacketData(c, buf, size);
+ }
+ }
+ }
+ }
+
+ if (sock != NULL)
+ {
+ Release(sock->ref);
+ }
+ }
+ else
+ {
+ Select(NULL, SELECT_TIME, c1, c2);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+ {
+ SNAT *snat = c->Session->SecureNAT;
+ VH *v = snat->Nat->Virtual;
+ UINT size;
+ void *data;
+ UINT num;
+ UINT select_wait_time = SELECT_TIME_FOR_NAT;
+ UINT next_delay_packet_diff = 0;
+
+ if (snat->Nat != NULL && snat->Nat->Option.UseNat == false)
+ {
+ select_wait_time = SELECT_TIME;
+ }
+ else
+ {
+ if (snat->Nat != NULL)
+ {
+ LockList(v->NatTable);
+ {
+ if (LIST_NUM(v->NatTable) == 0 && LIST_NUM(v->ArpWaitTable) == 0)
+ {
+ select_wait_time = SELECT_TIME;
+ }
+ }
+ UnlockList(v->NatTable);
+ }
+ }
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ select_wait_time = MIN(select_wait_time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || select_wait_time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? select_wait_time :
+ (select_wait_time > 100 ? (select_wait_time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+
+ num = 0;
+
+ if (hub != NULL)
+ {
+ NatSetHubOption(v, hub->Option);
+ }
+
+ // Receive a packet from the virtual machine
+ while (size = VirtualGetNextPacket(v, &data))
+ {
+ BLOCK *block;
+
+ // Generate packet block
+ block = NewBlock(data, size, 0);
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+// WHERE;
+ break;
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+ {
+ // HUB Link
+ // Waiting Cancel simply
+ if (c->SendBlocks->num_item == 0)
+ {
+ UINT time = SELECT_TIME;
+ UINT next_delay_packet_diff = 0;
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_LAYER3)
+ {
+ // Layer-3 switch session
+ L3IF *f = s->L3If;
+ UINT size, num = 0;
+ void *data;
+
+ if (f->SendQueue->num_item == 0)
+ {
+ UINT time = SELECT_TIME_FOR_NAT;
+ UINT next_delay_packet_diff = 0;
+
+ if (f->ArpWaitTable != NULL)
+ {
+ LockList(f->ArpWaitTable);
+ {
+ if (LIST_NUM(f->ArpWaitTable) == 0)
+ {
+ time = SELECT_TIME;
+ }
+ }
+ UnlockList(f->ArpWaitTable);
+ }
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+
+ // Get the next packet
+ while (size = L3GetNextPacket(f, &data))
+ {
+ BLOCK *block = NewBlock(data, size, 0);
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ FreeBlock(block);
+ }
+ else
+ {
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+ break;
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+ {
+ BRIDGE *b = c->Session->Bridge;
+
+ // Bridge session
+ if (b->Active)
+ {
+ void *data;
+ UINT ret;
+ UINT num = 0;
+ bool check_device_num = false;
+ UINT time = SELECT_TIME;
+ UINT next_delay_packet_diff = 0;
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ // Bridge is operating
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+
+ if ((b->LastNumDeviceCheck + BRIDGE_NUM_DEVICE_CHECK_SPAN) <= Tick64())
+ {
+ check_device_num = true;
+ b->LastNumDeviceCheck = Tick64();
+ }
+
+ // Get the next packet from the bridge
+ while (true)
+ {
+ if (check_device_num && b->LastNumDevice != GetEthDeviceHash())
+ {
+ ret = INFINITE;
+ }
+ else
+ {
+ ret = EthGetPacket(b->Eth, &data);
+ }
+
+#ifdef OS_WIN32
+ if (c->Session != NULL)
+ {
+ c->Session->BridgeIsEthLoopbackBlock = false;
+ if (b->Eth != NULL && b->Eth->LoopbackBlock)
+ {
+ // Check whether The Ethernet device in the bridge
+ // has the ability to block the loopback packet
+ c->Session->BridgeIsEthLoopbackBlock = true;
+ }
+ }
+#endif // OS_WIN32
+
+ if (ret == INFINITE)
+ {
+ // Error occured: stop the bridge
+ CloseEth(b->Eth);
+ b->Eth = NULL;
+ b->Active = false;
+ ReleaseCancel(s->Cancel2);
+ s->Cancel2 = NULL;
+
+ HLog(s->Hub, "LH_BRIDGE_2", s->Name, b->Name);
+ Debug("Bridge Device Error.\n");
+
+ break;
+ }
+ else if (ret == 0)
+ {
+ // There is no more packet to receive
+ break;
+ }
+ else
+ {
+ if (hub != NULL && hub->Option != NULL && hub->Option->DisableUdpFilterForLocalBridgeNic == false &&
+ b->Eth != NULL && IsDhcpPacketForSpecificMac(data, ret, b->Eth->MacAddress))
+ {
+ // DHCP Packet is filtered.
+ Free(data);
+ }
+ else
+ {
+ // Add the packet to queue
+ BLOCK *block = NewBlock(data, ret, 0);
+
+ PROBE_DATA2("ConnectionReceive: NewBlock", data, ret);
+
+ if (ret > 1514)
+ {
+ NormalizeEthMtu(b, c, ret);
+ }
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ InsertReveicedBlockToQueue(c, block);
+ }
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+ // WHERE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ETH *e;
+ // Bridge is stopped cureently
+ Select(NULL, SELECT_TIME, c1, NULL);
+
+ if (b->LastBridgeTry == 0 || (b->LastBridgeTry + BRIDGE_TRY_SPAN) <= Tick64())
+ {
+ b->LastBridgeTry = Tick64();
+
+ // Try to open an Ethernet device
+ e = OpenEth(b->Name, b->Local, b->TapMode, b->TapMacAddress);
+ if (e != NULL)
+ {
+ // Success
+ b->Eth = e;
+ b->Active = true;
+ b->LastNumDeviceCheck = Tick64();
+ b->LastNumDevice = GetEthDeviceHash();
+
+ // Update the NIC name of the bridge
+#ifdef OS_WIN32
+ if (IsEmptyStr(e->Title) == false)
+ {
+ StrCpy(b->Name, sizeof(b->Name), e->Title);
+
+ if (b->ParentLocalBridge != NULL)
+ {
+ StrCpy(b->ParentLocalBridge->DeviceName, sizeof(b->ParentLocalBridge->DeviceName), e->Title);
+ }
+ }
+#endif // OS_WIN32
+
+ Debug("Bridge Open Succeed.\n");
+
+ HLog(c->Session->Hub, "LH_BRIDGE_1", c->Session->Name, b->Name);
+
+ s->Cancel2 = EthGetCancel(b->Eth);
+ }
+ }
+ }
+ }
+}
+
+// Normalize the MTU of the Ethernet device
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size)
+{
+ // Validate arguments
+ if (packet_size == 0 || b == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Raise the MTU when the packet exceeds the current MTU
+ if (EthIsChangeMtuSupported(b->Eth))
+ {
+ UINT currentMtu = EthGetMtu(b->Eth);
+ if (currentMtu != 0)
+ {
+ if (packet_size > currentMtu)
+ {
+ bool ok = EthSetMtu(b->Eth, packet_size);
+
+ if (ok)
+ {
+ HLog(c->Session->Hub, "LH_SET_MTU", c->Session->Name,
+ b->Name, currentMtu, packet_size, packet_size);
+ }
+ else
+ {
+ UINT64 now = Tick64();
+
+ if (b->LastChangeMtuError == 0 ||
+ now >= (b->LastChangeMtuError + 60000ULL))
+ {
+ HLog(c->Session->Hub, "LH_SET_MTU_ERROR", c->Session->Name,
+ b->Name, currentMtu, packet_size, packet_size);
+
+ b->LastChangeMtuError = now;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Release of the block
+void FreeBlock(BLOCK *b)
+{
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+
+ Free(b->Buf);
+ Free(b);
+}
+
+// Create a new block
+BLOCK *NewBlock(void *data, UINT size, int compress)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ b = MallocFast(sizeof(BLOCK));
+
+ b->PriorityQoS = b->Ttl = b->Param1 = 0;
+
+ if (compress == 0)
+ {
+ // Uncompressed
+ b->Compressed = FALSE;
+ b->Buf = data;
+ b->Size = size;
+ b->SizeofData = size;
+ }
+ else if (compress == 1)
+ {
+ UINT max_size;
+
+ // Compressed
+ b->Compressed = TRUE;
+ max_size = CalcCompress(size);
+ b->Buf = MallocFast(max_size);
+ b->Size = Compress(b->Buf, max_size, data, size);
+ b->SizeofData = size;
+
+ // Discard old data block
+ Free(data);
+ }
+ else
+ {
+ // Expand
+ UINT max_size;
+
+ b->Compressed = FALSE;
+ max_size = MAX_PACKET_SIZE;
+ b->Buf = MallocFast(max_size);
+ b->Size = Uncompress(b->Buf, max_size, data, size);
+ b->SizeofData = size;
+
+ // Discard old data
+ Free(data);
+ }
+
+ return b;
+}
+
+// Create a TCP socket
+TCPSOCK *NewTcpSock(SOCK *s)
+{
+ TCPSOCK *ts;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ ts = ZeroMalloc(sizeof(TCPSOCK));
+
+ ts->Sock = s;
+ AddRef(s->ref);
+
+ ts->RecvFifo = NewFifo();
+ ts->SendFifo = NewFifo();
+ ts->EstablishedTick = ts->LastRecvTime = ts->LastCommTime = Tick64();
+
+ // Unset the time-out value
+ SetTimeout(s, TIMEOUT_INFINITE);
+
+ return ts;
+}
+
+// Set a encryption key for the TCP socket
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode)
+{
+ RC4_KEY_PAIR *pair;
+ CRYPT *c1, *c2;
+ // Validate arguments
+ if (ts == NULL)
+ {
+ return;
+ }
+
+ pair = &ts->Rc4KeyPair;
+
+ c1 = NewCrypt(pair->ClientToServerKey, sizeof(pair->ClientToServerKey));
+ c2 = NewCrypt(pair->ServerToClientKey, sizeof(pair->ServerToClientKey));
+
+ if (server_mode)
+ {
+ ts->RecvKey = c1;
+ ts->SendKey = c2;
+ }
+ else
+ {
+ ts->SendKey = c1;
+ ts->RecvKey = c2;
+ }
+}
+
+// Release of TCP socket
+void FreeTcpSock(TCPSOCK *ts)
+{
+ // Validate arguments
+ if (ts == NULL)
+ {
+ return;
+ }
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+ ReleaseFifo(ts->RecvFifo);
+ ReleaseFifo(ts->SendFifo);
+
+ if (ts->SendKey)
+ {
+ FreeCrypt(ts->SendKey);
+ }
+ if (ts->RecvKey)
+ {
+ FreeCrypt(ts->RecvKey);
+ }
+
+ Free(ts);
+}
+
+// Exit the tunneling mode of connection
+void EndTunnelingMode(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ DisconnectTcpSockets(c);
+ }
+ else
+ {
+ // UDP
+ DisconnectUDPSockets(c);
+ }
+}
+
+// Shift the connection to tunneling mode
+void StartTunnelingMode(CONNECTION *c)
+{
+ SOCK *s;
+ TCP *tcp;
+ TCPSOCK *ts;
+ IP ip;
+ UINT port;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ tcp = c->Tcp;
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ s = c->FirstSock;
+
+ if (c->IsInProc)
+ {
+ AddRef(s->ref);
+ c->TubeSock = s;
+ }
+
+ ts = NewTcpSock(s);
+
+ if (c->ServerMode == false)
+ {
+ if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+ }
+ }
+
+ LockList(tcp->TcpSockList);
+ {
+ Add(tcp->TcpSockList, ts);
+ }
+ UnlockList(tcp->TcpSockList);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ }
+ else
+ {
+ // UDP
+ s = c->FirstSock;
+ Copy(&ip, &s->RemoteIP, sizeof(IP));
+ // May disconnect TCP connection at this point
+ c->FirstSock = NULL;
+ Disconnect(s);
+ ReleaseSock(s);
+
+ // Initialization of UDP structure
+ c->Udp = ZeroMalloc(sizeof(UDP));
+
+ if (c->ServerMode)
+ {
+ // Server mode
+ // Add an UDP Entry
+ AddUDPEntry(c->Cedar, c->Session);
+ c->Udp->s = NULL;
+ }
+ else
+ {
+ port = c->Session->ClientOption->PortUDP;
+ // Client mode
+ c->Udp->s = NewUDP(0);
+ // Write the IP address and port number
+ Copy(&c->Udp->ip, &ip, sizeof(IP));
+ c->Udp->port = port;
+ }
+
+ // Queue
+ c->Udp->BufferQueue = NewQueue();
+ }
+}
+
+// Generate a random value that depends on each machine
+UINT GetMachineRand()
+{
+ char pcname[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+
+ Zero(pcname, sizeof(pcname));
+ GetMachineName(pcname, sizeof(pcname));
+
+ HashSha1(hash, pcname, StrLen(pcname));
+
+ return READ_UINT(hash);
+}
+
+// Function that accepts a new connection
+void ConnectionAccept(CONNECTION *c)
+{
+ SOCK *s;
+ X *x;
+ K *k;
+ char tmp[128];
+ UCHAR openssl_check_buf[2];
+ char *error_details = NULL;
+ SERVER *server;
+ UCHAR *peek_buf = NULL;
+ UINT peek_buf_size = 1500;
+ char sni[128] = {0};
+ bool native1 = false; // Non-SNI flag
+ bool native2 = false; // Non-TLS flag
+ bool native3 = false; // SSLv2 flag
+ bool no_native = false;
+ UINT peek_size = 0;
+ UINT initial_timeout = CONNECTING_TIMEOUT;
+ bool no_peek_log = false;
+ UCHAR ctoken_hash[SHA1_SIZE];
+ bool no_write_ctoken_log = false;
+
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Zero(ctoken_hash, sizeof(ctoken_hash));
+
+ peek_buf = ZeroMalloc(peek_buf_size);
+
+ Debug("ConnectionAccept()\n");
+
+ server = c->Cedar->Server;
+
+ // get a socket
+ s = c->FirstSock;
+ AddRef(s->ref);
+
+ Dec(c->Cedar->AcceptingSockets);
+
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ SLog(c->Cedar, "LS_CONNECTION_START_1", tmp, s->RemoteHostname, (IS_SPECIAL_PORT(s->RemotePort) ? 0 : s->RemotePort), c->Name);
+
+ // Timeout setting
+ initial_timeout += GetMachineRand() % (CONNECTING_TIMEOUT / 2);
+ SetTimeout(s, initial_timeout);
+
+
+ // Peek whether OpenSSL packet
+ if (s->IsReverseAcceptedSocket == false)
+ {
+ if (s->Type == SOCK_TCP && (c->Cedar != NULL && c->Cedar->Server != NULL && c->Cedar->Server->DisableOpenVPNServer == false))
+ {
+ if (Peek(s, openssl_check_buf, sizeof(openssl_check_buf)) == sizeof(openssl_check_buf))
+ {
+ if (OvsCheckTcpRecvBufIfOpenVPNProtocol(openssl_check_buf, sizeof(openssl_check_buf)))
+ {
+ // Detect OpenSSL packet
+ Debug("Detect OpenSSL on TCP!\n");
+
+ no_native = true;
+
+ if (OvsGetNoOpenVpnTcp() == false)
+ {
+ // Do OpenSSL processing
+ c->Type = CONNECTION_TYPE_OPENVPN;
+ if (OvsPerformTcpServer(c->Cedar, s) == false)
+ {
+ error_details = "OpenVPN_TCP_Aborted";
+ }
+ }
+
+ goto ERROR;
+ }
+ }
+ }
+
+
+ }
+
+ // Specify the encryption algorithm
+ Lock(c->Cedar->lock);
+ {
+ if (c->Cedar->CipherList != NULL)
+ {
+ SetWantToUseCipher(s, c->Cedar->CipherList);
+ }
+
+ x = CloneX(c->Cedar->ServerX);
+ k = CloneK(c->Cedar->ServerK);
+ }
+ Unlock(c->Cedar->lock);
+
+ // Start the SSL communication
+ Debug("StartSSL()\n");
+ if (StartSSL(s, x, k) == false)
+ {
+ // Failed
+ AddNoSsl(c->Cedar, &s->RemoteIP);
+ Debug("Failed to StartSSL.\n");
+ FreeX(x);
+ FreeK(k);
+
+ error_details = "StartSSL";
+
+ goto ERROR;
+ }
+
+ FreeX(x);
+ FreeK(k);
+
+ SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName);
+
+ Copy(c->CToken_Hash, ctoken_hash, SHA1_SIZE);
+
+ // Accept the connection
+ if (ServerAccept(c) == false)
+ {
+ // Failed
+ Debug("ServerAccept Failed. Err = %u\n", c->Err);
+ goto ERROR;
+ }
+
+ if (c->flag1 == false)
+ {
+ Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);
+ Disconnect(s);
+ }
+ DelConnection(c->Cedar, c);
+ ReleaseSock(s);
+
+ Free(peek_buf);
+ return;
+
+ERROR:
+ Debug("ConnectionAccept() Error.\n");
+
+
+ Disconnect(s);
+ DelConnection(c->Cedar, c);
+ ReleaseSock(s);
+ Free(peek_buf);
+}
+
+// Stop the threads putting additional connection of all that are currently running
+void StopAllAdditionalConnectThread(CONNECTION *c)
+{
+ UINT i, num;
+ SOCK **socks;
+ THREAD **threads;
+ // Validate arguments
+ if (c == NULL || c->ServerMode != false)
+ {
+ return;
+ }
+
+ // Disconnect the socket first
+ LockList(c->ConnectingSocks);
+ {
+ num = LIST_NUM(c->ConnectingSocks);
+ socks = ToArray(c->ConnectingSocks);
+ DeleteAll(c->ConnectingSocks);
+ }
+ UnlockList(c->ConnectingSocks);
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+
+ // Then, wait for the suspension of the thread
+ LockList(c->ConnectingThreads);
+ {
+ num = LIST_NUM(c->ConnectingThreads);
+ Debug("c->ConnectingThreads: %u\n", num);
+ threads = ToArray(c->ConnectingThreads);
+ DeleteAll(c->ConnectingThreads);
+ }
+ UnlockList(c->ConnectingThreads);
+ for (i = 0;i < num;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+ Free(threads);
+}
+
+// Stop the connection
+void StopConnection(CONNECTION *c, bool no_wait)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Debug("Stop Connection: %s\n", c->Name);
+
+ // Stop flag
+ c->Halt = true;
+ Disconnect(c->FirstSock);
+
+ if (no_wait == false)
+ {
+ // Wait until the thread terminates
+ WaitThread(c->Thread, INFINITE);
+ }
+}
+
+// Close all the UDP socket
+void DisconnectUDPSockets(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (c->Protocol != CONNECTION_UDP)
+ {
+ return;
+ }
+
+ // Delete entry
+ if (c->ServerMode)
+ {
+ DelUDPEntry(c->Cedar, c->Session);
+ }
+
+ // Delete the UDP structure
+ if (c->Udp != NULL)
+ {
+ if (c->Udp->s != NULL)
+ {
+ ReleaseSock(c->Udp->s);
+ }
+ if (c->Udp->BufferQueue != NULL)
+ {
+ // Release of the queue
+ BUF *b;
+ while (b = GetNext(c->Udp->BufferQueue))
+ {
+ FreeBuf(b);
+ }
+ ReleaseQueue(c->Udp->BufferQueue);
+ }
+ Free(c->Udp);
+ c->Udp = NULL;
+ }
+
+ if (c->FirstSock != NULL)
+ {
+ Disconnect(c->FirstSock);
+ ReleaseSock(c->FirstSock);
+ c->FirstSock = NULL;
+ }
+}
+
+// Close all TCP connections
+void DisconnectTcpSockets(CONNECTION *c)
+{
+ UINT i, num;
+ TCP *tcp;
+ TCPSOCK **tcpsocks;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (c->Protocol != CONNECTION_TCP)
+ {
+ return;
+ }
+
+ tcp = c->Tcp;
+ LockList(tcp->TcpSockList);
+ {
+ tcpsocks = ToArray(tcp->TcpSockList);
+ num = LIST_NUM(tcp->TcpSockList);
+ DeleteAll(tcp->TcpSockList);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ if (num != 0)
+ {
+ Debug("--- SOCKET STATUS ---\n");
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *ts = tcpsocks[i];
+ Debug(" SOCK %2u: %u\n", i, ts->Sock->SendSize);
+ FreeTcpSock(ts);
+ }
+ }
+
+ Free(tcpsocks);
+}
+
+// Clean up of the connection
+void CleanupConnection(CONNECTION *c)
+{
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(c->lock);
+ ReleaseCedar(c->Cedar);
+
+ switch (c->Protocol)
+ {
+ case CONNECTION_TCP:
+ // Release of TCP connection list
+ DisconnectTcpSockets(c);
+ break;
+
+ case CONNECTION_UDP:
+ break;
+ }
+
+ ReleaseList(c->Tcp->TcpSockList);
+ Free(c->Tcp);
+
+ ReleaseSock(c->FirstSock);
+ c->FirstSock = NULL;
+
+ ReleaseSock(c->TubeSock);
+ c->TubeSock = NULL;
+
+ ReleaseThread(c->Thread);
+ Free(c->Name);
+
+ // Release all the receive block and send block
+ if (c->SendBlocks)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->SendBlocks))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ if (c->SendBlocks2)
+ {
+ LockQueue(c->SendBlocks2);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->SendBlocks2))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->SendBlocks2);
+ }
+ if (c->ReceivedBlocks)
+ {
+ LockQueue(c->ReceivedBlocks);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->ReceivedBlocks))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->ReceivedBlocks);
+ }
+
+ if (c->ConnectingThreads)
+ {
+ THREAD **threads;
+ LockList(c->ConnectingThreads);
+ {
+ num = LIST_NUM(c->ConnectingThreads);
+ threads = ToArray(c->ConnectingThreads);
+ for (i = 0;i < num;i++)
+ {
+ ReleaseThread(threads[i]);
+ }
+ Free(threads);
+ }
+ UnlockList(c->ConnectingThreads);
+ ReleaseList(c->ConnectingThreads);
+ }
+
+ if (c->ConnectingSocks)
+ {
+ SOCK **socks;
+ LockList(c->ConnectingSocks);
+ {
+ num = LIST_NUM(c->ConnectingSocks);
+ socks = ToArray(c->ConnectingSocks);
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseList(c->ConnectingSocks);
+ }
+
+ if (c->RecvBuf)
+ {
+ Free(c->RecvBuf);
+ }
+
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+
+ if (c->ClientX != NULL)
+ {
+ FreeX(c->ClientX);
+ }
+
+ ReleaseQueue(c->ReceivedBlocks);
+ ReleaseQueue(c->SendBlocks);
+ ReleaseQueue(c->SendBlocks2);
+
+ DeleteCounter(c->CurrentNumConnection);
+
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ Free(c);
+}
+
+// Release of the connection
+void ReleaseConnection(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CleanupConnection(c);
+ }
+}
+
+// Comparison of connection
+int CompareConnection(void *p1, void *p2)
+{
+ CONNECTION *c1, *c2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(CONNECTION **)p1;
+ c2 = *(CONNECTION **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(c1->Name, c2->Name);
+}
+
+// Creating a server connection
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t)
+{
+ CONNECTION *c;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(CONNECTION));
+ c->ConnectedTick = Tick64();
+ c->lock = NewLock();
+ c->ref = NewRef();
+ c->Cedar = cedar;
+ AddRef(c->Cedar->ref);
+ c->Protocol = CONNECTION_TCP;
+ c->Type = CONNECTION_TYPE_INIT;
+ c->FirstSock = s;
+ if (s != NULL)
+ {
+ AddRef(c->FirstSock->ref);
+ Copy(&c->ClientIp, &s->RemoteIP, sizeof(IP));
+ StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+ }
+ c->Tcp = ZeroMalloc(sizeof(TCP));
+ c->Tcp->TcpSockList = NewList(NULL);
+ c->ServerMode = true;
+ c->Status = CONNECTION_STATUS_ACCEPTED;
+ c->Name = CopyStr("INITING");
+ c->Thread = t;
+ AddRef(t->ref);
+ c->CurrentNumConnection = NewCounter();
+ Inc(c->CurrentNumConnection);
+
+ c->ServerVer = cedar->Version;
+ c->ServerBuild = cedar->Build;
+ StrCpy(c->ServerStr, sizeof(c->ServerStr), cedar->ServerStr);
+ GetServerProductName(cedar->Server, c->ServerStr, sizeof(c->ServerStr));
+
+ if (s != NULL && s->RemoteX != NULL)
+ {
+ c->ServerX = CloneX(s->RemoteX);
+ }
+
+ if (s != NULL && s->Type == SOCK_INPROC)
+ {
+ // In-process socket
+ c->IsInProc = true;
+ }
+
+ // Creating a Queue
+ c->ReceivedBlocks = NewQueue();
+ c->SendBlocks = NewQueue();
+ c->SendBlocks2 = NewQueue();
+
+ return c;
+}
+
+// Creating a Client Connection
+CONNECTION *NewClientConnection(SESSION *s)
+{
+ return NewClientConnectionEx(s, NULL, 0, 0);
+}
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build)
+{
+ CONNECTION *c;
+
+ // Initialization of CONNECTION object
+ c = ZeroMalloc(sizeof(CONNECTION));
+ c->ConnectedTick = Tick64();
+ c->lock = NewLock();
+ c->ref = NewRef();
+ c->Cedar = s->Cedar;
+ AddRef(c->Cedar->ref);
+ c->Protocol = CONNECTION_TCP;
+ c->Tcp = ZeroMalloc(sizeof(TCP));
+ c->Tcp->TcpSockList = NewList(NULL);
+ c->ServerMode = false;
+ c->Status = CONNECTION_STATUS_CONNECTING;
+ c->Name = CopyStr("CLIENT_CONNECTION");
+ c->Session = s;
+ c->CurrentNumConnection = NewCounter();
+ c->LastCounterResetTick = Tick64();
+ Inc(c->CurrentNumConnection);
+
+ c->ConnectingThreads = NewList(NULL);
+ c->ConnectingSocks = NewList(NULL);
+
+ if (client_str == NULL)
+ {
+ c->ClientVer = s->Cedar->Version;
+ c->ClientBuild = s->Cedar->Build;
+
+ if (c->Session->VirtualHost == false)
+ {
+ if (c->Session->LinkModeClient == false)
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_CLIENT_STR);
+ }
+ else
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_SERVER_LINK_STR);
+ }
+ }
+ else
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_ROUTER_STR);
+ }
+ }
+ else
+ {
+ c->ClientVer = client_ver;
+ c->ClientBuild = client_build;
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), client_str);
+ }
+
+ // Server name and port number
+ StrCpy(c->ServerName, sizeof(c->ServerName), s->ClientOption->Hostname);
+ c->ServerPort = s->ClientOption->Port;
+
+ // TLS 1.0 using flag
+ c->DontUseTls1 = s->ClientOption->NoTls1;
+
+ // Create queues
+ c->ReceivedBlocks = NewQueue();
+ c->SendBlocks = NewQueue();
+ c->SendBlocks2 = NewQueue();
+
+ return c;
+}
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/