DWORD WINAPI ConnectThrProc(LPVOID lpParam) { #else void* ConnectThrProc(void* lpParam) { #endif int EndThread = 0; CLITCP* pCLITCP = (CLITCP*)lpParam; int connected = 0; do { memcpy_ts(&connected, &pCLITCP->connected, sizeof(int), &pCLITCP->CSconnected); // Thread-safe copy if (connected != 1) { // The client is not connected to the server, trying to connect or reconnect StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); if ( (InitTCP(&pCLITCP->ConnectSocket, pCLITCP->address, pCLITCP->port, &pCLITCP->addrinf) == EXIT_SUCCESS)&& // (SetSockOptTCP(pCLITCP->ConnectSocket, 1, 10000) == EXIT_SUCCESS)&& // Setting timeouts on the client socket (ConnectTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf) == EXIT_SUCCESS)//&& // (SetSockOptTCP(pCLITCP->ConnectSocket, 1, 10000) == EXIT_SUCCESS) // Setting timeouts on the client socket ) { fprintf(stdout, "Connection successful\n"); connected = 1; memcpy_ts(&pCLITCP->connected, &connected, sizeof(int), &pCLITCP->CSconnected); // Thread-safe copy } else fprintf(stdout, "Unable to connect\n"); } mSleep(1000); memcpy_ts(&EndThread, &pCLITCP->EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy } while(!EndThread); return 0; }
/* Stops the main loop of the TCP server. Can be called in the user-defined functions passed in parameters of MainLoopSRVTCP() if DontBlock is not set. SRVTCP* pSRVTCP : (IN,OUT) pointer to the data structure representing the server Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int StopLoopSRVTCP(SRVTCP* pSRVTCP) { int EndThread = 0; if ((pSRVTCP == NULL) || (pSRVTCP->initialized != 1)) { return EXIT_FAILURE; } memcpy_ts(&EndThread, &pSRVTCP->EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy if (EndThread == 0) { // A thread is currently running EndThread = 1; memcpy_ts((char*)&pSRVTCP->EndThread, (char*)&EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy if (pSRVTCP->DontBlock) { if (WaitForThread(pSRVTCP->ThrId) != EXIT_SUCCESS) { return EXIT_FAILURE; } } } else { // No thread was running, this function should not have been called return EXIT_FAILURE; } return EXIT_SUCCESS; }
/* Stops the TCP server. Should never be called in the user-defined functions passed in parameters of MainLoopSRVTCP(). Should not be used to stop the thread created by MainLoopSRVTCP(), use StopLoopSRVTCP() before. SRVTCP* pSRVTCP : (IN,OUT) pointer to the data structure representing the server Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int StopSRVTCP(SRVTCP* pSRVTCP) { int errflag = 0; int EndThread = 0; SOCKET_DATA* sd = NULL; SOCKET_DATA* sd_tmp = NULL; if ((pSRVTCP == NULL) || (pSRVTCP->initialized != 1)) { return EXIT_FAILURE; } pSRVTCP->initialized = 0; memcpy_ts(&EndThread, &pSRVTCP->EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy if (EndThread == 0) { // A thread is currently running, so it should be stopped EndThread = 1; memcpy_ts((char*)&pSRVTCP->EndThread, (char*)&EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy // Wait until the thread has terminated. if (WaitForThread(pSRVTCP->ThrId) != EXIT_SUCCESS) { errflag = 1; } } DeleteCriticalSection(&pSRVTCP->CSNbConnections); DeleteCriticalSection(&pSRVTCP->CSEndThread); // Close and remove every client socket of the fd_list and the fd_set sd = pSRVTCP->sock_list.first->next; // The server socket is excluded while (sd) { ShutdownTCP(&sd->sock, SD_BOTH); DisconnectTCP(&sd->sock); sd_tmp = sd->next; FD_REMOVE(sd, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd = sd_tmp; } // Removes the server socket from the fd_list and the fd_set FD_REMOVE(pSRVTCP->sock_list.first, &pSRVTCP->sock_list, &pSRVTCP->sock_set); ShutdownTCP(&pSRVTCP->ListenSocket, SD_BOTH); if (DestroySocketTCP(&pSRVTCP->ListenSocket, &pSRVTCP->addrinf) != EXIT_SUCCESS) { errflag = 1; } free(pSRVTCP->address);pSRVTCP->address = NULL; free(pSRVTCP->port);pSRVTCP->port = NULL; if (errflag) { return EXIT_FAILURE; } return EXIT_SUCCESS; }
/* Stops the TCP client. CLITCP* pCLITCP : (IN,OUT) pointer to the data structure representing the client Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int StopCLITCP(CLITCP* pCLITCP) { int EndThread = 1; if((pCLITCP == NULL) || (pCLITCP->initialized != 1)) { return EXIT_FAILURE; } pCLITCP->initialized = 0; memcpy_ts((char*)&pCLITCP->EndThread, (char*)&EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy if (WaitForThread(pCLITCP->ThrId) != EXIT_SUCCESS) { DelCriticalSection(&pCLITCP->CSEndThread); DelCriticalSection(&pCLITCP->CSconnected); StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_FAILURE; } DelCriticalSection(&pCLITCP->CSEndThread); DelCriticalSection(&pCLITCP->CSconnected); if(StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf) != EXIT_SUCCESS) { free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_FAILURE; } free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_SUCCESS; }
/* Connects to the server until it succeeds. This function should not block more than 10 s. If the client can not connect immediately, a thread keeps trying to connect to the server until it succeeds or StopCLITCP() is called. A return value of EXIT_SUCCESS does not necessary mean that the client is connected. Use GetStatusCLITCP() to verify it. CLITCP* pCLITCP : (IN,OUT) pointer to the data structure representing the client Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int ConnectCLITCP(CLITCP* pCLITCP) { int EndThread = 0; if ((pCLITCP == NULL) || (pCLITCP->initialized != 1)) { return EXIT_FAILURE; } memcpy_ts(&EndThread, &pCLITCP->EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy if (EndThread == 0) { // A thread is already running and only one thread should be running at a time return EXIT_FAILURE; // This function should not have been called } if (ConnectTCP(pCLITCP->ConnectSocket, &pCLITCP->addrinf) == EXIT_SUCCESS) { pCLITCP->connected = 1; // Notifies that the client is currently connected fprintf(stdout, "Connection successful\n"); } else { pCLITCP->connected = 0; // Notifies that the client is currently not connected fprintf(stdout, "Unable to connect\n"); } pCLITCP->EndThread = 0; // Notifies that a thread should be running if (CreateDefaultThread(ConnectThrProc, pCLITCP, &pCLITCP->ThrId) != EXIT_SUCCESS) { pCLITCP->EndThread = 1; // Notifies that no thread is running as its creation failed return EXIT_FAILURE; } return EXIT_SUCCESS; }
static uint16_t _store_mpiovd_sensors(void *out){ mavlink_message_t mavlink_message_struct; uint8_t sendbuf[MAVLINK_MAX_PACKET_LEN]; memcpy_ts(sendbuf, &mavlink_mpiovd_sensors_struct, sizeof(mavlink_mpiovd_sensors_struct), 4); // ((mavlink_mpiovd_sensors_t *)sendbuf)->time_usec = timestamp; mavlink_msg_mpiovd_sensors_encode(mavlink_system_struct.sysid, MAV_COMP_ID_MPIOVD, &mavlink_message_struct, (mavlink_mpiovd_sensors_t *)sendbuf); return _to_mmc_buf(out, sendbuf, &mavlink_message_struct); }
/* Stops the TCP client. CLITCP* pCLITCP : (IN,OUT) pointer to the data structure representing the client Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int StopCLITCP(CLITCP* pCLITCP) { int errflag = 0; int EndThread = 1; if ((pCLITCP == NULL) || (pCLITCP->initialized != 1)) { return EXIT_FAILURE; } pCLITCP->initialized = 0; memcpy_ts(&EndThread, &pCLITCP->EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy if (EndThread == 0) { // A thread is currently running, so it should be stopped EndThread = 1; memcpy_ts((char*)&pCLITCP->EndThread, (char*)&EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy // Wait until the thread has terminated. if (WaitForThread(pCLITCP->ThrId) != EXIT_SUCCESS) { errflag = 1; } } DeleteCriticalSection(&pCLITCP->CSconnected); DeleteCriticalSection(&pCLITCP->CSEndThread); ShutdownTCP(&pCLITCP->ConnectSocket, SD_BOTH); if (DestroySocketTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf) != EXIT_SUCCESS) { errflag = 1; } free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; if (errflag) { return EXIT_FAILURE; } return EXIT_SUCCESS; }
DWORD WINAPI ConnectThrProc(LPVOID lpParam) { #else void* ConnectThrProc(void* lpParam) { #endif int EndThread = 0; CLITCP* pCLITCP = (CLITCP*)lpParam; int connected = 0; do { // Checks whether the client is currently connected or not memcpy_ts(&connected, &pCLITCP->connected, sizeof(int), &pCLITCP->CSconnected); // Thread-safe copy if (connected != 1) { // The client is not connected to the server, trying to connect or reconnect ShutdownTCP(&pCLITCP->ConnectSocket, SD_BOTH); DestroySocketTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); if ( (CreateSocketTCP(&pCLITCP->ConnectSocket, pCLITCP->address, pCLITCP->port, &pCLITCP->addrinf) == EXIT_SUCCESS)&& (SetSockOptTCP(pCLITCP->ConnectSocket, 1, 10000) == EXIT_SUCCESS)&& // Setting timeouts on the client socket (ConnectTCP(pCLITCP->ConnectSocket, &pCLITCP->addrinf) == EXIT_SUCCESS) ) { connected = 1; memcpy_ts(&pCLITCP->connected, &connected, sizeof(int), &pCLITCP->CSconnected); // Thread-safe copy fprintf(stdout, "Connection successful\n"); } else { fprintf(stdout, "Unable to connect\n"); } } mSleep(1000); memcpy_ts(&EndThread, &pCLITCP->EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy } while(!EndThread); return 0; }
/* Retries to connect to the server until it succeeds. Should be called after a successful call to ConnectCLITCP(), in case of a SendCLITCP() or RecvCLITCP() failure (if the failure was unexpected). Whatever it happens, this function returns immediately, but a thread keeps trying to reconnect to the server until it succeeds or StopCLITCP() is called. A return value of EXIT_SUCCESS does not necessary mean that the client is connected. Use GetStatusCLITCP() to verify it. CLITCP* pCLITCP : (IN,OUT) pointer to the data structure representing the client Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int ReconnectCLITCP(CLITCP* pCLITCP) { int EndThread = 0; if ((pCLITCP == NULL) || (pCLITCP->initialized != 1)) { return EXIT_FAILURE; } memcpy_ts(&EndThread, &pCLITCP->EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy if (EndThread == 1) { // No thread is currently running, there was probably no successful call to ConnectCLITCP() before return EXIT_FAILURE; } EnterCriticalSection(&pCLITCP->CSconnected); if (pCLITCP->connected == 1) { // The client was supposed to be connected before pCLITCP->connected = 0; // Notifies the thread to try to reconnect the server fprintf(stdout, "Connection lost\n"); } LeaveCriticalSection(&pCLITCP->CSconnected); return EXIT_SUCCESS; }
/* Main loop of the server. Waits for incoming connections. When a new client is successfully connected to the server, the user-defined function OnNewCli() is called. When a client sends data to the server, the user-defined function OnCliReq() is called to handle the client request (only in REQSRVTCP mode). At each loop of the server, the user-defined function OnLoop() is called for every connected client. Every client should be disconnected if a SendSRVTCP() or RecvSRVTCP() fails in one of the user-defined functions by returning EXIT_FAILURE. TooManyConnectionsAction should be DENY_CONNECTION if new incoming connections should be denied if there is too many clients currently connected, or REMOVE_UNUSED if new incoming connections should replace oldest unused connections (only in REQSRVTCP mode). If DontBlock is set, this function return immediately, leaving a thread running. This thread should be stopped by calling StopLoopSRVTCP(). Otherwise, this function should block until StopLoopSRVTCP() is successfully called. The REQSRVTCP mode is designed for servers that wait for requests from the clients while the STREAMSRVTCP mode is designed for servers that continuously sends data to the clients without waiting for requests. SRVTCP* pSRVTCP : (IN,OUT) pointer to the data structure representing the server int (*OnLoop)(SRVTCP*, SOCKET, void*) : (IN) function called at every server loop, for each connected socket void* OnLoopParams : (IN) parameter passed to every call to OnLoopParams() int (*OnNewCli)(SRVTCP*, SOCKET, void*) : (IN) function called when a new client socket is successfully connected void* OnNewCliParams : (IN) parameter passed to every call to OnNewCliParams() int (*OnCliReq)(SRVTCP*, SOCKET, void*) : (IN) function called when a client socket sends data to the server (only in REQSRVTCP mode) void* OnCliReqParams : (IN) parameter passed to every call to OnCliReq() (only in REQSRVTCP mode) int TooManyConnectionsAction : (IN) DENY_CONNECTION or REMOVE_UNUSED (only in REQSRVTCP mode) int DontBlock : (IN) 1 or 0 int mode : (IN) REQSRVTCP or STREAMSRVTCP Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int MainLoopSRVTCP( SRVTCP* pSRVTCP, int (*OnLoop)(SRVTCP*, SOCKET, void*), void* OnLoopParams, int (*OnNewCli)(SRVTCP*, SOCKET, void*), void* OnNewCliParams, int (*OnCliReq)(SRVTCP*, SOCKET, void*), void* OnCliReqParams, int TooManyConnectionsAction, int DontBlock, int mode ) { struct THRPARAMS { SRVTCP* pSRVTCP; int (*OnLoop)(SRVTCP*, SOCKET, void*); void* OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*); void* OnNewCliParams; int (*OnCliReq)(SRVTCP*, SOCKET, void*); void* OnCliReqParams; int TooManyConnectionsAction; }; struct THRPARAMS params; int EndThread = 0; if ((pSRVTCP == NULL) || (pSRVTCP->initialized != 1)) { return EXIT_FAILURE; } if ((OnLoop == NULL) && (OnNewCli == NULL) && (OnCliReq == NULL)) { return EXIT_FAILURE; } memcpy_ts(&EndThread, &pSRVTCP->EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy if (EndThread == 0) { // A thread is already running and only one thread should be running at a time return EXIT_FAILURE; // This function should not have been called } pSRVTCP->EndThread = 0; // Notifies that a thread should be running // Thread parameters params.pSRVTCP = pSRVTCP; params.OnLoop = OnLoop; params.OnLoopParams = OnLoopParams; params.OnNewCli = OnNewCli; params.OnNewCliParams = OnNewCliParams; params.OnCliReq = OnCliReq; params.OnCliReqParams = OnCliReqParams; params.TooManyConnectionsAction = TooManyConnectionsAction; // If DontBlock is not set, this function will block until StopLoopSRVTCP() is successfully called. // Otherwise, it returns immediately after the creation of the thread pSRVTCP->DontBlock = DontBlock; if (mode == REQSRVTCP) { if (CreateDefaultThread(REQSRVTCPThrProc, ¶ms, &pSRVTCP->ThrId) != EXIT_SUCCESS) { pSRVTCP->EndThread = 1; // Notifies that no thread is running as its creation failed return EXIT_FAILURE; } if (!pSRVTCP->DontBlock) { // Should return after a successful call to StopLoopSRVTCP() if (WaitForThread(pSRVTCP->ThrId) != EXIT_SUCCESS) { return EXIT_FAILURE; } } } else { if (CreateDefaultThread(STREAMSRVTCPThrProc, ¶ms, &pSRVTCP->ThrId) != EXIT_SUCCESS) { pSRVTCP->EndThread = 1; // Notifies that no thread is running as its creation failed return EXIT_FAILURE; } if (!pSRVTCP->DontBlock) { // Should return after a successful call to StopLoopSRVTCP() if (WaitForThread(pSRVTCP->ThrId) != EXIT_SUCCESS) { return EXIT_FAILURE; } } } return EXIT_SUCCESS; }
DWORD WINAPI STREAMSRVTCPThrProc(LPVOID lpParam) { #else void* STREAMSRVTCPThrProc(void* lpParam) { #endif int EndThread = 0; struct THRPARAMS { SRVTCP* pSRVTCP; int (*OnLoop)(SRVTCP*, SOCKET, void*); void* OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*); void* OnNewCliParams; int (*OnCliReq)(SRVTCP*, SOCKET, void*); void* OnCliReqParams; int TooManyConnectionsAction; }; struct THRPARAMS* pParams = (struct THRPARAMS*)lpParam; int NbConnections = 0; // Copy of the thread parameters in local variables SRVTCP* pSRVTCP = pParams->pSRVTCP; int (*OnLoop)(SRVTCP*, SOCKET, void*) = pParams->OnLoop; void* OnLoopParams = pParams->OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*) = pParams->OnNewCli; void* OnNewCliParams = pParams->OnNewCliParams; SOCKET ClientSocket = INVALID_SOCKET; // New client socket THREAD_IDENTIFIER ThrId = 0; // Client thread ID struct CLITHRPARAMS { SRVTCP* pSRVTCP; SOCKET ClientSocket; int (*OnLoop)(SRVTCP*, SOCKET, void*); void* OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*); void* OnNewCliParams; }; struct CLITHRPARAMS params; // Main loop of the server. do { if ( (AcceptTCP(pSRVTCP->ListenSocket, &ClientSocket) == EXIT_SUCCESS)&& // New incoming connection (SetSockOptTCP(ClientSocket, 1, 10000) == EXIT_SUCCESS) // Setting timeouts for the client socket ) { // Client thread parameters params.pSRVTCP = pSRVTCP; params.ClientSocket = ClientSocket; params.OnLoop = OnLoop; params.OnLoopParams = OnLoopParams; params.OnNewCli = OnNewCli; params.OnNewCliParams = OnNewCliParams; // Creates a thread for the new client if ( (CreateDefaultThread(STREAMSRVTCPLoopCliThrProc, ¶ms, &ThrId) != EXIT_SUCCESS)|| (DetachThread(ThrId) != EXIT_SUCCESS) ) { // Disconnect the client as it can not be handled ShutdownTCP(&ClientSocket, SD_BOTH); DisconnectTCP(&ClientSocket); } } mSleep(100); memcpy_ts(&EndThread, &pSRVTCP->EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy } while (!EndThread); // Waits for the client threads to terminate do { mSleep(1000); memcpy_ts(&NbConnections, &pSRVTCP->NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy } while (NbConnections > 0); return 0; }
DWORD WINAPI STREAMSRVTCPLoopCliThrProc(LPVOID lpParam) { #else void* STREAMSRVTCPLoopCliThrProc(void* lpParam) { #endif int EndThread = 0; struct CLITHRPARAMS { SRVTCP* pSRVTCP; SOCKET ClientSocket; int (*OnLoop)(SRVTCP*, SOCKET, void*); void* OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*); void* OnNewCliParams; }; struct CLITHRPARAMS* pParams = (struct CLITHRPARAMS*)lpParam; // Copy of the thread parameters in local variables SRVTCP* pSRVTCP = pParams->pSRVTCP; SOCKET ClientSocket = pParams->ClientSocket; int (*OnLoop)(SRVTCP*, SOCKET, void*) = pParams->OnLoop; void* OnLoopParams = pParams->OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*) = pParams->OnNewCli; void* OnNewCliParams = pParams->OnNewCliParams; // Updates the number of client connections EnterCriticalSection(&pSRVTCP->CSNbConnections); pSRVTCP->NbConnections++; LeaveCriticalSection(&pSRVTCP->CSNbConnections); // For the newly accepted client socket, does user-defined actions if (OnNewCli(pSRVTCP, ClientSocket, OnNewCliParams) != EXIT_SUCCESS) { // On error, disconnects the client ShutdownTCP(&ClientSocket, SD_BOTH); DisconnectTCP(&ClientSocket); // Updates the number of client connections EnterCriticalSection(&pSRVTCP->CSNbConnections); pSRVTCP->NbConnections--; LeaveCriticalSection(&pSRVTCP->CSNbConnections); return 0; } // Main loop do { // Does user-defined actions if (OnLoop(pSRVTCP, ClientSocket, OnLoopParams) != EXIT_SUCCESS) { // On error, disconnects the client ShutdownTCP(&ClientSocket, SD_BOTH); DisconnectTCP(&ClientSocket); // Updates the number of client connections EnterCriticalSection(&pSRVTCP->CSNbConnections); pSRVTCP->NbConnections--; LeaveCriticalSection(&pSRVTCP->CSNbConnections); return 0; } mSleep(100); memcpy_ts(&EndThread, &pSRVTCP->EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy } while (!EndThread); ShutdownTCP(&ClientSocket, SD_BOTH); DisconnectTCP(&ClientSocket); // Updates the number of client connections EnterCriticalSection(&pSRVTCP->CSNbConnections); pSRVTCP->NbConnections--; LeaveCriticalSection(&pSRVTCP->CSNbConnections); return 0; }
DWORD WINAPI REQSRVTCPThrProc(LPVOID lpParam) { #else void* REQSRVTCPThrProc(void* lpParam) { #endif int EndThread = 0; struct THRPARAMS { SRVTCP* pSRVTCP; int (*OnLoop)(SRVTCP*, SOCKET, void*); void* OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*); void* OnNewCliParams; int (*OnCliReq)(SRVTCP*, SOCKET, void*); void* OnCliReqParams; int TooManyConnectionsAction; }; struct THRPARAMS* pParams = (struct THRPARAMS*)lpParam; int NbConnections = 0; // Copy of the thread parameters in local variables SRVTCP* pSRVTCP = pParams->pSRVTCP; int (*OnLoop)(SRVTCP*, SOCKET, void*) = pParams->OnLoop; void* OnLoopParams = pParams->OnLoopParams; int (*OnNewCli)(SRVTCP*, SOCKET, void*) = pParams->OnNewCli; void* OnNewCliParams = pParams->OnNewCliParams; int (*OnCliReq)(SRVTCP*, SOCKET, void*) = pParams->OnCliReq; void* OnCliReqParams = pParams->OnCliReqParams; int TooManyConnectionsAction = pParams->TooManyConnectionsAction; fd_set tmpset = {0}; // fd_set modified by select() fd_set tmpset1 = {0}; fd_set tmpset2 = {0}; SOCKET_DATA* sd = NULL; SOCKET_DATA* sd_tmp = NULL; struct timeval timeout = {SELECT_SEC_TIMEOUT_SRVTCP, SELECT_USEC_TIMEOUT_SRVTCP}; // Timeout for select() SOCKET ClientSocket = INVALID_SOCKET; // New client socket to add to the fd_set and its associated fd_list int iResult = SOCKET_ERROR; SOCKET_DATA* sd2 = NULL; SOCKET_DATA* sd2_tmp = NULL; long OldestTime = GetTickCount(); // Main loop of the server. // First, does user-defined actions for every client sockets (for example, sending some data). // Then, waits for data to read from the client sockets and does user-defined actions to // handle this data. // There is an exception when there is available data on the server socket. It is a client that // is requesting a connection. User-defined actions can be done in case of a successful new connection. do { if (OnLoop != NULL) { // Fo every client socket, does user-defined actions sd = pSRVTCP->sock_list.first->next; // Excludes the server socket which is the first while (sd) { // Does user-defined actions if (OnLoop(pSRVTCP, sd->sock, OnLoopParams) != EXIT_SUCCESS) { // On error, disconnects the client ShutdownTCP(&sd->sock, SD_BOTH); DisconnectTCP(&sd->sock); sd_tmp = sd->next; FD_REMOVE(sd, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd = sd_tmp; // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy continue; // Without continue we would miss the next element } sd = sd->next; } } // Copies the fd_set in a temporary variable that may be modified by select() // to indicate which sockets are readable memcpy(&tmpset, &pSRVTCP->sock_set, sizeof(pSRVTCP->sock_set)); // Timeout for select() timeout.tv_sec = SELECT_SEC_TIMEOUT_SRVTCP; timeout.tv_usec = SELECT_USEC_TIMEOUT_SRVTCP; // Waits for the readability of a socket in the fd_set, with a timeout of 100 ms iResult = select(pSRVTCP->sock_list.max_socket+1, &tmpset, NULL, NULL, &timeout); if (iResult == SOCKET_ERROR) { // Checks the validity of every socket and disconnects those which are bad sd = pSRVTCP->sock_list.first->next; // Excludes the server socket which is the first while (sd) { // Initialize 2 temporary fd_set which contain only one socket FD_ZERO(&tmpset1);FD_ZERO(&tmpset2); FD_SET(sd->sock, &tmpset1);FD_SET(sd->sock, &tmpset2); timeout.tv_sec = 0; timeout.tv_usec = 0; if (select((int)sd->sock+1, &tmpset1, &tmpset2, NULL, &timeout) == SOCKET_ERROR) { // On error, disconnects the client ShutdownTCP(&sd->sock, SD_BOTH); DisconnectTCP(&sd->sock); sd_tmp = sd->next; FD_REMOVE(sd, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd = sd_tmp; FD_CLR(sd->sock, &tmpset1);FD_CLR(sd->sock, &tmpset2); // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy continue; // Without continue we would miss the next element } FD_CLR(sd->sock, &tmpset1);FD_CLR(sd->sock, &tmpset2); sd = sd->next; } continue; } if (iResult == 0) { // The timeout on select() occured continue; } // Checks every socket of the fd_list associated with the fd_set sd = pSRVTCP->sock_list.first; while(sd) { if (FD_ISSET(sd->sock, &tmpset)) { // This socket is in tmp_set (modified by select()), so it is readable if (sd->sock == pSRVTCP->ListenSocket) { // New incoming connection (the server socket should be the first in the fd_list) if ( (AcceptTCP(pSRVTCP->ListenSocket, &ClientSocket) == EXIT_SUCCESS)&& (SetSockOptTCP(ClientSocket, 1, 10000) == EXIT_SUCCESS) // Setting timeouts for the client socket ) { // Adds it to the fd_set and its associated fd_list if (FD_ADD(ClientSocket, &pSRVTCP->sock_list, &pSRVTCP->sock_set) != EXIT_SUCCESS) { if (TooManyConnectionsAction == REMOVE_UNUSED) { // Removes an unused socket (the one that was not used for the longest time) sd2 = pSRVTCP->sock_list.first->next; // Excludes the server socket from the search OldestTime = sd2->LastUsedTime; // Looks for the oldest time while (sd2) { OldestTime = min(sd2->LastUsedTime, OldestTime); sd2 = sd2->next; } sd2 = pSRVTCP->sock_list.first->next; // Excludes the server socket from the search // Removes the socket corresponding to the oldest time while (sd2) { if (sd2->LastUsedTime == OldestTime) { ShutdownTCP(&sd2->sock, SD_BOTH); DisconnectTCP(&sd2->sock); sd2_tmp = sd2->next; FD_REMOVE(sd2, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd2 = sd2_tmp; // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy break; } else { sd2 = sd2->next; } } // Retries to add the client socket if (FD_ADD(ClientSocket, &pSRVTCP->sock_list, &pSRVTCP->sock_set) != EXIT_SUCCESS) { // Disconnects immediately the client as it can not be handled ShutdownTCP(&ClientSocket, SD_BOTH); DisconnectTCP(&ClientSocket); } else { // The new client socket was successfully added // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy if (OnNewCli != NULL) { // For the newly accepted client socket, does user-defined actions if (OnNewCli(pSRVTCP, ClientSocket, OnNewCliParams) != EXIT_SUCCESS) { // On error, disconnects the new client // Looks for the SOCKET_DATA corresponding to the new client socket sd2 = pSRVTCP->sock_list.first->next; // Excludes the server socket from the search while (sd2) { if (sd2->sock == ClientSocket) { ShutdownTCP(&sd2->sock, SD_BOTH); DisconnectTCP(&sd2->sock); sd2_tmp = sd2->next; FD_REMOVE(sd2, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd2 = sd2_tmp; // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy break; } else { sd2 = sd2->next; } } } } } } else { // Disconnects immediately the client ShutdownTCP(&ClientSocket, SD_BOTH); DisconnectTCP(&ClientSocket); } } else { // The new client socket was successfully added // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy if (OnNewCli != NULL) { // For the newly accepted client socket, does user-defined actions if (OnNewCli(pSRVTCP, ClientSocket, OnNewCliParams) != EXIT_SUCCESS) { // On error, disconnects the new client // Looks for the SOCKET_DATA corresponding to the new client socket sd2 = pSRVTCP->sock_list.first->next; // Excludes the server socket from the search while (sd2) { if (sd2->sock == ClientSocket) { ShutdownTCP(&sd2->sock, SD_BOTH); DisconnectTCP(&sd2->sock); sd2_tmp = sd2->next; FD_REMOVE(sd2, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd2 = sd2_tmp; // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy break; } else { sd2 = sd2->next; } } } } } } } else { // If we are here, the socket is a client and was already accepted before sd->LastUsedTime = GetTickCount(); if (OnCliReq != NULL) { // Fo the current client socket, does user-defined actions if (OnCliReq(pSRVTCP, sd->sock, OnCliReqParams) != EXIT_SUCCESS) { // On error, disconnects the client ShutdownTCP(&sd->sock, SD_BOTH); DisconnectTCP(&sd->sock); sd_tmp = sd->next; FD_REMOVE(sd, &pSRVTCP->sock_list, &pSRVTCP->sock_set); sd = sd_tmp; // Update the number of clients currently connected NbConnections = pSRVTCP->sock_list.fd_count - 1; memcpy_ts(&pSRVTCP->NbConnections, &NbConnections, sizeof(int), &pSRVTCP->CSNbConnections); // Thread-safe copy continue; // Without continue we would miss the next element } } } } sd = sd->next; } mSleep(100); memcpy_ts(&EndThread, &pSRVTCP->EndThread, sizeof(int), &pSRVTCP->CSEndThread); // Thread-safe copy } while (!EndThread); return 0; }
/* Initializes the TCP client. CLITCP* pCLITCP : (IN,OUT) pointer to the data structure representing the client char* address : (IN) server address to connect char* port : (IN) server port to connect Returns : EXIT_SUCCESS or EXIT_FAILURE if there is an error */ int InitCLITCP(CLITCP* pCLITCP, char* address, char* port) { int EndThread = 1; if((pCLITCP == NULL) || (pCLITCP->initialized == 1)) { return EXIT_FAILURE; } pCLITCP->address = (char*)calloc(strlen(address)+1, sizeof(char)); sprintf(pCLITCP->address, "%s", address); pCLITCP->port = (char*)calloc(strlen(port)+1, sizeof(char)); sprintf(pCLITCP->port, "%s", port); pCLITCP->ConnectSocket = INVALID_SOCKET; pCLITCP->addrinf = NULL; pCLITCP->EndThread = 0; pCLITCP->connected = 0; if ( (InitTCP(&pCLITCP->ConnectSocket, pCLITCP->address, pCLITCP->port, &pCLITCP->addrinf) == EXIT_SUCCESS)&& // (SetSockOptTCP(pCLITCP->ConnectSocket, 1, 10000) == EXIT_SUCCESS)&& // Setting timeouts on the client socket (ConnectTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf) == EXIT_SUCCESS)//&& // (SetSockOptTCP(pCLITCP->ConnectSocket, 1, 10000) == EXIT_SUCCESS) // Setting timeouts on the client socket ) { fprintf(stdout, "Connection successful\n"); pCLITCP->connected = 1; } else fprintf(stdout, "Unable to connect\n"); if (InitCriticalSection(&pCLITCP->CSEndThread) != EXIT_SUCCESS) { StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_FAILURE; } if (InitCriticalSection(&pCLITCP->CSconnected) != EXIT_SUCCESS) { DelCriticalSection(&pCLITCP->CSEndThread); StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_FAILURE; } if (CreateDefaultThread(ConnectThrProc, pCLITCP, &pCLITCP->ThrId) != EXIT_SUCCESS) { DelCriticalSection(&pCLITCP->CSEndThread); DelCriticalSection(&pCLITCP->CSconnected); StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_FAILURE; } if (SetThreadDefaultPriority(pCLITCP->ThrId, THREAD_PRIORITY_NORMAL) != EXIT_SUCCESS) { EndThread = 1; memcpy_ts((char*)&pCLITCP->EndThread, (char*)&EndThread, sizeof(int), &pCLITCP->CSEndThread); // Thread-safe copy WaitForThread(pCLITCP->ThrId); DelCriticalSection(&pCLITCP->CSEndThread); DelCriticalSection(&pCLITCP->CSconnected); StopTCP(&pCLITCP->ConnectSocket, &pCLITCP->addrinf); free(pCLITCP->address);pCLITCP->address = NULL; free(pCLITCP->port);pCLITCP->port = NULL; return EXIT_FAILURE; } pCLITCP->initialized = 1; return EXIT_SUCCESS; }