/*
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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; 
}