- Timestamp:
- Jan 10, 2020 2:04:36 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/ftp.h
r82702 r82715 175 175 /** Size (in bytes) of user data pointing at. Optional and can be 0. */ 176 176 size_t cbUser; 177 /** 178 * Callback which gets invoked when a user connected. 179 * 180 * @returns VBox status code. 181 * @param pcszUser User name. 182 */ 177 183 DECLCALLBACKMEMBER(int, pfnOnUserConnect)(PRTFTPCALLBACKDATA pData, const char *pcszUser); 184 /** 185 * Callback which gets invoked when a user tries to authenticate with a password. 186 * 187 * @returns VBox status code. 188 * @param pcszUser User name to authenticate. 189 * @param pcszPassword Password to authenticate with. 190 */ 178 191 DECLCALLBACKMEMBER(int, pfnOnUserAuthenticate)(PRTFTPCALLBACKDATA pData, const char *pcszUser, const char *pcszPassword); 192 /** 193 * Callback which gets invoked when a user disconnected. 194 * 195 * @returns VBox status code. 196 * @param pcszUser User name which disconnected. 197 */ 179 198 DECLCALLBACKMEMBER(int, pfnOnUserDisconnect)(PRTFTPCALLBACKDATA pData); 199 /** 200 * Callback which gets invoked when setting the current working directory. 201 * 202 * @returns VBox status code. 203 * @param pcszCWD Current working directory to set. 204 */ 180 205 DECLCALLBACKMEMBER(int, pfnOnPathSetCurrent)(PRTFTPCALLBACKDATA pData, const char *pcszCWD); 206 /** 207 * Callback which gets invoked when a client wants to retrieve the current working directory. 208 * 209 * @returns VBox status code. 210 * @param pszPWD Where to store the current working directory. 211 * @param cbPWD Size of buffer in bytes. 212 */ 181 213 DECLCALLBACKMEMBER(int, pfnOnPathGetCurrent)(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD); 182 DECLCALLBACKMEMBER(int, pfnOnList)(PRTFTPCALLBACKDATA pData, void **ppvData, size_t *pcbData); 214 /** 215 * Callback which gets invoked when the client wants to move up a directory (relative to the current working directory). 216 * 217 * @returns VBox status code. 218 */ 219 DECLCALLBACKMEMBER(int, pfnOnPathUp)(PRTFTPCALLBACKDATA pData); 220 /** 221 * Callback which gets invoked when the client wants to list a directory or file. 222 * 223 * @param pcszPath Path of file / directory to list. Optional. If NULL, the current directory will be listed. 224 * @param ppvData Where to return the listing data. Must be free'd by the caller. 225 * @param pcbvData Where to return the listing data size in bytes. 226 * @returns VBox status code. 227 */ 228 DECLCALLBACKMEMBER(int, pfnOnList)(PRTFTPCALLBACKDATA pData, const char *pcszPath, void **ppvData, size_t *pcbData); 183 229 } RTFTPSERVERCALLBACKS; 184 230 /** Pointer to a FTP server callback data table. */ -
trunk/src/VBox/Runtime/generic/ftp-server.cpp
r82702 r82715 40 40 *********************************************************************************************************************************/ 41 41 #define LOG_GROUP RTLOGGROUP_FTP 42 #include <iprt/ftp.h> 43 #include "internal/iprt.h" 44 #include "internal/magics.h" 45 42 46 #include <iprt/asm.h> 43 47 #include <iprt/assert.h> 44 48 #include <iprt/errcore.h> 45 #include <iprt/ftp.h>46 49 #include <iprt/getopt.h> 47 50 #include <iprt/mem.h> … … 53 56 #include <iprt/system.h> 54 57 #include <iprt/tcp.h> 55 56 #include "internal/magics.h"57 58 58 59 … … 172 173 return pCallbacks->a_Name(&Data); \ 173 174 } \ 175 else \ 176 return VERR_NOT_IMPLEMENTED; \ 177 } while (0) 178 179 /** Handles a FTP server callback with no arguments and sets rc accordingly. */ 180 #define RTFTPSERVER_HANDLE_CALLBACK(a_Name) \ 181 do \ 182 { \ 183 PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \ 184 if (pCallbacks->a_Name) \ 185 { \ 186 RTFTPCALLBACKDATA Data = { &pClient->State, pCallbacks->pvUser, pCallbacks->cbUser }; \ 187 rc = pCallbacks->a_Name(&Data); \ 188 } \ 189 else \ 190 rc = VERR_NOT_IMPLEMENTED; \ 191 } while (0) 192 193 /** Handles a FTP server callback with arguments and sets rc accordingly. */ 194 #define RTFTPSERVER_HANDLE_CALLBACK_VA(a_Name, ...) \ 195 do \ 196 { \ 197 PRTFTPSERVERCALLBACKS pCallbacks = &pClient->pServer->Callbacks; \ 198 if (pCallbacks->a_Name) \ 199 { \ 200 RTFTPCALLBACKDATA Data = { &pClient->State, pCallbacks->pvUser, pCallbacks->cbUser }; \ 201 rc = pCallbacks->a_Name(&Data, __VA_ARGS__); \ 202 } \ 203 else \ 204 rc = VERR_NOT_IMPLEMENTED; \ 174 205 } while (0) 175 206 … … 184 215 return pCallbacks->a_Name(&Data, __VA_ARGS__); \ 185 216 } \ 217 else \ 218 return VERR_NOT_IMPLEMENTED; \ 186 219 } while (0) 187 220 … … 323 356 324 357 /** @todo Anything to do here? */ 325 return V INF_SUCCESS;358 return VERR_NOT_IMPLEMENTED; 326 359 } 327 360 328 361 static int rtFtpServerHandleCDUP(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 362 { 363 RT_NOREF(cArgs, apcszArgs); 364 365 int rc; 366 367 RTFTPSERVER_HANDLE_CALLBACK(pfnOnPathUp); 368 369 if (RT_SUCCESS(rc)) 370 return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY); 371 372 return rc; 373 } 374 375 static int rtFtpServerHandleCWD(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 376 { 377 if (cArgs != 1) 378 return VERR_INVALID_PARAMETER; 379 380 int rc; 381 382 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnPathSetCurrent, apcszArgs[0]); 383 384 if (RT_SUCCESS(rc)) 385 return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY); 386 387 return rc; 388 } 389 390 static int rtFtpServerHandleLIST(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 391 { 392 RT_NOREF(cArgs, apcszArgs); 393 394 int rc; 395 396 void *pvData = NULL; 397 size_t cbData = 0; 398 399 /* The first argument might indicate a directory to list. */ 400 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnList, 401 cArgs == 1 402 ? apcszArgs[0] : NULL, &pvData, &cbData); 403 404 if (RT_SUCCESS(rc)) 405 { 406 RTMemFree(pvData); 407 } 408 409 return rc; 410 } 411 412 static int rtFtpServerHandleMODE(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 329 413 { 330 414 RT_NOREF(pClient, cArgs, apcszArgs); … … 334 418 } 335 419 336 static int rtFtpServerHandleCWD(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 337 { 338 AssertPtrReturn(apcszArgs, VERR_INVALID_POINTER); 339 340 if (cArgs != 1) 341 return VERR_INVALID_PARAMETER; 342 343 RTFTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnPathSetCurrent, apcszArgs[0]); 344 345 return VERR_NOT_IMPLEMENTED; 346 } 347 348 static int rtFtpServerHandleLIST(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 420 static int rtFtpServerHandleNOOP(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 349 421 { 350 422 RT_NOREF(cArgs, apcszArgs); 351 423 352 void *pvData = NULL; 353 size_t cbData = 0; 354 355 RTFTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnList, &pvData, &cbData); 356 357 return VERR_NOT_IMPLEMENTED; 358 } 359 360 static int rtFtpServerHandleMODE(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 361 { 362 RT_NOREF(pClient, cArgs, apcszArgs); 363 364 /** @todo Anything to do here? */ 365 return VINF_SUCCESS; 366 } 367 368 static int rtFtpServerHandleNOOP(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 369 { 370 RT_NOREF(pClient, cArgs, apcszArgs); 371 372 /* Nothing to do here. */ 373 return VINF_SUCCESS; 424 /* Save timestamp of last command sent. */ 425 pClient->State.tsLastCmdMs = RTTimeMilliTS(); 426 427 return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY); 374 428 } 375 429 … … 404 458 405 459 /** @todo Anything to do here? */ 406 return V INF_SUCCESS;460 return VERR_NOT_IMPLEMENTED; 407 461 } 408 462 … … 411 465 RT_NOREF(cArgs, apcszArgs); 412 466 413 #if 0 414 char *pszReply; 415 int rc = RTStrAPrintf(&pszReply, "%s\r\n", pClient->szCWD); 416 if (RT_SUCCESS(rc)) 417 { 418 rc = RTTcpWrite(pClient->hSocket, pszReply, strlen(pszReply) + 1); 419 RTStrFree(pszReply); 420 return rc; 421 } 422 423 return VERR_NO_MEMORY; 424 #endif 425 426 RT_NOREF(pClient); 427 return 0; 467 int rc; 468 469 char szPWD[RTPATH_MAX]; 470 471 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnPathGetCurrent, szPWD, sizeof(szPWD)); 472 473 if (RT_SUCCESS(rc)) 474 rc = rtFtpServerSendReplyStr(pClient, szPWD); 475 476 return rc; 428 477 } 429 478 … … 433 482 434 483 /** @todo Anything to do here? */ 435 return V INF_SUCCESS;484 return VERR_NOT_IMPLEMENTED; 436 485 } 437 486 … … 441 490 442 491 /** @todo Anything to do here? */ 443 return V INF_SUCCESS;492 return VERR_NOT_IMPLEMENTED; 444 493 } 445 494 … … 449 498 450 499 /** @todo Anything to do here? */ 451 return V INF_SUCCESS;500 return VERR_NOT_IMPLEMENTED; 452 501 } 453 502 … … 457 506 458 507 /** @todo Anything to do here? */ 459 return V INF_SUCCESS;508 return VERR_NOT_IMPLEMENTED; 460 509 } 461 510 … … 477 526 478 527 /** @todo Anything to do here? */ 479 return V INF_SUCCESS;528 return VERR_NOT_IMPLEMENTED; 480 529 } 481 530 … … 483 532 { 484 533 if (cArgs != 1) 485 return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS);534 return VERR_INVALID_PARAMETER; 486 535 487 536 const char *pcszUser = apcszArgs[0]; … … 591 640 if (pszCmdEnd) 592 641 *pszCmdEnd = '\0'; 642 643 int rcCmd = VINF_SUCCESS; 593 644 594 645 uint8_t cArgs = 0; … … 606 657 pClient->State.tsLastCmdMs = RTTimeMilliTS(); 607 658 608 rc = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL);659 rcCmd = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL); 609 660 break; 610 661 } … … 618 669 if (RT_SUCCESS(rc)) 619 670 rc = rc2; 671 672 continue; 620 673 } 621 674 … … 630 683 RTFTPSERVER_HANDLE_CALLBACK_RET(pfnOnUserDisconnect); 631 684 break; 685 } 686 687 switch (rcCmd) 688 { 689 case VERR_INVALID_PARAMETER: 690 RT_FALL_THROUGH(); 691 case VERR_INVALID_POINTER: 692 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS); 693 break; 694 695 case VERR_NOT_IMPLEMENTED: 696 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL); 697 break; 698 699 default: 700 break; 632 701 } 633 702 } … … 717 786 rc = RTTcpServerCreate(pcszAddress, uPort, RTTHREADTYPE_DEFAULT, "ftpsrv", 718 787 rtFtpServerClientThread, pThis /* pvUser */, &pThis->pTCPServer); 788 if (RT_SUCCESS(rc)) 789 { 790 *phFTPServer = (RTFTPSERVER)pThis; 791 } 719 792 } 720 793 else -
trunk/src/VBox/Runtime/tools/RTFTPServer.cpp
r82699 r82715 23 23 * You may elect to license modified versions of this file under the 24 24 * terms and conditions of either the GPL or the CDDL or both. 25 */ 26 27 /* 28 * Use this setup to best see what's going on: 29 * 30 * VBOX_LOG=rt_ftp=~0 31 * VBOX_LOG_DEST="nofile stderr" 32 * VBOX_LOG_FLAGS="unbuffered enabled thread msprog" 33 * 25 34 */ 26 35 … … 54 63 55 64 /********************************************************************************************************************************* 65 * Definitations * 66 *********************************************************************************************************************************/ 67 typedef struct FTPSERVERDATA 68 { 69 char szRootDir[RTPATH_MAX]; 70 char szCWD[RTPATH_MAX]; 71 } FTPSERVERDATA; 72 typedef FTPSERVERDATA *PFTPSERVERDATA; 73 74 75 /********************************************************************************************************************************* 56 76 * Global Variables * 57 77 *********************************************************************************************************************************/ 58 78 /** Set by the signal handler when the FTP server shall be terminated. */ 59 79 static volatile bool g_fCanceled = false; 60 static char *g_pszRootDir = NULL;80 static FTPSERVERDATA g_FTPServerData; 61 81 62 82 … … 150 170 RT_NOREF(pData, pcszUser); 151 171 152 RTPrintf("User '%s' connected ", pcszUser);172 RTPrintf("User '%s' connected\n", pcszUser); 153 173 154 174 return VINF_SUCCESS; … … 159 179 RT_NOREF(pData, pcszUser, pcszPassword); 160 180 161 RTPrintf("Authenticating user '%s' ... ", pcszUser);181 RTPrintf("Authenticating user '%s' ...\n", pcszUser); 162 182 163 183 return VINF_SUCCESS; … … 168 188 RT_NOREF(pData); 169 189 170 RTPrintf("User disconnected ");190 RTPrintf("User disconnected\n"); 171 191 172 192 return VINF_SUCCESS; … … 175 195 static DECLCALLBACK(int) onPathSetCurrent(PRTFTPCALLBACKDATA pData, const char *pcszCWD) 176 196 { 177 RT_NOREF(pData, pcszCWD); 197 PFTPSERVERDATA pThis = (PFTPSERVERDATA)pData->pvUser; 198 Assert(pData->cbUser == sizeof(FTPSERVERDATA)); 178 199 179 200 RTPrintf("Setting current directory to '%s'\n", pcszCWD); 180 201 181 return VINF_SUCCESS; 202 /** @todo BUGBUG Santiy checks! */ 203 204 return RTStrCopy(pThis->szCWD, sizeof(pThis->szCWD), pcszCWD); 182 205 } 183 206 184 207 static DECLCALLBACK(int) onPathGetCurrent(PRTFTPCALLBACKDATA pData, char *pszPWD, size_t cbPWD) 185 208 { 186 RT_NOREF(pData, pszPWD, cbPWD); 187 188 return VINF_SUCCESS; 189 } 190 191 static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, void **ppvData, size_t *pcbData) 192 { 193 RT_NOREF(pData, ppvData, pcbData); 209 PFTPSERVERDATA pThis = (PFTPSERVERDATA)pData->pvUser; 210 Assert(pData->cbUser == sizeof(FTPSERVERDATA)); 211 212 RTPrintf("Current directory is: '%s'\n", pThis->szCWD); 213 214 RTStrPrintf(pszPWD, cbPWD, "%s", pThis->szCWD); 215 216 return VINF_SUCCESS; 217 } 218 219 static DECLCALLBACK(int) onPathUp(PRTFTPCALLBACKDATA pData) 220 { 221 RT_NOREF(pData); 222 223 return VINF_SUCCESS; 224 } 225 226 static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, const char *pcszPath, void **ppvData, size_t *pcbData) 227 { 228 RT_NOREF(pData, pcszPath, ppvData, pcbData); 194 229 195 230 return VINF_SUCCESS; … … 203 238 204 239 /* Use some sane defaults. */ 205 char szAddress[64] = "localhost"; 206 uint16_t uPort = 2121; 240 char szAddress[64] = "localhost"; 241 uint16_t uPort = 2121; 242 243 RT_ZERO(g_FTPServerData); 207 244 208 245 /* … … 238 275 239 276 case 'r': 240 g_pszRootDir = RTStrDup(ValueUnion.psz);277 RTStrCopy(g_FTPServerData.szRootDir, sizeof(g_FTPServerData.szRootDir), ValueUnion.psz); 241 278 break; 242 279 … … 273 310 } 274 311 275 if (!g_pszRootDir) 276 { 277 char szRootDir[RTPATH_MAX]; 278 312 if (!strlen(g_FTPServerData.szRootDir)) 313 { 279 314 /* By default use the current directory as serving root directory. */ 280 rc = RTPathGetCurrent( szRootDir, sizeof(szRootDir));315 rc = RTPathGetCurrent(g_FTPServerData.szRootDir, sizeof(g_FTPServerData.szRootDir)); 281 316 if (RT_FAILURE(rc)) 282 317 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 } 318 } 319 320 /* Initialize CWD. */ 321 RTStrPrintf2(g_FTPServerData.szCWD, sizeof(g_FTPServerData.szCWD), "/"); 288 322 289 323 /* Install signal handler. */ … … 296 330 RTFTPSERVERCALLBACKS Callbacks; 297 331 RT_ZERO(Callbacks); 332 333 Callbacks.pvUser = &g_FTPServerData; 334 Callbacks.cbUser = sizeof(g_FTPServerData); 335 298 336 Callbacks.pfnOnUserConnect = onUserConnect; 299 337 Callbacks.pfnOnUserAuthenticate = onUserAuthenticate; … … 301 339 Callbacks.pfnOnPathSetCurrent = onPathSetCurrent; 302 340 Callbacks.pfnOnPathGetCurrent = onPathGetCurrent; 341 Callbacks.pfnOnPathUp = onPathUp; 342 Callbacks.pfnOnList = onList; 303 343 Callbacks.pfnOnList = onList; 304 344 … … 308 348 { 309 349 RTPrintf("Starting FTP server at %s:%RU16 ...\n", szAddress, uPort); 310 RTPrintf("Root directory is '%s'\n", g_ pszRootDir);350 RTPrintf("Root directory is '%s'\n", g_FTPServerData.szRootDir); 311 351 312 352 RTPrintf("Running FTP server ...\n"); … … 336 376 } 337 377 338 RTStrFree(g_pszRootDir);339 340 378 /* Set rcExit on failure in case we forgot to do so before. */ 341 379 if (RT_FAILURE(rc))
Note:
See TracChangeset
for help on using the changeset viewer.