Changeset 82770 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Jan 15, 2020 2:34:38 PM (5 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/ftp-server.cpp
r82737 r82770 155 155 } RTFTPSERVER_CMD; 156 156 157 struct RTFTPSERVERCLIENT; 158 157 159 /** 158 160 * Structure for maintaining a single data connection. … … 160 162 typedef struct RTFTPSERVERDATACONN 161 163 { 164 /** Pointer to associated client of this data connection. */ 165 RTFTPSERVERCLIENT *pClient; 162 166 /** Data connection IP. */ 163 167 RTNETADDRIPV4 Addr; … … 175 179 /** Thread stopped indicator. */ 176 180 volatile bool fStopped; 177 /** Overall result of data connection on stop. */181 /** Overall result when closing the data connection. */ 178 182 int rc; 179 /** For now we only support sending a single file per active data connection. */ 180 char szFile[RTPATH_MAX]; 183 /** Number of command arguments. */ 184 uint8_t cArgs; 185 /** Command arguments array. Optional and can be NULL. 186 * Will be free'd by the data connection thread. */ 187 char** papszArgs; 181 188 } RTFTPSERVERDATACONN; 182 189 /** Pointer to a data connection struct. */ … … 196 203 /** Data connection information. 197 204 * At the moment we only allow one data connection per client at a time. */ 198 RTFTPSERVERDATACONNDataConn;205 PRTFTPSERVERDATACONN pDataConn; 199 206 } RTFTPSERVERCLIENT; 200 207 /** Pointer to an internal FTP server client state. */ … … 267 274 *********************************************************************************************************************************/ 268 275 276 static int rtFtpServerDataConnOpen(PRTFTPSERVERDATACONN pDataConn, PRTNETADDRIPV4 pAddr, uint16_t uPort); 269 277 static void rtFtpServerDataConnReset(PRTFTPSERVERDATACONN pDataConn); 270 static int rtFtpServerDataConnOpen(PRTFTPSERVERDATACONN pDataConn, PRTNETADDRIPV4 pAddr, uint16_t uPort); 278 static int rtFtpServerDataConnStart(PRTFTPSERVERDATACONN pDataConn, PFNRTTHREAD pfnThread, 279 uint8_t cArgs, const char * const *apcszArgs); 280 static int rtFtpServerDataConnDestroy(PRTFTPSERVERDATACONN pDataConn); 281 271 282 static void rtFtpServerClientStateReset(PRTFTPSERVERCLIENTSTATE pState); 272 283 … … 293 304 static FNRTFTPSERVERCMD rtFtpServerHandleUSER; 294 305 295 296 306 /** 297 307 * Structure for maintaining a single command entry for the command table. … … 303 313 /** Command represented as ASCII string. */ 304 314 char szCmd[RTFTPSERVER_MAX_CMD_LEN]; 315 /** Whether the commands needs a logged in (valid) user. */ 316 bool fNeedsUser; 305 317 /** Function pointer invoked to handle the command. */ 306 318 PFNRTFTPSERVERCMD pfnCmd; 307 319 } RTFTPSERVER_CMD_ENTRY; 320 /** Pointer to a command entry. */ 321 typedef RTFTPSERVER_CMD_ENTRY *PRTFTPSERVER_CMD_ENTRY; 308 322 309 323 /** … … 312 326 const RTFTPSERVER_CMD_ENTRY g_aCmdMap[] = 313 327 { 314 { RTFTPSERVER_CMD_ABOR, "ABOR", 315 { RTFTPSERVER_CMD_CDUP, "CDUP", 316 { RTFTPSERVER_CMD_CWD, "CWD", 317 { RTFTPSERVER_CMD_FEAT, "FEAT", 318 { RTFTPSERVER_CMD_LIST, "LIST", 319 { RTFTPSERVER_CMD_MODE, "MODE", 320 { RTFTPSERVER_CMD_NOOP, "NOOP", 321 { RTFTPSERVER_CMD_PASS, "PASS", 322 { RTFTPSERVER_CMD_PORT, "PORT", 323 { RTFTPSERVER_CMD_PWD, "PWD", 324 { RTFTPSERVER_CMD_QUIT, "QUIT", 325 { RTFTPSERVER_CMD_RETR, "RETR", 326 { RTFTPSERVER_CMD_SIZE, "SIZE", 327 { RTFTPSERVER_CMD_STAT, "STAT", 328 { RTFTPSERVER_CMD_STRU, "STRU", 329 { RTFTPSERVER_CMD_SYST, "SYST", 330 { RTFTPSERVER_CMD_TYPE, "TYPE", 331 { RTFTPSERVER_CMD_USER, "USER", 332 { RTFTPSERVER_CMD_LAST, "", 328 { RTFTPSERVER_CMD_ABOR, "ABOR", true, rtFtpServerHandleABOR }, 329 { RTFTPSERVER_CMD_CDUP, "CDUP", true, rtFtpServerHandleCDUP }, 330 { RTFTPSERVER_CMD_CWD, "CWD", true, rtFtpServerHandleCWD }, 331 { RTFTPSERVER_CMD_FEAT, "FEAT", true, rtFtpServerHandleFEAT }, 332 { RTFTPSERVER_CMD_LIST, "LIST", true, rtFtpServerHandleLIST }, 333 { RTFTPSERVER_CMD_MODE, "MODE", true, rtFtpServerHandleMODE }, 334 { RTFTPSERVER_CMD_NOOP, "NOOP", true, rtFtpServerHandleNOOP }, 335 { RTFTPSERVER_CMD_PASS, "PASS", false, rtFtpServerHandlePASS }, 336 { RTFTPSERVER_CMD_PORT, "PORT", true, rtFtpServerHandlePORT }, 337 { RTFTPSERVER_CMD_PWD, "PWD", true, rtFtpServerHandlePWD }, 338 { RTFTPSERVER_CMD_QUIT, "QUIT", false, rtFtpServerHandleQUIT }, 339 { RTFTPSERVER_CMD_RETR, "RETR", true, rtFtpServerHandleRETR }, 340 { RTFTPSERVER_CMD_SIZE, "SIZE", true, rtFtpServerHandleSIZE }, 341 { RTFTPSERVER_CMD_STAT, "STAT", true, rtFtpServerHandleSTAT }, 342 { RTFTPSERVER_CMD_STRU, "STRU", true, rtFtpServerHandleSTRU }, 343 { RTFTPSERVER_CMD_SYST, "SYST", false, rtFtpServerHandleSYST }, 344 { RTFTPSERVER_CMD_TYPE, "TYPE", true, rtFtpServerHandleTYPE }, 345 { RTFTPSERVER_CMD_USER, "USER", false, rtFtpServerHandleUSER }, 346 { RTFTPSERVER_CMD_LAST, "", false, NULL } 333 347 }; 334 348 … … 612 626 613 627 /** 628 * Duplicates a command argument vector. 629 * 630 * @returns Duplicated argument vector or NULL if failed or no arguments given. Needs to be free'd with rtFtpCmdArgsFree(). 631 * @param cArgs Number of arguments in argument vector. 632 * @param papcszArgs Pointer to argument vector to duplicate. 633 */ 634 static char** rtFtpCmdArgsDup(uint8_t cArgs, const char * const *apcszArgs) 635 { 636 if (!cArgs) 637 return NULL; 638 639 char **apcszArgsDup = (char **)RTMemAlloc(cArgs * sizeof(char *)); 640 if (!apcszArgsDup) 641 { 642 AssertFailed(); 643 return NULL; 644 } 645 646 int rc2 = VINF_SUCCESS; 647 648 uint8_t i; 649 for (i = 0; i < cArgs; i++) 650 { 651 apcszArgsDup[i] = RTStrDup(apcszArgs[i]); 652 if (!apcszArgsDup[i]) 653 rc2 = VERR_NO_MEMORY; 654 } 655 656 if (RT_FAILURE(rc2)) 657 { 658 while (i--) 659 RTStrFree(apcszArgsDup[i]); 660 661 RTMemFree(apcszArgsDup); 662 return NULL; 663 } 664 665 return apcszArgsDup; 666 } 667 668 /** 669 * Frees a command argument vector. 670 * 671 * @param cArgs Number of arguments in argument vector. 672 * @param papcszArgs Pointer to argument vector to free. 673 */ 674 static void rtFtpCmdArgsFree(uint8_t cArgs, char **papcszArgs) 675 { 676 while (cArgs--) 677 RTStrFree(papcszArgs[cArgs]); 678 679 RTMemFree(papcszArgs); 680 } 681 682 /** 614 683 * Opens a data connection to the client. 615 684 * … … 674 743 675 744 /** 676 * Thread serving a data connection.745 * Data connection thread for writing (sending) a file to the client. 677 746 * 678 747 * @returns VBox status code. … … 680 749 * @param pvUser Pointer to user-provided data. Of type PRTFTPSERVERCLIENT. 681 750 */ 682 static DECLCALLBACK(int) rtFtpServerDataConn Thread(RTTHREAD ThreadSelf, void *pvUser)751 static DECLCALLBACK(int) rtFtpServerDataConnFileWriteThread(RTTHREAD ThreadSelf, void *pvUser) 683 752 { 684 753 RT_NOREF(ThreadSelf); … … 687 756 AssertPtr(pClient); 688 757 689 PRTFTPSERVERDATACONN pDataConn = &pClient->DataConn; 758 PRTFTPSERVERDATACONN pDataConn = pClient->pDataConn; 759 AssertPtr(pDataConn); 690 760 691 761 LogFlowFuncEnter(); 692 693 int rc = rtFtpServerDataConnOpen(pDataConn, &pDataConn->Addr, pDataConn->uPort);694 if (RT_FAILURE(rc))695 return rc;696 762 697 763 uint32_t cbBuf = _64K; /** @todo Improve this. */ … … 700 766 return VERR_NO_MEMORY; 701 767 768 int rc; 769 702 770 /* Set start indicator. */ 703 771 pDataConn->fStarted = true; … … 705 773 RTThreadUserSignal(RTThreadSelf()); 706 774 707 const char *pcszFile = pDataConn->szFile; 775 AssertPtr(pDataConn->papszArgs); 776 const char *pcszFile = pDataConn->papszArgs[0]; 777 AssertPtr(pcszFile); 708 778 709 779 void *pvHandle = NULL; /* Opaque handle known to the actual implementation. */ … … 738 808 } 739 809 740 rtFtpServerDataConnClose(pDataConn);741 742 810 RTMemFree(pvBuf); 743 811 pvBuf = NULL; … … 751 819 752 820 /** 753 * Opens a data connection to the client.821 * Creates a data connection. 754 822 * 755 823 * @returns VBox status code. 756 * @param pClient Client to open data connection for. 757 * @param pDataConn Data connection to open. 758 */ 759 static int rtFtpServerDataConnCreate(PRTFTPSERVERCLIENT pClient, PRTFTPSERVERDATACONN pDataConn) 760 { 761 int rc = RTThreadCreate(&pDataConn->hThread, rtFtpServerDataConnThread, 762 pClient, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, 763 "ftpdata"); 764 if (RT_SUCCESS(rc)) 765 { 766 int rc2 = RTThreadUserWait(pDataConn->hThread, 30 * 1000 /* Timeout in ms */); 767 AssertRC(rc2); 768 769 if (!pDataConn->fStarted) /* Did the thread indicate that it started correctly? */ 770 rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */ 771 } 772 773 return rc; 774 } 775 776 /** 777 * Closes a data connection to the client. 824 * @param pClient Client to create data connection for. 825 * @param ppDataConn Where to return the (allocated) data connection. 826 */ 827 static int rtFtpServerDataConnCreate(PRTFTPSERVERCLIENT pClient, PRTFTPSERVERDATACONN *ppDataConn) 828 { 829 if (pClient->pDataConn) 830 return VERR_FTP_DATA_CONN_LIMIT_REACHED; 831 832 PRTFTPSERVERDATACONN pDataConn = (PRTFTPSERVERDATACONN)RTMemAllocZ(sizeof(RTFTPSERVERDATACONN)); 833 if (!pDataConn) 834 return VERR_NO_MEMORY; 835 836 rtFtpServerDataConnReset(pDataConn); 837 838 pDataConn->pClient = pClient; 839 840 *ppDataConn = pDataConn; 841 842 LogFlowFuncLeaveRC(VINF_SUCCESS); 843 return VINF_SUCCESS; 844 } 845 846 /** 847 * Starts a data connection. 778 848 * 779 849 * @returns VBox status code. 780 * @param pClient Client to close data connection for. 781 * @param pDataConn Data connection to close. 782 */ 783 static int rtFtpServerDataConnDestroy(PRTFTPSERVERCLIENT pClient, PRTFTPSERVERDATACONN pDataConn) 784 { 785 RT_NOREF(pClient); 786 787 if (pDataConn->hThread == NIL_RTTHREAD) 850 * @param pClient Client to start data connection for. 851 * @param pfnThread Pointer to thread function to use. 852 * @param cArgs Number of arguments. 853 * @param apcszArgs Array of arguments. 854 */ 855 static int rtFtpServerDataConnStart(PRTFTPSERVERDATACONN pDataConn, PFNRTTHREAD pfnThread, 856 uint8_t cArgs, const char * const *apcszArgs) 857 { 858 AssertPtrReturn(pDataConn, VERR_INVALID_POINTER); 859 AssertPtrReturn(pfnThread, VERR_INVALID_POINTER); 860 861 AssertReturn(!pDataConn->fStarted, VERR_WRONG_ORDER); 862 AssertReturn(!pDataConn->fStop, VERR_WRONG_ORDER); 863 AssertReturn(!pDataConn->fStopped, VERR_WRONG_ORDER); 864 865 int rc = VINF_SUCCESS; 866 867 if (cArgs) 868 { 869 pDataConn->papszArgs = rtFtpCmdArgsDup(cArgs, apcszArgs); 870 if (!pDataConn->papszArgs) 871 rc = VERR_NO_MEMORY; 872 } 873 874 if (RT_SUCCESS(rc)) 875 { 876 pDataConn->cArgs = cArgs; 877 878 rc = rtFtpServerDataConnOpen(pDataConn, &pDataConn->Addr, pDataConn->uPort); 879 if (RT_SUCCESS(rc)) 880 { 881 rc = RTThreadCreate(&pDataConn->hThread, pfnThread, 882 pDataConn->pClient, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, 883 "ftpdata"); 884 if (RT_SUCCESS(rc)) 885 { 886 int rc2 = RTThreadUserWait(pDataConn->hThread, 30 * 1000 /* Timeout in ms */); 887 AssertRC(rc2); 888 889 if (!pDataConn->fStarted) /* Did the thread indicate that it started correctly? */ 890 rc = VERR_FTP_DATA_CONN_INIT_FAILED; 891 } 892 893 if (RT_FAILURE(rc)) 894 rtFtpServerDataConnClose(pDataConn); 895 } 896 } 897 898 if (RT_FAILURE(rc)) 899 { 900 rtFtpCmdArgsFree(pDataConn->cArgs, pDataConn->papszArgs); 901 902 pDataConn->cArgs = 0; 903 pDataConn->papszArgs = NULL; 904 } 905 906 LogFlowFuncLeaveRC(rc); 907 return rc; 908 } 909 910 /** 911 * Destroys a data connection. 912 * 913 * @returns VBox status code. 914 * @param pDataConn Data connection to destroy. The pointer is not valid anymore after successful return. 915 */ 916 static int rtFtpServerDataConnDestroy(PRTFTPSERVERDATACONN pDataConn) 917 { 918 if (!pDataConn) 788 919 return VINF_SUCCESS; 789 920 790 921 LogFlowFuncEnter(); 791 922 792 /* Set stop indicator. */ 793 pDataConn->fStop = true; 794 795 int rcThread = VERR_WRONG_ORDER; 796 int rc = RTThreadWait(pDataConn->hThread, 30 * 1000 /* Timeout in ms */, &rcThread); 923 int rc = VINF_SUCCESS; 924 925 if (pDataConn->hThread != NIL_RTTHREAD) 926 { 927 /* Set stop indicator. */ 928 pDataConn->fStop = true; 929 930 int rcThread = VERR_WRONG_ORDER; 931 rc = RTThreadWait(pDataConn->hThread, 30 * 1000 /* Timeout in ms */, &rcThread); 932 } 933 797 934 if (RT_SUCCESS(rc)) 798 935 { 799 936 rtFtpServerDataConnClose(pDataConn); 800 rtFtpServerDataConnReset(pDataConn); 801 802 rc = rcThread; 803 } 804 937 rtFtpCmdArgsFree(pDataConn->cArgs, pDataConn->papszArgs); 938 939 RTMemFree(pDataConn); 940 pDataConn = NULL; 941 942 /** @todo Also check / handle rcThread? */ 943 } 944 945 LogFlowFuncLeaveRC(rc); 805 946 return rc; 806 947 } … … 834 975 RT_NOREF(cArgs, apcszArgs); 835 976 836 int rc = rtFtpServerDataConnDestroy(pClient, &pClient->DataConn); 837 if (RT_SUCCESS(rc)) 977 int rc = rtFtpServerDataConnDestroy(pClient->pDataConn); 978 if (RT_SUCCESS(rc)) 979 { 980 pClient->pDataConn = NULL; 981 838 982 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY); 983 } 839 984 840 985 return rc; … … 885 1030 } 886 1031 1032 /** 1033 * Thread for handling the LIST command's output in a separate data connection. 1034 * 1035 * @returns VBox status code. 1036 * @param ThreadSelf Thread handle. Unused. 1037 * @param pvUser User-provided arguments. Of type PRTFTPSERVERCLIENT. 1038 */ 1039 static DECLCALLBACK(int) rtFtpServerDataConnListThread(RTTHREAD ThreadSelf, void *pvUser) 1040 { 1041 RT_NOREF(ThreadSelf); 1042 1043 PRTFTPSERVERCLIENT pClient = (PRTFTPSERVERCLIENT)pvUser; 1044 AssertPtr(pClient); 1045 1046 PRTFTPSERVERDATACONN pDataConn = pClient->pDataConn; 1047 AssertPtr(pDataConn); 1048 1049 LogFlowFuncEnter(); 1050 1051 uint32_t cbBuf = _64K; /** @todo Improve this. */ 1052 void *pvBuf = RTMemAlloc(cbBuf); 1053 if (!pvBuf) 1054 return VERR_NO_MEMORY; 1055 1056 int rc; 1057 1058 /* Set start indicator. */ 1059 pDataConn->fStarted = true; 1060 1061 RTThreadUserSignal(RTThreadSelf()); 1062 1063 for (;;) 1064 { 1065 /* The first argument might indicate a directory to list. 1066 * If no argument is given, the implementation must use the last directory set. */ 1067 size_t cbRead = 0; 1068 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnList, 1069 pDataConn->cArgs == 1 1070 ? pDataConn->papszArgs[0] : NULL, pvBuf, cbBuf, &cbRead); 1071 if (RT_SUCCESS(rc)) 1072 { 1073 int rc2 = rtFtpServerDataConnWrite(pDataConn, pvBuf, cbRead, NULL /* pcbWritten */); 1074 AssertRC(rc2); 1075 1076 if (rc == VINF_EOF) 1077 break; 1078 } 1079 else 1080 break; 1081 1082 if (ASMAtomicReadBool(&pDataConn->fStop)) 1083 break; 1084 } 1085 1086 RTMemFree(pvBuf); 1087 pvBuf = NULL; 1088 1089 pDataConn->fStopped = true; 1090 pDataConn->rc = rc; 1091 1092 LogFlowFuncLeaveRC(rc); 1093 return rc; 1094 } 1095 887 1096 static int rtFtpServerHandleLIST(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 888 1097 { 889 RT_NOREF(cArgs, apcszArgs);890 891 1098 int rc; 892 1099 893 void *pvData = NULL; 894 size_t cbData = 0; 895 896 /* The first argument might indicate a directory to list. */ 897 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnList, 898 cArgs == 1 899 ? apcszArgs[0] : NULL, &pvData, &cbData); 900 901 if (RT_SUCCESS(rc)) 902 { 903 RTMemFree(pvData); 904 } 1100 /* Note: Data connection gets created when the PORT command was sent. */ 1101 if (pClient->pDataConn) 1102 { 1103 rc = rtFtpServerDataConnStart(pClient->pDataConn, rtFtpServerDataConnListThread, cArgs, apcszArgs); 1104 } 1105 else 1106 rc = VERR_FTP_DATA_CONN_NOT_FOUND; 1107 1108 int rc2 = rtFtpServerSendReplyRc(pClient, RT_SUCCESS(rc) 1109 ? RTFTPSERVER_REPLY_PATHNAME_OK 1110 : RTFTPSERVER_REPLY_CANT_OPEN_DATA_CONN); 1111 if (RT_SUCCESS(rc)) 1112 rc = rc2; 905 1113 906 1114 return rc; … … 955 1163 return rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS); 956 1164 957 /* Only allow one data connection per client at a time. */ 958 rtFtpServerDataConnClose(&pClient->DataConn); 959 960 int rc = rtFtpParseHostAndPort(apcszArgs[0], &pClient->DataConn.Addr, &pClient->DataConn.uPort); 961 if (RT_SUCCESS(rc)) 962 { 963 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY); 964 } 965 else 966 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_CANT_OPEN_DATA_CONN); 967 968 return rc; 969 } 970 971 static int rtFtpServerHandlePWD(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 972 { 973 RT_NOREF(cArgs, apcszArgs); 974 975 int rc; 976 977 char szPWD[RTPATH_MAX]; 978 979 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnPathGetCurrent, szPWD, sizeof(szPWD)); 980 981 if (RT_SUCCESS(rc)) 982 rc = rtFtpServerSendReplyStr(pClient, szPWD); 983 984 return rc; 985 } 986 987 static int rtFtpServerHandleQUIT(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 988 { 989 RT_NOREF(cArgs, apcszArgs); 990 991 return rtFtpServerDataConnDestroy(pClient, &pClient->DataConn); 992 } 993 994 static int rtFtpServerHandleRETR(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 995 { 996 if (cArgs != 1) 997 return VERR_INVALID_PARAMETER; 998 999 int rc; 1000 1001 const char *pcszPath = apcszArgs[0]; 1002 1003 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnFileStat, pcszPath, NULL /* PRTFSOBJINFO */); 1004 1005 if (RT_SUCCESS(rc)) 1006 { 1007 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_FILE_STATUS_OKAY); 1165 PRTFTPSERVERDATACONN pDataConn; 1166 int rc = rtFtpServerDataConnCreate(pClient, &pDataConn); 1167 if (RT_SUCCESS(rc)) 1168 { 1169 pClient->pDataConn = pDataConn; 1170 1171 rc = rtFtpParseHostAndPort(apcszArgs[0], &pDataConn->Addr, &pDataConn->uPort); 1008 1172 if (RT_SUCCESS(rc)) 1009 1173 { 1010 rc = RTStrCopy(pClient->DataConn.szFile, sizeof(pClient->DataConn.szFile), pcszPath); 1174 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_OKAY); 1175 } 1176 } 1177 1178 if (RT_FAILURE(rc)) 1179 { 1180 int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_CANT_OPEN_DATA_CONN); 1181 AssertRC(rc2); 1182 } 1183 1184 return rc; 1185 } 1186 1187 static int rtFtpServerHandlePWD(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 1188 { 1189 RT_NOREF(cArgs, apcszArgs); 1190 1191 int rc; 1192 1193 char szPWD[RTPATH_MAX]; 1194 1195 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnPathGetCurrent, szPWD, sizeof(szPWD)); 1196 1197 if (RT_SUCCESS(rc)) 1198 rc = rtFtpServerSendReplyRcEx(pClient, RTFTPSERVER_REPLY_PATHNAME_OK, "\"%s\"", szPWD); /* See RFC 959, APPENDIX II. */ 1199 1200 return rc; 1201 } 1202 1203 static int rtFtpServerHandleQUIT(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 1204 { 1205 RT_NOREF(cArgs, apcszArgs); 1206 1207 int rc = rtFtpServerDataConnDestroy(pClient->pDataConn); 1208 if (RT_SUCCESS(rc)) 1209 pClient->pDataConn = NULL; 1210 1211 return rc; 1212 } 1213 1214 static int rtFtpServerHandleRETR(PRTFTPSERVERCLIENT pClient, uint8_t cArgs, const char * const *apcszArgs) 1215 { 1216 if (cArgs != 1) /* File name needs to be present. */ 1217 return VERR_INVALID_PARAMETER; 1218 1219 int rc; 1220 1221 const char *pcszPath = apcszArgs[0]; 1222 1223 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnFileStat, pcszPath, NULL /* PRTFSOBJINFO */); 1224 1225 if (RT_SUCCESS(rc)) 1226 { 1227 if (pClient->pDataConn) 1228 { 1229 /* Note: Data connection gets created when the PORT command was sent. */ 1230 rc = rtFtpServerDataConnStart(pClient->pDataConn, rtFtpServerDataConnFileWriteThread, cArgs, apcszArgs); 1011 1231 if (RT_SUCCESS(rc)) 1012 { 1013 rc = rtFtpServerDataConnCreate(pClient, &pClient->DataConn); 1014 } 1232 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_FILE_STATUS_OKAY); 1015 1233 } 1234 else 1235 rc = VERR_FTP_DATA_CONN_NOT_FOUND; 1016 1236 } 1017 1237 … … 1252 1472 *pszCmdEnd = '\0'; 1253 1473 1474 /* Reply which gets sent back to the client. */ 1475 RTFTPSERVER_REPLY rcClient = RTFTPSERVER_REPLY_INVALID; 1476 1254 1477 int rcCmd = VINF_SUCCESS; 1255 1478 … … 1265 1488 for (; i < RT_ELEMENTS(g_aCmdMap); i++) 1266 1489 { 1267 if (!RTStrICmp(papszArgs[0], g_aCmdMap[i].szCmd)) 1490 const RTFTPSERVER_CMD_ENTRY *pCmdEntry = &g_aCmdMap[i]; 1491 1492 if (!RTStrICmp(papszArgs[0], pCmdEntry->szCmd)) 1268 1493 { 1494 /* Some commands need a valid user before they can be executed. */ 1495 if ( pCmdEntry->fNeedsUser 1496 && pClient->State.pszUser == NULL) 1497 { 1498 rcClient = RTFTPSERVER_REPLY_NOT_LOGGED_IN; 1499 break; 1500 } 1501 1269 1502 /* Save timestamp of last command sent. */ 1270 1503 pClient->State.tsLastCmdMs = RTTimeMilliTS(); 1271 1504 1272 rcCmd = g_aCmdMap[i].pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL); 1505 /* Hand in arguments only without the actual command. */ 1506 rcCmd = pCmdEntry->pfnCmd(pClient, cArgs - 1, cArgs > 1 ? &papszArgs[1] : NULL); 1507 if (RT_FAILURE(rcCmd)) 1508 { 1509 LogFunc(("Handling command '%s' failed with %Rrc\n", papszArgs[0], rcCmd)); 1510 1511 switch (rcCmd) 1512 { 1513 case VERR_INVALID_PARAMETER: 1514 RT_FALL_THROUGH(); 1515 case VERR_INVALID_POINTER: 1516 rcClient = RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS; 1517 break; 1518 1519 case VERR_NOT_IMPLEMENTED: 1520 rcClient = RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL; 1521 break; 1522 1523 default: 1524 break; 1525 } 1526 } 1273 1527 break; 1274 1528 } … … 1279 1533 if (i == RT_ELEMENTS(g_aCmdMap)) 1280 1534 { 1281 int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL);1282 if (RT_SUCCESS(rc))1283 rc = rc2;1284 1285 1535 LogFlowFunc(("Command not implemented\n")); 1286 return rc; 1536 Assert(rcClient == RTFTPSERVER_REPLY_INVALID); 1537 rcClient = RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL; 1287 1538 } 1288 1539 … … 1291 1542 if (fDisconnect) 1292 1543 { 1293 int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_CLOSING_CTRL_CONN);1294 if (RT_SUCCESS(rc))1295 rc = rc2;1296 1297 1544 RTFTPSERVER_HANDLE_CALLBACK_VA(pfnOnUserDisconnect, pClient->State.pszUser); 1298 return rc; 1545 1546 Assert(rcClient == RTFTPSERVER_REPLY_INVALID); 1547 rcClient = RTFTPSERVER_REPLY_CLOSING_CTRL_CONN; 1299 1548 } 1300 1301 switch (rcCmd)1302 {1303 case VERR_INVALID_PARAMETER:1304 RT_FALL_THROUGH();1305 case VERR_INVALID_POINTER:1306 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS);1307 break;1308 1309 case VERR_NOT_IMPLEMENTED:1310 rc = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_CMD_NOT_IMPL);1311 break;1312 1313 default:1314 break;1315 }1316 1549 } 1317 1550 else 1318 { 1319 int rc2 = rtFtpServerSendReplyRc(pClient, RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS); 1551 rcClient = RTFTPSERVER_REPLY_ERROR_INVALID_PARAMETERS; 1552 1553 if (rcClient != RTFTPSERVER_REPLY_INVALID) 1554 { 1555 int rc2 = rtFtpServerSendReplyRc(pClient, rcClient); 1320 1556 if (RT_SUCCESS(rc)) 1321 1557 rc = rc2; … … 1359 1595 if (RT_FAILURE(rc)) 1360 1596 break; 1361 1362 PRTFTPSERVERDATACONN pDataConn = &pClient->DataConn; 1363 1364 if ( ASMAtomicReadBool(&pDataConn->fStarted) 1365 && ASMAtomicReadBool(&pDataConn->fStopped)) 1597 } 1598 1599 /* 1600 * Handle data connection replies. 1601 */ 1602 if (pClient->pDataConn) 1603 { 1604 if ( ASMAtomicReadBool(&pClient->pDataConn->fStarted) 1605 && ASMAtomicReadBool(&pClient->pDataConn->fStopped)) 1366 1606 { 1367 Assert(p DataConn->rc != VERR_IPE_UNINITIALIZED_STATUS);1368 1369 rc = rtFtpServerSendReplyRc(pClient, RT_SUCCESS(p DataConn->rc)1607 Assert(pClient->pDataConn->rc != VERR_IPE_UNINITIALIZED_STATUS); 1608 1609 rc = rtFtpServerSendReplyRc(pClient, RT_SUCCESS(pClient->pDataConn->rc) 1370 1610 ? RTFTPSERVER_REPLY_CLOSING_DATA_CONN 1371 1611 : RTFTPSERVER_REPLY_CONN_CLOSED_TRANSFER_ABORTED); 1372 1612 1373 int rc2 = rtFtpServerDataConnDestroy(pClient, pDataConn); 1613 int rc2 = rtFtpServerDataConnDestroy(pClient->pDataConn); 1614 if (RT_SUCCESS(rc2)) 1615 pClient->pDataConn = NULL; 1616 1374 1617 if (RT_SUCCESS(rc)) 1375 1618 rc = rc2; … … 1378 1621 } 1379 1622 1380 /* Make sure to close any open data connections. */ 1381 int rc2 = rtFtpServerDataConnDestroy(pClient, &pClient->DataConn); 1623 /* Make sure to destroy all data connections. */ 1624 int rc2 = rtFtpServerDataConnDestroy(pClient->pDataConn); 1625 if (RT_SUCCESS(rc2)) 1626 pClient->pDataConn = NULL; 1627 1382 1628 if (RT_SUCCESS(rc)) 1383 1629 rc = rc2; -
trunk/src/VBox/Runtime/tools/RTFTPServer.cpp
r82732 r82770 47 47 #include <iprt/assert.h> 48 48 #include <iprt/ctype.h> 49 #include <iprt/err core.h>49 #include <iprt/err.h> 50 50 #include <iprt/file.h> 51 51 #include <iprt/getopt.h> … … 305 305 } 306 306 307 static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, const char *pcszPath, void * *ppvData, size_t *pcbData)308 { 309 RT_NOREF(pData, pcszPath, p pvData, pcbData);310 311 return VINF_ SUCCESS;307 static DECLCALLBACK(int) onList(PRTFTPCALLBACKDATA pData, const char *pcszPath, void *pvData, size_t cbData, size_t *pcbRead) 308 { 309 RT_NOREF(pData, pcszPath, pvData, cbData, pcbRead); 310 311 return VINF_EOF; 312 312 } 313 313
Note:
See TracChangeset
for help on using the changeset viewer.