/** * Feathery FTP-Server * Copyright (C) 2005-2010 Andreas Martin (andreas.martin@linuxmail.org) * * ftpRuntime.c - ftp-server runtime environment * * This is the central module of feathery. It defines all runtime functions * of feathery. That is startup, state, main-thread an shutdown. * * * 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 3 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, see . */ #include #include "ftpTypes.h" #include "ftpConfig.h" #include "ftp.h" #include "ftpMessages.h" /** * @brief server-sockets that listens for incoming connections */ LOCAL socket_t server; LOCAL int serverListenPort; LOCAL int serverPassiveListenPort; //LOCAL socket_t serverPassivePort; void ftpInit(ftpFindExternalFTPServerIpType cb1, ftpAddUPNPPortForwardType cb2, ftpRemoveUPNPPortForwardType cb3, ftpIsValidClientType cb4, ftpIsClientAllowedToGetFileType cb5) { ftpFindExternalFTPServerIp = cb1; ftpAddUPNPPortForward = cb2; ftpRemoveUPNPPortForward = cb3; ftpIsValidClient = cb4; ftpIsClientAllowedToGetFile = cb5; } int ftpGetListenPort() { return serverListenPort; } int ftpGetPassivePort() { return serverPassiveListenPort; } //socket_t ftpGetServerPassivePortListenSocket() //{ // return serverPassivePort; //} /** * @brief Initializes and starts the server * * * @return - 0: server started successfully * - -1: could not create server socket */ int ftpStart(int portNumber) { serverListenPort = portNumber; serverPassiveListenPort = portNumber + 1; server = -1; // set server socket to invalid value //serverPassivePort = -1; if(VERBOSE_MODE_ENABLED) printf("Feathery FTP-Server\n"); ftpArchInit(); if(VERBOSE_MODE_ENABLED) printf("Creating server socket"); server = ftpCreateServerSocket(serverListenPort); // create main listener socket if(server < 0) { if(VERBOSE_MODE_ENABLED) printf("\t\terror\n"); return -1; } if(VERBOSE_MODE_ENABLED) printf("\t\tok\n"); if(VERBOSE_MODE_ENABLED) printf("Server successfully started\n"); ftpTrackSocket(server); // add socket to "watchlist" /* if(VERBOSE_MODE_ENABLED) printf("Creating server PASSIVE socket"); serverPassivePort = ftpCreateServerSocket(serverPassiveListenPort); // create main listener socket if(serverPassivePort < 0) { if(VERBOSE_MODE_ENABLED) printf("\t\tpassive port error\n"); return -1; } if(VERBOSE_MODE_ENABLED) printf("\t\tok\n"); if(VERBOSE_MODE_ENABLED) printf("Server passive port successfully started\n"); */ return 0; } /** * @brief Checks if the server has something to do * * In order of avoid blocking of ftpExecute this function can be used to * determine if the server has something to do. You can call this function in * a loop and everytime it returns nonezero its time to call ftpExecute(). * @todo implement me * * @return 0 noting to do; else server has received some data */ int ftpState(void) { return 0; } /** * @brief Main server-thread * * Manages all client connections and active transmitions. In addtition * all received control-strings are dispatched to the command-module. * Note, the function blocks if there is nothing to do. */ int ftpExecute(void) { int processedWork=0; int n=0; int socksRdy=0; ftpSession_S *pSession=NULL; int sessionId=0; //int activeJobs=0; int len; int bufLen; int activeJobs = ftpGetActiveTransCnt(); // are there any active transmitions? //for(n = 0; (activeJobs > 0) && (n < MAX_CONNECTIONS); n++) for(n = 0; n < MAX_CONNECTIONS; n++) { pSession = ftpGetSession(n); if(pSession->activeTrans.op) // has this session an active transmition? { processedWork = 1; ftpExecTransmission(n); // do the job activeJobs--; } } if(ftpGetActiveTransCnt()) // don't block if there's still something to do { socksRdy = ftpSelect(TRUE); } else { //if(VERBOSE_MODE_ENABLED) printf("ftpExecute calling blocking select\n"); socksRdy = ftpSelect(FALSE); } if(socksRdy > 0) { if(VERBOSE_MODE_ENABLED) printf("ftpExecute socksRdy = %d\n",socksRdy); processedWork = 1; if(ftpTestSocket(server)) // server listner-socket signaled? { socket_t clientSocket; ip_t remoteIP; port_t remotePort; socksRdy--; clientSocket = ftpAcceptServerConnection(server, &remoteIP, &remotePort); if(clientSocket >= 0) { if(VERBOSE_MODE_ENABLED) printf("ftpExecute ftpAcceptServerConnection = %d\n",clientSocket); sessionId = ftpOpenSession(clientSocket, remoteIP, remotePort); if(sessionId >= 0) { ftpTrackSocket(clientSocket); ftpSendMsg(MSG_NORMAL, sessionId, 220, ftpMsg037); } else { if(VERBOSE_MODE_ENABLED) printf("ERROR: Connection refused; Session limit reached, about to close socket = %d\n",clientSocket); ftpUntrackSocket(clientSocket); ftpCloseSocket(&clientSocket); } } } //socksRdy = ftpSelect(TRUE); for(n = 0; (socksRdy > 0) && (n < MAX_CONNECTIONS); n++) { pSession = ftpGetSession(n); if(pSession->open) { socket_t ctrlSocket = pSession->ctrlSocket; if(ftpTestSocket(ctrlSocket)) { if(VERBOSE_MODE_ENABLED) printf("ftpExecute signaled socket = %d, session = %d\n",ctrlSocket,n); socksRdy--; bufLen = (LEN_RXBUF - pSession->rxBufWriteIdx); len = ftpReceive(ctrlSocket, &pSession->rxBuf[pSession->rxBufWriteIdx], bufLen); if(len <= 0) // has client shutdown the connection? { int errorNumber = getLastSocketError(); const char *errText = getLastSocketErrorText(&errorNumber); if(VERBOSE_MODE_ENABLED) printf("In ftpExecute ERROR ON RECEIVE session = %d for socket = %d, data len = %d index = %d, len = %d, error = %d [%s]\n",n,ctrlSocket,bufLen,pSession->rxBufWriteIdx,len,errorNumber,errText); ftpUntrackSocket(ctrlSocket); ftpCloseSession(n); } else { pSession->rxBufWriteIdx += len; ftpParseCmd(n); } } /// @bug Session-Timeout-Management doesn't work if((ftpGetUnixTime() - pSession->timeLastCmd) > SESSION_TIMEOUT) { if(VERBOSE_MODE_ENABLED) printf("\nIn ftpExecute ERROR: SESSION TIMED OUT for socket = %d\n",ctrlSocket); ftpSendMsg(MSG_NORMAL, n, 421, ftpMsg036); ftpUntrackSocket(ctrlSocket); ftpCloseSession(n); } } } } return processedWork; } /** * @brief Shut down the server * * Cuts all tcp-connections and frees all used resources. * @return 0 */ int ftpShutdown(void) { int n; if(VERBOSE_MODE_ENABLED) printf("About to Shutdown Feathery FTP-Server server [%d]\n",server); ftpUntrackSocket(server); ftpCloseSocket(&server); //ftpCloseSocket(serverPassivePort); if(VERBOSE_MODE_ENABLED) printf("About to Shutdown clients\n"); for(n = 0; n < MAX_CONNECTIONS; n++) { if(ftpGetSession(n)->open) { ftpUntrackSocket(ftpGetSession(n)->ctrlSocket); } ftpCloseSession(n); } if(VERBOSE_MODE_ENABLED) printf("About to Shutdown stack\n"); ftpArchCleanup(); return 0; }