Skip to main content
  • Products
  • Evaluate our Software
  • Downloads
  • Free Utilities
  • Purchase
  • Support
  • About Us
  • Blog
  • Forum
  • Search
    • Contact Us
    • Forum
    • Knowledge Base
    • Web Shop
    • Newsletter
    • RSS
  •   Jobs
  •   Videos
  •   Blog
  •   Sustainability
  • emCrypt
  • ECDHE Key Agreement
  • Technology
  • Examples

End-to-End encryption with ECDHE Key Agreement
Example applications

Contact us
Downloads
Documentation
SEGGER emCrypt

ECDHE Key Agreement enables the setup of end-to-end encrypted communication between two clients without user interaction, on a single, potentially insecure channel.

In contrast, password-based end-to-end encryption requires that both clients agree on one password prior to setting up the communication. The password is agreed on via a different channel such as face to face, or fixed on one side and printed in a user guide.

End-to-end encryption with ECDHE Key Agreement can be used for communication with embedded targets or a remote server. It can is also be used for communication between two users, such as for instant messaging.

ECDHE Key Agreement - Example Application

This application demonstrates how to use the ECDHE Key Agreement. All algorithms and cryptography primitives enabling this are provided by emCrypt.

The first instance runs as the "server" and waits for a connection. A second instance runs as the "client" and connects to the server. Both instances generate a random EC key pair and perform a handshake to agree on encryption keys.

The client sends its public key (Qc) to the server and receives the server's public key (Qs). From the reveiced public key (Q') and the own private key (d), both instances compute the master key (K = Q' * d).

Using AES-CMAC-PRF-128 and the master key, the session key data used to encrypt further communication is generated. Now, data can be sent from one instance to the other.

Source Listing

This is the source code for the example application.

The key agreement is shown in _HandshakeServer() and _HandshakeClient(), which make use of _GenKey() to generate a random key pair on both sides
and _GenKeyBlock() to derive the session keys for encryption after key exchange.

Encryption and decryption of packets is done in _Encrypt() and _Decrypt(). The remaining functions are common code for client-server communication.

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

Purpose     : Example application to demonstrate E2E encrypted 
              communication with ECDHE session key agreement, 
              using emCrypt.
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/

#include "CRYPTO.h"
#include "SYS.h"
#include <stdio.h>
#include <stdlib.h>

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/

#define COPYRIGHT_STRING      "emCrypt E2E Encryption with ECDHE\n(c) 2021 SEGGER Microcontroller GmbH."
#define SERVER_LISTENER_PORT  (19099)                       // TCP/IP port that server listens to
#define MAX_MSG_LEN           (2048)                        // Maximum size (bytes) for a message. This includes a terminating \0.
#define MASTER_KEY_LEN        32                            // Size of EC key with chosen curve (on Curve25519: 32 bytes)
#define IV_LEN                8                             // Lenth of initialization vector/nonce for AES-CCM
#define TAG_LEN               CRYPTO_AES128_KEY_SIZE        // Length of authentication tag with AES-CCM

#define CHECK(X)              do { if ((Status = (X)) < 0) goto Finally; } while (0)

/*********************************************************************
*
*       Local types
*
**********************************************************************
*/
//
// KeyBlock[0]: Client Tx Stream Cipher / Server Rx Stream Cipher
// KeyBlock[1]: Client Tx Counter/IV    / Server Rx Counter/IV
// KeyBlock[2]: Client Rx Stream Cipher / Server Tx Stream Cipher
// KeyBlock[3]: Client Rx Counter/IV    / Server Tx Counter/IV
//
typedef struct {
  U8                  aMasterKey[MASTER_KEY_LEN];
  U8                  aKeyBlock[CRYPTO_AES128_KEY_SIZE * 4];
  struct {
    CRYPTO_AES_CONTEXT  Context;
    U8*                 pIV;
  } Rx;
  struct {
    CRYPTO_AES_CONTEXT  Context;
    U8*                 pIV;
  } Tx;
} SESSION_CONTEXT;

typedef struct {
  SYS_SOCKET_HANDLE   hSock;
  SESSION_CONTEXT*    pSession;
} THREAD_INFO;

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static SEGGER_MEM_CONTEXT     _MemContext;
static volatile int           _ErrorOccurred;  // Used by threads to determine if an error occurred

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _HexDump()
*
*  Function description
*    Dump hex data.
*
*  Parameters
*    sText   - Pointer to title.
*    pData   - Pointer to octet string.
*    DataLen - Octet length of octet string.
*/
static void _HexDump(const char *sText, const U8 *pData, unsigned DataLen) {
  unsigned i;
  //
  printf("%s:", sText);
  for (i = 0; i < DataLen; ++i) {
    if (i % 16u == 0) {
      printf("\n ");
    }
    printf(" %02x", pData[i]);
  }
  printf("\n");
}

/*********************************************************************
*
*       _GenKey()
*
*  Function description
*    Generate a random key on EC Curve25519.
*
*  Parameters
*    pd        - Pointer to store private key data.
*    pQ        - Pointer to store public key data.
*/
static int _GenKey(CRYPTO_MPI* pd, CRYPTO_MPI* pQ) {
  int Status;
  
  CHECK(CRYPTO_MPI_RandomBits(pd, 255));
  CHECK(CRYPTO_EC_Curve25519_Clamp(pd));
  CHECK(CRYPTO_EC_X25519_BaseMul(pQ, pd, &_MemContext));
  //
  Status = 0;
Finally:
  return Status;
}

/*********************************************************************
*
*       _GenKeyBlock()
*
*  Function description
*    Generate a session key block 
*    from the private key and the received public key.
*
*  Parameters
*    pSession  - Pointer to session data.
*    pd        - Pointer to private key.
*    pQ        - Pointer to public key.
*/
static int _GenKeyBlock(SESSION_CONTEXT* pSession, CRYPTO_MPI* pd, CRYPTO_MPI* pQ) {
  int Status;
  //
  // Compute shared secret, K, which is the X coordinate of d*Q_S.
  //
  CHECK(CRYPTO_EC_X25519_Mul(pQ, pd, &_MemContext));
  CRYPTO_MPI_StoreBytes(pQ, pSession->aMasterKey, sizeof(pSession->aMasterKey));
  _HexDump("Master key", pSession->aMasterKey, sizeof(pSession->aMasterKey));
  //
  // Generate key blocks from master key, using AES-CMAC-PRF-128.
  //
  CRYPTO_CMAC_AES_PRF_128_Calc(pSession->aMasterKey, sizeof(pSession->aMasterKey), (const U8 *)"key block A", 11, &pSession->aKeyBlock[0*CRYPTO_AES128_KEY_SIZE]);
  CRYPTO_CMAC_AES_PRF_128_Calc(pSession->aMasterKey, sizeof(pSession->aMasterKey), (const U8 *)"key block B", 11, &pSession->aKeyBlock[1*CRYPTO_AES128_KEY_SIZE]);
  CRYPTO_CMAC_AES_PRF_128_Calc(pSession->aMasterKey, sizeof(pSession->aMasterKey), (const U8 *)"key block C", 11, &pSession->aKeyBlock[2*CRYPTO_AES128_KEY_SIZE]);
  CRYPTO_CMAC_AES_PRF_128_Calc(pSession->aMasterKey, sizeof(pSession->aMasterKey), (const U8 *)"key block D", 11, &pSession->aKeyBlock[3*CRYPTO_AES128_KEY_SIZE]);
  //
  _HexDump("Key block", pSession->aKeyBlock, sizeof(pSession->aKeyBlock));
  //
  Status = 0;
Finally:
  return Status;
}

/*********************************************************************
*
*       _HandshakeServer()
*
*  Function description
*    Run server handshake.
*
*  Parameters
*    pSession  - Pointer to session data.
*    hSock     - Socket handle of the connection.
*/
static int _HandshakeServer(SESSION_CONTEXT *pSession, SYS_SOCKET_HANDLE hSock) {
  CRYPTO_MPI d;
  CRYPTO_MPI Q_S;
  CRYPTO_MPI Q_C;
  U8         aKey[32];
  int        Status;
  //
  CRYPTO_MPI_Init(&Q_S, &_MemContext);
  CRYPTO_MPI_Init(&Q_C, &_MemContext);
  CRYPTO_MPI_Init(&d, &_MemContext);
  //
  // Generate server's ephemeral session key pair
  //
  CHECK(_GenKey(&d, &Q_S));
  //
  // Receive client's public key.
  //
#ifdef _LOG_VERBOSE
  printf("Receive client's public key\n");
#endif
  SYS_SOCKET_Receive(hSock, (char *)aKey, sizeof(aKey));
  CRYPTO_MPI_LoadBytesLE(&Q_C, aKey, sizeof(aKey));
  //
  // Send server's public key.
  //
#ifdef _LOG_VERBOSE
  printf("Send server's public key\n");
#endif
  CRYPTO_MPI_StoreBytesLE(&Q_S, aKey, sizeof(aKey));
  SYS_SOCKET_Send(hSock, (char *)aKey, sizeof(aKey));
  //
  // Generate key block
  //
  CHECK(_GenKeyBlock(pSession, &d, &Q_C));
  //
  // Initialize AEAD cipher streams.
  //
  CRYPTO_AES_InitEncrypt(&pSession->Rx.Context, &pSession->aKeyBlock[0*CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
  pSession->Rx.pIV = &pSession->aKeyBlock[1*CRYPTO_AES128_KEY_SIZE];
  CRYPTO_AES_InitEncrypt(&pSession->Tx.Context, &pSession->aKeyBlock[2*CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
  pSession->Tx.pIV = &pSession->aKeyBlock[3*CRYPTO_AES128_KEY_SIZE];
  //
  CRYPTO_MPI_Kill(&Q_S);
  CRYPTO_MPI_Kill(&Q_C);
  CRYPTO_MPI_Kill(&d);
  //
Finally:
  return Status;
}

/*********************************************************************
*
*       _HandshakeClient()
*
*  Function description
*    Run client handshake.
*
*  Parameters
*    pSession  - Pointer to session data.
*    hSock     - Socket handle of the connection.
*/
static int _HandshakeClient(SESSION_CONTEXT *pSession, SYS_SOCKET_HANDLE hSock) {
  CRYPTO_MPI d;
  CRYPTO_MPI Q_S;
  CRYPTO_MPI Q_C;
  U8         aKey[32];
  int        Status;
  //
  CRYPTO_MPI_Init(&Q_S, &_MemContext);
  CRYPTO_MPI_Init(&Q_C, &_MemContext);
  CRYPTO_MPI_Init(&d, &_MemContext);
  //
  // Generate clients's ephemeral session key pair
  //
  CHECK(_GenKey(&d, &Q_C));
  //
  // Send client's public key.
  //
#ifdef _LOG_VERBOSE
  printf("Send client's public key\n");
#endif
  CRYPTO_MPI_StoreBytesLE(&Q_C, aKey, sizeof(aKey));
  SYS_SOCKET_Send(hSock, (char *)aKey, sizeof(aKey));
  //
  // Receive server's public key.
  //
#ifdef _LOG_VERBOSE
  printf("Receive server's public key\n");
#endif
  SYS_SOCKET_Receive(hSock, (char *)aKey, sizeof(aKey));
  CRYPTO_MPI_LoadBytesLE(&Q_S, aKey, sizeof(aKey));
  //
  // Generate key block
  //
  CHECK(_GenKeyBlock(pSession, &d, &Q_S));
  //
  // Initialize AEAD cipher streams.
  //
  CRYPTO_AES_InitEncrypt(&pSession->Tx.Context, &pSession->aKeyBlock[0*CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
  pSession->Tx.pIV = &pSession->aKeyBlock[1*CRYPTO_AES128_KEY_SIZE];
  CRYPTO_AES_InitEncrypt(&pSession->Rx.Context, &pSession->aKeyBlock[2*CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
  pSession->Rx.pIV = &pSession->aKeyBlock[3*CRYPTO_AES128_KEY_SIZE];
  //
  CRYPTO_MPI_Kill(&Q_S);
  CRYPTO_MPI_Kill(&Q_C);
  CRYPTO_MPI_Kill(&d);
  //
Finally:
  return Status;
}

/*********************************************************************
*
*       _Encrypt()
*
*  Function description
*    Encrypt and authenticate an input string to a packet.
*
*  Parameters
*    pSession - Pointer to connection state.
*    pSrc     - Source buffer.
*    DestLen  - Length of source buffer.
*    pDest    - Destination buffer.
*    DestLen  - Length of destination buffer. Has to be at least SrcLen + 4 + TAG_LEN.
*
*  Additional information
*    Packet = Input Length + Authentication Tag + Encrypted data
*/
static int _Encrypt(SESSION_CONTEXT *pSession, const char* pSrc, U32 SrcLen, U8* pDest, U32 DestLen) {
  //
  // Write input length to packet
  //
  CRYPTO_WRU32LE(pDest, SrcLen);
  //
  // Write authentication tag and encrypted data to packet.
  //
  CRYPTO_AES_CCM_Encrypt(&pSession->Tx.Context,
                         &pDest[4 + TAG_LEN],
                         &pDest[4],
                         TAG_LEN,
                         (const U8*)pSrc,
                         SrcLen,
                         NULL,
                         0,
                         pSession->Tx.pIV,
                         IV_LEN);
  //
  // Increment counter value
  //
  CRYPTO_IncCTRBE(pSession->Tx.pIV, IV_LEN, 1);
  
  return SrcLen + 4 + TAG_LEN;
}

/*********************************************************************
*
*       _Decrypt()
*
*  Function description
*    Decrypt encrypted data.
*
*  Parameters
*    pSession - Pointer to connection state.
*    pSrc     - Source buffer.
*    DestLen  - Length of source buffer.
*    pDest    - Destination buffer.
*    DestLen  - Length of destination buffer. Has to be at least SrcLen - TAG_LEN.
*
*  Additional information
*    For in-place decryption, pDest may be == pSrc + TAG_LEN.
*/
static int _Decrypt(SESSION_CONTEXT *pSession, const U8* pSrc, U32 SrcLen, U8* pDest, U32 DestLen) {
  int Status;
  //
  // Decrypt data and authentication tag.
  //
  Status = CRYPTO_AES_CCM_Decrypt(&pSession->Rx.Context,
                                  pDest,
                                  pSrc,
                                  TAG_LEN,
                                  pSrc + TAG_LEN,
                                  SrcLen,
                                  NULL,
                                  0,
                                  pSession->Rx.pIV,
                                  IV_LEN);
  //
  // Increment counter value
  //
  CRYPTO_IncCTRBE(pSession->Rx.pIV, IV_LEN, 1);
  
  return Status;
}

/*********************************************************************
*
*       _SendThread()
*
*  Function description
*    Thread that is responsible for handling data to send from the server to the client.
*/
static SYS_THREAD_PROC_EX_TYPE _SendThread(void* p) {
  int Result;
  int r;
  U32 Len;
  char acIn [MAX_MSG_LEN];
  U8   abOut[MAX_MSG_LEN + 4 + TAG_LEN];
  THREAD_INFO* pInfo;
  
  Result = 0;
  pInfo = (THREAD_INFO*)p;
  do {
    SYS_ConsoleGetString(">  ", acIn, MAX_MSG_LEN);
    Len = strlen(acIn) + 1;  // Include terminating \0
    Len = _Encrypt(pInfo->pSession, acIn, Len, abOut, sizeof(abOut));
#ifdef _LOG_VERBOSE
    _HexDump("Sending packet", abOut, Len);
#endif
    r = SYS_SOCKET_Send(pInfo->hSock, abOut, Len);
    if (r != Len) {  // Failed to send data? => Done
      printf("ERROR: Failed to send data to peer\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }
  } while (_ErrorOccurred == 0);
  return Result;
}

/*********************************************************************
*
*       _RecvThread()
*
*  Function description
*    Thread that is responsible for handling data to receive by the server from the client.
*/
static SYS_THREAD_PROC_EX_TYPE _RecvThread(void* p) {
  int           Result;
  int           r;
  U8            abIn [MAX_MSG_LEN + 4 + TAG_LEN + 1];
  THREAD_INFO*  pInfo;
  U32           DataLen;
  
  Result = 0;
  pInfo = (THREAD_INFO*)p;
  do {
    r = SYS_SOCKET_IsReadable(pInfo->hSock, 100);  // Poll for data every 100 ms
    if (r == 0) {  // Nothing to read yet? => Try again.
      SYS_Sleep(10);
      continue;
    }
    //
    // Receive data length
    //
    r = SYS_SOCKET_Receive(pInfo->hSock, &abIn[0], 4);
    if (r != 4) {
      printf("ERROR: Failed to receive data length\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }    
    DataLen = CRYPTO_RDU32LE(&abIn[0]);
    if ((4 + TAG_LEN + DataLen) > sizeof(abIn)) {
      printf("Bad packet length\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }
    //
    // Receive tag and data
    //
    r = SYS_SOCKET_Receive(pInfo->hSock, &abIn[4], TAG_LEN + DataLen);
    if (r != (TAG_LEN + DataLen)) {
      printf("ERROR: Failed to receive data from client\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }
    //
#ifdef _LOG_VERBOSE
    _HexDump("Received packet", abIn, 4 + TAG_LEN + DataLen);
#endif
    //
    // Decrypt data
    //
    r = _Decrypt(pInfo->pSession, &abIn[4], DataLen, &abIn[4 + TAG_LEN], sizeof(abIn) - (4 + TAG_LEN));
    if (r == 0) {
      abIn[4+TAG_LEN+DataLen] = 0;
      printf("\n<  %s", &abIn[4+TAG_LEN]);
    } else {
      printf("Authentication tag error\n");
    }
    printf("\n>  ");
  } while (_ErrorOccurred == 0);
  return Result;
}

/*********************************************************************
*
*       _RunServer()
*
*  Function description
*    Runs server
*
*  Parameters
*    hSock    Opened TCP socket listening on SERVER_LISTENER_PORT
*
*/
static int _RunServer(SYS_SOCKET_HANDLE hSockListen) {
  int               Result;
  int               r;
  SYS_SOCKET_HANDLE hSockClient;
  SESSION_CONTEXT*  pSession;
  THREAD_INFO*      pThreadInfo;
  //
  // Start with title
  //
  Result      = 0;
  pSession    = NULL;
  pThreadInfo = NULL;
  hSockClient = SYS_SOCKET_INVALID_HANDLE;
  printf("\n\n");
  printf(COPYRIGHT_STRING "\n");
  printf("Operating in server mode\n");
  printf("\n\n");
  //
  // Allocate session context
  //
  pSession = (SESSION_CONTEXT*)malloc(sizeof(SESSION_CONTEXT));
  if (pSession == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  memset(pSession, 0, sizeof(SESSION_CONTEXT));
  //
  // Wait for localhost client to connect
  //
  printf("Waiting for client to connect (Port = %d)...", SERVER_LISTENER_PORT);
  hSockClient = SYS_SOCKET_Accept(hSockListen);
  if (hSockListen == SYS_SOCKET_INVALID_HANDLE) {  // Failed to open socket?  => Done
    printf("ERROR: An error occurred while waiting for a client to connect.\n");
    Result = -1;
    goto Done;
  }
  printf("OK\n\n");
  SYS_SOCKET_SetBlocking(hSockClient);  // Make sure socket operations are blocking
  //
  // After a client has connected, perform the handshake
  // to setup the encrypted communication.
  //
  r = _HandshakeServer(pSession, hSockClient);
  if (r < 0) {
    printf("ERROR: Cannot negotiate a secure connection.\n");
    Result = -1;
    goto Done;
  }
  //
  // After a successful handshake, E2EE communication between server and client can begin.
  //
  pThreadInfo = (THREAD_INFO*)malloc(sizeof(THREAD_INFO));
  if (pThreadInfo == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  pThreadInfo->hSock    = hSockClient;
  pThreadInfo->pSession = pSession;
  SYS_SOCKET_SetNonBlocking(hSockClient);
  printf("\n========== Secure connection established. ==========\n========== Type anything and press <Enter> to send. ==========\n\n");
  SYS_CreateThreadEx(_SendThread, pThreadInfo, NULL, "Sender thread",   0);
  SYS_CreateThreadEx(_RecvThread, pThreadInfo, NULL, "Receiver thread", 0);
  //
  // From here on, the other threads handle further communication
  //
  while(_ErrorOccurred == 0);
  SYS_Sleep(100);            // If one thread reported an error, the other might still access some resources. Give the other thread enought time to terminate.
Done:
  //
  // Clean-up
  //
  if (hSockClient != SYS_SOCKET_INVALID_HANDLE) {
    SYS_SOCKET_Close(hSockClient);
  }
  if (hSockListen != SYS_SOCKET_INVALID_HANDLE) {
    SYS_SOCKET_Close(hSockListen);
  }
  if (pSession) {
    free(pSession);
  }
  if (pThreadInfo) {
    free(pThreadInfo);
  }
  return Result;
}

/*********************************************************************
*
*       _RunClient()
*
*  Function description
*    Runs client
*
*  Parameters
*    hSock    Opened TCP socket
*/
static int _RunClient(SYS_SOCKET_HANDLE hSock) {
  int               Result;
  int               r;
  SESSION_CONTEXT*  pSession;
  THREAD_INFO*      pThreadInfo;
  //
  // Start with title
  //
  Result      = 0;
  pSession    = NULL;
  pThreadInfo = NULL;
  printf("\n\n");
  printf(COPYRIGHT_STRING "\n");
  printf("Operating in client mode\n");
  printf("\n\n");
  //
  // Connect to server
  //
  printf("Connecting to server...");
  SYS_SOCKET_SetBlocking(hSock);
  r = SYS_SOCKET_Connect(hSock, SYS_SOCKET_IP_ADDR_LOCALHOST, SERVER_LISTENER_PORT);
  if (r != 0) {  // Failed to connect? => Done
    printf("ERROR: Failed to connect to server.\n");
    Result = -1;
    goto Done;
  }
  printf("OK\n\n");
  //
  // Allocate session context
  //
  pSession = (SESSION_CONTEXT*)malloc(sizeof(SESSION_CONTEXT));
  if (pSession == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  memset(pSession, 0, sizeof(SESSION_CONTEXT));
  //
  // After a client has connected, perform the handshake
  // to setup the encrypted communication.
  //
  r = _HandshakeClient(pSession, hSock);
  if (r < 0) {
    printf("ERROR: Cannot negotiate a secure connection.\n");
    Result = -1;
    goto Done;
  }
  //
  // After a successful handshake, E2EE communication between server and client can begin.
  //
  pThreadInfo = (THREAD_INFO*)malloc(sizeof(THREAD_INFO));
  if (pThreadInfo == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  pThreadInfo->hSock    = hSock;
  pThreadInfo->pSession = pSession;
  SYS_SOCKET_SetNonBlocking(hSock);
  printf("\n========== Secure connection established. ==========\n========== Type anything and press <Enter> to send. ==========\n\n");
  SYS_CreateThreadEx(_SendThread, pThreadInfo, NULL, "Sender thread",   0);
  SYS_CreateThreadEx(_RecvThread, pThreadInfo, NULL, "Receiver thread", 0);
  //
  // From here on, the other threads handle further communication
  //
  while(_ErrorOccurred == 0);
  SYS_Sleep(100);            // If one thread reported an error, the other might still access some resources. Give the other thread enought time to terminate.
Done:
  //
  // Clean-up
  //
  if (hSock != SYS_SOCKET_INVALID_HANDLE) {
    SYS_SOCKET_Close(hSock);
  }
  if (pSession) {
    free(pSession);
  }
  if (pThreadInfo) {
    free(pThreadInfo);
  }
  return Result;
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       main()
*
*  Function description
*    Main entry point for application.
*/
int main(void) {
  int Result;
  int r;
  SYS_SOCKET_HANDLE hSock;

  setvbuf(stdout, (char*)NULL, _IONBF, 0);
  CRYPTO_Init();
  SEGGER_MEM_SYSTEM_HEAP_Init(&_MemContext);
  //
  // Determine if this is the server or client side
  //
  Result = 0;
  hSock  = SYS_SOCKET_OpenTCP();
  if (hSock == SYS_SOCKET_INVALID_HANDLE) {  // Failed to open socket?  => Done
    printf("ERROR: Failed to open TCP socket.\n");
    Result = -1;
    goto Done;
  }
  r = SYS_SOCKET_ListenAtTCPAddr(hSock, SYS_SOCKET_IP_ADDR_LOCALHOST, SERVER_LISTENER_PORT, 1);
  if (r == 0) {                  // We are able to listen at server listener port? => Run server
    Result = _RunServer(hSock);  // Blocking until server stops
  } else {                       // We cannot listen at server listener port? => Server must already be running so run client.
    Result = _RunClient(hSock);  // Blocking until client stops
  }
Done:
  return Result;
}

/*************************** End of file ****************************/

Headquarters

SEGGER Microcontroller GmbH

Ecolab-Allee 5
40789 Monheim am Rhein, Germany
info@segger.com
Tel.: +49-2173-99312-0
Fax: +49-2173-99312-28

Locations

USA: SEGGER Microcontroller Systems LLC

Boston area
101 Suffolk Lane
Gardner, MA 01440, USA
us-east@segger.com
Tel.: +1-978-874-0299
Fax: +1-978-874-0599

Silicon Valley
Milpitas, CA 95035, USA
us-west@segger.com
Tel.: +1-408-767-4068

China: SEGGER Microcontroller China Co., Ltd.

Room 218, Block A, Dahongqiaoguoji
No. 133 Xiulian Road
Minhang District, Shanghai 201199, China
china@segger.com
Tel.: +86-133-619-907-60

ISO 9001 certified

ISO 9001

30+ years of experience

First-class embedded software tools since 1992
  • Imprint
  • Disclaimer
  • Privacy Policy
© 2025 SEGGER - All rights reserved.