Another unix like addition?
Do we really need this and the previous telnet server in our source?
We're always discussing ways to get the build time down but constantly adding more and
more extras.
Ged.
-----Original Message-----
From: ros-diffs-bounces(a)reactos.org [mailto:ros-diffs-bounces@reactos.org] On Behalf Of
sedwards(a)svn.reactos.org
Sent: 14 May 2009 15:52
To: ros-diffs(a)reactos.org
Subject: [ros-diffs] [sedwards] 40919: imported the MT snapshot of the GPL tftp-server for
win32 from sourceforge. Minor changes such as formatting and renaming the files, totally
untested except for building, will be used later to serve up ReactOS images to PXE b
Author: sedwards
Date: Thu May 14 18:52:22 2009
New Revision: 40919
URL:
http://svn.reactos.org/svn/reactos?rev=40919&view=rev
Log:
imported the MT snapshot of the GPL tftp-server for win32 from sourceforge. Minor changes
such as formatting and renaming the files, totally untested except for building, will be
used later to serve up ReactOS images to PXE boot
Added:
trunk/reactos/base/services/tftpd/
trunk/reactos/base/services/tftpd/README.txt (with props)
trunk/reactos/base/services/tftpd/tftpd.cpp (with props)
trunk/reactos/base/services/tftpd/tftpd.h (with props)
trunk/reactos/base/services/tftpd/tftpd.rbuild (with props)
Modified:
trunk/reactos/base/services/services.rbuild
Modified: trunk/reactos/base/services/services.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/services.rbu…
==============================================================================
--- trunk/reactos/base/services/services.rbuild [iso-8859-1] (original)
+++ trunk/reactos/base/services/services.rbuild [iso-8859-1] Thu May 14 18:52:22 2009
@@ -25,6 +25,9 @@
<directory name="telnetd">
<xi:include href="telnetd/telnetd.rbuild" />
</directory>
+ <directory name="tftpd">
+ <xi:include href="tftpd/tftpd.rbuild" />
+ </directory>
<directory name="umpnpmgr">
<xi:include href="umpnpmgr/umpnpmgr.rbuild" />
</directory>
Added: trunk/reactos/base/services/tftpd/README.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/tftpd/README…
==============================================================================
--- trunk/reactos/base/services/tftpd/README.txt (added)
+++ trunk/reactos/base/services/tftpd/README.txt [iso-8859-1] Thu May 14 18:52:22 2009
@@ -1,0 +1,3 @@
+This is a snapshot from the 1.6 release of tftp-server for win32 from sourceforge.
+
+http://tftp-server.sourceforge.net
Propchange: trunk/reactos/base/services/tftpd/README.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/reactos/base/services/tftpd/README.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: trunk/reactos/base/services/tftpd/tftpd.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/tftpd/tftpd.…
==============================================================================
--- trunk/reactos/base/services/tftpd/tftpd.cpp (added)
+++ trunk/reactos/base/services/tftpd/tftpd.cpp [iso-8859-1] Thu May 14 18:52:22 2009
@@ -1,0 +1,2245 @@
+/**************************************************************************
+* Copyright (C) 2005 by Achal Dhir *
+* achaldhir(a)gmail.com *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+***************************************************************************/
+// TFTPServer.cpp
+
+#include <stdio.h>
+#include <winsock2.h>
+#include <process.h>
+#include <time.h>
+#include <tchar.h>
+#include <ws2tcpip.h>
+#include <limits.h>
+#include <iphlpapi.h>
+#include "tftpd.h"
+
+//Global Variables
+char serviceName[] = "TFTPServer";
+char displayName[] = "TFTP Server Multithreaded";
+char sVersion[] = "TFTP Server MultiThreaded Version 1.61 Windows Built 1611";
+char iniFile[_MAX_PATH];
+char logFile[_MAX_PATH];
+char tempbuff[256];
+char logBuff[512];
+char fileSep = '\\';
+char notFileSep = '/';
+WORD blksize = 65464;
+char verbatim = 0;
+WORD timeout = 3;
+data2 cfig;
+//ThreadPool Variables
+HANDLE tEvent;
+HANDLE cEvent;
+HANDLE sEvent;
+HANDLE lEvent;
+BYTE currentServer = UCHAR_MAX;
+WORD totalThreads=0;
+WORD minThreads=1;
+WORD activeThreads=0;
+
+//Service Variables
+SERVICE_STATUS serviceStatus;
+SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
+HANDLE stopServiceEvent = 0;
+
+void WINAPI ServiceControlHandler(DWORD controlCode)
+{
+ switch (controlCode)
+ {
+ case SERVICE_CONTROL_INTERROGATE:
+ break;
+
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_STOP:
+ serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+ SetEvent(stopServiceEvent);
+ return ;
+
+ case SERVICE_CONTROL_PAUSE:
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ break;
+
+ default:
+ if (controlCode >= 128 && controlCode <= 255)
+ break;
+ else
+ break;
+ }
+
+ SetServiceStatus(serviceStatusHandle, &serviceStatus);
+}
+
+void WINAPI ServiceMain(DWORD /*argc*/, TCHAR* /*argv*/[])
+{
+ serviceStatus.dwServiceType = SERVICE_WIN32;
+ serviceStatus.dwCurrentState = SERVICE_STOPPED;
+ serviceStatus.dwControlsAccepted = 0;
+ serviceStatus.dwWin32ExitCode = NO_ERROR;
+ serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
+ serviceStatus.dwCheckPoint = 0;
+ serviceStatus.dwWaitHint = 0;
+
+ serviceStatusHandle = RegisterServiceCtrlHandler(serviceName,
ServiceControlHandler);
+
+ if (serviceStatusHandle)
+ {
+ serviceStatus.dwCurrentState = SERVICE_START_PENDING;
+ SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+ //init
+ verbatim = false;
+ init();
+ fd_set readfds;
+ timeval tv;
+ int fdsReady = 0;
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+
+ stopServiceEvent = CreateEvent(0, FALSE, FALSE, 0);
+
+ serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
+ serviceStatus.dwCurrentState = SERVICE_RUNNING;
+ SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+ do
+ {
+ FD_ZERO(&readfds);
+
+ for (int i = 0; i < MAX_SERVERS && cfig.tftpConn[i].port; i++)
+ FD_SET(cfig.tftpConn[i].sock, &readfds);
+
+ int fdsReady = select(cfig.maxFD, &readfds, NULL, NULL, &tv);
+
+ for (int i = 0; fdsReady > 0 && i < MAX_SERVERS &&
cfig.tftpConn[i].port; i++)
+ {
+ if (FD_ISSET(cfig.tftpConn[i].sock, &readfds))
+ {
+ WaitForSingleObject(sEvent, INFINITE);
+
+ currentServer = i;
+
+ if (!totalThreads || activeThreads >= totalThreads)
+ {
+ _beginthread(
+ processRequest, // thread function
+ 0, // default security
attributes
+ NULL); // argument to thread
function
+
+ }
+
+ SetEvent(tEvent);
+ WaitForSingleObject(sEvent, INFINITE);
+ fdsReady--;
+ SetEvent(sEvent);
+ }
+ }
+ }
+ while (WaitForSingleObject(stopServiceEvent, 0) == WAIT_TIMEOUT);
+
+ if (cfig.logfile)
+ fclose(cfig.logfile);
+
+ serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+ sprintf(logBuff, "Closing Network Connections...");
+ logMess(logBuff, 1);
+
+ for (int i = 0; i < MAX_SERVERS && cfig.tftpConn[i].port; i++)
+ closesocket(cfig.tftpConn[i].sock);
+
+ WSACleanup();
+
+ sprintf(logBuff, "TFTP Server Stopped !");
+ logMess(logBuff, 1);
+
+ serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
+ serviceStatus.dwCurrentState = SERVICE_STOPPED;
+ SetServiceStatus(serviceStatusHandle, &serviceStatus);
+ CloseHandle(stopServiceEvent);
+ stopServiceEvent = 0;
+ }
+}
+
+void runService()
+{
+ SERVICE_TABLE_ENTRY serviceTable[] =
+ {
+ {serviceName, ServiceMain},
+ {0, 0}
+ };
+
+ StartServiceCtrlDispatcher(serviceTable);
+}
+
+bool stopService(SC_HANDLE service)
+{
+ if (service)
+ {
+ SERVICE_STATUS serviceStatus;
+ QueryServiceStatus(service, &serviceStatus);
+ if (serviceStatus.dwCurrentState != SERVICE_STOPPED)
+ {
+ ControlService(service, SERVICE_CONTROL_STOP, &serviceStatus);
+ printf("Stopping Service.");
+ for (int i = 0; i < 100; i++)
+ {
+ QueryServiceStatus(service, &serviceStatus);
+ if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
+ {
+ printf("Stopped\n");
+ return true;
+ }
+ else
+ {
+ Sleep(500);
+ printf(".");
+ }
+ }
+ printf("Failed\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+void installService()
+{
+ SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+
+ if (serviceControlManager)
+ {
+ SC_HANDLE service = OpenService(serviceControlManager,
+ serviceName, SERVICE_QUERY_STATUS);
+ if (service)
+ {
+ printf("Service Already Exists..\n");
+ StartService(service,0,NULL);
+ CloseServiceHandle(service);
+ }
+ else
+ {
+ TCHAR path[ _MAX_PATH + 1 ];
+ if (GetModuleFileName(0, path, sizeof(path) / sizeof(path[0])) > 0)
+ {
+ SC_HANDLE service = CreateService(serviceControlManager,
+ serviceName, displayName,
+ SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE, path,
+ 0, 0, 0, 0, 0);
+ if (service)
+ {
+ printf("Successfully installed.. !\n");
+ StartService(service,0,NULL);
+ CloseServiceHandle(service);
+ }
+ else
+ printf("Installation Failed..\n");
+ }
+ }
+ CloseServiceHandle(serviceControlManager);
+ }
+ else
+ printWindowsError();
+}
+
+void uninstallService()
+{
+ SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+
+ if (serviceControlManager)
+ {
+ SC_HANDLE service = OpenService(serviceControlManager,
+ serviceName, SERVICE_QUERY_STATUS | SERVICE_STOP
| DELETE);
+ if (service)
+ {
+ if (stopService(service))
+ {
+ DeleteService(service);
+ printf("Successfully Removed !\n");
+ }
+ else
+ printf("Failed to Stop Service..\n");
+
+ CloseServiceHandle(service);
+ }
+
+ CloseServiceHandle(serviceControlManager);
+ }
+ else
+ printWindowsError();
+}
+
+void printWindowsError()
+{
+ DWORD dw = GetLastError();
+
+ if (dw)
+ {
+ LPVOID lpMsgBuf;
+ LPVOID lpDisplayBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ printf("Error: %s\nPress Enter..\n", lpMsgBuf);
+ getchar();
+ }
+}
+
+int main(int argc, TCHAR* argv[])
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ bool result = GetVersionEx(&osvi);
+
+ if (result && osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT)
+ {
+ if (argc > 1 && lstrcmpi(argv[1], TEXT("-i")) == 0)
+ installService();
+ else if (argc > 1 && lstrcmpi(argv[1], TEXT("-u")) == 0)
+ uninstallService();
+ else if (argc > 1 && lstrcmpi(argv[1], TEXT("-v")) == 0)
+ {
+ SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ bool serviceStopped = true;
+
+ if (serviceControlManager)
+ {
+ SC_HANDLE service = OpenService(serviceControlManager,
+ serviceName, SERVICE_QUERY_STATUS |
SERVICE_STOP);
+ if (service)
+ {
+ serviceStopped = stopService(service);
+ CloseServiceHandle(service);
+ }
+ CloseServiceHandle(serviceControlManager);
+ }
+ else
+ printWindowsError();
+
+ if (serviceStopped)
+ runProg();
+ else
+ printf("Failed to Stop Service\n");
+ }
+ else
+ runService();
+ }
+ else if (argc == 1 || lstrcmpi(argv[1], TEXT("-v")) == 0)
+ runProg();
+ else
+ printf("This option is not available on Windows95/98/ME\n");
+
+ return 0;
+}
+
+void runProg()
+{
+ verbatim = true;
+ init();
+ fd_set readfds;
+ timeval tv;
+ int fdsReady = 0;
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+
+ printf("\naccepting requests..\n");
+
+ do
+ {
+ //printf("Active=%u Total=%u\n",activeThreads, totalThreads);
+
+ FD_ZERO(&readfds);
+
+ for (int i = 0; i < MAX_SERVERS && cfig.tftpConn[i].port; i++)
+ FD_SET(cfig.tftpConn[i].sock, &readfds);
+
+ fdsReady = select(cfig.maxFD, &readfds, NULL, NULL, &tv);
+
+ //if (errno)
+ // printf("%s\n", strerror(errno));
+
+ for (int i = 0; fdsReady > 0 && i < MAX_SERVERS &&
cfig.tftpConn[i].port; i++)
+ {
+ if (FD_ISSET(cfig.tftpConn[i].sock, &readfds))
+ {
+ //printf("Request Waiting\n");
+
+ WaitForSingleObject(sEvent, INFINITE);
+
+ currentServer = i;
+
+ if (!totalThreads || activeThreads >= totalThreads)
+ {
+ _beginthread(
+ processRequest, // thread function
+ 0, // default security attributes
+ NULL); // argument to thread function
+ }
+ SetEvent(tEvent);
+
+ //printf("thread signalled=%u\n",SetEvent(tEvent));
+
+ WaitForSingleObject(sEvent, INFINITE);
+ fdsReady--;
+ SetEvent(sEvent);
+ }
+ }
+ }
+ while (true);
+
+ for (int i = 0; i < MAX_SERVERS && cfig.tftpConn[i].port; i++)
+ closesocket(cfig.tftpConn[i].sock);
+
+ WSACleanup();
+}
+
+void processRequest(void *lpParam)
+{
+ //printf("New Thread %u\n",GetCurrentThreadId());
+
+ request req;
+
+ WaitForSingleObject(cEvent, INFINITE);
+ totalThreads++;
+ SetEvent(cEvent);
+
+ do
+ {
+ WaitForSingleObject(tEvent, INFINITE);
+ //printf("In Thread %u\n",GetCurrentThreadId());
+
+ WaitForSingleObject(cEvent, INFINITE);
+ activeThreads++;
+ SetEvent(cEvent);
+
+ if (currentServer >= MAX_SERVERS || !cfig.tftpConn[currentServer].port)
+ {
+ SetEvent(sEvent);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ memset(&req, 0, sizeof(request));
+ req.sock = INVALID_SOCKET;
+
+ req.clientsize = sizeof(req.client);
+ req.sockInd = currentServer;
+ currentServer = UCHAR_MAX;
+ req.knock = cfig.tftpConn[req.sockInd].sock;
+
+ if (req.knock == INVALID_SOCKET)
+ {
+ SetEvent(sEvent);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ errno = 0;
+ req.bytesRecd = recvfrom(req.knock, (char*)&req.mesin, sizeof(message), 0,
(sockaddr*)&req.client, &req.clientsize);
+ errno = WSAGetLastError();
+
+ //printf("socket Signalled=%u\n",SetEvent(sEvent));
+ SetEvent(sEvent);
+
+ if (!errno && req.bytesRecd > 0)
+ {
+ if (cfig.hostRanges[0].rangeStart)
+ {
+ DWORD iip = ntohl(req.client.sin_addr.s_addr);
+ bool allowed = false;
+
+ for (int j = 0; j <= 32 && cfig.hostRanges[j].rangeStart;
j++)
+ {
+ if (iip >= cfig.hostRanges[j].rangeStart && iip <=
cfig.hostRanges[j].rangeEnd)
+ {
+ allowed = true;
+ break;
+ }
+ }
+
+ if (!allowed)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Access Denied");
+ logMess(&req, 1);
+ sendto(req.knock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0, (sockaddr*)&req.client, req.clientsize);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ }
+
+ if ((htons(req.mesin.opcode) == 5))
+ {
+ sprintf(req.serverError.errormessage, "Error Code %i at Client,
%s", ntohs(req.clientError.errorcode), req.clientError.errormessage);
+ logMess(&req, 2);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ else if (htons(req.mesin.opcode) != 1 && htons(req.mesin.opcode) !=
2)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(5);
+ sprintf(req.serverError.errormessage, "Unknown Transfer Id");
+ logMess(&req, 2);
+ sendto(req.knock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0, (sockaddr*)&req.client, req.clientsize);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ }
+ else
+ {
+ sprintf(req.serverError.errormessage, "Communication Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ req.blksize = 512;
+ req.timeout = timeout;
+ req.expiry = time(NULL) + req.timeout;
+ bool fetchAck = false;
+
+ req.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ if (req.sock == INVALID_SOCKET)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(0);
+ strcpy(req.serverError.errormessage, "Thread Socket Creation
Error");
+ sendto(req.knock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0, (sockaddr*)&req.client, req.clientsize);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ sockaddr_in service;
+ service.sin_family = AF_INET;
+ service.sin_addr.s_addr = cfig.tftpConn[req.sockInd].server;
+
+ if (cfig.minport)
+ {
+ for (WORD comport = cfig.minport; ; comport++)
+ {
+ service.sin_port = htons(comport);
+
+ if (comport > cfig.maxport)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(0);
+ strcpy(req.serverError.errormessage, "No port is free");
+ sendto(req.knock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0, (sockaddr*)&req.client, req.clientsize);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else if (bind(req.sock, (sockaddr*) &service, sizeof(service)) ==
-1)
+ continue;
+ else
+ break;
+ }
+ }
+ else
+ {
+ service.sin_port = 0;
+
+ if (bind(req.sock, (sockaddr*) &service, sizeof(service)) == -1)
+ {
+ strcpy(req.serverError.errormessage, "Thread failed to bind");
+ sendto(req.knock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0, (sockaddr*)&req.client, req.clientsize);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ }
+ }
+
+ if (req.attempt >= 3)
+ continue;
+
+ if (connect(req.sock, (sockaddr*)&req.client, req.clientsize) == -1)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(0);
+ strcpy(req.serverError.errormessage, "Connect Failed");
+ sendto(req.knock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0, (sockaddr*)&req.client, req.clientsize);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ //sprintf(req.serverError.errormessage, "In Temp, Socket");
+ //logMess(&req, 1);
+
+ char *inPtr = req.mesin.buffer;
+ *(inPtr + (req.bytesRecd - 3)) = 0;
+ req.filename = inPtr;
+
+ if (!strlen(req.filename) || strlen(req.filename) > UCHAR_MAX)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ strcpy(req.serverError.errormessage, "Malformed Request, Invalid/Missing
Filename");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ logMess(&req, 1);
+ continue;
+ }
+
+ inPtr += strlen(inPtr) + 1;
+ req.mode = inPtr;
+
+ if (!strlen(req.mode) || strlen(req.mode) > 25)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ strcpy(req.serverError.errormessage, "Malformed Request, Invalid/Missing
Mode");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ logMess(&req, 1);
+ continue;
+ }
+
+ inPtr += strlen(inPtr) + 1;
+
+ for (DWORD i = 0; i < strlen(req.filename); i++)
+ if (req.filename[i] == notFileSep)
+ req.filename[i] = fileSep;
+
+ tempbuff[0] = '.';
+ tempbuff[1] = '.';
+ tempbuff[2] = fileSep;
+ tempbuff[3] = 0;
+
+ if (strstr(req.filename, tempbuff))
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Access violation");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ if (req.filename[0] == fileSep)
+ req.filename++;
+
+ if (!cfig.homes[0].alias[0])
+ {
+ if (strlen(cfig.homes[0].target) + strlen(req.filename) >=
sizeof(req.path))
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, "Filename too large");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ strcpy(req.path, cfig.homes[0].target);
+ strcat(req.path, req.filename);
+ }
+ else
+ {
+ char *bname = strchr(req.filename, fileSep);
+
+ if (bname)
+ {
+ *bname = 0;
+ bname++;
+ }
+ else
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ sprintf(req.serverError.errormessage, "Missing
directory/alias");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ for (int i = 0; i < 8; i++)
+ {
+ //printf("%s=%i\n", req.filename, cfig.homes[i].alias[0]);
+ if (cfig.homes[i].alias[0] && !strcasecmp(req.filename,
cfig.homes[i].alias))
+ {
+ if (strlen(cfig.homes[i].target) + strlen(bname) >=
sizeof(req.path))
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, "Filename too
large");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+
+ strcpy(req.path, cfig.homes[i].target);
+ strcat(req.path, bname);
+ break;
+ }
+ else if (i == 7 || !cfig.homes[i].alias[0])
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ sprintf(req.serverError.errormessage, "No such directory/alias
%s", req.filename);
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ }
+
+ if (req.attempt >= 3)
+ continue;
+
+ if (ntohs(req.mesin.opcode) == 1)
+ {
+ if (!cfig.fileRead)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "GET Access Denied");
+ logMess(&req, 1);
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ if (*inPtr)
+ {
+ char *tmp = inPtr;
+
+ while (*tmp)
+ {
+ if (!strcasecmp(tmp, "blksize"))
+ {
+ tmp += strlen(tmp) + 1;
+ DWORD val = atol(tmp);
+
+ if (val < 512)
+ val = 512;
+ else if (val > blksize)
+ val = blksize;
+
+ req.blksize = val;
+ break;
+ }
+
+ tmp += strlen(tmp) + 1;
+ }
+ }
+
+ errno = 0;
+
+ if (!strcasecmp(req.mode, "netascii") || !strcasecmp(req.mode,
"ascii"))
+ req.file = fopen(req.path, "rt");
+ else
+ req.file = fopen(req.path, "rb");
+
+ if (errno || !req.file)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(1);
+ strcpy(req.serverError.errormessage, "File not found or No
Access");
+ logMess(&req, 1);
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ setvbuf(req.file, NULL, _IOFBF, req.blksize);
+ }
+ else
+ {
+ if (!cfig.fileWrite && !cfig.fileOverwrite)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "PUT Access Denied");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ req.file = fopen(req.path, "rb");
+
+ if (req.file)
+ {
+ fclose(req.file);
+ req.file = NULL;
+
+ if (!cfig.fileOverwrite)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(6);
+ strcpy(req.serverError.errormessage, "File already
exists");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ }
+ else if (!cfig.fileWrite)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Create File Access
Denied");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ errno = 0;
+
+ if (!strcasecmp(req.mode, "netascii") || !strcasecmp(req.mode,
"ascii"))
+ req.file = fopen(req.path, "wt");
+ else
+ req.file = fopen(req.path, "wb");
+
+ if (errno || !req.file)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Invalid Path or No
Access");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ }
+
+ if (*inPtr)
+ {
+ fetchAck = true;
+ char *outPtr = req.mesout.buffer;
+ req.mesout.opcode = htons(6);
+ DWORD val;
+ while (*inPtr)
+ {
+ //printf("%s\n", inPtr);
+ if (!strcasecmp(inPtr, "blksize"))
+ {
+ strcpy(outPtr, inPtr);
+ outPtr += strlen(outPtr) + 1;
+ inPtr += strlen(inPtr) + 1;
+ val = atol(inPtr);
+
+ if (val < 512)
+ val = 512;
+ else if (val > blksize)
+ val = blksize;
+
+ req.blksize = val;
+ sprintf(outPtr, "%u", val);
+ outPtr += strlen(outPtr) + 1;
+ }
+ else if (!strcasecmp(inPtr, "tsize"))
+ {
+ strcpy(outPtr, inPtr);
+ outPtr += strlen(outPtr) + 1;
+ inPtr += strlen(inPtr) + 1;
+
+ if (ntohs(req.mesin.opcode) == 1)
+ {
+ if (!fseek(req.file, 0, SEEK_END))
+ {
+ if (ftell(req.file) >= 0)
+ {
+ req.tsize = ftell(req.file);
+ sprintf(outPtr, "%u", req.tsize);
+ outPtr += strlen(outPtr) + 1;
+ }
+ else
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Invalid Path
or No Access");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ else
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Invalid Path or No
Access");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ else
+ {
+ req.tsize = 0;
+ sprintf(outPtr, "%u", req.tsize);
+ outPtr += strlen(outPtr) + 1;
+ }
+ }
+ else if (!strcasecmp(inPtr, "timeout"))
+ {
+ strcpy(outPtr, inPtr);
+ outPtr += strlen(outPtr) + 1;
+ inPtr += strlen(inPtr) + 1;
+ val = atoi(inPtr);
+
+ if (val < 1)
+ val = 1;
+ else if (val > UCHAR_MAX)
+ val = UCHAR_MAX;
+
+ req.timeout = val;
+ req.expiry = time(NULL) + req.timeout;
+ sprintf(outPtr, "%u", val);
+ outPtr += strlen(outPtr) + 1;
+ }
+
+ inPtr += strlen(inPtr) + 1;
+ //printf("=%u\n", val);
+ }
+
+ if (req.attempt >= 3)
+ continue;
+
+ errno = 0;
+ req.bytesReady = (DWORD)outPtr - (DWORD)&req.mesout;
+ //printf("Bytes Ready=%u\n", req.bytesReady);
+ send(req.sock, (const char*)&req.mesout, req.bytesReady, 0);
+ errno = WSAGetLastError();
+ }
+ else if (htons(req.mesin.opcode) == 2)
+ {
+ req.acout.opcode = htons(4);
+ req.acout.block = htons(0);
+ errno = 0;
+ req.bytesReady = 4;
+ send(req.sock, (const char*)&req.mesout, req.bytesReady, 0);
+ errno = WSAGetLastError();
+ }
+
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ else if (ntohs(req.mesin.opcode) == 1)
+ {
+ errno = 0;
+ req.pkt[0] = (packet*)calloc(1, req.blksize + 4);
+ req.pkt[1] = (packet*)calloc(1, req.blksize + 4);
+
+ if (errno || !req.pkt[0] || !req.pkt[1])
+ {
+ sprintf(req.serverError.errormessage, "Memory Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ long ftellLoc = ftell(req.file);
+
+ if (ftellLoc > 0)
+ {
+ if (fseek(req.file, 0, SEEK_SET))
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "File Access Error");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+ }
+ else if (ftellLoc < 0)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "File Access Error");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ errno = 0;
+ req.pkt[0]->opcode = htons(3);
+ req.pkt[0]->block = htons(1);
+ req.bytesRead[0] = fread(&req.pkt[0]->buffer, 1, req.blksize,
req.file);
+
+ if (errno)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Invalid Path or No
Access");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ if (req.bytesRead[0] == req.blksize)
+ {
+ req.pkt[1]->opcode = htons(3);
+ req.pkt[1]->block = htons(2);
+ req.bytesRead[1] = fread(&req.pkt[1]->buffer, 1, req.blksize,
req.file);
+ if (req.bytesRead[1] < req.blksize)
+ {
+ fclose(req.file);
+ req.file = 0;
+ }
+ }
+ else
+ {
+ fclose(req.file);
+ req.file = 0;
+ }
+
+ if (errno)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(2);
+ strcpy(req.serverError.errormessage, "Invalid Path or No
Access");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ while (req.attempt <= 3)
+ {
+ if (fetchAck)
+ {
+ FD_ZERO(&req.readfds);
+ req.tv.tv_sec = 1;
+ req.tv.tv_usec = 0;
+ FD_SET(req.sock, &req.readfds);
+ select(req.sock + 1, &req.readfds, NULL, NULL, &req.tv);
+
+ if (FD_ISSET(req.sock, &req.readfds))
+ {
+ errno = 0;
+ req.bytesRecd = recv(req.sock, (char*)&req.mesin,
sizeof(message), 0);
+ errno = WSAGetLastError();
+ if (req.bytesRecd <= 0 || errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else if(req.bytesRecd >= 4 && ntohs(req.mesin.opcode)
== 4)
+ {
+ if (ntohs(req.acin.block) == req.block)
+ {
+ req.block++;
+ req.fblock++;
+ req.attempt = 0;
+ }
+ else if (req.expiry > time(NULL))
+ continue;
+ else
+ req.attempt++;
+ }
+ else if (ntohs(req.mesin.opcode) == 5)
+ {
+ sprintf(req.serverError.errormessage, "Client %s:%u,
Error Code %i at Client, %s", inet_ntoa(req.client.sin_addr),
ntohs(req.client.sin_port), ntohs(req.clientError.errorcode),
req.clientError.errormessage);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, "Unexpected Option
Code %i", ntohs(req.mesin.opcode));
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ else if (req.expiry > time(NULL))
+ continue;
+ else
+ req.attempt++;
+ }
+ else
+ {
+ fetchAck = true;
+ req.acin.block = 1;
+ req.block = 1;
+ req.fblock = 1;
+ }
+
+ if (req.attempt >= 3)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(0);
+
+ if (req.fblock && !req.block)
+ strcpy(req.serverError.errormessage, "Large File, Block#
Rollover not supported by Client");
+ else
+ strcpy(req.serverError.errormessage, "Timeout");
+
+ logMess(&req, 1);
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else if (!req.fblock)
+ {
+ errno = 0;
+ send(req.sock, (const char*)&req.mesout, req.bytesReady, 0);
+ errno = WSAGetLastError();
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ req.expiry = time(NULL) + req.timeout;
+ }
+ else if (ntohs(req.pkt[0]->block) == req.block)
+ {
+ errno = 0;
+ send(req.sock, (const char*)req.pkt[0], req.bytesRead[0] + 4, 0);
+ errno = WSAGetLastError();
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ req.expiry = time(NULL) + req.timeout;
+
+ if (req.file)
+ {
+ req.tblock = ntohs(req.pkt[1]->block) + 1;
+ if (req.tblock == req.block)
+ {
+ req.pkt[1]->block = htons(++req.tblock);
+ req.bytesRead[1] = fread(&req.pkt[1]->buffer, 1,
req.blksize, req.file);
+
+ if (errno)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, strerror(errno));
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else if (req.bytesRead[1] < req.blksize)
+ {
+ fclose(req.file);
+ req.file = 0;
+ }
+ }
+ }
+ }
+ else if (ntohs(req.pkt[1]->block) == req.block)
+ {
+ errno = 0;
+ send(req.sock, (const char*)req.pkt[1], req.bytesRead[1] + 4, 0);
+ errno = WSAGetLastError();
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+
+ req.expiry = time(NULL) + req.timeout;
+
+ if (req.file)
+ {
+ req.tblock = ntohs(req.pkt[0]->block) + 1;
+ if (req.tblock == req.block)
+ {
+ req.pkt[0]->block = htons(++req.tblock);
+ req.bytesRead[0] = fread(&req.pkt[0]->buffer, 1,
req.blksize, req.file);
+ if (errno)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, strerror(errno));
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else if (req.bytesRead[0] < req.blksize)
+ {
+ fclose(req.file);
+ req.file = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ sprintf(req.serverError.errormessage, "%u Blocks Served",
req.fblock - 1);
+ logMess(&req, 2);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ }
+ else if (ntohs(req.mesin.opcode) == 2)
+ {
+ errno = 0;
+ req.pkt[0] = (packet*)calloc(1, req.blksize + 4);
+
+ if (errno || !req.pkt[0])
+ {
+ sprintf(req.serverError.errormessage, "Memory Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ continue;
+ }
+
+ while (req.attempt <= 3)
+ {
+ FD_ZERO(&req.readfds);
+ req.tv.tv_sec = 1;
+ req.tv.tv_usec = 0;
+ FD_SET(req.sock, &req.readfds);
+ select(req.sock + 1, &req.readfds, NULL, NULL, &req.tv);
+
+ if (FD_ISSET(req.sock, &req.readfds))
+ {
+ errno = 0;
+ req.bytesRecd = recv(req.sock, (char*)req.pkt[0], req.blksize + 4,
0);
+ errno = WSAGetLastError();
+
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ else
+ req.bytesRecd = 0;
+
+ if (req.bytesRecd >= 4)
+ {
+ if (ntohs(req.pkt[0]->opcode) == 3)
+ {
+ req.tblock = req.block + 1;
+
+ if (ntohs(req.pkt[0]->block) == req.tblock)
+ {
+ req.acout.opcode = htons(4);
+ req.acout.block = req.pkt[0]->block;
+ req.block++;
+ req.fblock++;
+ req.bytesReady = 4;
+ req.expiry = time(NULL) + req.timeout;
+
+ errno = 0;
+ send(req.sock, (const char*)&req.mesout, req.bytesReady,
0);
+ errno = WSAGetLastError();
+
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+
+ if (req.bytesRecd > 4)
+ {
+ errno = 0;
+ if (fwrite(&req.pkt[0]->buffer, req.bytesRecd - 4,
1, req.file) != 1 || errno)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(3);
+ strcpy(req.serverError.errormessage, "Disk full
or allocation exceeded");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else
+ req.attempt = 0;
+ }
+ else
+ req.attempt = 0;
+
+ if ((WORD)req.bytesRecd < req.blksize + 4)
+ {
+ fclose(req.file);
+ req.file = 0;
+ sprintf(req.serverError.errormessage, "%u Blocks
Received", req.fblock);
+ logMess(&req, 2);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ else if (req.expiry > time(NULL))
+ continue;
+ else if (req.attempt >= 3)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(0);
+
+ if (req.fblock && !req.block)
+ strcpy(req.serverError.errormessage, "Large File,
Block# Rollover not supported by Client");
+ else
+ strcpy(req.serverError.errormessage,
"Timeout");
+
+ logMess(&req, 1);
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else
+ {
+ req.expiry = time(NULL) + req.timeout;
+ errno = 0;
+ send(req.sock, (const char*)&req.mesout, req.bytesReady,
0);
+ errno = WSAGetLastError();
+ req.attempt++;
+
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ }
+ else if (req.bytesRecd > (int)sizeof(message))
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, "Error: Incoming
Packet too large");
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else if (ntohs(req.pkt[0]->opcode) == 5)
+ {
+ sprintf(req.serverError.errormessage, "Error Code %i at
Client, %s", ntohs(req.pkt[0]->block), &req.pkt[0]->buffer);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(4);
+ sprintf(req.serverError.errormessage, "Unexpected Option
Code %i", ntohs(req.pkt[0]->opcode));
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ else if (req.expiry > time(NULL))
+ continue;
+ else if (req.attempt >= 3)
+ {
+ req.serverError.opcode = htons(5);
+ req.serverError.errorcode = htons(0);
+
+ if (req.fblock && !req.block)
+ strcpy(req.serverError.errormessage, "Large File, Block#
Rollover not supported by Client");
+ else
+ strcpy(req.serverError.errormessage, "Timeout");
+
+ logMess(&req, 1);
+ send(req.sock, (const char*)&req.serverError,
strlen(req.serverError.errormessage) + 5, 0);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ else
+ {
+ req.expiry = time(NULL) + req.timeout;
+ errno = 0;
+ send(req.sock, (const char*)&req.mesout, req.bytesReady, 0);
+ errno = WSAGetLastError();
+ req.attempt++;
+
+ if (errno)
+ {
+ sprintf(req.serverError.errormessage, "Communication
Error");
+ logMess(&req, 1);
+ req.attempt = UCHAR_MAX;
+ break;
+ }
+ }
+ }
+ }
+ }
+ while (cleanReq(&req));
+
+ WaitForSingleObject(cEvent, INFINITE);
+ totalThreads--;
+ SetEvent(cEvent);
+
+ //printf("Thread %u Killed\n",GetCurrentThreadId());
+ _endthread();
+ return;
+}
+
+bool cleanReq(request* req)
+{
+ //printf("cleaning\n");
+
+ if (req->file)
+ fclose(req->file);
+
+ if (!(req->sock == INVALID_SOCKET))
+ {
+ //printf("Here\n");
+ closesocket(req->sock);
+ }
+
+ if (req->pkt[0])
+ free(req->pkt[0]);
+
+ if (req->pkt[1])
+ free(req->pkt[1]);
+
+ WaitForSingleObject(cEvent, INFINITE);
+ activeThreads--;
+ SetEvent(cEvent);
+
+ //printf("cleaned\n");
+
+ return (totalThreads <= minThreads);
+}
+
+char* myGetToken(char* buff, BYTE index)
+{
+ while (*buff)
+ {
+ if (index)
+ index--;
+ else
+ break;
+
+ buff += strlen(buff) + 1;
+ }
+
+ return buff;
+}
+
+WORD myTokenize(char *target, char *source, char *sep, bool whiteSep)
+{
+ bool found = true;
+ char *dp = target;
+ WORD kount = 0;
+
+ while (*source)
+ {
+ if (sep && sep[0] && strchr(sep, (*source)))
+ {
+ found = true;
+ source++;
+ continue;
+ }
+ else if (whiteSep && *source <= 32)
+ {
+ found = true;
+ source++;
+ continue;
+ }
+
+ if (found)
+ {
+ if (target != dp)
+ {
+ *dp = 0;
+ dp++;
+ }
+ kount++;
+ }
+
+ found = false;
+ *dp = *source;
+ dp++;
+ source++;
+ }
+
+ *dp = 0;
+ dp++;
+ *dp = 0;
+
+ //printf("%s\n", target);
+
+ return kount;
+}
+
+char* myTrim(char *target, char *source)
+{
+ while ((*source) && (*source) <= 32)
+ source++;
+
+ int i = 0;
+
+ for (; i < 511 && source[i]; i++)
+ target[i] = source[i];
+
+ target[i] = source[i];
+ i--;
+
+ for (; i >= 0 && target[i] <= 32; i--)
+ target[i] = 0;
+
+ return target;
+}
+
+void mySplit(char *name, char *value, char *source, char splitChar)
+{
+ int i = 0;
+ int j = 0;
+ int k = 0;
+
+ for (; source[i] && j <= 510 && source[i] != splitChar; i++, j++)
+ {
+ name[j] = source[i];
+ }
+
+ if (source[i])
+ {
+ i++;
+ for (; k <= 510 && source[i]; i++, k++)
+ {
+ value[k] = source[i];
+ }
+ }
+
+ name[j] = 0;
+ value[k] = 0;
+
+ myTrim(name, name);
+ myTrim(value, value);
+ //printf("%s %s\n", name, value);
+}
+
+bool getSection(char *sectionName, char *buffer, BYTE serial, char *fileName)
+{
+ //printf("%s=%s\n",fileName,sectionName);
+ char section[128];
+ sprintf(section, "[%s]", sectionName);
+ myUpper(section);
+ FILE *f = fopen(fileName, "rt");
+ char buff[512];
+ BYTE found = 0;
+
+ if (f)
+ {
+ while (fgets(buff, 511, f))
+ {
+ myUpper(buff);
+ myTrim(buff, buff);
+
+ if (strstr(buff, section) == buff)
+ {
+ found++;
+ if (found == serial)
+ {
+ //printf("%s=%s\n",fileName,sectionName);
+ while (fgets(buff, 511, f))
+ {
+ myTrim(buff, buff);
+
+ if (strstr(buff, "[") == buff)
+ break;
+
+ if ((*buff) >= '0' && (*buff) <=
'9' || (*buff) >= 'A' && (*buff) <= 'Z' || (*buff)
>= 'a' && (*buff) <= 'z' || ((*buff) &&
strchr("/\\?*", (*buff))))
+ {
+ buffer += sprintf(buffer, "%s", buff);
+ buffer++;
+ }
+ }
+ break;
+ }
+ }
+ }
+ fclose(f);
+ }
+
+ *buffer = 0;
+ *(buffer + 1) = 0;
+ return (found == serial);
+}
+
+char *IP2String(char *target, DWORD ip)
+{
+ data15 inaddr;
+ inaddr.ip = ip;
+ sprintf(target, "%u.%u.%u.%u", inaddr.octate[0], inaddr.octate[1],
inaddr.octate[2], inaddr.octate[3]);
+ return target;
+}
+
+bool isIP(char *string)
+{
+ int j = 0;
+
+ for (; *string; string++)
+ {
+ if (*string == '.' && *(string + 1) != '.')
+ j++;
+ else if (*string < '0' || *string > '9')
+ return 0;
+ }
+
+ if (j == 3)
+ return 1;
+ else
+ return 0;
+}
+
+char *myUpper(char *string)
+{
+ char diff = 'a' - 'A';
+ WORD len = strlen(string);
+ for (int i = 0; i < len; i++)
+ if (string[i] >= 'a' && string[i] <= 'z')
+ string[i] -= diff;
+ return string;
+}
+
+char *myLower(char *string)
+{
+ char diff = 'a' - 'A';
+ WORD len = strlen(string);
+ for (int i = 0; i < len; i++)
+ if (string[i] >= 'A' && string[i] <= 'Z')
+ string[i] += diff;
+ return string;
+}
+
+void init()
+{
+ memset(&cfig, 0, sizeof(cfig));
+
+ GetModuleFileName(NULL, iniFile, MAX_PATH);
+ char *iniFileExt = strrchr(iniFile, '.');
+ strcpy(iniFileExt, ".ini");
+ GetModuleFileName(NULL, logFile, MAX_PATH);
+ iniFileExt = strrchr(logFile, '.');
+ strcpy(iniFileExt, ".log");
+
+ char iniStr[4096];
+ char name[256];
+ char value[256];
+
+ if (verbatim)
+ {
+ cfig.logLevel = 2;
+ printf("%s\n\n", sVersion);
+ }
+ else if (getSection("LOGGING", iniStr, 1, iniFile))
+ {
+ char *iniStrPtr = myGetToken(iniStr, 0);
+
+ if (!iniStrPtr[0] || !strcasecmp(iniStrPtr, "None"))
+ cfig.logLevel = 0;
+ else if (!strcasecmp(iniStrPtr, "Errors"))
+ cfig.logLevel = 1;
+ else if (!strcasecmp(iniStrPtr, "All"))
+ cfig.logLevel = 2;
+ else if (!strcasecmp(iniStrPtr, "Debug"))
+ cfig.logLevel = 3;
+ else
+ cfig.logLevel = UCHAR_MAX;
+ }
+
+ if (!verbatim && cfig.logLevel)
+ {
+ cfig.logfile = fopen(logFile, "wt");
+
+ if (cfig.logfile)
+ {
+ fclose(cfig.logfile);
+ cfig.logfile = fopen(logFile, "at");
+ fprintf(cfig.logfile, "%s\n", sVersion);
+ }
+ }
+
+ if (cfig.logLevel == UCHAR_MAX)
+ {
+ cfig.logLevel = 1;
+ sprintf(logBuff, "Section [LOGGING], Invalid Logging Level: %s,
ignored", myGetToken(iniStr, 0));
+ logMess(logBuff, 1);
+ }
+
+ WORD wVersionRequested = MAKEWORD(1, 1);
+ WSAStartup(wVersionRequested, &cfig.wsaData);
+
+ if (cfig.wsaData.wVersion != wVersionRequested)
+ {
+ sprintf(logBuff, "WSAStartup Error");
+ logMess(logBuff, 1);
+ }
+
+ if (getSection("LISTEN-ON", iniStr, 1, iniFile))
+ {
+ char *iniStrPtr = myGetToken(iniStr, 0);
+
+ for (int i = 0; i < MAX_SERVERS && iniStrPtr[0]; iniStrPtr =
myGetToken(iniStrPtr, 1))
+ {
+ strncpy(name, iniStrPtr, UCHAR_MAX);
+ WORD port = 69;
+ char *dp = strchr(name, ':');
+ if (dp)
+ {
+ *dp = 0;
+ dp++;
+ port = atoi(dp);
+ }
+
+ DWORD ip = my_inet_addr(name);
+
+ if (isIP(name) && ip)
+ {
+ for (BYTE j = 0; j < MAX_SERVERS; j++)
+ {
+ if (cfig.servers[j] == ip)
+ break;
+ else if (!cfig.servers[j])
+ {
+ cfig.servers[j] = ip;
+ cfig.ports[j] = port;
+ i++;
+ break;
+ }
+ }
+ }
+ else
+ {
+ sprintf(logBuff, "Warning: Section [LISTEN-ON], Invalid IP Address
%s, ignored", iniStrPtr);
+ logMess(logBuff, 1);
+ }
+ }
+ }
+
+ if (getSection("HOME", iniStr, 1, iniFile))
+ {
+ char *iniStrPtr = myGetToken(iniStr, 0);
+ for (; iniStrPtr[0]; iniStrPtr = myGetToken(iniStrPtr, 1))
+ {
+ mySplit(name, value, iniStrPtr, '=');
+ if (strlen(value))
+ {
+ if (!cfig.homes[0].alias[0] && cfig.homes[0].target[0])
+ {
+ sprintf(logBuff, "Section [HOME], alias and bare path mixup,
entry %s ignored", iniStrPtr);
+ logMess(logBuff, 1);
+ }
+ else if (strchr(name, notFileSep) || strchr(name, fileSep) ||
strchr(name, '>') || strchr(name, '<') || strchr(name,
'.'))
+ {
+ sprintf(logBuff, "Section [HOME], invalid chars in alias %s,
entry ignored", name);
+ logMess(logBuff, 1);
+ }
+ else if (name[0] && strlen(name) < 64 && value[0])
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ if (cfig.homes[i].alias[0] && !strcasecmp(name,
cfig.homes[i].alias))
+ {
+ sprintf(logBuff, "Section [HOME], Duplicate Entry: %s
ignored", iniStrPtr);
+ logMess(logBuff, 1);
+ break;
+ }
+ else if (!cfig.homes[i].alias[0])
+ {
+ strcpy(cfig.homes[i].alias, name);
+ strcpy(cfig.homes[i].target, value);
+
+ if (cfig.homes[i].target[strlen(cfig.homes[i].target) - 1] !=
fileSep)
+ {
+ tempbuff[0] = fileSep;
+ tempbuff[1] = 0;
+ strcat(cfig.homes[i].target, tempbuff);
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ sprintf(logBuff, "Section [HOME], alias name too large",
name);
+ logMess(logBuff, 1);
+ }
+ }
+ else if (!cfig.homes[0].alias[0] && !cfig.homes[0].target[0])
+ {
+ strcpy(cfig.homes[0].target, name);
+
+ if (cfig.homes[0].target[strlen(cfig.homes[0].target) - 1] != fileSep)
+ {
+ tempbuff[0] = fileSep;
+ tempbuff[1] = 0;
+ strcat(cfig.homes[0].target, tempbuff);
+ }
+ }
+ else if (cfig.homes[0].alias[0])
+ {
+ sprintf(logBuff, "Section [HOME], alias and bare path mixup, entry
%s ignored", iniStrPtr);
+ logMess(logBuff, 1);
+ }
+ else if (cfig.homes[0].target[0])
+ {
+ sprintf(logBuff, "Section [HOME], Duplicate Path: %s ignored",
iniStrPtr);
+ logMess(logBuff, 1);
+ }
+ else
+ {
+ sprintf(logBuff, "Section [HOME], missing = sign, Invalid Entry: %s
ignored", iniStrPtr);
+ logMess(logBuff, 1);
+ }
+ }
+ }
+
+ if (!cfig.homes[0].target[0])
+ {
+ GetModuleFileName(NULL, cfig.homes[0].target, UCHAR_MAX);
+ char *iniFileExt = strrchr(cfig.homes[0].target, fileSep);
+ *(++iniFileExt) = 0;
+ }
+
+ cfig.fileRead = true;
+
+ if (getSection("TFTP-OPTIONS", iniStr, 1, iniFile))
+ {
+ char *iniStrPtr = myGetToken(iniStr, 0);
+ for (;strlen(iniStrPtr);iniStrPtr = myGetToken(iniStrPtr, 1))
+ {
+ mySplit(name, value, iniStrPtr, '=');
+ if (strlen(value))
+ {
+ if (!strcasecmp(name, "blksize"))
+ {
+ DWORD tblksize = atol(value);
+
+ if (tblksize < 512)
+ blksize = 512;
+ else if (tblksize > USHRT_MAX - 32)
+ blksize = USHRT_MAX - 32;
+ else
+ blksize = tblksize;
+ }
+ else if (!strcasecmp(name, "threadpoolsize"))
+ {
+ minThreads = atol(value);
+ if (minThreads < 1)
+ minThreads = 0;
+ else if (minThreads > 100)
+ minThreads = 100;
+ }
+ else if (!strcasecmp(name, "timeout"))
+ {
+ timeout = atol(value);
+ if (timeout < 1)
+ timeout = 1;
+ else if (timeout > UCHAR_MAX)
+ timeout = UCHAR_MAX;
+ }
+ else if (!strcasecmp(name, "Read"))
+ {
+ if (strchr("Yy", *value))
+ cfig.fileRead = true;
+ else
+ cfig.fileRead = false;
+ }
+ else if (!strcasecmp(name, "Write"))
+ {
+ if (strchr("Yy", *value))
+ cfig.fileWrite = true;
+ else
+ cfig.fileWrite = false;
+ }
+ else if (!strcasecmp(name, "Overwrite"))
+ {
+ if (strchr("Yy", *value))
+ cfig.fileOverwrite = true;
+ else
+ cfig.fileOverwrite = false;
+ }
+ else if (!strcasecmp(name, "port-range"))
+ {
+ char *ptr = strchr(value, '-');
+ if (ptr)
+ {
+ *ptr = 0;
+ cfig.minport = atol(value);
+ cfig.maxport = atol(++ptr);
+
+ if (cfig.minport < 1024 || cfig.minport >= USHRT_MAX ||
cfig.maxport < 1024 || cfig.maxport >= USHRT_MAX || cfig.minport > cfig.maxport)
+ {
+ cfig.minport = 0;
+ cfig.maxport = 0;
+
+ sprintf(logBuff, "Invalid port range %s", value);
+ logMess(logBuff, 1);
+ }
+ }
+ else
+ {
+ sprintf(logBuff, "Invalid port range %s", value);
+ logMess(logBuff, 1);
+ }
+ }
+ else
+ {
+ sprintf(logBuff, "Warning: unknown option %s, ignored",
name);
+ logMess(logBuff, 1);
+ }
+ }
+ }
+ }
+
+ if (getSection("ALLOWED-CLIENTS", iniStr, 1, iniFile))
+ {
+ char *iniStrPtr = myGetToken(iniStr, 0);
+ for (int i = 0; i < 32 && iniStrPtr[0]; iniStrPtr =
myGetToken(iniStrPtr, 1))
+ {
+ DWORD rs = 0;
+ DWORD re = 0;
+ mySplit(name, value, iniStrPtr, '-');
+ rs = htonl(my_inet_addr(name));
+
+ if (strlen(value))
+ re = htonl(my_inet_addr(value));
+ else
+ re = rs;
+
+ if (rs && rs != INADDR_NONE && re && re !=
INADDR_NONE && rs <= re)
+ {
+ cfig.hostRanges[i].rangeStart = rs;
+ cfig.hostRanges[i].rangeEnd = re;
+ i++;
+ }
+ else
+ {
+ sprintf(logBuff, "Section [ALLOWED-CLIENTS] Invalid entry %s in ini
file, ignored", iniStrPtr);
+ logMess(logBuff, 1);
+ }
+ }
+ }
+
+// if (!cfig.servers[0])
+// getServ();
+
+ int i = 0;
+
+ for (int j = 0; j < MAX_SERVERS; j++)
+ {
+ if (j && !cfig.servers[j])
+ break;
+
+ cfig.tftpConn[i].sock = socket(PF_INET,
+ SOCK_DGRAM,
+ IPPROTO_UDP);
+
+ if (cfig.tftpConn[i].sock == INVALID_SOCKET)
+ {
+ sprintf(logBuff, "Failed to Create Socket");
+ logMess(logBuff, 1);
+ continue;
+ }
+
+ cfig.tftpConn[i].addr.sin_family = AF_INET;
+
+ if (!cfig.ports[j])
+ cfig.ports[j] = 69;
+
+ cfig.tftpConn[i].addr.sin_addr.s_addr = cfig.servers[j];
+ cfig.tftpConn[i].addr.sin_port = htons(cfig.ports[j]);
+
+ socklen_t nRet = bind(cfig.tftpConn[i].sock,
+ (sockaddr*)&cfig.tftpConn[i].addr,
+ sizeof(struct sockaddr_in)
+ );
+
+ if (nRet == SOCKET_ERROR)
+ {
+ closesocket(cfig.tftpConn[i].sock);
+ sprintf(logBuff, "%s Port %u, bind failed", IP2String(tempbuff,
cfig.servers[j]), cfig.ports[j]);
+ logMess(logBuff, 1);
+ continue;
+ }
+
+ if (cfig.maxFD < cfig.tftpConn[i].sock)
+ cfig.maxFD = cfig.tftpConn[i].sock;
+
+ cfig.tftpConn[i].server = cfig.tftpConn[i].addr.sin_addr.s_addr;
+ cfig.tftpConn[i].port = htons(cfig.tftpConn[i].addr.sin_port);
+ i++;
+ }
+
+ cfig.maxFD++;
+
+ if (!cfig.tftpConn[0].port)
+ {
+ sprintf(logBuff, "no listening interfaces available, stopping..\nPress Enter
to exit\n");
+ logMess(logBuff, 1);
+ getchar();
+ exit(-1);
+ }
+ else if (verbatim)
+ {
+ printf("starting TFTP...\n");
+ }
+ else
+ {
+ sprintf(logBuff, "starting TFTP service");
+ logMess(logBuff, 1);
+ }
+
+ for (int i = 0; i < MAX_SERVERS; i++)
+ if (cfig.homes[i].target[0])
+ {
+ sprintf(logBuff, "alias /%s is mapped to %s", cfig.homes[i].alias,
cfig.homes[i].target);
+ logMess(logBuff, 1);
+ }
+
+ if (cfig.hostRanges[0].rangeStart)
+ {
+ char temp[128];
+
+ for (WORD i = 0; i <= sizeof(cfig.hostRanges) &&
cfig.hostRanges[i].rangeStart; i++)
+ {
+ sprintf(logBuff, "%s", "permitted clients: ");
+ sprintf(temp, "%s-", IP2String(tempbuff,
htonl(cfig.hostRanges[i].rangeStart)));
+ strcat(logBuff, temp);
+ sprintf(temp, "%s", IP2String(tempbuff,
htonl(cfig.hostRanges[i].rangeEnd)));
+ strcat(logBuff, temp);
+ logMess(logBuff, 1);
+ }
+ }
+ else
+ {
+ sprintf(logBuff, "%s", "permitted clients: all");
+ logMess(logBuff, 1);
+ }
+
+ if (cfig.minport)
+ {
+ sprintf(logBuff, "server port range: %u-%u", cfig.minport,
cfig.maxport);
+ logMess(logBuff, 1);
+ }
+ else
+ {
+ sprintf(logBuff, "server port range: all");
+ logMess(logBuff, 1);
+ }
+
+ sprintf(logBuff, "max blksize: %u", blksize);
+ logMess(logBuff, 1);
+ sprintf(logBuff, "default blksize: %u", 512);
+ logMess(logBuff, 1);
+ sprintf(logBuff, "default timeout: %u", timeout);
+ logMess(logBuff, 1);
+ sprintf(logBuff, "file read allowed: %s", cfig.fileRead ? "Yes" :
"No");
+ logMess(logBuff, 1);
+ sprintf(logBuff, "file create allowed: %s", cfig.fileWrite ?
"Yes" : "No");
+ logMess(logBuff, 1);
+ sprintf(logBuff, "file overwrite allowed: %s", cfig.fileOverwrite ?
"Yes" : "No");
+ logMess(logBuff, 1);
+
+ if (!verbatim)
+ {
+ sprintf(logBuff, "logging: %s", cfig.logLevel > 1 ? "all"
: "errors");
+ logMess(logBuff, 1);
+ }
+
+ lEvent = CreateEvent(
+ NULL, // default security descriptor
+ FALSE, // ManualReset
+ TRUE, // Signalled
+ TEXT("AchalTFTServerLogEvent")); // object name
+
+ if (lEvent == NULL)
+ {
+ printf("CreateEvent error: %d\n", GetLastError());
+ exit(-1);
+ }
+ else if ( GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ sprintf(logBuff, "CreateEvent opened an existing Event\nServer May already
be Running");
+ logMess(logBuff, 0);
+ exit(-1);
+ }
+
+ tEvent = CreateEvent(
+ NULL, // default security descriptor
+ FALSE, // ManualReset
+ FALSE, // Signalled
+ TEXT("AchalTFTServerThreadEvent")); // object name
+
+ if (tEvent == NULL)
+ {
+ printf("CreateEvent error: %d\n", GetLastError());
+ exit(-1);
+ }
+ else if ( GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ sprintf(logBuff, "CreateEvent opened an existing Event\nServer May already
be Running");
+ logMess(logBuff, 0);
+ exit(-1);
+ }
+
+ sEvent = CreateEvent(
+ NULL, // default security descriptor
+ FALSE, // ManualReset
+ TRUE, // Signalled
+ TEXT("AchalTFTServerSocketEvent")); // object name
+
+ if (sEvent == NULL)
+ {
+ printf("CreateEvent error: %d\n", GetLastError());
+ exit(-1);
+ }
+ else if ( GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ sprintf(logBuff, "CreateEvent opened an existing Event\nServer May already
be Running");
+ logMess(logBuff, 0);
+ exit(-1);
+ }
+
+ cEvent = CreateEvent(
+ NULL, // default security descriptor
+ FALSE, // ManualReset
+ TRUE, // Signalled
+ TEXT("AchalTFTServerCountEvent")); // object name
+
+ if (cEvent == NULL)
+ {
+ printf("CreateEvent error: %d\n", GetLastError());
+ exit(-1);
+ }
+ else if ( GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ sprintf(logBuff, "CreateEvent opened an existing Event\nServer May already
be Running");
+ logMess(logBuff, 0);
+ exit(-1);
+ }
+
+ if (minThreads)
+ {
+ for (int i = 0; i < minThreads; i++)
+ {
+ _beginthread(
+ processRequest, // thread function
+ 0, // default security attributes
+ NULL); // argument to thread function
+ }
+
+ sprintf(logBuff, "thread pool size: %u", minThreads);
+ logMess(logBuff, 1);
+ }
+
+ for (int i = 0; i < MAX_SERVERS && cfig.tftpConn[i].port; i++)
+ {
+ sprintf(logBuff, "listening on: %s:%i", IP2String(tempbuff,
cfig.tftpConn[i].server), cfig.tftpConn[i].port);
+ logMess(logBuff, 1);
+ }
+}
+
+void logMess(char *logBuff, BYTE logLevel)
+{
+ WaitForSingleObject(lEvent, INFINITE);
+
+ char tempbuff[256];
+
+ if (verbatim)
+ printf("%s\n", logBuff);
+ else if (cfig.logfile && logLevel <= cfig.logLevel)
+ {
+ char currentTime[32];
+ time_t t = time(NULL);
+ tm *ttm = localtime(&t);
+ strftime(currentTime, sizeof(currentTime), "%d-%b-%y %X", ttm);
+ fprintf(cfig.logfile, "[%s] %s\n", currentTime, logBuff);
+ fflush(cfig.logfile);
+ }
+ SetEvent(lEvent);
+}
+
+void logMess(request *req, BYTE logLevel)
+{
+ WaitForSingleObject(lEvent, INFINITE);
+
+ char tempbuff[256];
+
+ if (verbatim)
+ {
+ if (!req->serverError.errormessage[0])
+ sprintf(req->serverError.errormessage, strerror(errno));
+
+ if (req->path[0])
+ printf("Client %s:%u %s, %s\n", IP2String(tempbuff,
req->client.sin_addr.s_addr), ntohs(req->client.sin_port), req->path,
req->serverError.errormessage);
+ else
+ printf("Client %s:%u, %s\n", IP2String(tempbuff,
req->client.sin_addr.s_addr), ntohs(req->client.sin_port),
req->serverError.errormessage);
+ }
+ else if (cfig.logfile && logLevel <= cfig.logLevel)
+ {
+ char currentTime[32];
+ time_t t = time(NULL);
+ tm *ttm = localtime(&t);
+ strftime(currentTime, sizeof(currentTime), "%d-%b-%y %X", ttm);
+
+ if (req->path[0])
+ fprintf(cfig.logfile, "[%s] Client %s:%u %s, %s\n", currentTime,
IP2String(tempbuff, req->client.sin_addr.s_addr), ntohs(req->client.sin_port),
req->path, req->serverError.errormessage);
+ else
+ fprintf(cfig.logfile, "[%s] Client %s:%u, %s\n", currentTime,
IP2String(tempbuff, req->client.sin_addr.s_addr), ntohs(req->client.sin_port),
req->serverError.errormessage);
+
+ fflush(cfig.logfile);
+ }
+ SetEvent(lEvent);
+}
Propchange: trunk/reactos/base/services/tftpd/tftpd.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/reactos/base/services/tftpd/tftpd.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: trunk/reactos/base/services/tftpd/tftpd.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/tftpd/tftpd.…
==============================================================================
--- trunk/reactos/base/services/tftpd/tftpd.h (added)
+++ trunk/reactos/base/services/tftpd/tftpd.h [iso-8859-1] Thu May 14 18:52:22 2009
@@ -1,0 +1,161 @@
+/**************************************************************************
+* Copyright (C) 2005 by Achal Dhir *
+* achaldhir(a)gmail.com *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+***************************************************************************/
+// TFTPServer.cpp
+
+#ifdef _MSC_VER
+ #define strcasecmp _stricmp
+ #define _CRT_SECURE_NO_WARNINGS
+ #pragma comment(lib, "ws2_32.lib")
+ #pragma comment(lib, "iphlpapi.lib")
+#endif
+
+//Constants
+#define my_inet_addr inet_addr
+#define MAX_SERVERS 8
+
+//Structs
+struct home
+{
+ char alias[64];
+ char target[256];
+};
+
+struct tftpConnType
+{
+ SOCKET sock;
+ sockaddr_in addr;
+ DWORD server;
+ WORD port;
+};
+
+struct acknowledgement
+{
+ WORD opcode;
+ WORD block;
+};
+
+struct message
+{
+ WORD opcode;
+ char buffer[514];
+};
+
+struct tftperror
+{
+ WORD opcode;
+ WORD errorcode;
+ char errormessage[512];
+};
+
+struct packet
+{
+ WORD opcode;
+ WORD block;
+ char buffer;
+};
+
+struct data12
+{
+ DWORD rangeStart;
+ DWORD rangeEnd;
+};
+
+struct request
+{
+ timeval tv;
+ fd_set readfds;
+ time_t expiry;
+ SOCKET sock;
+ SOCKET knock;
+ BYTE sockInd;
+ BYTE attempt;
+ char path[256];
+ FILE *file;
+ char *filename;
+ char *mode;
+ char *alias;
+ DWORD tsize;
+ DWORD fblock;
+ int bytesReady;
+ int bytesRecd;
+ int bytesRead[2];
+ packet* pkt[2];
+ sockaddr_in client;
+ socklen_t clientsize;
+ union
+ {
+ tftperror serverError;
+ message mesout;
+ acknowledgement acout;
+ };
+ union
+ {
+ tftperror clientError;
+ message mesin;
+ acknowledgement acin;
+ };
+ WORD blksize;
+ WORD timeout;
+ WORD block;
+ WORD tblock;
+};
+
+struct data2
+{
+ WSADATA wsaData;
+ tftpConnType tftpConn[MAX_SERVERS];
+ DWORD servers[MAX_SERVERS];
+ WORD ports[MAX_SERVERS];
+ home homes[8];
+ FILE *logfile;
+ data12 hostRanges[32];
+ char fileRead;
+ char fileWrite;
+ char fileOverwrite;
+ int minport;
+ int maxport;
+ SOCKET maxFD;
+ BYTE logLevel;
+};
+
+struct data15
+{
+ union
+ {
+ //DWORD ip;
+ unsigned ip:32;
+ BYTE octate[4];
+ };
+};
+
+//Functions
+void runProg();
+void processRequest(LPVOID lpParam);
+char* myGetToken(char*, BYTE);
+void init();
+bool cleanReq(request*);
+bool getSection(char*, char*, BYTE, char*);
+bool isIP(char*s);
+char* myLower(char*);
+char* myUpper(char*);
+char* IP2String(char*, DWORD);
+void printWindowsError();
+void logMess(request*, BYTE);
+void logMess(char*, BYTE);
Propchange: trunk/reactos/base/services/tftpd/tftpd.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/reactos/base/services/tftpd/tftpd.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: trunk/reactos/base/services/tftpd/tftpd.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/tftpd/tftpd.…
==============================================================================
--- trunk/reactos/base/services/tftpd/tftpd.rbuild (added)
+++ trunk/reactos/base/services/tftpd/tftpd.rbuild [iso-8859-1] Thu May 14 18:52:22 2009
@@ -1,0 +1,12 @@
+<module name="tftpd" type="win32cui"
installbase="system32" installname="tftpd.exe"
allowwarnings="true" unicode="no">
+ <include base="reactos"></include>
+ <include base="telnetd">..</include>
+
+ <library>ntdll</library>
+ <library>kernel32</library>
+ <library>advapi32</library>
+ <library>ws2_32</library>
+ <library>wine</library>
+
+ <file>tftpd.cpp</file>
+</module>
Propchange: trunk/reactos/base/services/tftpd/tftpd.rbuild
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/reactos/base/services/tftpd/tftpd.rbuild
------------------------------------------------------------------------------
svn:mime-type = text/plain