硬汉嵌入式论坛

 找回密码
 立即注册
查看: 712|回复: 2
收起左侧

[emWin] Web网页访问emWin界面驱动

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107143
QQ
发表于 2022-2-14 10:52:06 | 显示全部楼层 |阅读模式


驱动文件:

  1. /*********************************************************************
  2. *                    SEGGER Microcontroller GmbH                     *
  3. *        Solutions for real time microcontroller applications        *
  4. **********************************************************************
  5. *                                                                    *
  6. *        (c) 1996 - 2020  SEGGER Microcontroller GmbH                *
  7. *                                                                    *
  8. *        Internet: www.segger.com    Support:  support@segger.com    *
  9. *                                                                    *
  10. **********************************************************************

  11. ** emWin V6.20 - Graphical user interface for embedded applications **
  12. All  Intellectual Property rights  in the Software belongs to  SEGGER.
  13. emWin is protected by  international copyright laws.  Knowledge of the
  14. source code may not be used to write a similar product.  This file may
  15. only be used in accordance with the following terms:

  16. The software has been licensed to  ARM LIMITED whose registered office
  17. is situated at  110 Fulbourn Road,  Cambridge CB1 9NJ,  England solely
  18. for  the  purposes  of  creating  libraries  for  ARM7, ARM9, Cortex-M
  19. series,  and   Cortex-R4   processor-based  devices,  sublicensed  and
  20. distributed as part of the  MDK-ARM  Professional  under the terms and
  21. conditions  of  the   End  User  License  supplied  with  the  MDK-ARM
  22. Professional.
  23. Full source code is available at: www.segger.com

  24. We appreciate your understanding and fairness.
  25. ----------------------------------------------------------------------
  26. Licensing information
  27. Licensor:                 SEGGER Software GmbH
  28. Licensed to:              ARM Ltd, 110 Fulbourn Road, CB1 9NJ Cambridge, UK
  29. Licensed SEGGER software: emWin
  30. License number:           GUI-00181
  31. License model:            LES-SLA-20007, Agreement, effective since October 1st 2011
  32. Licensed product:         MDK-ARM Professional
  33. Licensed platform:        ARM7/9, Cortex-M/R4
  34. Licensed number of seats: -
  35. -------------------------- END-OF-HEADER -----------------------------

  36. File    : GUI_VNC_X_StartServer.c
  37. Purpose : Starts the VNC server using plain BSD socket API and
  38.           alternate prepares handling of an incoming WebSocket
  39.           connection handled by the embOS/IP web server.
  40.           By default only the plain BSD socket API will be used.
  41.           The WebSocket handling can be activated in GUIConf.h by
  42.           enabling GUI_VNC_SUPPORT_WEBSOCKET_SERVER .
  43.           The WebSocket based connection is intended to be used
  44.           with the noVNC client written in HTML5 that uses
  45.           WebSockets for communication.
  46.           The noVNC sample per default uses the URI "/websockify"
  47.                   and port 80.
  48.                   
  49. Software: - emWin, with VNC
  50.                   - embOS
  51.                   - emNet (f.k.a. embOS/IP)
  52.                   
  53. Hardware: - STM32F746G-DISCO
  54.                   
  55. How To
  56. Start   : Configure the maximum amount of VNC connections with the
  57.                   VNC_MAX_CLIENTS macro.
  58.                   To start, simply call GUI_VNC_X_StartServer()
  59.                   in your application, incrementing the ServerIndex parameter
  60.                   for each desired connection.
  61. */

  62. #include "GUI.h"
  63. #include "GUI_VNC.h"
  64. #include "RTOS.h"
  65. #include "IP.h"
  66. #include "TaskPrio.h"
  67. #include <stdio.h>

  68. /*********************************************************************
  69. *
  70. *       Defines, configurable
  71. *
  72. **********************************************************************
  73. */

  74. //
  75. // Default configuration. Use GUIConf.h for override.
  76. //
  77. #ifndef   GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER
  78.   #define GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER  0
  79. #endif
  80. #ifndef   GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  81.   #define GUI_VNC_SUPPORT_WEBSOCKET_SERVER     1
  82. #endif

  83. //
  84. // Define maximum number of VNC clients that can connect
  85. //
  86. #define VNC_MAX_CLIENTS  3

  87. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  88. #include "IP_WEBSOCKET.h"
  89. #include "IP_Webserver.h"
  90. #include "WEBS_Conf.h"        // Stack size depends on configuration

  91. //
  92. // WebSocket web server configuration.
  93. //
  94. #ifndef   WEBSOCKET_VNC_URI
  95.   #define WEBSOCKET_VNC_URI    "/websockify"
  96. #endif
  97. #ifndef   WEBSOCKET_VNC_PROTO
  98.   #define WEBSOCKET_VNC_PROTO  ""
  99. #endif

  100. #endif

  101. #define USE_RX_TASK   0  // 0: Packets are read in ISR, 1: Packets are read in a task of its own.

  102. //
  103. // Web server and IP stack
  104. //
  105. #define MAX_CONNECTIONS           1
  106. #define BACK_LOG                 20
  107. #define IDLE_TIMEOUT           1000  // Timeout [ms] after which the connection will be closed if no new data is received.
  108. #define SERVER_PORT              80
  109. #define CHILD_ALLOC_SIZE       2560  // NumBytes required from memory pool for one connection. Should be fine tuned according
  110.                                      // to your configuration using IP_WEBS_CountRequiredMem() .
  111. //
  112. // Task priorities.
  113. //
  114. enum {
  115.    TASK_PRIO_WEBS_CHILD = 150
  116.   ,TASK_PRIO_WEBS_PARENT
  117.   ,TASK_PRIO_IP_TASK           // Priority must be higher as all IP application tasks.
  118. #if USE_RX_TASK
  119.   ,TASK_PRIO_IP_RX_TASK        // Must be the highest priority of all IP related tasks.
  120. #endif
  121. };

  122. //
  123. // Task stack sizes that might not fit for some interfaces (multiples of sizeof(int)).
  124. //
  125. #ifndef   WEBS_TASK_STACK_OVERHEAD
  126.   #define WEBS_TASK_STACK_OVERHEAD   0
  127. #endif

  128. #ifndef   STACK_SIZE_SERVER
  129.   #define STACK_SIZE_SERVER           (2304 + WEBS_TASK_STACK_OVERHEAD)
  130. #endif

  131. //
  132. // UDP discover
  133. //
  134. #define ETH_UDP_DISCOVER_PORT    50020
  135. #define PACKET_SIZE              0x80

  136. //
  137. // Task stack sizes that might not fit for some interfaces (multiples of sizeof(int)).
  138. //
  139. #ifndef   APP_TASK_STACK_OVERHEAD
  140.   #define APP_TASK_STACK_OVERHEAD  0
  141. #endif

  142. /*********************************************************************
  143. *
  144. *       Defines, fixed
  145. *
  146. **********************************************************************
  147. */

  148. /*********************************************************************
  149. *
  150. *       Types
  151. *
  152. **********************************************************************
  153. */
  154. enum {
  155.   SOCKET_TYPE_BSD = 0,
  156.   SOCKET_TYPE_WEBSOCKET
  157. };

  158. typedef struct {
  159.   void              * pConnection;                   // Pointer to connection context. NULL if disconnected.
  160.                                                      // Set (if NULL) when accepting a connection to tell the VNC
  161.                                                      // server task that a new connection has been opened.
  162.   U8                  SocketType;                    // Socket type of this connection instance.
  163.   U8                  MessageType;                   // Last received WebSocket message type.
  164.   GUI_VNC_CONTEXT     Context;                       // VNC context necessary for GUI.
  165. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  166.   WEBS_WEBSOCKET_HOOK WebSocketHook;                 // WebSocket resources.
  167. #endif
  168.   U8                  acBuffer[GUI_VNC_BUFFER_SIZE]; // Buffer used for reading RFB protocol.
  169. } GUI_IP_VNC_CONNECTION;

  170. typedef struct {
  171.   OS_STACKPTR int VNCServer_Stack[(4000 + APP_TASK_STACK_OVERHEAD)/sizeof(int)];
  172.   OS_TASK         VNCServer_TCB;
  173. } GUI_VNC_TASK;

  174. /*********************************************************************
  175. *
  176. *       Prototypes
  177. *
  178. **********************************************************************
  179. */

  180. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  181. static int  _cbWebSocket_GenerateAcceptKey (WEBS_OUTPUT* pOutput, void* pSecWebSocketKey, int SecWebSocketKeyLen, void* pBuffer, int BufferSize);
  182. static void _cbWebSocket_DispatchConnection(WEBS_OUTPUT* pOutput, void* pConnection);
  183. static int  _cbWebSocket_Recv              (IP_WEBSOCKET_CONTEXT* pContext, IP_WEBSOCKET_CONNECTION* pConnection,       void* pData, unsigned NumBytes);
  184. static int  _cbWebSocket_Send              (IP_WEBSOCKET_CONTEXT* pContext, IP_WEBSOCKET_CONNECTION* pConnection, const void* pData, unsigned NumBytes);
  185. #endif

  186. /*********************************************************************
  187. *
  188. *       Static data
  189. *
  190. **********************************************************************
  191. */
  192. static GUI_IP_VNC_CONNECTION _aConnections[VNC_MAX_CLIENTS];
  193. static GUI_VNC_TASK          _aTasks      [VNC_MAX_CLIENTS];
  194. static GUI_VNC_CONTEXT     * _pFirstContext;

  195. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER

  196. static const IP_WEBS_WEBSOCKET_API _WebServerWebSocketAPI = {
  197.   _cbWebSocket_GenerateAcceptKey,  // pfGenerateAcceptKey
  198.   _cbWebSocket_DispatchConnection  // pfDispatchConnection
  199. };

  200. static const IP_WEBSOCKET_TRANSPORT_API _WebSocketTransportAPI = {
  201.   _cbWebSocket_Recv,  // pfReceive
  202.   _cbWebSocket_Send   // pfSend
  203. };

  204. //
  205. // WebServer related
  206. //
  207. static U32                   _aPool[(CHILD_ALLOC_SIZE * MAX_CONNECTIONS) / sizeof(int)];  // Memory pool for the Web server child tasks.

  208. #endif

  209. //
  210. // IP task related
  211. //
  212. static IP_HOOK_ON_STATE_CHANGE _StateChangeHook;
  213. static int                     _IFaceId;
  214. static U8                      _IPStackInit;

  215. //
  216. // Task stacks and Task-Control-Blocks.
  217. //
  218. static OS_STACKPTR int _IPStack[TASK_STACK_SIZE_IP_TASK/sizeof(int)];       // Stack of the IP_Task.
  219. static OS_TASK         _IPTCB;                                              // Task-Control-Block of the IP_Task.

  220. #if USE_RX_TASK
  221. static OS_STACKPTR int _IPRxStack[TASK_STACK_SIZE_IP_RX_TASK/sizeof(int)];  // Stack of the IP_RxTask.
  222. static OS_TASK         _IPRxTCB;                                            // Task-Control-Block of the IP_RxTask.
  223. #endif

  224. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER

  225. static int             _ConnectCnt;
  226. //
  227. // Webserver TCBs and stacks
  228. //
  229. static OS_TASK         _aWebTasks[MAX_CONNECTIONS];
  230. static OS_STACKPTR int _aWebStacks[MAX_CONNECTIONS][STACK_SIZE_SERVER/sizeof(int)];

  231. //
  232. // Task stacks and Task-Control-Blocks for main WebServer task.
  233. //
  234. static OS_STACKPTR int Stack_IP_Main[1536];
  235. static OS_TASK         TCB_IP_Main;

  236. //
  237. // File system info
  238. //
  239. static const IP_FS_API *_pFS_API;

  240. #endif

  241. /*********************************************************************
  242. *
  243. *       WebServer related
  244. *
  245. **********************************************************************
  246. */


  247. /*********************************************************************
  248. *
  249. *       _OnStateChange()
  250. *
  251. * Function description
  252. *   Callback that will be notified once the state of an interface
  253. *   changes.
  254. *
  255. * Parameters
  256. *   IFaceId   : Zero-based interface index.
  257. *   AdminState: Is this interface enabled ?
  258. *   HWState   : Is this interface physically ready ?
  259. */
  260. static void _OnStateChange(unsigned IFaceId, U8 AdminState, U8 HWState) {
  261.   //
  262.   // Check if this is a disconnect from the peer or a link down.
  263.   // In this case call IP_Disconnect() to get into a known state.
  264.   //
  265.   if (((AdminState == IP_ADMIN_STATE_DOWN) && (HWState == 1)) ||  // Typical for dial-up connection e.g. PPP when closed from peer. Link up but app. closed.
  266.       ((AdminState == IP_ADMIN_STATE_UP)   && (HWState == 0))) {  // Typical for any Ethernet connection e.g. PPPoE. App. opened but link down.
  267.     IP_Disconnect(IFaceId);                                       // Disconnect the interface to a clean state.
  268.   }
  269. }

  270. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  271. /*********************************************************************
  272. *
  273. *       _closesocket()
  274. *
  275. *  Function description
  276. *    Wrapper for closesocket()
  277. */
  278. static int _closesocket(long pConnectionInfo) {
  279.   int r;
  280.   struct linger Linger;

  281.   Linger.l_onoff  = 1;  // Enable linger for this socket to verify that all data is send.
  282.   Linger.l_linger = 1;  // Linger timeout in seconds
  283.   setsockopt((long)pConnectionInfo, SOL_SOCKET, SO_LINGER, &Linger, sizeof(Linger));
  284.   r = closesocket((long)pConnectionInfo);
  285.   return r;
  286. }

  287. /*********************************************************************
  288. *
  289. *       _Recv()
  290. *
  291. *  Function description
  292. *    Wrapper for recv()
  293. */
  294. static int _Recv(unsigned char *buf, int len, void *pConnectionInfo) {
  295.   int r;

  296.   r = recv((long)pConnectionInfo, (char *)buf, len, 0);
  297.   return r;
  298. }

  299. /*********************************************************************
  300. *
  301. *       _Send()
  302. *
  303. *  Function description
  304. *    Wrapper for send()
  305. */
  306. static int _Send(const unsigned char *buf, int len, void* pConnectionInfo) {
  307.   int r;

  308.   r = send((long)pConnectionInfo, (const char *)buf, len, 0);
  309.   return r;
  310. }

  311. /*********************************************************************
  312. *
  313. *       WEBS_IP_API
  314. *
  315. *  Description
  316. *   IP related function table
  317. */
  318. static const WEBS_IP_API _Webs_IP_API = {
  319.   _Send,
  320.   _Recv
  321. };

  322. /*********************************************************************
  323. *
  324. *       _Alloc()
  325. *
  326. *  Function description
  327. *    Wrapper for Alloc(). (emNet: IP_MEM_Alloc())
  328. */
  329. static void * _Alloc(U32 NumBytesReq) {
  330.   return IP_AllocEx(_aPool, NumBytesReq);
  331. }

  332. /*********************************************************************
  333. *
  334. *       _Free()
  335. *
  336. *  Function description
  337. *    Wrapper for Alloc(). (emNet: IP_MEM_Alloc())
  338. */
  339. static void _Free(void *p) {
  340.   IP_Free(p);
  341. }

  342. /*********************************************************************
  343. *
  344. *       WEBS_SYS_API
  345. *
  346. *  Description
  347. *   System related function table
  348. */
  349. static const WEBS_SYS_API _Webs_SYS_API = {
  350.   _Alloc,
  351.   _Free
  352. };

  353. /*********************************************************************
  354. *
  355. *       _AddToConnectCnt
  356. */
  357. static void _AddToConnectCnt(int Delta) {
  358.   OS_IncDI();
  359.   _ConnectCnt += Delta;
  360.   OS_DecRI();
  361. }

  362. /*********************************************************************
  363. *
  364. *       _WebServerChildTask
  365. */
  366. static void _WebServerChildTask(void *pContext) {
  367.   WEBS_CONTEXT ChildContext;
  368.   long hSock;
  369.   int  Opt;
  370.   int  r;

  371.   hSock    = (long)pContext;
  372.   Opt      = 1;
  373.   setsockopt(hSock, SOL_SOCKET, SO_KEEPALIVE, &Opt, sizeof(Opt));
  374.   IP_WEBS_Init(&ChildContext, &_Webs_IP_API, &_Webs_SYS_API, _pFS_API, &WebsSample_Application);  // Initialize the context of the child task.
  375.   if (_ConnectCnt < MAX_CONNECTIONS) {
  376.     r = IP_WEBS_ProcessEx(&ChildContext, pContext, NULL);
  377.   } else {
  378.     r = IP_WEBS_ProcessLastEx(&ChildContext, pContext, NULL);
  379.   }
  380.   if (r != WEBS_CONNECTION_DETACHED) {
  381.     //
  382.     // Only close the socket if it is still in web server context and has
  383.     // not been detached to another handler like a WebSocket handler.
  384.     //
  385.     _closesocket(hSock);
  386.   }
  387.   OS_EnterRegion();
  388.   _AddToConnectCnt(-1);
  389.   OS_Terminate(0);
  390.   OS_LeaveRegion();
  391. }

  392. /*********************************************************************
  393. *
  394. *       _WebServerParentTask
  395. */
  396. static void _WebServerParentTask(void) {
  397.   struct sockaddr_in InAddr;
  398.   U32  Timeout;
  399.   U32  NumBytes;
  400.   long hSockListen;
  401.   long hSock;
  402.   int  i;
  403.   int  t;
  404.   int  t0;
  405.   int  r;
  406.   WEBS_BUFFER_SIZES BufferSizes;

  407.   Timeout = IDLE_TIMEOUT;
  408.   //
  409.   // Assign file system
  410.   //
  411.   _pFS_API = &IP_FS_ReadOnly;  // To use a a real filesystem like emFile replace this line.
  412. //  _pFS_API = &IP_FS_emFile;    // Use emFile
  413. //  IP_WEBS_AddUpload();         // Enable upload
  414.   //
  415.   // Configure buffer size.
  416.   //
  417.   IP_MEMSET(&BufferSizes, 0, sizeof(BufferSizes));
  418.   BufferSizes.NumBytesInBuf       = WEBS_IN_BUFFER_SIZE;
  419.   BufferSizes.NumBytesOutBuf      = IP_TCP_GetMTU(_IFaceId) - 72;  // Use max. MTU configured for the last interface added minus worst case IPv4/TCP/VLAN headers.
  420.                                                                    // Calculation for the memory pool is done under assumption of the best case headers with - 40 bytes.
  421.   BufferSizes.NumBytesParaBuf     = WEBS_PARA_BUFFER_SIZE;
  422.   BufferSizes.NumBytesFilenameBuf = WEBS_FILENAME_BUFFER_SIZE;
  423.   BufferSizes.MaxRootPathLen      = WEBS_MAX_ROOT_PATH_LEN;
  424.   //
  425.   // Configure the size of the buffers used by the Webserver child tasks.
  426.   //
  427.   IP_WEBS_ConfigBufSizes(&BufferSizes);
  428.   //
  429.   // Check memory pool size.
  430.   //
  431.   NumBytes = IP_WEBS_CountRequiredMem(NULL);     // Get NumBytes for internals of one child thread.
  432.   NumBytes = (NumBytes + 64) * MAX_CONNECTIONS;  // Calc. the total amount for x connections (+ some bytes for managing a memory pool).
  433.   IP_Logf_Application("WEBS: Using a memory pool of %lu bytes for %lu connections.", sizeof(_aPool), MAX_CONNECTIONS);
  434.   if (NumBytes > sizeof(_aPool)) {
  435.     IP_Warnf_Application("WEBS: Memory pool should be at least %lu bytes.", NumBytes);
  436.   }
  437.   //
  438.   // Give the stack some more memory to enable the dynamical memory allocation for the Web server child tasks
  439.   //
  440.   IP_AddMemory(_aPool, sizeof(_aPool));
  441.   //
  442.   // Get a socket into listening state
  443.   //
  444.   hSockListen = socket(AF_INET, SOCK_STREAM, 0);
  445.   if (hSockListen == SOCKET_ERROR) {
  446.     while(1); // This should never happen!
  447.   }
  448.   IP_MEMSET(&InAddr, 0, sizeof(InAddr));
  449.   InAddr.sin_family      = AF_INET;
  450.   InAddr.sin_port        = htons(SERVER_PORT);
  451.   InAddr.sin_addr.s_addr = INADDR_ANY;
  452.   bind(hSockListen, (struct sockaddr *)&InAddr, sizeof(InAddr));
  453.   listen(hSockListen, BACK_LOG);
  454.   //
  455.   // Loop once per client and create a thread for the actual server
  456.   //
  457.   do {
  458. Next:
  459.     //
  460.     // Wait for an incoming connection
  461.     //
  462.     hSock = 0;
  463.     if ((hSock = accept(hSockListen, NULL, NULL)) == SOCKET_ERROR) {
  464.       continue;    // Error
  465.     }
  466.     //
  467.     // Create server thread to handle connection.
  468.     // If connection limit is reached, keep trying for some time before giving up and outputting an error message
  469.     //
  470.     t0 = OS_GetTime32() + 1000;
  471.     do {
  472.       if (_ConnectCnt < MAX_CONNECTIONS) {
  473.         for (i = 0; i < MAX_CONNECTIONS; i++) {
  474.           r = OS_IsTask(&_aWebTasks[i]);
  475.           if (r == 0) {
  476.             setsockopt(hSock, SOL_SOCKET, SO_RCVTIMEO, &Timeout, sizeof(Timeout));  // Set receive timeout for the client.
  477.             OS_CREATETASK_EX(&_aWebTasks[i], "Webserver Child", _WebServerChildTask, TASK_PRIO_WEBS_CHILD, _aWebStacks[i], (void *)hSock);
  478.             _AddToConnectCnt(1);
  479.             goto Next;
  480.           }
  481.         }
  482.       }
  483.       //
  484.       // Check time out
  485.       //
  486.       t = OS_GetTime32();
  487.       if ((t - t0) > 0) {
  488.         IP_WEBS_OnConnectionLimit(_Send, _Recv, (void*)hSock);
  489.         _closesocket(hSock);
  490.         break;
  491.       }
  492.       OS_Delay(10);
  493.     } while(1);
  494.   }  while(1);
  495. }

  496. /*********************************************************************
  497. *
  498. *       _OnRx
  499. *
  500. *  Function description
  501. *    Discover client UDP callback. Called from stack
  502. *    whenever we get a discover request.
  503. *
  504. *  Return value
  505. *    IP_RX_ERROR  if packet is invalid for some reason
  506. *    IP_OK        if packet is valid
  507. */
  508. #if ETH_UDP_DISCOVER_PORT
  509. static int _OnRx(IP_PACKET *pInPacket, void *pContext) {
  510.   char *      pInData;
  511.   IP_PACKET * pOutPacket;
  512.   char *      pOutData;
  513.   U32         TargetAddr;
  514.   U32         IPAddr;
  515.   unsigned    IFaceId;

  516.   (void)pContext;

  517.   IFaceId = IP_UDP_GetIFIndex(pInPacket);  // Find out the interface that the packet came in.
  518.   IPAddr  = htonl(IP_GetIPAddr(IFaceId));
  519.   if (IPAddr == 0) {
  520.     goto Done;
  521.   }
  522.   pInData = (char*)IP_UDP_GetDataPtr(pInPacket);
  523.   if (memcmp(pInData, "Discover", 8)) {
  524.     goto Done;
  525.   }
  526.   //
  527.   // Alloc packet
  528.   //
  529.   pOutPacket = IP_UDP_AllocEx(IFaceId, PACKET_SIZE);
  530.   if (pOutPacket == NULL) {
  531.     goto Done;
  532.   }
  533.   //
  534.   // Fill packet with data
  535.   //
  536.   pOutData = (char*)IP_UDP_GetDataPtr(pOutPacket);
  537.   IP_UDP_GetSrcAddr(pInPacket, &TargetAddr, sizeof(TargetAddr));    // Send back Unicast
  538.   memset(pOutData, 0, PACKET_SIZE);
  539.   strcpy(pOutData + 0x00, "Found");
  540.   IPAddr = htonl(IP_GetIPAddr(IFaceId));
  541.   memcpy(pOutData + 0x20, (void*)&IPAddr, 4);      // 0x20: IP address
  542.   IP_GetHWAddr(IFaceId, (U8*)pOutData + 0x30, 6);  // 0x30: MAC address
  543.   //
  544.   // Send packet
  545.   //
  546.   IP_UDP_SendAndFree(IFaceId, TargetAddr, ETH_UDP_DISCOVER_PORT, ETH_UDP_DISCOVER_PORT, pOutPacket);
  547. Done:
  548.   return IP_OK;
  549. }
  550. #endif

  551. #endif

  552. /*********************************************************************
  553. *
  554. *       _StartIPTask
  555. *
  556. *  Function description
  557. *    Task that initializes the IP stack and starts the WebServer tasks
  558. *    if required.
  559. */
  560. static void _StartIPTask(void) {
  561.   IP_Init();
  562.   _IFaceId = IP_INFO_GetNumInterfaces() - 1;                                           // Get the last registered interface ID as this is most likely the interface we want to use in this sample.
  563.   //
  564.   // Start TCP/IP task
  565.   //
  566.   OS_CREATETASK(&_IPTCB,   "IP_Task",   IP_Task,   TASK_PRIO_IP_TASK,    _IPStack);
  567. #if USE_RX_TASK
  568.   OS_CREATETASK(&_IPRxTCB, "IP_RxTask", IP_RxTask, TASK_PRIO_IP_RX_TASK, _IPRxStack);  // Start the IP_RxTask, optional.
  569. #endif
  570.   IP_AddStateChangeHook(&_StateChangeHook, _OnStateChange);                            // Register hook to be notified on disconnects.
  571.   IP_Connect(_IFaceId);                                                                // Connect the interface if necessary.
  572.   //
  573.   // IPv4 address configured ?
  574.   //
  575.   while (IP_IFaceIsReadyEx(_IFaceId) == 0) {
  576.     OS_Delay(200);
  577.   }
  578. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  579.   OS_SetPriority(OS_GetTaskID(), TASK_PRIO_WEBS_PARENT);                                  // This task has highest prio!
  580.   OS_SetTaskName(OS_GetTaskID(), "IP_WebServer");
  581. #if ETH_UDP_DISCOVER_PORT
  582.   //
  583.   // Open UDP port ETH_UDP_DISCOVER_PORT for emNet discover
  584.   //
  585.   IP_UDP_Open(0L /* any foreign host */,  ETH_UDP_DISCOVER_PORT, ETH_UDP_DISCOVER_PORT,  _OnRx, 0L);
  586. #endif

  587.   IP_WEBS_X_SampleConfig();  // Load a web server sample config that might add other resources like REST.
  588.   _WebServerParentTask();
  589. #endif
  590. }

  591. /*********************************************************************
  592. *
  593. *       Local functions
  594. *
  595. **********************************************************************
  596. */
  597. /*********************************************************************
  598. *
  599. *       _GetTaskIndex()
  600. *
  601. *  Function description
  602. *    Returns the zero-based index of the currently scheduled VNC task.
  603. *
  604. *  Return value
  605. *    Task index : >=  0
  606. *    Error      : == -1
  607. */
  608. static int _GetTaskIndex(void) {
  609.   OS_TASK * pTask;
  610.   int       i;

  611.   pTask = OS_GetTaskID();
  612.   i     = 0;
  613.   //
  614.   // Look for index of this task.
  615.   //
  616.   while (&_aTasks[i].VNCServer_TCB != pTask) {
  617.     if (i >= VNC_MAX_CLIENTS) {
  618.       return -1;
  619.     }
  620.     i++;
  621.   }
  622.   //
  623.   return i;
  624. }

  625. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER

  626. /*********************************************************************
  627. *
  628. *       _cbWebSocket_GenerateAcceptKey()
  629. *
  630. *  Function description
  631. *    Generates the value to send back for the Sec-WebSocket-Accept
  632. *    field when accepting the connection.
  633. *
  634. *  Parameters
  635. *    pOutput           : Web server connection context.
  636. *    pSecWebSocketKey  : Pointer to a buffer containing the string of
  637. *                        the Sec-WebSocket-Key from the HTTP request.
  638. *    SecWebSocketKeyLen: Number of characters of the Sec-WebSocket-Key
  639. *                        (without string termination).
  640. *    pBuffer           : Buffer where to store the accept key.
  641. *    BufferSize        : Size of buffer where to store the accept key.
  642. *
  643. *  Return value
  644. *    Length of accept key        : >  0
  645. *    Error, buffer not big enough: == 0
  646. */
  647. static int _cbWebSocket_GenerateAcceptKey(WEBS_OUTPUT* pOutput, void* pSecWebSocketKey, int SecWebSocketKeyLen, void* pBuffer, int BufferSize) {
  648.   WEBS_USE_PARA(pOutput);

  649.   return IP_WEBSOCKET_GenerateAcceptKey(pSecWebSocketKey, SecWebSocketKeyLen, pBuffer, BufferSize);
  650. }

  651. /*********************************************************************
  652. *
  653. *       _cbWebSocket_DispatchConnection()
  654. *
  655. *  Function description
  656. *    Dispatches the web server connection to the VNC server for
  657. *    further handling and signals the VNC server task.
  658. *
  659. *  Parameters
  660. *    pOutput    : Web server connection context.
  661. *    pConnection: Network connection handle.
  662. */
  663. static void _cbWebSocket_DispatchConnection(WEBS_OUTPUT* pOutput, void* pConnection) {
  664.   int i;

  665.   WEBS_USE_PARA(pOutput);
  666.   OS_EnterRegion();  // Make sure that _pConnection does not get set from another task after being read by us.
  667.   //
  668.   // Check current connections
  669.   //
  670.   for (i = 0; i < VNC_MAX_CLIENTS; i++) {
  671.     if (_aConnections[i].pConnection == pConnection) {
  672.       break;
  673.     }
  674.     if (_aConnections[i].pConnection == NULL) {
  675.       _aConnections[i].pConnection = pConnection;
  676.       _aConnections[i].SocketType  = SOCKET_TYPE_WEBSOCKET;
  677.       OS_LeaveRegion();
  678.       return;
  679.     }
  680.   }
  681.   //
  682.   OS_LeaveRegion();
  683.   closesocket((long)pConnection);
  684. }

  685. /*********************************************************************
  686. *
  687. *       _cbWebSocket_Recv()
  688. *
  689. *  Function description
  690. *    WebSocket callback that for sending data using the underlying
  691. *    network communication API (typically BSD socket API).
  692. *
  693. *  Parameters
  694. *    pContext   : WebSocket context.
  695. *    pConnection: Network connection handle.
  696. *    pData      : Where to store the received data.
  697. *    NumBytes   : Maximum amount of data to receive.
  698. *
  699. *  Return value
  700. *    Amount of data received: >  0
  701. *    Connection closed      : == 0
  702. *    Error                  : <  0
  703. */
  704. static int _cbWebSocket_Recv(IP_WEBSOCKET_CONTEXT* pContext, IP_WEBSOCKET_CONNECTION* pConnection, void* pData, unsigned NumBytes) {
  705.   IP_USE_PARA(pContext);

  706.   return recv((long)pConnection, (char*)pData, NumBytes, 0);
  707. }

  708. /*********************************************************************
  709. *
  710. *       _cbWebSocket_Send()
  711. *
  712. *  Function description
  713. *    WebSocket callback that for sending data using the underlying
  714. *    network communication API (typically BSD socket API).
  715. *
  716. *  Parameters
  717. *    pContext   : WebSocket context.
  718. *    pConnection: Network connection handle.
  719. *    pData      : Data to send.
  720. *    NumBytes   : Amount of data to send.
  721. *
  722. *  Return value
  723. *    Amount of data sent: >  0
  724. *    Connection closed  : == 0
  725. *    Error              : <  0
  726. */
  727. static int _cbWebSocket_Send(IP_WEBSOCKET_CONTEXT* pContext, IP_WEBSOCKET_CONNECTION* pConnection, const void* pData, unsigned NumBytes) {
  728.   IP_USE_PARA(pContext);

  729.   return send((long)pConnection, (const char*)pData, NumBytes, 0);
  730. }

  731. /*********************************************************************
  732. *
  733. *       _cbVNC_RecvWebSocket()
  734. *
  735. *  Function description
  736. *    This function is called indirectly by the server; it's address
  737. *    is passed to the actual server code as function pointer. It is
  738. *    needed because the server is independent of the TCP/IP stack
  739. *    implementation, so details for the TCP/IP stack can be placed
  740. *    here.
  741. *
  742. *  Parameters
  743. *    pData      : Where to store the received data.
  744. *    NumBytes   : Maximum amount of data to receive.
  745. *    pConnection: Connection handle (WebSocket context).
  746. *
  747. *  Return value
  748. *    Amount of data received: >  0
  749. *    Connection closed      : == 0
  750. *    Error                  : <  0
  751. */
  752. static int _cbVNC_RecvWebSocket(U8* pData, int NumBytes, void* pConnection) {
  753.   IP_WEBSOCKET_CONTEXT * pContext;
  754.   int                    r;
  755.   int                    NumBytesAtOnce;
  756.   int                    i;
  757.   U8                   * pMsgType;
  758.   U8                     Close;

  759.   r = -1;  // Assume error.
  760.   //
  761.   // Get ID of task to get the correct pointer to the message type.
  762.   // If for some reason an incorrect task index is returned, close the socket.
  763.   //
  764.   i        = _GetTaskIndex();
  765.   Close    = IP_WEBSOCKET_FRAME_TYPE_CLOSE;
  766.   pMsgType = (i < 0) ? &Close : &_aConnections[i].MessageType;
  767.   //
  768.   pContext = (IP_WEBSOCKET_CONTEXT*)pConnection;
  769.   if (NumBytes != 0) {
  770.     do {
  771.       if (pContext->NumBytesLeft != 0u) {
  772.         r = (int)pContext->NumBytesLeft;
  773.       } else {
  774.         r = IP_WEBSOCKET_WaitForNextMessage(pContext, pMsgType);
  775.       }
  776.       if (r > 0) {  // O.K. ?
  777.         if        (*pMsgType == IP_WEBSOCKET_FRAME_TYPE_CLOSE) {
  778.           IP_WEBSOCKET_Close(pContext, NULL, IP_WEBSOCKET_CLOSE_CODE_NORMAL_CLOSURE);
  779.           r = 0;    // Pretend connection closed.
  780.         } else if (*pMsgType == IP_WEBSOCKET_FRAME_TYPE_BINARY) {  // VNC uses binary messages.
  781.           NumBytesAtOnce = SEGGER_MIN(NumBytes, pContext->NumBytesLeft);
  782.           r = IP_WEBSOCKET_Recv(pContext, pData, NumBytesAtOnce);
  783.           if (r > 0) {
  784.             NumBytes -= r;
  785.           }
  786.         } else {
  787.           r = -1;   // Error, pretend communication error as we expect binary messages.
  788.         }
  789.       }
  790.     } while ((r > 0) && (NumBytes != 0));
  791.   }
  792.   return r;
  793. }

  794. /*********************************************************************
  795. *
  796. *       _cbVNC_SendWebSocket()
  797. *
  798. *  Function description
  799. *    This function is called indirectly by the server; it's address
  800. *    is passed to the actual server code as function pointer. It is
  801. *    needed because the server is independent of the TCP/IP stack
  802. *    implementation, so details for the TCP/IP stack can be placed
  803. *    here.
  804. *
  805. *  Parameters
  806. *    pData      : Data to send.
  807. *    NumBytes   : Amount of data to send.
  808. *    pConnection: Connection handle.
  809. *
  810. *  Return value
  811. *    Amount of data sent: >  0
  812. *    Connection closed  : == 0
  813. *    Error              : <  0
  814. */
  815. static int _cbVNC_SendWebSocket(const U8* pData, int NumBytes, void* pConnection) {
  816.   IP_WEBSOCKET_CONTEXT* pContext;
  817.   int r;

  818.   pContext = (IP_WEBSOCKET_CONTEXT*)pConnection;
  819.   r        = IP_WEBSOCKET_Send(pContext, pData, NumBytes, IP_WEBSOCKET_FRAME_TYPE_BINARY, 0);  // Send a single frame (FIN bit set of data).
  820.   if (r == 0) {  // Connection closed ? => Send our close.
  821.     IP_WEBSOCKET_Close(pContext, NULL, IP_WEBSOCKET_CLOSE_CODE_NORMAL_CLOSURE);
  822.   }
  823.   return r;
  824. }

  825. #endif

  826. #if GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER

  827. /*********************************************************************
  828. *
  829. *       _cbVNC_Recv()
  830. *
  831. *  Function description
  832. *    This function is called indirectly by the server; it's address
  833. *    is passed to the actual server code as function pointer. It is
  834. *    needed because the server is independent of the TCP/IP stack
  835. *    implementation, so details for the TCP/IP stack can be placed
  836. *    here.
  837. *
  838. *  Parameters
  839. *    pData      : Where to store the received data.
  840. *    NumBytes   : Maximum amount of data to receive.
  841. *    pConnection: Connection handle (WebSocket context).
  842. *
  843. *  Return value
  844. *    Amount of data received: >  0
  845. *    Connection closed      : == 0
  846. *    Error                  : <  0
  847. */
  848. static int _cbVNC_Recv(U8* pData, int NumBytes, void* pConnection) {
  849.   return recv((long)pConnection, (char*)pData, NumBytes, 0);
  850. }

  851. /*********************************************************************
  852. *
  853. *       _cbVNC_Send()
  854. *
  855. *  Function description
  856. *    This function is called indirectly by the server; it's address
  857. *    is passed to the actual server code as function pointer. It is
  858. *    needed because the server is independent of the TCP/IP stack
  859. *    implementation, so details for the TCP/IP stack can be placed
  860. *    here.
  861. *
  862. *  Parameters
  863. *    pData      : Data to send.
  864. *    NumBytes   : Amount of data to send.
  865. *    pConnection: Connection handle.
  866. *
  867. *  Return value
  868. *    Amount of data sent: >  0
  869. *    Connection closed  : == 0
  870. *    Error              : <  0
  871. */
  872. static int _cbVNC_Send(const U8* pData, int NumBytes, void* pConnection) {
  873.   return send((long)pConnection, (const char*)pData, NumBytes, 0);
  874. }

  875. /*********************************************************************
  876. *
  877. *       _ListenAtTCPAddr()
  878. *
  879. *  Function description
  880. *    Creates a non-blocking socket for accepting a VNC connection.
  881. *
  882. *  Parameters
  883. *    Port: Port to use for accepting connections.
  884. *
  885. *  Return value
  886. *    Parent socket handle.
  887. */
  888. static int _ListenAtTCPAddr(U16 Port) {
  889.          int         hSock;
  890.   struct sockaddr_in InAddr;

  891.   hSock = socket(AF_INET, SOCK_STREAM, 0);
  892.   if (hSock <= 0) {
  893.     while (1);  // Should not happen.
  894.   }
  895.   memset(&InAddr, 0, sizeof(InAddr));
  896.   InAddr.sin_family      = AF_INET;
  897.   InAddr.sin_port        = htons(Port);
  898.   InAddr.sin_addr.s_addr = INADDR_ANY;
  899.   bind(hSock, (struct sockaddr*)&InAddr, sizeof(InAddr));
  900.   listen(hSock, 1);
  901.   setsockopt(hSock, SOL_SOCKET, SO_NBIO, NULL, 0);  // Set socket non-blocking.
  902.   return hSock;
  903. }

  904. #endif

  905. /*********************************************************************
  906. *
  907. *       _ServerTask()
  908. *
  909. *  Function description
  910. *    This routine is the actual server task.
  911. *    It waits in an endless loop for a new WebSocket connection to be
  912. *    signaled and handles the VNC connection.
  913. */
  914. static void _ServerTask(void) {
  915. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  916.   IP_WEBSOCKET_CONTEXT WebSocketContext[VNC_MAX_CLIENTS];
  917. #elif GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER
  918.   int                  hSockParent;
  919.   int                  SoError;
  920.   int                  hSock;
  921. #endif
  922.   int                  i;
  923.   //
  924.   // Get ID of this task.
  925.   //
  926.   i = _GetTaskIndex();
  927. #if GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER
  928.   //
  929.   // Start listening on a BSD socket for a connection.
  930.   // WebSocket connections will be dispatched by the Web Server.
  931.   //
  932.   hSockParent = _ListenAtTCPAddr(5900 + _aConnections[i].Context.ServerIndex);  // Default port for VNC is is 590x, where x is the 0-based layer index.
  933. #endif
  934.   while (1) {
  935.     //
  936.     // Check that the connection handle is actually valid.
  937.     // A handle of NULL is treated as invalid although some
  938.     // TCP/IP stacks like Windows treat a socket handle of
  939.     // 0 as valid. However this occurs very rare and in this
  940.     // situation the peer should simply close the connection
  941.     // after some time due to a timeout.
  942.     // We will first check if a connection handle is present
  943.     // which means checking for a WebSocket handle. If no
  944.     // WebSocket handle is active we will check non-blocking
  945.     // if there is any BSD socket to accept.
  946.     //
  947. #if (GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER == 0)
  948.     if (_aConnections[i].pConnection == NULL) {
  949.       OS_Delay(50);  // Grant the system some time between retrying.
  950.       continue;
  951.     }
  952. #else
  953.     OS_EnterRegion();  // Make sure that _pConnection does not get set from another task after being read by us.
  954.     if (_aConnections[i].pConnection == NULL) {
  955.       //
  956.       // Check if we have a connection to accept on the regular VNC port.
  957.       //
  958.       hSock = accept(hSockParent, NULL, NULL);
  959.       if (hSock == SOCKET_ERROR) {
  960.         OS_LeaveRegion();
  961.         //
  962.         // Check if this is an IP_ERR_WOULD_BLOCK or a real error.
  963.         //
  964.         getsockopt(hSockParent, SOL_SOCKET, SO_ERROR, &SoError, sizeof(SoError));
  965.         if (SoError != IP_ERR_WOULD_BLOCK) {
  966.           while(1);    // Should not happen.
  967.         }
  968.         OS_Delay(50);  // Grant the system some time between retrying.
  969.         continue;
  970.       }
  971.       //
  972.       // We have a connection on the regular VNC port.
  973.       //
  974.       setsockopt(hSock, SOL_SOCKET, SO_BIO, NULL, 0);  // Set child socket blocking.
  975.       _aConnections[i].SocketType  = SOCKET_TYPE_BSD;
  976.       _aConnections[i].pConnection = (void*)hSock;
  977.     }
  978.     OS_LeaveRegion();
  979. #endif
  980. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  981.     if (_aConnections[i].SocketType == SOCKET_TYPE_WEBSOCKET) {
  982.       //
  983.       // Initialize the WebSocket context for the server.
  984.       //
  985.       IP_WEBSOCKET_InitServer(&WebSocketContext[i], &_WebSocketTransportAPI, (IP_WEBSOCKET_CONNECTION*)_aConnections[i].pConnection);
  986.       //
  987.       // Run the actual server using the WebSocket context as connection handle.
  988.       //
  989.       GUI_VNC_Process(&_aConnections[i].Context, _cbVNC_SendWebSocket, _cbVNC_RecvWebSocket, (void*)&WebSocketContext[i]);
  990.     }
  991. #endif
  992. #if GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER
  993.     if (_aConnections[i].SocketType == SOCKET_TYPE_BSD) {
  994.       //
  995.       // Run the actual server using the BSD socket handle as connection handle.
  996.       //
  997.       GUI_VNC_Process(&_aConnections[i].Context, _cbVNC_Send, _cbVNC_Recv, _aConnections[i].pConnection);
  998.     }
  999. #endif
  1000.     //
  1001.     // Close the connection and invalidate the connection handle
  1002.     // so we can accept a new client.
  1003.     //
  1004.     closesocket((long)_aConnections[i].pConnection);
  1005.     _aConnections[i].pConnection = NULL;
  1006.   }
  1007. }

  1008. /*********************************************************************
  1009. *
  1010. *       Global functions
  1011. *
  1012. **********************************************************************
  1013. */
  1014. /*********************************************************************
  1015. *
  1016. *       GUI_VNC_X_StartServer()
  1017. *
  1018. *  Function description
  1019. *    This routine starts a separate task for the VNC server. It
  1020. *    requires that the OS and TCP/IP stack are already initialized.
  1021. *
  1022. *  Parameters
  1023. *    LayerIndex : Index of the GUI layer that is shown via VNC.
  1024. *    ServerIndex: Zero-based server index.
  1025. *
  1026. *  Return value
  1027. *    O.K.: 0
  1028. *
  1029. *  Additional information
  1030. *    This sample is intended to be used for starting one VNC server.
  1031. *    In case multiple layers shall be accessed by different server
  1032. *    instances (ServerIndex) this sample needs to be modified.
  1033. */
  1034. int GUI_VNC_X_StartServer(int LayerIndex, int ServerIndex) {
  1035.   GUI_VNC_CONTEXT * pContext;
  1036.   char              acName[16];
  1037.   GUI_VNC_CONTEXT * pContextTemp;

  1038.   //
  1039.   // Check if maximum number of VNC clients is not exceeded.
  1040.   //
  1041.   if (ServerIndex >= VNC_MAX_CLIENTS) {
  1042.     return -1;
  1043.   }
  1044.   pContext = &_aConnections[ServerIndex].Context;
  1045.   //
  1046.   // Init VNC context and attach to layer (so context is
  1047.   // updated if the display-layer-contents change).
  1048.   //
  1049.   // If we already have a device, set the device pointer
  1050.   // to the already created one.
  1051.   //
  1052.   if (_pFirstContext == NULL) {
  1053.     GUI_VNC_AttachToLayer(pContext, LayerIndex);
  1054.     _pFirstContext = pContext;
  1055.   } else {
  1056.     //
  1057.     // New context makes use of existing device.
  1058.     //
  1059.     pContext->pDevice      = _pFirstContext->pDevice;
  1060.     pContext->xSize        = _pFirstContext->xSize;
  1061.     pContext->ySize        = _pFirstContext->ySize;
  1062.     pContext->BitsPerPixel = _pFirstContext->BitsPerPixel;
  1063.     pContext->pNext        = NULL;
  1064.     //
  1065.     // Update pNext pointers
  1066.     //
  1067.     pContextTemp = _pFirstContext;
  1068.     while (pContextTemp->pNext) {
  1069.       pContextTemp = pContextTemp->pNext;
  1070.     }
  1071.     pContextTemp->pNext = pContext;
  1072.   }
  1073.   pContext->ServerIndex = ServerIndex;
  1074.   //
  1075.   // Set up pointer to RFB buffer.
  1076.   //
  1077.   pContext->pBuffer      = _aConnections[ServerIndex].acBuffer;
  1078.   pContext->SizeOfBuffer = GUI_VNC_BUFFER_SIZE;
  1079.   //
  1080.   // If this is the first time a VNC server is opened, start the IP stack.
  1081.   //
  1082.   if (!_IPStackInit) {
  1083. #if   GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  1084.     OS_CREATETASK(&TCB_IP_Main, "IP_MainTask", _StartIPTask, 110, Stack_IP_Main);
  1085. #elif GUI_VNC_SUPPORT_PLAIN_SOCKET_SERVER
  1086.     _StartIPTask();
  1087. #endif
  1088.     _IPStackInit = 1;
  1089.   }
  1090.   //
  1091.   // Create task for VNC server. It will wait for the signal
  1092.   // of a dispatched WebSocket connection.
  1093.   //
  1094.   sprintf(acName, "VNC Server %d", ServerIndex);
  1095.   OS_CREATETASK(&_aTasks[ServerIndex].VNCServer_TCB, acName, _ServerTask, TASKPRIO_VNC, _aTasks[ServerIndex].VNCServer_Stack);
  1096. #if GUI_VNC_SUPPORT_WEBSOCKET_SERVER
  1097.   //
  1098.   // Enable WebSockets for the web server and setup the
  1099.   // URI "/websockify" with sub protocol "binary" for the
  1100.   // VNC data transfer.
  1101.   //
  1102.   IP_WEBS_WEBSOCKET_AddHook(&_aConnections[ServerIndex].WebSocketHook, &_WebServerWebSocketAPI, WEBSOCKET_VNC_URI, WEBSOCKET_VNC_PROTO);
  1103. #endif
  1104.   return 0;
  1105. }

  1106. /*********************************************************************
  1107. *
  1108. *       GUI_VNC_X_getpeername()
  1109. *
  1110. *  Function description
  1111. *    Retrieves the IP addr. of the currently connected VNC client.
  1112. *
  1113. *  Parameters
  1114. *    ServerIndex: Index of server instance.
  1115. *    pIPAddr:[OUT] VNC client connected: U32 IP addr. in network endianess.
  1116. *                  No client connected : 0
  1117. */
  1118. void GUI_VNC_X_getpeername(int ServerIndex, U32 * pIPAddr) {
  1119.   struct sockaddr_in Client;
  1120.   int                Len;
  1121.   void             * pConnection;

  1122.   if ((ServerIndex >= VNC_MAX_CLIENTS) || (ServerIndex < 0)) {
  1123.     return;
  1124.   }
  1125.   if (pIPAddr) {
  1126.     pConnection = _aConnections[ServerIndex].pConnection;
  1127.     if (pConnection != NULL) {
  1128.       Len   = sizeof(Client);
  1129.       getpeername((long)pConnection, (struct sockaddr*)&Client, &Len);
  1130.       *pIPAddr = Client.sin_addr.s_addr;
  1131.     } else {
  1132.       *pIPAddr = 0;
  1133.     }
  1134.   }
  1135. }

  1136. /*************************** End of file ****************************/
复制代码


回复

使用道具 举报

5

主题

22

回帖

37

积分

新手上路

积分
37
发表于 2022-2-14 16:09:01 | 显示全部楼层
效果图有没有的,看看什么风格
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107143
QQ
 楼主| 发表于 2022-2-14 17:18:00 | 显示全部楼层
shuangbang 发表于 2022-2-14 16:09
效果图有没有的,看看什么风格

还没有测试。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-20 10:50 , Processed in 0.152290 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表