VirtualBox

Changeset 82687 in vbox


Ignore:
Timestamp:
Jan 9, 2020 10:45:36 AM (5 years ago)
Author:
vboxsync
Message:

IPRT/FTP: More protocol handling and callback work. bugref:9437

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/ftp.h

    r82673 r82687  
    133133
    134134/**
     135 * Structure for maintaining a FTP server client state.
     136 */
     137typedef struct RTFTPSERVERCLIENTSTATE
     138{
     139    /** Timestamp (in ms) of last command issued by the client. */
     140    uint64_t      tsLastCmdMs;
     141} RTFTPSERVERCLIENTSTATE;
     142/** Pointer to a FTP server client state. */
     143typedef RTFTPSERVERCLIENTSTATE *PRTFTPSERVERCLIENTSTATE;
     144
     145/**
     146 * Structure for storing FTP server callback data.
     147 */
     148typedef struct RTFTPCALLBACKDATA
     149{
     150    /** Pointer to the client state. */
     151    PRTFTPSERVERCLIENTSTATE  pClient;
     152    /** Saved user pointer. */
     153    void                    *pvUser;
     154    /** Size (in bytes) of data at user pointer. */
     155    size_t                   cbUser;
     156} RTFTPCALLBACKDATA;
     157/** Pointer to FTP server callback data. */
     158typedef RTFTPCALLBACKDATA *PRTFTPCALLBACKDATA;
     159
     160/**
     161 * Function callback table for the FTP server implementation.
     162 *
     163 * All callbacks are optional and therefore can be NULL.
     164 */
     165typedef struct RTFTPSERVERCALLBACKS
     166{
     167    /** User pointer to data. Optional and can be NULL. */
     168    void  *pvUser;
     169    /** Size (in bytes) of user data pointing at. Optional and can be 0. */
     170    size_t cbUser;
     171    DECLCALLBACKMEMBER(int,  pfnOnUserConnect)(PRTFTPCALLBACKDATA pData, const char *pcszUser);
     172    DECLCALLBACKMEMBER(int,  pfnOnUserAuthenticate)(PRTFTPCALLBACKDATA pData, const char *pcszUser, const char *pcszPassword);
     173    DECLCALLBACKMEMBER(int,  pfnOnUserDisconnect)(PRTFTPCALLBACKDATA pData);
     174    DECLCALLBACKMEMBER(int,  pfnOnPathSetCurrent)(PRTFTPCALLBACKDATA pData, const char *pcszCWD);
     175    DECLCALLBACKMEMBER(int,  pfnOnPathGetCurrent)(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD);
     176    DECLCALLBACKMEMBER(int,  pfnOnList)(PRTFTPCALLBACKDATA pData, void **ppvData, size_t *pcbData);
     177} RTFTPSERVERCALLBACKS, *PRTFTPSERVERCALLBACKS;
     178/** Pointer to a FTP server callback data table. */
     179typedef RTFTPSERVERCALLBACKS *PRTFTPSERVERCALLBACKS;
     180
     181/**
    135182 * Creates a FTP server instance.
    136183 *
     
    140187 *                              If NULL or empty string the server is bound to all interfaces.
    141188 * @param   uPort               The port for creating a listening socket.
    142  * @param   pcszPathRoot        Root path of the FTP server serving.
     189 * @param   pCallbacks          Callback table to use.
    143190 */
    144191RTR3DECL(int) RTFTPServerCreate(PRTFTPSERVER phFTPServer, const char *pcszAddress, uint16_t uPort,
    145                                 const char *pcszPathRoot);
     192                                PRTFTPSERVERCALLBACKS pCallbacks);
    146193
    147194/**
  • trunk/src/VBox/Runtime/generic/ftp-server.cpp

    r82678 r82687  
    4040*********************************************************************************************************************************/
    4141#define LOG_GROUP RTLOGGROUP_FTP
     42#include <iprt/asm.h>
    4243#include <iprt/assert.h>
    4344#include <iprt/errcore.h>
     
    4546#include <iprt/mem.h>
    4647#include <iprt/log.h>
     48#include <iprt/path.h>
    4749#include <iprt/poll.h>
    4850#include <iprt/socket.h>
     
    6365{
    6466    /** Magic value. */
    65     uint32_t            u32Magic;
     67    uint32_t                u32Magic;
     68    /** Callback table. */
     69    RTFTPSERVERCALLBACKS    Callbacks;
    6670    /** Pointer to TCP server instance. */
    67     PRTTCPSERVER        pTCPServer;
     71    PRTTCPSERVER            pTCPServer;
     72    /** Number of currently connected clients. */
     73    uint32_t                cClients;
    6874} RTFTPSERVERINTERNAL;
    6975/** Pointer to an internal FTP server instance. */
     
    136142
    137143/**
    138  * Structure for maintaining an internal FTP server client state.
    139  */
    140 typedef struct RTFTPSERVERCLIENTSTATE
     144 * Structure for maintaining an internal FTP server client.
     145 */
     146typedef struct RTFTPSERVERCLIENT
    141147{
    142148    /** Pointer to internal server state. */
    143     PRTFTPSERVERINTERNAL pServer;
     149    PRTFTPSERVERINTERNAL        pServer;
    144150    /** Socket handle the client is bound to. */
    145     RTSOCKET             hSocket;
    146 } RTFTPSERVERCLIENTSTATE;
     151    RTSOCKET                    hSocket;
     152    /** Actual client state. */
     153    RTFTPSERVERCLIENTSTATE      State;
     154} RTFTPSERVERCLIENT;
    147155/** Pointer to an internal FTP server client state. */
    148 typedef RTFTPSERVERCLIENTSTATE *PRTFTPSERVERCLIENTSTATE;
     156typedef RTFTPSERVERCLIENT *PRTFTPSERVERCLIENT;
    149157
    150158/** Function pointer declaration for a specific FTP server command handler. */
    151 typedef DECLCALLBACK(int) FNRTFTPSERVERCMD(PRTFTPSERVERCLIENTSTATE pClient);
     159typedef DECLCALLBACK(int) FNRTFTPSERVERCMD(PRTFTPSERVERCLIENT pClient);
    152160/** Pointer to a FNRTFTPSERVERCMD(). */
    153161typedef FNRTFTPSERVERCMD *PFNRTFTPSERVERCMD;
     162
     163/** Handles a FTP server callback with no arguments and returns. */
     164#define RTFTPSERVER_HANDLE_CALLBACK_RET(a_Name) \
     165    do \
     166    { \
     167        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     168        if (pCallbacks->a_Name) \
     169        { \
     170            RTFTPCALLBACKDATA Data = { &pClient->State, pCallbacks->pvUser, pCallbacks->cbUser }; \
     171            return pCallbacks->a_Name(&Data); \
     172        } \
     173    } while (0)
     174
     175/** Handles a FTP server callback with arguments and returns. */
     176#define RTFTPSERVER_HANDLE_CALLBACK_VA_RET(a_Name, ...) \
     177    do \
     178    { \
     179        PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \
     180        if (pCallbacks->a_Name) \
     181        { \
     182            RTFTPCALLBACKDATA Data = { &pClient->State, pCallbacks->pvUser, pCallbacks->cbUser }; \
     183            return pCallbacks->a_Name(&Data, __VA_ARGS__); \
     184        } \
     185    } while (0)
    154186
    155187/**
     
    207239
    208240
    209 static int rtFTPServerSendReplyRc(PRTFTPSERVERCLIENTSTATE pClient, RTFTPSERVER_REPLY enmReply)
     241/*********************************************************************************************************************************
     242*   Protocol Functions                                                                                                           *
     243*********************************************************************************************************************************/
     244
     245/**
     246 * Replies a (three digit) reply code back to the client.
     247 *
     248 * @returns VBox status code.
     249 * @param   pClient             Client to reply to.
     250 * @param   enmReply            Reply code to send.
     251 */
     252static int rtFTPServerSendReplyRc(PRTFTPSERVERCLIENT pClient, RTFTPSERVER_REPLY enmReply)
    210253{
    211254    char szReply[32];
     
    215258}
    216259
    217 static int rtFTPServerSendReplyStr(PRTFTPSERVERCLIENTSTATE pClient, const char *pcszStr)
     260/**
     261 * Replies a string back to the client.
     262 *
     263 * @returns VBox status code.
     264 * @param   pClient             Client to reply to.
     265 * @param   pcszStr             String to reply.
     266 */
     267static int rtFTPServerSendReplyStr(PRTFTPSERVERCLIENT pClient, const char *pcszStr)
    218268{
    219269    char *pszReply;
     
    229279}
    230280
    231 static int rtFTPServerLookupUser(PRTFTPSERVERCLIENTSTATE pClient, const char *pcszUser)
    232 {
    233     RT_NOREF(pClient, pcszUser);
    234 
    235     LogFunc(("User='%s'\n", pcszUser));
    236 
    237     return VINF_SUCCESS; /** @todo Implement lookup. */
    238 }
    239 
    240 static int rtFTPServerAuthenticate(PRTFTPSERVERCLIENTSTATE pClient, const char *pcszUser, const char *pcszPassword)
    241 {
    242     RT_NOREF(pClient, pcszUser, pcszPassword);
    243 
    244     LogFunc(("User='%s', Password='%s'\n", pcszUser, pcszPassword));
    245 
    246     return VINF_SUCCESS; /** @todo Implement authentication. */
    247 }
    248 
    249 static int rtFTPServerHandleABOR(PRTFTPSERVERCLIENTSTATE pClient)
    250 {
    251     RT_NOREF(pClient);
    252 
    253     /** @todo Anything to do here? */
    254     return VINF_SUCCESS;
    255 }
    256 
    257 static int rtFTPServerHandleCDUP(PRTFTPSERVERCLIENTSTATE pClient)
    258 {
    259     RT_NOREF(pClient);
    260 
    261     /** @todo Anything to do here? */
    262     return VINF_SUCCESS;
    263 }
    264 
    265 static int rtFTPServerHandleCWD(PRTFTPSERVERCLIENTSTATE pClient)
    266 {
    267     RT_NOREF(pClient);
    268 
    269     /** @todo Anything to do here? */
    270     return VINF_SUCCESS;
    271 }
    272 
    273 static int rtFTPServerHandleLIST(PRTFTPSERVERCLIENTSTATE pClient)
    274 {
    275     RT_NOREF(pClient);
    276 
    277     /** @todo Anything to do here? */
    278     return VINF_SUCCESS;
    279 }
    280 
    281 static int rtFTPServerHandleMODE(PRTFTPSERVERCLIENTSTATE pClient)
    282 {
    283     RT_NOREF(pClient);
    284 
    285     /** @todo Anything to do here? */
    286     return VINF_SUCCESS;
    287 }
    288 
    289 static int rtFTPServerHandleNOOP(PRTFTPSERVERCLIENTSTATE pClient)
    290 {
    291     RT_NOREF(pClient);
    292 
    293     /** @todo Anything to do here? */
    294     return VINF_SUCCESS;
    295 }
    296 
    297 static int rtFTPServerHandlePORT(PRTFTPSERVERCLIENTSTATE pClient)
    298 {
    299     RT_NOREF(pClient);
    300 
    301     /** @todo Anything to do here? */
    302     return VINF_SUCCESS;
    303 }
    304 
    305 static int rtFTPServerHandlePWD(PRTFTPSERVERCLIENTSTATE pClient)
    306 {
    307     RT_NOREF(pClient);
    308 
    309     /** @todo Anything to do here? */
    310     return VINF_SUCCESS;
    311 }
    312 
    313 static int rtFTPServerHandleQUIT(PRTFTPSERVERCLIENTSTATE pClient)
    314 {
    315     RT_NOREF(pClient);
    316 
    317     /** @todo Anything to do here? */
    318     return VINF_SUCCESS;
    319 }
    320 
    321 static int rtFTPServerHandleRETR(PRTFTPSERVERCLIENTSTATE pClient)
    322 {
    323     RT_NOREF(pClient);
    324 
    325     /** @todo Anything to do here? */
    326     return VINF_SUCCESS;
    327 }
    328 
    329 static int rtFTPServerHandleRGET(PRTFTPSERVERCLIENTSTATE pClient)
    330 {
    331     RT_NOREF(pClient);
    332 
    333     /** @todo Anything to do here? */
    334     return VINF_SUCCESS;
    335 }
    336 
    337 static int rtFTPServerHandleSTAT(PRTFTPSERVERCLIENTSTATE pClient)
    338 {
    339     RT_NOREF(pClient);
    340 
    341     /** @todo Anything to do here? */
    342     return VINF_SUCCESS;
    343 }
    344 
    345 static int rtFTPServerHandleSYST(PRTFTPSERVERCLIENTSTATE pClient)
     281/**
     282 * Looks up an user account.
     283 *
     284 * @returns VBox status code, or VERR_NOT_FOUND if user has not been found.
     285 * @param   pClient             Client to look up user for.
     286 * @param   pcszUser            User name to look up.
     287 */
     288static int rtFTPServerLookupUser(PRTFTPSERVERCLIENT pClient, const char *pcszUser)
     289{
     290    RTFTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnUserConnect, pcszUser);
     291
     292    return VERR_NOT_FOUND;
     293}
     294
     295/**
     296 * Handles the actual client authentication.
     297 *
     298 * @returns VBox status code, or VERR_ACCESS_DENIED if authentication failed.
     299 * @param   pClient             Client to authenticate.
     300 * @param   pcszUser            User name to authenticate with.
     301 * @param   pcszPassword        Password to authenticate with.
     302 */
     303static int rtFTPServerAuthenticate(PRTFTPSERVERCLIENT pClient, const char *pcszUser, const char *pcszPassword)
     304{
     305    RTFTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnUserAuthenticate, pcszUser, pcszPassword);
     306
     307    return VERR_ACCESS_DENIED;
     308}
     309
     310
     311/*********************************************************************************************************************************
     312*   Command Protocol Handlers                                                                                                    *
     313*********************************************************************************************************************************/
     314
     315static int rtFTPServerHandleABOR(PRTFTPSERVERCLIENT pClient)
     316{
     317    RT_NOREF(pClient);
     318
     319    /** @todo Anything to do here? */
     320    return VINF_SUCCESS;
     321}
     322
     323static int rtFTPServerHandleCDUP(PRTFTPSERVERCLIENT pClient)
     324{
     325    RT_NOREF(pClient);
     326
     327    /** @todo Anything to do here? */
     328    return VINF_SUCCESS;
     329}
     330
     331static int rtFTPServerHandleCWD(PRTFTPSERVERCLIENT pClient)
     332{
     333    RT_NOREF(pClient);
     334
     335    /** @todo Anything to do here? */
     336    return VINF_SUCCESS;
     337}
     338
     339static int rtFTPServerHandleLIST(PRTFTPSERVERCLIENT pClient)
     340{
     341    RT_NOREF(pClient);
     342
     343    /** @todo Anything to do here? */
     344    return VINF_SUCCESS;
     345}
     346
     347static int rtFTPServerHandleMODE(PRTFTPSERVERCLIENT pClient)
     348{
     349    RT_NOREF(pClient);
     350
     351    /** @todo Anything to do here? */
     352    return VINF_SUCCESS;
     353}
     354
     355static int rtFTPServerHandleNOOP(PRTFTPSERVERCLIENT pClient)
     356{
     357    RT_NOREF(pClient);
     358
     359    /* Nothing to do here. */
     360    return VINF_SUCCESS;
     361}
     362
     363static int rtFTPServerHandlePORT(PRTFTPSERVERCLIENT pClient)
     364{
     365    RT_NOREF(pClient);
     366
     367    /** @todo Anything to do here? */
     368    return VINF_SUCCESS;
     369}
     370
     371static int rtFTPServerHandlePWD(PRTFTPSERVERCLIENT pClient)
     372{
     373#if 0
     374    char *pszReply;
     375    int rc = RTStrAPrintf(&pszReply, "%s\r\n", pClient->szCWD);
     376    if (RT_SUCCESS(rc))
     377    {
     378        rc = RTTcpWrite(pClient->hSocket, pszReply, strlen(pszReply) + 1);
     379        RTStrFree(pszReply);
     380        return rc;
     381    }
     382
     383    return VERR_NO_MEMORY;
     384#endif
     385
     386    RT_NOREF(pClient);
     387    return 0;
     388}
     389
     390static int rtFTPServerHandleQUIT(PRTFTPSERVERCLIENT pClient)
     391{
     392    RT_NOREF(pClient);
     393
     394    /** @todo Anything to do here? */
     395    return VINF_SUCCESS;
     396}
     397
     398static int rtFTPServerHandleRETR(PRTFTPSERVERCLIENT pClient)
     399{
     400    RT_NOREF(pClient);
     401
     402    /** @todo Anything to do here? */
     403    return VINF_SUCCESS;
     404}
     405
     406static int rtFTPServerHandleRGET(PRTFTPSERVERCLIENT pClient)
     407{
     408    RT_NOREF(pClient);
     409
     410    /** @todo Anything to do here? */
     411    return VINF_SUCCESS;
     412}
     413
     414static int rtFTPServerHandleSTAT(PRTFTPSERVERCLIENT pClient)
     415{
     416    RT_NOREF(pClient);
     417
     418    /** @todo Anything to do here? */
     419    return VINF_SUCCESS;
     420}
     421
     422static int rtFTPServerHandleSYST(PRTFTPSERVERCLIENT pClient)
    346423{
    347424    char szOSInfo[64];
     
    353430}
    354431
    355 static int rtFTPServerHandleTYPE(PRTFTPSERVERCLIENTSTATE pClient)
    356 {
    357     RT_NOREF(pClient);
    358 
    359     /** @todo Anything to do here? */
    360     return VINF_SUCCESS;
    361 }
    362 
    363 static int rtFTPServerDoLogin(PRTFTPSERVERCLIENTSTATE pClient)
     432static int rtFTPServerHandleTYPE(PRTFTPSERVERCLIENT pClient)
     433{
     434    RT_NOREF(pClient);
     435
     436    /** @todo Anything to do here? */
     437    return VINF_SUCCESS;
     438}
     439
     440
     441/*********************************************************************************************************************************
     442*   Internal server functions                                                                                                    *
     443*********************************************************************************************************************************/
     444
     445/**
     446 * Handles the client's login procedure.
     447 *
     448 * @returns VBox status code.
     449 * @param   pClient             Client to handle login procedure for.
     450 */
     451static int rtFTPServerDoLogin(PRTFTPSERVERCLIENT pClient)
    364452{
    365453    LogFlowFuncEnter();
     
    408496}
    409497
    410 static int rtFTPServerProcessCommands(PRTFTPSERVERCLIENTSTATE pClient)
     498/**
     499 * Main loop for processing client commands.
     500 *
     501 * @returns VBox status code.
     502 * @param   pClient             Client to process commands for.
     503 */
     504static int rtFTPServerProcessCommands(PRTFTPSERVERCLIENT pClient)
    411505{
    412506    int rc;
     
    417511        char   szCmd[RTFTPSERVER_MAX_CMD_LEN];
    418512        rc = RTTcpRead(pClient->hSocket, szCmd, sizeof(szCmd), &cbRead);
    419         if (   RT_SUCCESS(rc)
    420             && strlen(szCmd))
     513        if (RT_SUCCESS(rc))
    421514        {
     515            /* Make sure to terminate the string in any case. */
     516            szCmd[RTFTPSERVER_MAX_CMD_LEN - 1] = '\0';
     517
    422518            /* A tiny bit of sanitation. */
    423519            RTStrStripL(szCmd);
     
    439535                if (!RTStrICmp(szCmd, g_aCmdMap[i].szCmd))
    440536                {
     537                    /* Save timestamp of last command sent. */
     538                    pClient->State.tsLastCmdMs = RTTimeMilliTS();
     539
    441540                    rc = g_aCmdMap[i].pfnCmd(pClient);
    442541                    break;
     
    452551
    453552            if (g_aCmdMap[i].enmCmd == RTFTPSERVER_CMD_QUIT)
     553            {
     554                RTFTPSERVER_HANDLE_CALLBACK_RET(pfnOnUserDisconnect);
    454555                break;
     556            }
    455557        }
    456558        else
     
    465567}
    466568
    467 static DECLCALLBACK(int) rtFTPServerThread(RTSOCKET hSocket, void *pvUser)
     569/**
     570 * Resets the client's state.
     571 *
     572 * @param   pState              Client state to reset.
     573 */
     574static void rtFTPServerClientStateReset(PRTFTPSERVERCLIENTSTATE pState)
     575{
     576    pState->tsLastCmdMs = RTTimeMilliTS();
     577}
     578
     579/**
     580 * Per-client thread for serving the server's control connection.
     581 *
     582 * @returns VBox status code.
     583 * @param   hSocket             Socket handle to use for the control connection.
     584 * @param   pvUser              User-provided arguments. Of type PRTFTPSERVERINTERNAL.
     585 */
     586static DECLCALLBACK(int) rtFTPServerClientThread(RTSOCKET hSocket, void *pvUser)
    468587{
    469588    PRTFTPSERVERINTERNAL pThis = (PRTFTPSERVERINTERNAL)pvUser;
    470589    RTFTPSERVER_VALID_RETURN(pThis);
    471590
    472     RTFTPSERVERCLIENTSTATE ClientState;
    473     RT_ZERO(ClientState);
    474 
    475     ClientState.pServer = pThis;
    476     ClientState.hSocket = hSocket;
    477 
    478     int rc = rtFTPServerDoLogin(&ClientState);
     591    RTFTPSERVERCLIENT Client;
     592    RT_ZERO(Client);
     593
     594    Client.pServer     = pThis;
     595    Client.hSocket     = hSocket;
     596
     597    rtFTPServerClientStateReset(&Client.State);
     598
     599    int rc = rtFTPServerDoLogin(&Client);
    479600    if (RT_SUCCESS(rc))
    480         rc = rtFTPServerProcessCommands(&ClientState);
     601    {
     602        ASMAtomicIncU32(&pThis->cClients);
     603
     604        rc = rtFTPServerProcessCommands(&Client);
     605
     606        ASMAtomicDecU32(&pThis->cClients);
     607    }
    481608
    482609    return rc;
     
    484611
    485612RTR3DECL(int) RTFTPServerCreate(PRTFTPSERVER phFTPServer, const char *pcszAddress, uint16_t uPort,
    486                                 const char *pcszPathRoot)
     613                                PRTFTPSERVERCALLBACKS pCallbacks)
    487614{
    488615    AssertPtrReturn(phFTPServer,  VERR_INVALID_POINTER);
    489616    AssertPtrReturn(pcszAddress,  VERR_INVALID_POINTER);
    490     AssertPtrReturn(pcszPathRoot, VERR_INVALID_POINTER);
    491617    AssertReturn   (uPort,        VERR_INVALID_PARAMETER);
     618    AssertPtrReturn(pCallbacks,   VERR_INVALID_POINTER);
    492619
    493620    int rc;
     
    496623    if (pThis)
    497624    {
    498         pThis->u32Magic = RTFTPSERVER_MAGIC;
     625        pThis->u32Magic  = RTFTPSERVER_MAGIC;
     626        pThis->Callbacks = *pCallbacks;
    499627
    500628        rc = RTTcpServerCreate(pcszAddress, uPort, RTTHREADTYPE_DEFAULT, "ftpsrv",
    501                                rtFTPServerThread, pThis /* pvUser */, &pThis->pTCPServer);
     629                               rtFTPServerClientThread, pThis /* pvUser */, &pThis->pTCPServer);
    502630    }
    503631    else
  • trunk/src/VBox/Runtime/tools/RTFTPServer.cpp

    r82671 r82687  
    5757*********************************************************************************************************************************/
    5858/** Set by the signal handler when the FTP server shall be terminated. */
    59 static volatile bool g_fCanceled = false;
     59static volatile bool  g_fCanceled  = false;
     60static char          *g_pszRootDir = NULL;
    6061
    6162
     
    145146}
    146147
     148static DECLCALLBACK(int) onUserConnect(PRTFTPCALLBACKDATA pData, const char *pcszUser)
     149{
     150    RT_NOREF(pData, pcszUser);
     151
     152    RTPrintf("User '%s' connected", pcszUser);
     153
     154    return VINF_SUCCESS;
     155}
     156
     157static DECLCALLBACK(int) onUserAuthenticate(PRTFTPCALLBACKDATA pData, const char *pcszUser, const char *pcszPassword)
     158{
     159    RT_NOREF(pData, pcszUser, pcszPassword);
     160
     161    RTPrintf("Authenticating user '%s' ...", pcszUser);
     162
     163    return VINF_SUCCESS;
     164}
     165
     166static DECLCALLBACK(int) onUserDisonnect(PRTFTPCALLBACKDATA pData)
     167{
     168    RT_NOREF(pData);
     169
     170    RTPrintf("User disconnected");
     171
     172    return VINF_SUCCESS;
     173}
     174
     175static DECLCALLBACK(int) onPathSetCurrent(PRTFTPCALLBACKDATA pData, const char *pcszCWD)
     176{
     177    RT_NOREF(pData, pcszCWD);
     178
     179    RTPrintf("Setting current directory to '%s'\n", pcszCWD);
     180
     181    return VINF_SUCCESS;
     182}
     183
     184static DECLCALLBACK(int) onPathGetCurrent(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD)
     185{
     186    RT_NOREF(pData, pszPWD, cbPWD);
     187
     188    return VINF_SUCCESS;
     189}
     190
     191static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, void **ppvData, size_t *pcbData)
     192{
     193    RT_NOREF(pData, ppvData, pcbData);
     194
     195    return VINF_SUCCESS;
     196}
     197
    147198int main(int argc, char **argv)
    148199{
     
    154205    char     szAddress[64]         = "localhost";
    155206    uint16_t uPort                 = 2121;
    156 
    157     /* By default use the current directory as serving root directory. */
    158     char     szRootDir[RTPATH_MAX];
    159     rc = RTPathGetCurrent(szRootDir, sizeof(szRootDir));
    160     if (RT_FAILURE(rc))
    161         return RTMsgErrorExit(RTEXITCODE_FAILURE, "Retrieving current directory failed: %Rrc", rc);
    162207
    163208    /*
     
    190235            case 'p':
    191236                uPort = ValueUnion.u16;
     237                break;
     238
     239            case 'r':
     240                g_pszRootDir = RTStrDup(ValueUnion.psz);
    192241                break;
    193242
     
    224273    }
    225274
     275    if (!g_pszRootDir)
     276    {
     277        char szRootDir[RTPATH_MAX];
     278
     279        /* By default use the current directory as serving root directory. */
     280        rc = RTPathGetCurrent(szRootDir, sizeof(szRootDir));
     281        if (RT_FAILURE(rc))
     282            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Retrieving current directory failed: %Rrc", rc);
     283
     284        g_pszRootDir = RTStrDup(szRootDir);
     285        if (!g_pszRootDir)
     286            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Allocating current directory failed");
     287    }
     288
    226289    /* Install signal handler. */
    227290    rc = signalHandlerInstall();
     
    231294         * Create the FTP server instance.
    232295         */
     296        RTFTPSERVERCALLBACKS Callbacks;
     297        RT_ZERO(Callbacks);
     298        Callbacks.pfnOnUserConnect      = onUserConnect;
     299        Callbacks.pfnOnUserAuthenticate = onUserAuthenticate;
     300        Callbacks.pfnOnUserDisconnect   = onUserDisonnect;
     301        Callbacks.pfnOnPathSetCurrent   = onPathSetCurrent;
     302        Callbacks.pfnOnPathGetCurrent   = onPathGetCurrent;
     303        Callbacks.pfnOnList             = onList;
     304
    233305        RTFTPSERVER hFTPServer;
    234         rc = RTFTPServerCreate(&hFTPServer, szAddress, uPort, szRootDir);
     306        rc = RTFTPServerCreate(&hFTPServer, szAddress, uPort, &Callbacks);
    235307        if (RT_SUCCESS(rc))
    236308        {
    237309            RTPrintf("Starting FTP server at %s:%RU16 ...\n", szAddress, uPort);
    238             RTPrintf("Root directory is '%s'\n", szRootDir);
     310            RTPrintf("Root directory is '%s'\n", g_pszRootDir);
    239311
    240312            RTPrintf("Running FTP server ...\n");
     
    264336    }
    265337
     338    RTStrFree(g_pszRootDir);
     339
    266340    /* Set rcExit on failure in case we forgot to do so before. */
    267341    if (RT_FAILURE(rc))
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette