imported the MT snapshot of the GPL tftp-server for win32 from sourceforge. Minor...
authorSteven Edwards <winehacker@gmail.com>
Thu, 14 May 2009 14:52:22 +0000 (14:52 +0000)
committerSteven Edwards <winehacker@gmail.com>
Thu, 14 May 2009 14:52:22 +0000 (14:52 +0000)
svn path=/trunk/; revision=40919

reactos/base/services/services.rbuild
reactos/base/services/tftpd/README.txt [new file with mode: 0644]
reactos/base/services/tftpd/tftpd.cpp [new file with mode: 0644]
reactos/base/services/tftpd/tftpd.h [new file with mode: 0644]
reactos/base/services/tftpd/tftpd.rbuild [new file with mode: 0644]

index a5edc08..3ab9421 100644 (file)
@@ -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>
diff --git a/reactos/base/services/tftpd/README.txt b/reactos/base/services/tftpd/README.txt
new file mode 100644 (file)
index 0000000..608a986
--- /dev/null
@@ -0,0 +1,3 @@
+This is a snapshot from the 1.6 release of tftp-server for win32 from sourceforge.
+
+http://tftp-server.sourceforge.net
diff --git a/reactos/base/services/tftpd/tftpd.cpp b/reactos/base/services/tftpd/tftpd.cpp
new file mode 100644 (file)
index 0000000..b03c606
--- /dev/null
@@ -0,0 +1,2245 @@
+/**************************************************************************
+*   Copyright (C) 2005 by Achal Dhir                                      *
+*   achaldhir@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);
+}
diff --git a/reactos/base/services/tftpd/tftpd.h b/reactos/base/services/tftpd/tftpd.h
new file mode 100644 (file)
index 0000000..b75f62a
--- /dev/null
@@ -0,0 +1,161 @@
+/**************************************************************************
+*   Copyright (C) 2005 by Achal Dhir                                      *
+*   achaldhir@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);
diff --git a/reactos/base/services/tftpd/tftpd.rbuild b/reactos/base/services/tftpd/tftpd.rbuild
new file mode 100644 (file)
index 0000000..28e6762
--- /dev/null
@@ -0,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>