/* 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; }
long _cdecl sys_f_close (MetaDOSFile short fd) { PROC *p = curproc; FILEPTR *f; long r; TRACE (("Fclose: %d", fd)); r = GETFILEPTR (&p, &fd, &f); if (r) return r; r = do_close (p, f); /* XXX do this before do_close? */ FD_REMOVE (p, fd); # if 0 /* standard handles should be restored to default values * in TOS domain! * * XXX: why? */ if (p->domain == DOM_TOS) { f = NULL; if (fd == 0 || fd == 1) f = p->p_fd->ofiles[-1]; else if (fd == 2 || fd == 3) f = p->p_fd->ofiles[-fd]; if (f) { FP_DONE (p, f, fd, 0); f->links++; } } # endif return r; }
long _cdecl sys_f_open (MetaDOSFile const char *name, short mode) { PROC *p = curproc; FILEPTR *fp = NULL; short fd = MIN_OPEN - 1; # if O_GLOBAL int global = 0; #endif long ret; TRACE (("Fopen(%s, %x)", name, mode)); # if O_GLOBAL if (mode & O_GLOBAL) { if (p->p_cred->ucr->euid) { DEBUG (("Fopen(%s): O_GLOBAL denied for non root")); return EPERM; } /* from now the sockets are clean */ if (!stricmp (name, "u:\\dev\\socket")) { ALERT ("O_GLOBAL for sockets denied; update your network tools"); return EINVAL; } ALERT ("Opening a global handle (%s)", name); p = rootproc; global = 1; } # endif /* make sure the mode is legal */ mode &= O_USER; /* note: file mode 3 is reserved for the kernel; * for users, transmogrify it into O_RDWR (mode 2) */ if ((mode & O_RWMODE) == O_EXEC) mode = (mode & ~O_RWMODE) | O_RDWR; assert (p->p_fd && p->p_cwd); ret = FD_ALLOC (p, &fd, MIN_OPEN); if (ret) goto error; ret = FP_ALLOC (p, &fp); if (ret) goto error; ret = do_open (&fp, name, mode, 0, NULL); if (ret) goto error; /* activate the fp, default is to close non-standard files on exec */ FP_DONE (p, fp, fd, FD_CLOEXEC); # if O_GLOBAL if (global) /* we just opened a global handle */ fd += 100; # endif TRACE (("Fopen: returning %d", fd)); return fd; error: if (fd >= MIN_OPEN) FD_REMOVE (p, fd); if (fp) { fp->links--; FP_FREE (fp); } return ret; }
long _cdecl sys_f_create (MetaDOSFile const char *name, short attrib) { PROC *p = curproc; FILEPTR *fp = NULL; short fd = MIN_OPEN - 1; long ret; TRACE (("Fcreate(%s, %x)", name, attrib)); # if O_GLOBAL if (attrib & O_GLOBAL) { DEBUG (("Fcreate(%s): O_GLOBAL denied")); return EPERM; } # endif assert (p->p_fd && p->p_cwd); ret = FD_ALLOC (p, &fd, MIN_OPEN); if (ret) goto error; ret = FP_ALLOC (p, &fp); if (ret) goto error; if (attrib == FA_LABEL) { char temp1[PATH_MAX]; fcookie dir; #ifndef ARAnyM_MetaDOS /* just in case the caller tries to do something with this handle, * make it point to u:\dev\null */ ret = do_open (&fp, "u:\\dev\\null", O_RDWR|O_CREAT|O_TRUNC, 0, NULL); if (ret) goto error; #endif // ARAnyM_MetaDOS ret = path2cookie (name, temp1, &dir); if (ret) goto error; ret = xfs_writelabel (dir.fs, &dir, temp1); release_cookie (&dir); if (ret) goto error; } else if (attrib & (FA_LABEL|FA_DIR)) { DEBUG (("Fcreate(%s,%x): illegal attributes", name, attrib)); ret = EACCES; goto error; } else { ret = do_open (&fp, name, O_RDWR|O_CREAT|O_TRUNC, attrib, NULL); if (ret) { DEBUG (("Fcreate(%s) failed, error %d", name, ret)); goto error; } } /* activate the fp, default is to close non-standard files on exec */ FP_DONE (p, fp, fd, FD_CLOEXEC); TRACE (("Fcreate: returning %d", fd)); return fd; error: if (fd >= MIN_OPEN) FD_REMOVE (p, fd); if (fp) { fp->links--; FP_FREE (fp); } return ret; }
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; }