SocketTlsHandshake

TLS Tokalaşma protokolü aracılığıyla belirli bir ana bilgisayara güvenli TLS (SSL) bağlantısı kurar. Tokalaşma sırasında, bir müşteri ve bir sunucu bağlantı parametreleri üzerinde hemfikir olur: uygulanan protokol sürümü ve veri şifreleme yöntemi.

bool  SocketTlsHandshake(
   int           socket,               // soket
   const string  host                  // ana bilgisayar adresi
   );

Parametreler

socket

[in] SocketCreate fonksiyonu tarafından geri döndürülen soket tanıtıcı değeri. Yanlış bir tanıtıcı değeri iletildiğinde; hata 5270 (ERR_NETSOCKET_INVALIDHANDLE), _LastError'a yazılır.

host

[in]  Güvenli bir bağlantı kurulan sunucunun adresi.

Geri dönüş değeri

Başarılı olursa true, aksi takdirde false olarak geri döner.

Not

Güvenli bir bağlantıdan önce, program SocketConnect kullanarak ana bilgisayarla standart bir TCP bağlantısı kurmalıdır.

Güvenli bağlantı başarısız olursa; hata 5274 (ERR_NETSOCKET_HANDSHAKE_FAILED), _LastError'a yazılır.

443 numaralı bağlantı noktasına bağlanırken fonksiyonu çağırmanıza gerek yoktur. Bu, güvenli TLS (SSL) bağlantıları için kullanılan standart bir TCP bağlantı noktasıdır.

Fonksiyon, yalnızca kendi yürütme iş parçacıklarında çalışan Uzman Danışmanlardan ve komut dosyalarından çağrılabilir. Bir göstergeden çağrılırsa; GetLastError(), 4014 hatasını geri döndürür - "Çağırma için fonksiyona izin verilmiyor".

Örnek:

//+------------------------------------------------------------------+
//|                                           SocketTlsHandshake.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com
#property version     "1.00"
 
