Contents
In the first sample, we explored basic SocketPro features. We haven’t completed the sample yet because it lacks a set of key features. We’ll finish the rest of ignored key features in the first tutorial. You will learn a few how-tos:
· How to secure data communication between a client and a server using secure socket layer (SSL)
· How to authenticate a client
· How to reuse high performance libraries
· How to limit the number of socket connections for a client
· How to use chat service for notifying various messages among connected clients
At the end, you will see a few FAQs and their answers with comments.
2. How to secure data communication between a client and a server using secure socket layer (SSL)
Here is the article named as Secure
your data communication between two networked machines at this site http://www.udaparts.com/document/articles/security.htm.
SocketPro uses either SSL/TLS or Blowfish to encrypt data so that only two partners can know data exchanged. This tutorial demonstrates how to use MSTLSv1 to encrypt all of data movements between a client and a SocketPro server through MS secure channel (SSPI).
At client side, you just use one line code to complete the job as shown in the below.
m_ClientSocket.GetUSocket().EncryptionMethod = (short)(chkUseSSL.Checked ? USOCKETLib.tagEncryptionMethod.MSTLSv1 : USOCKETLib.tagEncryptionMethod.NoEncryption);
On client side, you can use the property ISocketBase::PeerCertificate to get an interface to the interface IUCert to a server certificate. With help of the interface, you can authenticate a remote server before sending credentials (user id and password) to avoid man-in-middle attack. See the commented code inside the client sample.
At server side, you also need one line to complete the work like the below.
UseSSL("C:\\cyetest\\socketpro4\\bin\\udacert.pfx",
"mypassword", "udaparts", tagEncryptionMethod.MSTLSv1);
3. How to authenticate a client
The above code ensures data communication in the encryption format. We should also make sure people who have valid user ids and passwords are allowed to access a SocketPro server. This process is called as authentication. At this time, SocketPro supports three methods to authenticate a client according to given user id and password. For details, see the above article. This tutorial sample uses amMixed method, which is the combination of amOwn and amIntegrated. You can authenticate a client by overwriting the virtual function CSocketProServer::OnIsPermitted. Here is the code:
protected override bool OnIsPermitted(int hSocket, int lSvsID)
{
string strUID = CBaseService.GetUserID(hSocket);
//password is available ONLY IF authentication method to either amOwn or amMixed
string strPassword = CBaseService.GetPassword(hSocket);
Console.WriteLine("For service = {0}, User ID = {1}, Password = {2}", lSvsID, strUID, strPassword);
tagAuthenticationMethod am = AuthenticationMethod;
if(am == tagAuthenticationMethod.amOwn || am == tagAuthenticationMethod.amMixed)
{
//do my own authentication
return IsAllowed(strUID, strPassword);
}
return true;
}
Note that once the function is called, password is immediately cleaned from the SocketPro server for the better security and you can not use CBaseService.GetPassword to retrieve a password any more.
4. How to reuse libraries at server side
You can load previously created libraries into a SocketPro server. For how to create these libraries in C/C++, you may see the attached samples Udemo and Winfile. Here is the code to reuse these libraries
private void ReuseLibraries()
{
//those libraries are distributed in the directory ..\bin
IntPtr hInst = CBaseService.AddALibrary("uodbsvr.dll", 0);
if(hInst == (IntPtr)0)
{
Console.WriteLine("library uodbsvr.dll not available.");
}
hInst = CBaseService.AddALibrary("ufilesvr.dll", 0);
if(hInst == (IntPtr)0)
{
Console.WriteLine("library ufilesvr.dll not available.");
}
hInst = CBaseService.AddALibrary("c:\\socketpro4\\bin\\udemo.dll", 0);
if(hInst == (IntPtr)0)
{
Console.WriteLine("library udemo.dll not available.");
}
}
5. How to limit the number of socket connections for a client
Sometimes, we like to restrict the number of socket connections from a client. It reduces DOS attacks from a hacker. To do so, simply put one line code before starting a SocketPro listening socket as show in the below.
//limit the max number of connections to 2 for a client machine
MaxConnectionsPerClient = 2;
6. How to use chat service for notifying various messages among
connected clients
A typical distributed application contains a net communication between a server and a client only. There is no communication among two connected clients at all. However, very often this architecture does not meet application requirements. We need some ways to enable communications among clients whenever an interested thing happens. This type of communication is similar to Internet chat among a group of people. Therefore, SocketPro provides this type of chat service. Actually, it is a built-in service for all of connected socket connections. Notification is very useful in many cases for real time communication. Use of notification may help you design much better and true distributed applications. Traditional client/server applications are not real distributed applications with all distribution powers. We believe that our SocketPro can help you create real distributed applications that clients can easily communicate not only with a server but also among clients themselves.
To set up a chat group at server side, see the below code for starting one chat group.
bool bSuc = AddAChatGroup(1, "Group
for SOne"); //group number must be 1, 2, 4, 8, ...... etc
You can also set up what will happen when a client join or leave the group by the following code.
//Other clients will be notified when a client join the group 1
GroupsNotifiedWhenEntering
= 1; //-1 means all of
32 groups
//Other clients will be notified when a client leave the group 1
GroupsNotifiedWhenExiting
= 1; //-1 means all of
32 groups
With the above two lines of code, all of clients joined the group will be automatically notified whenever a client joins or leaves the group.
You can join or leave a group at either client side or server side. To join or leave a group at client side, call the IUChat::Enter or Exit. To join or leave a group at server side, you can call CClientPeer::Enter or Exit. See the below code from the function OnSocketConnected for joining a chat group.
//join the
group 1 -- SOne Group
m_ClientSocket.GetUSocket().Enter(1);
With SocketPro, you can send out a message at either client or server side. Take this tutorial sample. At client side, you call IUChat::Speak using the following code.
//send a text message to group 1, SOneSvs Group
GetAttchedClientSocket().GetUSocket().Speak("EchoData
called", 1);
At server side, similarly call the following code.
//inform all of joined clients that idSleep is called
Speak("Sleep
called", 1);
Now we need a way to track various notification events at client side. To set up tracking notification events, you simply set a delegate to OnBaseRequestProcessed as shown in the below.
public void
OnBaseRequestProcessed ( System.Int16
sRequestID )
{
switch(sRequestID)
{
case
(short)USOCKETLib.tagChatRequestID.idEnter:
{
string strMsg;
int nGroup = 0;
int nPort = 0;
int nSvsID = 0;
string strUID = null;
string strIPAddr =
m_ClientSocket.GetUSocket().GetInfo(0, out
nGroup, out strUID, out
nSvsID, out nPort);
strMsg = strUID;
strMsg
+= "@";
strMsg += strIPAddr;
strMsg += ":";
strMsg += nPort;
strMsg += " has just joined the group";
txtMsg.Text = strMsg;
}
break;
case
(short)USOCKETLib.tagChatRequestID.idExit:
{
string strMsg;
int nGroup = 0;
int nPort = 0;
int nSvsID = 0;
string strUID = null;
string strIPAddr =
m_ClientSocket.GetUSocket().GetInfo(0, out
nGroup, out strUID, out
nSvsID, out nPort);
strMsg = strUID;
strMsg += "@";
strMsg += strIPAddr;
strMsg += ":";
strMsg += nPort;
strMsg += " has just exited from the group";
txtMsg.Text = strMsg;
}
break;
case
(short)USOCKETLib.tagChatRequestID.idSpeak:
{
int nGroup = 0;
int nPort = 0;
int nSvsID = 0;
string strUID = null;
string strMsg = (string)m_ClientSocket.GetUSocket().Message;
string strIPAddr =
m_ClientSocket.GetUSocket().GetInfo(0, out
nGroup, out strUID, out
nSvsID, out nPort);
strMsg += " from ";
strMsg += strUID;
strMsg += "@";
strMsg += strIPAddr;
strMsg += ":";
strMsg += nPort;
txtMsg.Text = strMsg;
}
break;
default:
break;
}
}
With this tutorial sample, you can see different notifications whenever a client is connected or disconnected, or whenever a client calls either method Echo and Sleep. Note some of messages originate from a client, and some from its server.
You can also send a message privately to a client identified by its IP address and port number from either a client or a server.
7. Summary:
This tutorial shows you
(a) how to use industrial standard SSL/TLS to secure data communication between client and server,
(b) how to authenticate a client, and give or deny a client connection from given user id and password,
(c) how to plug and reuse libraries,
(d) how to limit the number of socket connections per client,
(e) and how to use SocketPro built-in chat/notification service.
8. FAQs
a. Inside the above function OnIsPermitted, what about authentication methods amTrusted and amIntegrated?
First of all, SocketPro defines the method amTrusted, but it does not support it at this time.
In regards to the authentication method amIntegrated, SocketPro does authentication inside for you automatically. Password is immediately cleaned after SSPI authentication. The above virtual function is an event only. The failure or success of authentication does not depend on your code at all. Also, you can’t retrieve a password because the password is already cleaned before this function is called.
b. Looking at your tutorial sample code, you use the following code to ask for a service. Could you elaborate a bit more about the code comment?
//when
switch from sidStartup to another, false is a must.
m_ClientSocket.Commit(false);
This is a good question though. It is related how to batch a set of requests at client side.
When you call the method Commit with true, internally object USocket will insert two requests idStartBatching and idCommitBatching automatically to inform a SocketPro server when a returned result should be started to batch and when the batching should be ended. This is fine with all of services except the service sidStartup. This particular service is an initial service that only supports one request idSwitchTo. All of other requests or strange ones will cause immediately aborting the established socket connection. When you set true here, you will certainly close the socket connection. If you commit a batch with input false, object USocket will not insert the two requests. This is a design of SocketPro and not a problem. This design will enforce that a client must call IUSocket::SwicthTo first after a socket connection is established without exception. Once a client calls the method, SocketPro will automatically retrieve a user id and password for validation. If the validation is fine, the client can do anything else. Otherwise, the socket will be closed immediately for the sake of security.
c. DCOM has callbacks. Dotnet remoting also has callback. Your SocketPro also has these events and notifications. What difference among them?
At the very beginning, maybe you don’t know the difference and think they are very similar on the surface. However, they function very different internally. SocketPro differs from the other two in three aspects.
SocketPro is much faster than other two. At server side, DCOM and dotNet remoting must wait a returned result from a client, but SocketPro does not and just posts a message into local buffers and returns immediately. When a server supports hundreds or thousands of clients, SocketPro will be very fast in comparison to the other two because DCOM and dotNet remoting have to wait all of callback returned results one by one.
SocketPro is more reliable than the other two. Considering one or two clients suddenly power off, SocketPro will still function correctly, but DCOM and dotNet remoting will either throw an exception or hang.
SocketPro does not have firewall and NAT devices problem at all. DotNet remoting may have a problem with these network devices.
d. Can I use SocketPro to write an application with security features that MS Internet Information Server has? For example, can I do anonymous access, authenticated access, impersonation, IP address and domain name restrictions?
Yes! You can do all of the above ones easily inside the virtual function OnIsPermitted of CSocketProServer, when you set authentication method to either amOwn or amMixed.