error_t ftpLogin(FtpClientContext *context, const char_t *username, const char_t *password, const char_t *account) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Format the USER command sprintf(context->buffer, "USER %s\r\n", username); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(FTP_REPLY_CODE_2YZ(replyCode)) return NO_ERROR; else if(!FTP_REPLY_CODE_3YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Format the PASS command sprintf(context->buffer, "PASS %s\r\n", password); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(FTP_REPLY_CODE_2YZ(replyCode)) return NO_ERROR; else if(!FTP_REPLY_CODE_3YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Format the ACCT command sprintf(context->buffer, "ACCT %s\r\n", account); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Successful processing return NO_ERROR; }
error_t ftpCloseFile(FtpClientContext *context) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Graceful shutdown socketShutdown(context->dataSocket, SOCKET_SD_BOTH); //Close the data socket socketClose(context->dataSocket); context->dataSocket = NULL; //Check the transfer status error = ftpSendCommand(context, NULL, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Successful processing return NO_ERROR; }
error_t ftpRenameFile(FtpClientContext *context, const char_t *oldName, const char_t *newName) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Format the RNFR command sprintf(context->buffer, "RNFR %s\r\n", oldName); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_3YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Format the RNTO command sprintf(context->buffer, "RNTO %s\r\n", newName); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Successful processing return NO_ERROR; }
error_t ftpGetWorkingDir(FtpClientContext *context, char_t *path, size_t size) { error_t error; size_t length; uint_t replyCode; char_t *p; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Check parameters if(path == NULL || size == 0) return ERROR_INVALID_PARAMETER; //Send the command to the server error = ftpSendCommand(context, "PWD\r\n", &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Search for the last double quote p = strrchr(context->buffer, '\"'); //Failed to parse the response? if(!p) return ERROR_INVALID_SYNTAX; //Split the string *p = '\0'; //Search for the first double quote p = strchr(context->buffer, '\"'); //Failed to parse the response? if(!p) return ERROR_INVALID_SYNTAX; //Retrieve the length of the working directory length = strlen(p + 1); //Limit the number of characters to copy length = MIN(length, size - 1); //Copy the string strncpy(path, p + 1, length); //Properly terminate the string with a NULL character path[length] = '\0'; //Successful processing return NO_ERROR; }
error_t ftpChangeToParentDir(FtpClientContext *context) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Send the command to the server error = ftpSendCommand(context, "CDUP\r\n", &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Successful processing return NO_ERROR; }
error_t ftpMakeDir(FtpClientContext *context, const char_t *path) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Format the MKD command sprintf(context->buffer, "MKD %s\r\n", path); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Successful processing return NO_ERROR; }
int main(int argc, char *argv[]){ int mySock; char cmd[1024], *param, *cp; char *par[3]; int connecte = 0; ctxClient* client = (ctxClient*)malloc(1*sizeof(ctxClient)); client->serverAddress = (char*)malloc(1*sizeof(char)); printf("Pour voir la liste des commandes supportées tappez 'help' :\n"); do{ printPrompt(); fgets(cmd, sizeof(cmd), stdin); param = strchr(cmd,' '); if (param) { strcpy(cp,param); par[0] = strtok (cp, " "); par[1] = strtok (cp, " "); printf("Par 1 : %s Par 2 %s", par[0], par[1]); } if(strcmp(cmd,"open\n\0")==0){ if(connecte){ printf("Vous êtes déja connecté à un serveur. \n"); } else{ printf("OK connect to server !\n"); mySock = ftpConnect(client,"127.0.0.1", 21); connecte=1; ftpReceiveCommand(client); ftpSendCommand(client,"PASV"); ftpReceiveCommand(client); } } else if(strcmp(cmd,"close\n\0")==0){ ftpSendCommand(client,"close"); } else if(strcmp(cmd,"cd\n\0")==0){ ftpSendCommand(client,"cd"); } else if(strcmp(cmd,"pwd\n\0")==0){ ftpSendCommand(client,"pwd"); } else if(strcmp(cmd,"get\n\0")==0){ ftpSendCommand(client,"get"); } else if(strcmp(cmd,"put\n\0")==0){ ftpSendCommand(client,"put"); } else if(strcmp(cmd,"del\n\0")==0){ ftpSendCommand(client,"del"); } else if(strcmp(cmd,"mkd\n\0")==0){ ftpSendCommand(client,"mkd"); } else if(strcmp(cmd,"rmd\n\0")==0){ ftpSendCommand(client,"rmd"); } else if(strcmp(cmd,"dir\n\0")==0){ ftpSendCommand(client,"dir"); } else if(strcmp(cmd,"help\n\0")==0){ printHelp(); } else if(strcmp(cmd,"exit\n\0")==0); else if(strcmp(cmd,"\n\0")==0); else{ printf("Commande non reconnue \n"); } }while(strcmp(cmd,"exit\n\0")); return 0; }
error_t ftpOpenFile(FtpClientContext *context, const char_t *path, uint_t flags) { error_t error; uint_t replyCode; IpAddr ipAddr; uint16_t port; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Open data socket context->dataSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->dataSocket) return ERROR_OPEN_FAILED; //Start of exception handling block do { //Bind the socket to a particular network interface? if(context->interface != NULL) { //Associate the socket with the relevant interface error = socketBindToInterface(context->dataSocket, context->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->dataSocket, FTP_CLIENT_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Check data transfer direction if(flags & (FTP_FOR_WRITING | FTP_FOR_APPENDING)) { //Maximize transmission throughput by using a large buffer error = socketSetTxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MAX_TX_BUFFER_SIZE); //Any error to report? if(error) break; //Use a small buffer for the reception path error = socketSetRxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MIN_RX_BUFFER_SIZE); //Any error to report? if(error) break; } else { //Use a small buffer for the transmission path error = socketSetTxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MIN_TX_BUFFER_SIZE); //Any error to report? if(error) break; //Maximize reception throughput by using a large buffer error = socketSetRxBufferSize(context->dataSocket, FTP_CLIENT_SOCKET_MAX_RX_BUFFER_SIZE); //Any error to report? if(error) break; } //Set representation type if(flags & FTP_TEXT_TYPE) { //Use ASCII type error = ftpSetType(context, 'A'); //Any error to report? if(error) break; } else { //Use image type error = ftpSetType(context, 'I'); //Any error to report? if(error) break; } //Check transfer mode if(!context->passiveMode) { //Place the data socket in the listening state error = socketListen(context->dataSocket, 1); //Any error to report? if(error) break; //Retrieve local IP address error = socketGetLocalAddr(context->controlSocket, &ipAddr, NULL); //Any error to report? if(error) break; //Retrieve local port number error = socketGetLocalAddr(context->dataSocket, NULL, &port); //Any error to report? if(error) break; //Set the port to be used in data connection error = ftpSetPort(context, &ipAddr, port); //Any error to report? if(error) break; } else { //Enter passive mode error = ftpSetPassiveMode(context, &port); //Any error to report? if(error) break; //Establish data connection error = socketConnect(context->dataSocket, &context->serverAddr, port); //Connection to server failed? if(error) break; } //Format the command if(flags & FTP_FOR_WRITING) sprintf(context->buffer, "STOR %s\r\n", path); else if(flags & FTP_FOR_APPENDING) sprintf(context->buffer, "APPE %s\r\n", path); else sprintf(context->buffer, "RETR %s\r\n", path); //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) break; //Check FTP response code if(!FTP_REPLY_CODE_1YZ(replyCode)) { //Report an error error = ERROR_UNEXPECTED_RESPONSE; break; } //Check transfer mode if(!context->passiveMode) { //Wait for the server to connect back to the client's data port Socket *socket = socketAccept(context->dataSocket, NULL, NULL); //No connection request? if(!socket) { //Report an error error = ERROR_FAILURE; break; } //Close the listening socket socketClose(context->dataSocket); //Save socket handle context->dataSocket = socket; //Set timeout for blocking operations error = socketSetTimeout(context->dataSocket, FTP_CLIENT_DEFAULT_TIMEOUT); //Any error to report? if(error) break; } //End of exception handling block } while(0); //Any error to report? if(error) { //Clean up side effects socketClose(context->dataSocket); context->dataSocket = NULL; } //Return status code return error; }
error_t ftpConnect(FtpClientContext *context, NetInterface *interface, IpAddr *serverAddr, uint16_t serverPort, uint_t flags) { error_t error; uint_t replyCode; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; //Clear context memset(context, 0, sizeof(FtpClientContext)); //Underlying network interface context->interface = interface; //Save the IP address of the FTP server context->serverAddr = *serverAddr; //Use passive mode? if(flags & FTP_PASSIVE_MODE) context->passiveMode = TRUE; //Open control socket context->controlSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); //Failed to open socket? if(!context->controlSocket) return ERROR_OPEN_FAILED; //Start of exception handling block do { //Bind the socket to a particular network interface? if(context->interface != NULL) { //Associate the socket with the relevant interface error = socketBindToInterface(context->controlSocket, context->interface); //Any error to report? if(error) break; } //Set timeout for blocking operations error = socketSetTimeout(context->controlSocket, FTP_CLIENT_DEFAULT_TIMEOUT); //Any error to report? if(error) break; //Specify the size of the send buffer error = socketSetTxBufferSize(context->controlSocket, FTP_CLIENT_SOCKET_MIN_TX_BUFFER_SIZE); //Any error to report? if(error) break; //Specify the size of the receive buffer error = socketSetRxBufferSize(context->controlSocket, FTP_CLIENT_SOCKET_MIN_RX_BUFFER_SIZE); //Any error to report? if(error) break; //Connect to the FTP server error = socketConnect(context->controlSocket, serverAddr, serverPort); //Connection to server failed? if(error) break; //Wait for the connection greeting reply error = ftpSendCommand(context, NULL, &replyCode); //Any communication error to report? if(error) break; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) error = ERROR_UNEXPECTED_RESPONSE; //End of exception handling block } while(0); //Any error to report? if(error) { //Clean up side effects socketClose(context->controlSocket); context->controlSocket = NULL; } //Return status code return error; }
error_t ftpSetPassiveMode(FtpClientContext *context, uint16_t *port) { error_t error; uint_t replyCode; char_t delimiter; char_t *p; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; #if (IPV4_SUPPORT == ENABLED) //IPv4 FTP server? if(context->serverAddr.length == sizeof(Ipv4Addr)) { //Send the command to the server error = ftpSendCommand(context, "PASV\r\n", &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Delimiter character delimiter = ','; //Retrieve the low byte of the port number p = strrchr(context->buffer, delimiter); //Failed to parse the response? if(!p) return ERROR_INVALID_SYNTAX; //Convert the resulting string *port = atoi(p + 1); //Split the string *p = '\0'; //Retrieve the high byte of the port number p = strrchr(context->buffer, delimiter); //Failed to parse the response? if(!p) return ERROR_INVALID_SYNTAX; //Convert the resulting string *port |= atoi(p + 1) << 8; } else #endif #if (IPV6_SUPPORT == ENABLED) //IPv6 FTP server? if(context->serverAddr.length == sizeof(Ipv6Addr)) { //Send the command to the server error = ftpSendCommand(context, "EPSV\r\n", &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Search for the opening parenthesis p = strrchr(context->buffer, '('); //Failed to parse the response? if(!p || p[1] == '\0') return ERROR_INVALID_SYNTAX; //Retrieve the delimiter character delimiter = p[1]; //Search for the last delimiter character p = strrchr(context->buffer, delimiter); //Failed to parse the response? if(!p) return ERROR_INVALID_SYNTAX; //Split the string *p = '\0'; //Search for the last but one delimiter character p = strrchr(context->buffer, delimiter); //Failed to parse the response? if(!p) return ERROR_INVALID_SYNTAX; //Convert the resulting string *port = atoi(p + 1); } else #endif //Invalid IP address? { //Report an error return ERROR_INVALID_ADDRESS; } //Successful processing return NO_ERROR; }
error_t ftpSetPort(FtpClientContext *context, const IpAddr *ipAddr, uint16_t port) { error_t error; uint_t replyCode; char_t *p; //Invalid context? if(context == NULL) return ERROR_INVALID_PARAMETER; #if (IPV4_SUPPORT == ENABLED) //IPv4 FTP client? if(ipAddr->length == sizeof(Ipv4Addr)) { //Format the PORT command strcpy(context->buffer, "PORT "); //Append host address ipv4AddrToString(ipAddr->ipv4Addr, context->buffer + 5); //Parse the resulting string for(p = context->buffer; *p != '\0'; p++) { //Change dots to commas if(*p == '.') *p = ','; } //Append port number sprintf(p, ",%" PRIu8 ",%" PRIu8 "\r\n", MSB(port), LSB(port)); } else #endif #if (IPV6_SUPPORT == ENABLED) //IPv6 FTP client? if(ipAddr->length == sizeof(Ipv6Addr)) { //Format the EPRT command strcpy(context->buffer, "EPRT |2|"); //Append host address ipv6AddrToString(&ipAddr->ipv6Addr, context->buffer + 8); //Point to the end of the resulting string p = context->buffer + strlen(context->buffer); //Append port number sprintf(p, "|%" PRIu16 "|\r\n", port); } else #endif //Invalid IP address? { //Report an error return ERROR_INVALID_ADDRESS; } //Send the command to the server error = ftpSendCommand(context, context->buffer, &replyCode); //Any error to report? if(error) return error; //Check FTP response code if(!FTP_REPLY_CODE_2YZ(replyCode)) return ERROR_UNEXPECTED_RESPONSE; //Successful processing return NO_ERROR; }