#define   SERVER    "smtp.gmail.com"
#define   PORT      587
//+------------------------------------------------------------------+
//| Güvenli bağlantıya manuel olarak geç                             |
//+------------------------------------------------------------------+
bool TlsHandshake(int socket)
  {
//--- sunucu karşılamasını al
   string rsp;
 
   if(!RecvString(socket,rsp))
      return(false);
//--- sunucuyu karşıla
   if(!SendString(socket,"EHLO my.domain.com\r\n"))
      return(false);
//--- desteklenen komutların listesini içeren bir sunucu yanıtı al
   if(!RecvString(socket,rsp))
      return(false);
//--- karşılamayı yazdır
   Print("SERVER: ",rsp);
//--- TLS kullanarak güvensiz bir bağlantıdan güvenli bir bağlantıya geçmek istediğimizi sunucuya bildir
   if(!SendString(socket,"STARTTLS\r\n"))
      return(false);
//--- sunucu yanıtını al
   if(!RecvString(socket,rsp))
      return(false);
//--- örnekte, TLS'ye geçmeye hazır olup olunmadığına ilişkin sunucu yanıtını kontrol etmiyoruz ('Ready to start TLS')
 
//--- TLS Handshake protokolünü kullanarak belirtilen ana bilgisayara güvenli bir TLS (SSL) bağlantısı başlat
   if(SocketTlsHandshake(socket,InpTimeout))
      return(true);
 
   Print("SocketTlsHandshake() failed. Error ",GetLastError());
   return(false);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart(void)
  {
//--- bir soket oluştur ve tanıtıcısını al
   int socket=SocketCreate();
 
   if(socket==INVALID_HANDLE)
     {
      Print("SocketCreate() failed. Error ",GetLastError());
      return;
     }
//--- port üzerinden sunucuya bağlan
   if(!SocketConnect(socket,SERVER,PORT,10000))
     {
      Print("SocketConnect() failed. Error ",GetLastError());
     }
   else
     {
      //--- güvensiz bağlantı kuruldu
      PrintFormat("%s connection has been established to %s:%d",(PORT==443 ? "A secured" : "An unsecured"),SERVER,PORT);
      //--- güvenli bağlantıya geç
      if(PORT!=443 && TlsHandshake(socket))
        {
         PrintFormat("Unsecured connection to %s:%d switched to secured",SERVER,PORT);
         //--- bağlantı sertifika ile korunuyorsa, verilerini görüntüle
         string   subject,issuer,serial,thumbprint;
         datetime expiration;
 
         if(SocketTlsCertificate(socket,subject,issuer,serial,thumbprint,expiration))
           {
            Print("TLS certificate:");
            Print("   Owner:      ",subject);
            Print("   Issuer:     ",issuer);
            Print("   Number:     ",serial);
            Print("   Print:      ",thumbprint);
            Print("   Expiration: ",expiration);
           }
        }
     }
//--- kullanımdan sonra soketi kapat
   SocketClose(socket);
   /*
   sonuç:
   An unsecured connection has been established to smtp.gmail.com:587
   SERVER220 smtp.gmail.com ESMTP a640c23a62f3a-a9b1f298319sm82305866b.105 - gsmtp
 
   SERVER250-smtp.gmail.com at your service, [37.193.40.122]
   250-SIZE 35882577
   250-8BITMIME
   250-STARTTLS
   250-ENHANCEDSTATUSCODES
   250-PIPELINING
   250-CHUNKING
   250 SMTPUTF8
 
   SERVER220 2.0.0 Ready to start TLS
 
   SocketTlsHandshake(): A secure connection to smtp.gmail.com:587 is now established
   TLS certificate:
      Owner:  /CN=smtp.gmail.com
      Issuer:  /C=US/O=Google Trust Services/CN=WR2
      Number:     1f:f4:db:2a:5a:e6:dc:52:0a:4c:05:ce:81:cc:c3:f7
      Printd6be8af229b5329cd3d4c2789c02aa94f89b421c
      Expiration2024.12.30 08:25:30
   */
  }
//+------------------------------------------------------------------+
//| Sunucuya dizge gönder                                            |
//+------------------------------------------------------------------+
bool SendString(int socket,const string str)
  {
//--- dizgeyi bir karakter dizisine dönüştür
   uchar data[];
   int   size=StringToCharArray(str,data,0,str.Length(),CP_UTF8);
//--- sokete veri gönder
   ResetLastError();
   if(SocketSend(socket,data,size)==size)
      return(true);
//--- veri gönderme hatası
   Print("Failed to send data to server. Error ",GetLastError());
   return false;
  }
//+------------------------------------------------------------------+
//| Sunucudan bir dizge al                                           |
//+------------------------------------------------------------------+
bool RecvString(int socket,stringresult,uint timeout_ms=1000)
  {
//--- verinin sokette görünmesini bekle
   ulong wait_time_end=GetMicrosecondCount()+timeout_ms*1000;
 
   while(!SocketIsReadable(socket))
     {
      Sleep(10);
      //--- veriyi beklerken zaman aşımı - yanıt olarak NULL geri döndür
      if(wait_time_end<GetMicrosecondCount())
        {
         Print("ERROR: No response from server");
         return(false);
        }
     }
//--- soketten veri oku
   uchar  data[128];
   uint   size=0;
   string resp=NULL;
 
   do
     {
      uchar b[1];
      int   n=SocketRead(socket,b,1,1000);
 
      if(n < 0)
         break;
 
      if(n)
        {
         data[size++]=b[0];
 
         if(size==data.Size())
           {
            resp += CharArrayToString(data,0,data.Size(),CP_UTF8);
            size = 0;
           }
        }
     }
   while(SocketIsReadable(socket));
//--- okunan veriyi dizgeye kopyala
   if(size)
      resp+=CharArrayToString(data,0,size,CP_UTF8);
//--- dizge boşsa, hata geri döndür
   if(!resp.Length())
     {
      Print("ERROR: No response from server");
      return(false);
     }
//--- dizgeyi geri döndür
   result=resp;
   return(true);
  }