mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-07 18:20:41 +03:00
3662 lines
79 KiB
C
3662 lines
79 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Cedar Communication Module
|
|
//
|
|
// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
|
|
//
|
|
// Copyright (c) Daiyuu Nobori.
|
|
// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
|
|
// Copyright (c) SoftEther Corporation.
|
|
//
|
|
// All Rights Reserved.
|
|
//
|
|
// http://www.softether.org/
|
|
//
|
|
// Author: Daiyuu Nobori, Ph.D.
|
|
// 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 THIS SOFTWARE IN ANOTHER COUNTRY UNLESS
|
|
// YOU HAVE A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY
|
|
// CRIMINAL LAWS OR CIVIL RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS
|
|
// SOFTWARE IN OTHER COUNTRIES IS COMPLETELY AT YOUR OWN RISK. THE
|
|
// SOFTETHER VPN PROJECT HAS DEVELOPED AND DISTRIBUTED THIS SOFTWARE TO
|
|
// COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING CIVIL RIGHTS INCLUDING
|
|
// PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER COUNTRIES' LAWS OR
|
|
// CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. WE HAVE
|
|
// NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
|
|
// INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+
|
|
// COUNTRIES AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE
|
|
// WORLD, WITH DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY
|
|
// COUNTRIES' LAWS, REGULATIONS AND CIVIL RIGHTS TO MAKE THE SOFTWARE
|
|
// COMPLY WITH ALL COUNTRIES' LAWS BY THE PROJECT. EVEN IF YOU WILL BE
|
|
// SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A PUBLIC SERVANT IN YOUR
|
|
// COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE LIABLE TO
|
|
// RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
|
|
// RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT
|
|
// JUST A STATEMENT FOR WARNING AND DISCLAIMER.
|
|
//
|
|
//
|
|
// SOURCE CODE CONTRIBUTION
|
|
// ------------------------
|
|
//
|
|
// Your contribution to SoftEther VPN Project is much appreciated.
|
|
// Please send patches to us through GitHub.
|
|
// Read the SoftEther VPN Patch Acceptance Policy in advance:
|
|
// http://www.softether.org/5-download/src/9.patch
|
|
//
|
|
//
|
|
// 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.
|
|
//
|
|
//
|
|
// NO MEMORY OR RESOURCE LEAKS
|
|
// ---------------------------
|
|
//
|
|
// The memory-leaks and resource-leaks verification under the stress
|
|
// test has been passed before release this source code.
|
|
|
|
|
|
// 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;
|
|
}
|
|
|
|
WriteFifo(ts->SendFifo, data, size);
|
|
}
|
|
|
|
// Write data to the reception FIFO (automatic decryption)
|
|
void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
|
|
{
|
|
// Validate arguments
|
|
if (s == NULL || ts == NULL || data == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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->UseEncrypt);
|
|
}
|
|
|
|
// TCP socket send
|
|
UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size)
|
|
{
|
|
// Transmission
|
|
return Send(ts->Sock, data, size, s->UseEncrypt);
|
|
}
|
|
|
|
// 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
|
|
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;
|
|
}
|
|
|
|
// 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
|
|
InsertReceivedBlockToQueue(c, block, false);
|
|
}
|
|
}
|
|
|
|
// 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 InsertReceivedBlockToQueue(CONNECTION *c, BLOCK *block, bool no_lock)
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (no_lock == false)
|
|
{
|
|
LockQueue(c->ReceivedBlocks);
|
|
}
|
|
|
|
if (c->ReceivedBlocks->num_item < MAX_STORED_QUEUE_NUM)
|
|
{
|
|
InsertQueue(c->ReceivedBlocks, block);
|
|
}
|
|
else
|
|
{
|
|
FreeBlock(block);
|
|
}
|
|
|
|
if (no_lock == false)
|
|
{
|
|
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, UINT64 now)
|
|
{
|
|
UINT i, num;
|
|
UINT min_count;
|
|
UINT64 max_recv_tick;
|
|
TCPSOCK **tcpsocks;
|
|
UINT size;
|
|
SESSION *s;
|
|
HUB *hub = NULL;
|
|
bool use_qos = false;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s = c->Session;
|
|
|
|
if (s != NULL)
|
|
{
|
|
hub = s->Hub;
|
|
use_qos = s->QoS;
|
|
}
|
|
|
|
// Protocol
|
|
if (c->Protocol == CONNECTION_TCP)
|
|
{
|
|
// TCP
|
|
TCP *tcp = c->Tcp;
|
|
TCPSOCK *ts;
|
|
TCPSOCK *ts_hp;
|
|
UINT num_available;
|
|
bool is_rudp = false;
|
|
UINT tcp_queue_size = 0;
|
|
int tcp_queue_size_diff = 0;
|
|
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 (s != NULL && tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
|
|
IS_SEND_TCP_SOCK(tcpsock))
|
|
{
|
|
// Processing of KeepAlive
|
|
if (now >= tcpsock->NextKeepAliveTime || tcpsock->NextKeepAliveTime == 0 ||
|
|
(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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tcp_queue_size += tcpsock->SendFifo->size;
|
|
}
|
|
|
|
tcp_queue_size_diff = ((int)tcp_queue_size) - ((int)c->LastTcpQueueSize);
|
|
|
|
CedarAddCurrentTcpQueueSize(c->Cedar, tcp_queue_size_diff);
|
|
|
|
c->LastTcpQueueSize = tcp_queue_size;
|
|
|
|
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
|
|
if (q->num_item != 0)
|
|
{
|
|
UINT num_data;
|
|
BLOCK *b;
|
|
UINT size_quota_v1 = MAX_SEND_SOCKET_QUEUE_SIZE / s->MaxConnection;
|
|
UINT size_quota_v2 = MIN_SEND_SOCKET_QUEUE_SIZE;
|
|
UINT size_quota = MAX(size_quota_v1, size_quota_v2);
|
|
|
|
if (tss->SendFifo->size >= size_quota)
|
|
{
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
UPDATE_LAST_COMM_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;
|
|
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);
|
|
}
|
|
}
|
|
else if (c->Protocol == CONNECTION_HUB_LAYER3)
|
|
{
|
|
// Layer-3 session
|
|
L3IF *f = s->L3If;
|
|
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);
|
|
}
|
|
}
|
|
else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
|
|
{
|
|
// HUB Link
|
|
LINK *k = (LINK *)s->Link;
|
|
|
|
if (k != NULL)
|
|
{
|
|
UINT num_blocks = 0;
|
|
LockQueue(k->SendPacketQueue);
|
|
{
|
|
BLOCK *block;
|
|
|
|
// Transfer the packet queue to the client thread
|
|
while (block = GetNext(c->SendBlocks))
|
|
{
|
|
c->CurrentSendQueueSize -= block->Size;
|
|
|
|
if (k->SendPacketQueue->num_item >= MAX_STORED_QUEUE_NUM)
|
|
{
|
|
FreeBlock(block);
|
|
}
|
|
else
|
|
{
|
|
num_blocks++;
|
|
k->CurrentSendPacketQueueSize += block->Size;
|
|
InsertQueue(k->SendPacketQueue, block);
|
|
}
|
|
}
|
|
}
|
|
UnlockQueue(k->SendPacketQueue);
|
|
|
|
if (num_blocks != 0)
|
|
{
|
|
// Issue of cancellation
|
|
Cancel(k->ClientSession->Cancel1);
|
|
}
|
|
}
|
|
}
|
|
else if (c->Protocol == CONNECTION_HUB_BRIDGE)
|
|
{
|
|
// Local bridge
|
|
BRIDGE *b = s->Bridge;
|
|
|
|
if (b != NULL)
|
|
{
|
|
if (b->Active)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
UINT time;
|
|
UINT num_delayed = 0;
|
|
bool no_spinlock_for_delay = false;
|
|
UINT64 now = Tick64();
|
|
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;
|
|
}
|
|
|
|
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;
|
|
UINT current_recv_fifo_size = 0;
|
|
int recv_fifo_size_middle_update = 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();
|
|
}
|
|
}
|
|
|
|
now = Tick64();
|
|
|
|
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)
|
|
{
|
|
UINT current_packet_index = 0;
|
|
BLOCK *b = GetNext(s->UdpAccel->RecvBlockQueue);
|
|
|
|
if (b == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (b->Size > MAX_PACKET_SIZE)
|
|
{
|
|
// Packet size exceeded
|
|
FreeBlock(b);
|
|
}
|
|
else
|
|
{
|
|
if (CedarGetQueueBudgetBalance(c->Cedar) == 0)
|
|
{
|
|
FreeBlock(b);
|
|
}
|
|
else
|
|
{
|
|
// Add the data block to queue
|
|
InsertReceivedBlockToQueue(c, b, true);
|
|
|
|
if ((current_packet_index % 32) == 0)
|
|
{
|
|
UINT current_recv_block_num = c->ReceivedBlocks->num_item;
|
|
int diff = (int)current_recv_block_num - (int)c->LastRecvBlocksNum;
|
|
|
|
CedarAddQueueBudget(c->Cedar, diff);
|
|
|
|
c->LastRecvBlocksNum = current_recv_block_num;
|
|
}
|
|
|
|
current_packet_index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
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))
|
|
{
|
|
UINT current_packet_index = 0;
|
|
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
|
|
{
|
|
if (CedarGetQueueBudgetBalance(c->Cedar) == 0)
|
|
{
|
|
FreeBlock(block);
|
|
}
|
|
else
|
|
{
|
|
// Add the data block to queue
|
|
InsertReceivedBlockToQueue(c, block, true);
|
|
|
|
if ((current_packet_index % 32) == 0)
|
|
{
|
|
UINT current_recv_block_num = c->ReceivedBlocks->num_item;
|
|
int diff = (int)current_recv_block_num - (int)c->LastRecvBlocksNum;
|
|
|
|
CedarAddQueueBudget(c->Cedar, diff);
|
|
|
|
c->LastRecvBlocksNum = current_recv_block_num;
|
|
}
|
|
|
|
current_packet_index++;
|
|
}
|
|
}
|
|
|
|
FreeTubeData(d);
|
|
|
|
UPDATE_LAST_COMM_TIME(ts->LastCommTime, now);
|
|
UPDATE_LAST_COMM_TIME(ts->LastRecvTime, now);
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (c->IsInProc)
|
|
{
|
|
TUBEDATA *d;
|
|
UINT current_packet_index = 0;
|
|
|
|
// 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
|
|
{
|
|
if (CedarGetQueueBudgetBalance(c->Cedar) == 0)
|
|
{
|
|
FreeBlock(block);
|
|
}
|
|
else
|
|
{
|
|
// Add the data block to queue
|
|
InsertReceivedBlockToQueue(c, block, true);
|
|
|
|
if ((current_packet_index % 32) == 0)
|
|
{
|
|
UINT current_recv_block_num = c->ReceivedBlocks->num_item;
|
|
int diff = (int)current_recv_block_num - (int)c->LastRecvBlocksNum;
|
|
|
|
CedarAddQueueBudget(c->Cedar, diff);
|
|
|
|
c->LastRecvBlocksNum = current_recv_block_num;
|
|
}
|
|
|
|
current_packet_index++;
|
|
}
|
|
}
|
|
|
|
FreeTubeData(d);
|
|
}
|
|
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
}
|
|
else
|
|
{
|
|
UINT current_fifo_budget = 0;
|
|
UINT current_packet_index = 0;
|
|
// A normal socket (Not in-process)
|
|
if (ts->WantSize == 0)
|
|
{
|
|
// Read for sizeof(UINT) first
|
|
ts->WantSize = sizeof(UINT);
|
|
}
|
|
|
|
now = Tick64();
|
|
|
|
RECV_START:
|
|
current_fifo_budget = CedarGetFifoBudgetBalance(c->Cedar);
|
|
// Receive
|
|
if (ts->RecvFifo->size < current_fifo_budget)
|
|
{
|
|
UINT recv_buf_size = current_fifo_budget - ts->RecvFifo->size;
|
|
|
|
recv_buf_size = MIN(recv_buf_size, RECV_BUF_SIZE);
|
|
|
|
size = TcpSockRecv(s, ts, buf, recv_buf_size);
|
|
}
|
|
else
|
|
{
|
|
size = SOCK_LATER;
|
|
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
UPDATE_LAST_COMM_TIME(ts->LastCommTime, now);
|
|
}
|
|
|
|
/*
|
|
// 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
|
|
{
|
|
UINT budget_balance = CedarGetFifoBudgetBalance(c->Cedar);
|
|
UINT fifo_size_limit = budget_balance;
|
|
|
|
if (fifo_size_limit > MAX_BUFFERING_PACKET_SIZE)
|
|
{
|
|
fifo_size_limit = MAX_BUFFERING_PACKET_SIZE;
|
|
}
|
|
|
|
// Update the last communication time
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
UPDATE_LAST_COMM_TIME(ts->LastRecvTime, now);
|
|
|
|
CedarAddFifoBudget(c->Cedar, (int)size);
|
|
recv_fifo_size_middle_update += (int)size;
|
|
|
|
// 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 < fifo_size_limit)
|
|
{
|
|
goto RECV_START;
|
|
}
|
|
}
|
|
|
|
current_recv_fifo_size += FifoSize(ts->RecvFifo);
|
|
|
|
// 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);
|
|
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
UPDATE_LAST_COMM_TIME(ts->LastCommTime, now);
|
|
|
|
if (block->Size > MAX_PACKET_SIZE)
|
|
{
|
|
// Packet size exceeded
|
|
FreeBlock(block);
|
|
}
|
|
else
|
|
{
|
|
if (CedarGetQueueBudgetBalance(c->Cedar) == 0)
|
|
{
|
|
FreeBlock(block);
|
|
}
|
|
else
|
|
{
|
|
// Add the data block to queue
|
|
InsertReceivedBlockToQueue(c, block, true);
|
|
|
|
if ((current_packet_index % 32) == 0)
|
|
{
|
|
UINT current_recv_block_num = c->ReceivedBlocks->num_item;
|
|
int diff = (int)current_recv_block_num - (int)c->LastRecvBlocksNum;
|
|
|
|
CedarAddQueueBudget(c->Cedar, diff);
|
|
|
|
c->LastRecvBlocksNum = current_recv_block_num;
|
|
}
|
|
|
|
current_packet_index++;
|
|
}
|
|
}
|
|
|
|
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));
|
|
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
UPDATE_LAST_COMM_TIME(ts->LastCommTime, now);
|
|
|
|
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);
|
|
|
|
UPDATE_LAST_COMM_TIME(c->Session->LastCommTime, now);
|
|
UPDATE_LAST_COMM_TIME(ts->LastCommTime, now);
|
|
|
|
s->TotalRecvSize += sz;
|
|
s->TotalRecvSizeReal += sz;
|
|
|
|
ts->WantSize = sizeof(UINT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ShrinkFifoMemory(ts->RecvFifo);
|
|
//printf("Fifo: %u\n", ts->RecvFifo->memsize);
|
|
}
|
|
}
|
|
|
|
if (true)
|
|
{
|
|
int diff;
|
|
|
|
diff = (int)current_recv_fifo_size - (int)c->LastRecvFifoTotalSize;
|
|
|
|
CedarAddFifoBudget(c->Cedar, (diff - recv_fifo_size_middle_update));
|
|
|
|
c->LastRecvFifoTotalSize = current_recv_fifo_size;
|
|
}
|
|
|
|
if (true)
|
|
{
|
|
UINT current_recv_block_num = c->ReceivedBlocks->num_item;
|
|
int diff = (int)current_recv_block_num - (int)c->LastRecvBlocksNum;
|
|
|
|
CedarAddQueueBudget(c->Cedar, diff);
|
|
|
|
c->LastRecvBlocksNum = current_recv_block_num;
|
|
}
|
|
|
|
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
|
|
InsertReceivedBlockToQueue(c, block, true);
|
|
}
|
|
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
|
|
{
|
|
InsertReceivedBlockToQueue(c, block, true);
|
|
}
|
|
|
|
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())
|
|
{
|
|
#ifdef OS_WIN32
|
|
check_device_num = true;
|
|
#endif // OS_WIN32
|
|
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
|
|
{
|
|
InsertReceivedBlockToQueue(c, block, true);
|
|
}
|
|
num++;
|
|
if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
|
|
{
|
|
// WHERE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ETH *e;
|
|
// Bridge is stopped currently
|
|
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->IsFlooding = false;
|
|
|
|
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[256] = {0};
|
|
bool native1 = false;
|
|
bool native2 = false;
|
|
bool native3 = false;
|
|
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");
|
|
Copy(&s->SslAcceptSettings, &c->Cedar->SslAcceptSettings, sizeof(SSL_ACCEPT_SETTINGS));
|
|
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;
|
|
}
|
|
|
|
if (c->LastRecvFifoTotalSize != 0)
|
|
{
|
|
CedarAddFifoBudget(c->Cedar, -((int)c->LastRecvFifoTotalSize));
|
|
c->LastRecvFifoTotalSize = 0;
|
|
}
|
|
|
|
if (c->LastRecvBlocksNum != 0)
|
|
{
|
|
CedarAddQueueBudget(c->Cedar, -((int)c->LastRecvBlocksNum));
|
|
c->LastRecvBlocksNum = 0;
|
|
}
|
|
|
|
if (c->LastTcpQueueSize != 0)
|
|
{
|
|
int diff = -((int)c->LastTcpQueueSize);
|
|
CedarAddCurrentTcpQueueSize(c->Cedar, diff);
|
|
c->LastTcpQueueSize = 0;
|
|
}
|
|
|
|
if (c->LastPacketQueueSize != 0)
|
|
{
|
|
int diff = -((int)c->LastPacketQueueSize);
|
|
CedarAddCurrentTcpQueueSize(c->Cedar, diff);
|
|
c->LastPacketQueueSize = 0;
|
|
}
|
|
|
|
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;
|
|
}
|