/** * Parse arguments. * * @param argc Argument count. * @param argv Argument vector. * @param[out] conf Configuration. */ static void ParseArgs(int argc, char** argv, Config& conf) { std::stringstream usage; usage << "Usage: " PROJECT_NAME " <command> [options]"; opts::options_description visible_desc(usage.str()); try { opts::options_description common_desc("# Common options"); common_desc.add_options() ("config", opts::value<std::string>(), "Path to configuration file.") ("cert-log", opts::value<std::string>(), "Certification log.") ("help", "Print this usage information.") ("port", opts::value<uint16_t>(), "Port.") ; visible_desc.add(common_desc); opts::variables_map vm; opts::store( opts::command_line_parser(argc, argv) .options(visible_desc) .run(), vm); if (vm.count("config")) { fs::path path(vm["config"].as<std::string>()); if (!fs::exists(path)) ExitError(visible_desc, "configuration file does not exist"); try { opts::store(opts::parse_config_file<char>(path.c_str(), visible_desc), vm); } catch (const std::exception& e) { ExitError(visible_desc, "unable to parse configuration file"); } } opts::notify(vm); if (vm.count("cert-log")) { conf.cert_log_ = vm["cert-log"].as<std::string>(); } if (vm.count("port")) { conf.port_ = vm["port"].as<uint16_t>(); } if (vm.count("help")) { std::cout << visible_desc; exit(0); } FLAGS_logtostderr = true; } catch (const std::exception& e) { std::stringstream msg; msg << "unable to process options -- " << e.what(); ExitError(visible_desc, msg.str()); } }
BOOL CRegressTreeDlg::OnInitDialog(){ CDialog::OnInitDialog(); DNAStat_Tree = (CTreeCtrl *)GetDlgItem(IDC_TREE1); DepthEdit = (CEdit *)GetDlgItem(IDC_DEPTH); CString d; d.Format("%d", DNAStat->getDepth()); DepthEdit->SetWindowText(d); try{ DNAStat->toTreeCtrl(DNAStat_Tree, DNAStat_Tree->GetRootItem()); } catch(CString ErrMsg){ CString Messg2(_T("--> Unable to display CDNAStatement in TreeForm at CRegressTreeDlg::OnInitDialog()")); Messg2 = ErrMsg + Messg2; ExitError(Messg2); } ExpandTree(DNAStat_Tree->GetRootItem()); VarEdit = (CEdit*)GetDlgItem(IDC_X1EDIT); FuncRes = (CEdit*)GetDlgItem(IDC_FXEDID); FuncPrime = (CEdit*)GetDlgItem(IDC_PRIMEFX); VarEdit->SetWindowText(CString(_T("UNDEF"))); FuncRes->SetWindowText(CString(_T("UNDEF"))); FuncPrime->SetWindowText(CString(_T("UNDEF"))); return TRUE; }
/* Get file info about a certain file (directories count as files). Note that "." and ".." are considering special files, not dirs. */ FileInfoEnum GetFileInfo(char* path) { FileInfoEnum fileInfo; int fileDesc = open(path, O_RDONLY); if (fileDesc == -1) { if (errno = ENOENT) fileInfo = FILEINFO_DOESNOTEXIST; else fileInfo = FILEINFO_ERROR; close(fileDesc); return fileInfo; } struct stat statBuf; if ( fstat(fileDesc, &statBuf) != 0 ) ExitError("fstat() failed to get file info."); if ( S_ISDIR(statBuf.st_mode) ) fileInfo = FILEINFO_DIR; else if ( S_ISREG(statBuf.st_mode) ) fileInfo = FILEINFO_REGULARFILE; else fileInfo = FILEINFO_SPECIALFILE; close(fileDesc); return fileInfo; }
void CheckForBreak( void ) { if( sig_count > 0 ) { sig_count = 0; PrtMsg( ERR | USER_BREAK_ENCOUNTERED ); ExitError(); } }
int CreateListenSocket(int maxBacklogConnections, int listenPort, bool dynamicPort = false, bool allowAddrInUseBind = false) { /* binding with a port value of 0 in the sock address struct will bind to a dynamic port */ if (dynamicPort) { listenPort = 0; } /* create our listentng socket */ int listenSocket = socket(AF_INET, SOCK_STREAM, 0); // create socket for TCP/IP connection if (listenSocket == -1) // socket() returns -1 upon failure ExitError("Failed to create listening socket."); if (allowAddrInUseBind) { /* this alleviates "address already in use" errors when the kernel has not gotten around to freeing the socket on the specified port from previous instances of this or other processes */ int yes = 1; // apparently for setting socket options on Solaris this would need to be '1' if ( setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) ExitError("Could not set socket option."); } /* fill in the local address struct for binding to */ struct sockaddr_in localAddr; // local machine internet address information localAddr.sin_family = AF_INET; // host byte order localAddr.sin_port = htons(listenPort); // port to listen on, network byte order localAddr.sin_addr.s_addr = htonl(INADDR_ANY); // fill with the host machine's IP //localAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // another way memset(localAddr.sin_zero, 0, sizeof(localAddr.sin_zero)); // zero the sin_zero field /* bind the listen socket to the address and port */ if ( bind(listenSocket, (struct sockaddr *)&localAddr, sizeof(localAddr)) == -1 ) ExitError("Could not bind address to socket."); /* set the socket to listen for connections */ if ( listen(listenSocket, maxBacklogConnections) == -1 ) ExitError("Could not listen and on the address and port."); return listenSocket; }
int AcceptConnectionFromListenSocket(int listenSocket, struct sockaddr_in * remoteAddr) { /* Accept the first connection on the backlog queue. accept() blocks if there are no connections in the queue. */ socklen_t sinSize = sizeof(sockaddr_in); int acceptSocket = accept(listenSocket, (struct sockaddr *)remoteAddr, &sinSize); if (acceptSocket == -1) ExitError("Failure creating socket for accepting connection."); return acceptSocket; }
void Vm::exec(std::vector<Token> &listInstr, bool verbose) { Factory f; _verbose = verbose; for (std::vector<Token>::iterator it = listInstr.begin(); it != listInstr.end(); ++it) { if (_functInstr.find(it->getInstr()) != _functInstr.end()) { if (_verbose) std::cout << it->getInstr() << " " << it->getType() << " " << it->getValue() << std::endl; (this->*_functInstr[it->getInstr()])(f.createOperand(Vm::_typeMap[it->getType()], it->getValue())); } else if (_functInstrNoArgs.find(it->getInstr()) != _functInstrNoArgs.end()) { if (_verbose) std::cout << it->getInstr() << std::endl; (this->*_functInstrNoArgs[it->getInstr()])(); } } throw ExitError(); }
int main(int argc, char* argv[]) { /* Parse the command line arguments */ int listenPort = -1; // port to listen on char* dir = NULL; // directory to serve ParseCmdLineArgs(argc, argv, dir, listenPort); printf("Running server in directory %s, and on port %i.\n", dir, listenPort); /* Create the listening socket for our FTP server */ int listenSocket = CreateListenSocket( FTP_MAX_BACKLOG_CONNECTIONS, listenPort, false, true ); /* Do this to reap zombie child processes */ struct sigaction sa; // need this struct for handling signals and destroying zombie child procs sa.sa_handler = SigChildHandler; // function pointer sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if ( sigaction(SIGCHLD, &sa, NULL) == -1 ) ExitError("sigaction() failed."); while (1) { /* Accept the next connection on the backlog queue. Blocks if there are no connections in the queue. */ struct sockaddr_in remoteAddr; int acceptSocket = AcceptConnectionFromListenSocket(listenSocket, &remoteAddr); printf("FTP server received connection from %s\n", inet_ntoa(remoteAddr.sin_addr)); /* Each FTP session gets its own process. */ if ( !fork() ) { // child process code close(listenSocket); // child doesn't need listen socket FTPSession(acceptSocket, dir, remoteAddr); // begin the FTP session close(acceptSocket); // when done with the session close the socket exit(EXIT_SUCCESS); // exit with success code 0 } // parent process continues here close(acceptSocket); // parent doesn't need the accept socket anymore } return 0; }
STATIC RET_T perform( TARGET *targ, DEPEND *dep, DEPEND *impldep, time_t max_time ) /*********************************************************************************/ { CLIST *clist; CLIST *before; RET_T ret; DEPEND *depend; DEPEND *impliedDepend; depend = NULL; impliedDepend = NULL; assert( targ != NULL && dep != NULL ); if( Glob.query ) { ++cListCount; return( RET_WARN ); } if( Glob.touch ) { ++cListCount; ResetExecuted(); if( !targ->attr.symbolic ) { CacheRelease(); if( TouchFile( targ->node.name ) != RET_SUCCESS ) { PrtMsg( ERR | COULD_NOT_TOUCH, targ->node.name ); return( RET_ERROR ); } } targ->touched = true; return( RET_SUCCESS ); } /* means that this is a sufsuf made implicit rule */ if( impldep == NULL ) { clist = dep->clist; depend = dep; impliedDepend = NULL; } else { clist = impldep->clist; depend = targ->depend; impliedDepend = dep; } if( clist == NULL ) { clist = DotCList( DOT_DEFAULT ); if( clist == NULL ) { // No commands in Microsoft and POSIX mode is considered OK // and executed if( Glob.compat_nmake || Glob.compat_posix ) { targ->cmds_done = true; return( RET_SUCCESS ); } if( targ->attr.symbolic != false ) { targ->cmds_done = true; return( RET_SUCCESS ); } if( targ->allow_nocmd ) { /* for UNIX folks: make target symbolic */ targ->attr.symbolic = true; return( RET_SUCCESS ); } PrtMsg( FTL | NO_DEF_CMDS_FOR_MAKE, DotNames[DOT_DEFAULT], targ->node.name ); ExitFatal(); } } if( !Glob.noexec ) { ResetExecuted(); } if( !doneBefore ) { before = DotCList( DOT_BEFORE ); if( before != NULL ) { ++cListCount; if( ExecCList( before ) != RET_SUCCESS ) { PrtMsg( FTL | S_COMMAND_RET_BAD, DotNames[DOT_BEFORE] ); ExitFatal(); } } doneBefore = true; } exPush( targ, depend, impliedDepend ); ret = carryOut( targ, clist, findMaxTime( targ, dep, max_time ) ); exPop(); if( ret == RET_ERROR ) { ExitError(); } return( ret ); }
CRegressTreeDlg::CRegressTreeDlg(CWnd* pParent /*=NULL*/, CDNAStatement* D) : CDialog(CRegressTreeDlg::IDD, pParent), DNAStat(D) { if(!DNAStat) ExitError(_T("No Tree Provided To Dialog Box")); }
void vcerror(long lexIdx, short etype, const char *buf, va_list va, short eno) { static const char *TNames[] = { "?","Warning","Error", "Fatal", "SoftError" #ifndef REGISTERED , "Unimplemented" #endif }; long lexIdxBeg; long lexFileNameLen; long lexLine; char *lexFile; long errcol = 0; char ebuf[100]; long ebufoff = 0; lexLine=FindLexFileLine(lexIdx, &lexFile, &lexFileNameLen, &lexIdxBeg); /* * Use original lexer file to obtain line for printing since the * internal copy could be munged. * * We need to determine a couple of things: * lexLine - Indicates the line number of the error (0 if no associated line) * errcol - The physical column where the error occurred (0 for no line) * ebuf - The null terminated buffer. This buffer is at most 80 characters * but will contain the character position that has the error. * ebufoff - The logical start of the error buffer. This will be 0 as long as * the error occurs in the first 80 columns. Beyond that, this will * jump by 10. * lexFile - The name of the file containing the error * lexFileNameLen */ ebuf[0] = 0; if (lexLine && ErrorInFileValid) { short c; long i = lexIdxBeg; short pos = 0; while ((c = FindLexCharAt(i)) != EOF && c != '\n') { if (c == '\t') { short tab; tab = ((pos + ebufoff + 8) & ~7) - ebufoff; while (pos < tab) ebuf[pos++] = ' '; } else ebuf[pos++] = c; if (i == lexIdx) errcol = pos + ebufoff; if (pos > 80) { if ((errcol - (pos + ebufoff)) > 10) break; memcpy(ebuf, ebuf+10, pos-10); pos -= 10; ebufoff += 10; } ++i; } ebuf[pos] = 0; } eprintf(1, "DC1: \"%.*s\" L:%d ", lexFileNameLen, lexFile, lexLine); if (ErrorOpt & 1) eprintf(1, "C:%d %c:%d ", errcol + 1, TNames[etype][0], eno); else eprintf(1, "%s:%d ", TNames[etype], eno); veprintf(1, buf, va); eprintf(1, "\n"); if (lexLine && ErrorInFileValid && (ErrorOpt & 2)) { short pos = errcol - ebufoff; /* We Need to account for the fact that the ^ will take up one space */ if (pos) pos = pos - 1; eprintf(0, "%s\n%*.*s^\n", ebuf, pos, pos, ""); } if (etype == ESOFT || etype == EFATAL) { ExitError(20); } if (etype == EWARN && ExitCode < 5) ExitCode = 5; if (etype != EWARN && ExitCode < 20) ExitCode = 20; }
void FTPDataTransferSession(int controlSocket, int dataTransferSessionSocket) { /* LIST command - Sends a list of files to be displayed. */ if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_LIST]) == 0) { printf("Receivied LIST command.\n"); send(controlSocket, replies[REPLY_150_SENDING_DIR_LIST], strlen(replies[REPLY_150_SENDING_DIR_LIST]), 0); //FILE* lsOutput = popen("ls -l -n", "r"); char cmdString[PATH_MAX+100]; // path plus room for the command sprintf(cmdString, "sh -c \"ls %s -l > .dirlist\"", dir); system(cmdString); FILE* dirListFile = fopen(".dirlist", "r"); // open in program's working directory char lineBuf[2000]; // HACK HACK: totally made up buffer size while ( fgets( lineBuf, 2000, dirListFile ) != NULL ) { int lineBufLen = strlen( lineBuf ); lineBuf[lineBufLen-1] = '\r'; lineBuf[lineBufLen] = '\n'; lineBufLen++; send(dataTransferSessionSocket, lineBuf, lineBufLen, 0); } fclose(dirListFile); send(controlSocket, replies[REPLY_226_DIR_SEND_OK], strlen(replies[REPLY_226_DIR_SEND_OK]), 0); } /* RETR command - Retrieve file over the data transfer connection. */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_RETR]) == 0) { printf("Received RETR command.\n"); sprintf(pathBuf, "%s%s", dir, cmdTokens[1]); // cmdTokens[1] is the file name FILE* fileToSend = fopen(pathBuf, "rb"); if (fileToSend == NULL) { printf("RETR couldn't open file.\n"); send(controlSocket, replies[REPLY_550_FILE_NOT_FOUND], strlen(replies[REPLY_550_FILE_NOT_FOUND]), 0); return; // error } //char fileSizeInBytes[20]; char retrReply[PATH_MAX+1000]; // HACK : max path + max number of digits for byte size + reply string int fileSize = GetFileSize(pathBuf); sprintf(retrReply, replies[REPLY_150_OPEN_BINARY_DATA_CONNECTION], cmdTokens[1], fileSize); send(controlSocket, retrReply, strlen(retrReply), 0); /* FTP has three transfer modes: STREAM, BLOCK, and COMPRESSED. We will send using STERAM mode which simply sends a stream of bytes and treat all files as "file structures" as defined in RFC 959 as opposed to "record structures." From RFC959: "If the structure is a file structure, the EOF is indicated by the sending host closing the data connection and all bytes are data bytes." So, we just close the connection after sending all the bytes. */ while ( 1 ) { /* read blocks of 1024 bytes into msgBuf and then send */ size_t numBytesRead = fread(msgBuf, 1, 1024, fileToSend); send(dataTransferSessionSocket, msgBuf, numBytesRead, 0); if (numBytesRead < 1024) // reached end of file break; } fclose(fileToSend); send(controlSocket, replies[REPLY_226_FILE_SEND_OK], strlen(replies[REPLY_226_FILE_SEND_OK]), 0); } /* STOR command - Receive file from user. */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_STOR]) == 0) { printf("Received STOR command.\n"); char* newFileName = cmdTokens[1]; sprintf(pathBuf, "%s%s", dir, newFileName); FILE* fileToReceive = fopen(pathBuf, "wb"); if (fileToReceive == NULL) { printf("STOR couldn't create file.\n"); send(controlSocket, replies[REPLY_550_COULDNT_OPEN_FILE], strlen(replies[REPLY_550_COULDNT_OPEN_FILE]), 0); return; // error } send(controlSocket, replies[REPLY_150_READY_FOR_TRANSFER], strlen(replies[REPLY_150_READY_FOR_TRANSFER]), 0); /* keep reading until the connection is closed */ while (1) { if ( ( msgBufLen = recv( dataTransferSessionSocket, msgBuf, MSG_BUF_MAX_SIZE, 0 ) ) == -1 ) ExitError("Error receiving control connection data."); if ( msgBufLen == 0 ) // recv() returns 0 if the remote side has closed the connection */ break; fwrite( msgBuf, 1, msgBufLen, fileToReceive ); } send(controlSocket, replies[REPLY_226_RECEIVED_FILE_CLOSING_CONNECTION], strlen(replies[REPLY_226_RECEIVED_FILE_CLOSING_CONNECTION]), 0); } /* Unknown or invalid command */ else { printf("Received invalid DTP command.\n"); send(controlSocket, replies[REPLY_500_UNKNOWN_COMMAND], strlen(replies[REPLY_500_UNKNOWN_COMMAND]), 0); return; // error } }
void FTPSession(int controlSocket, char* inputRootDir, struct sockaddr_in remoteAddr) { strcpy( dir, inputRootDir ); // copy into new buffer so we can make the directory string larger if needed AddTrailingSlashIfNeeded( dir ); // make sure we have a trailing slash on the file char properRootDir[PATH_MAX]; strcpy( properRootDir, dir ); /* Test to see if the directory to serve exists */ if ( GetFileInfo(dir) == FILEINFO_DOESNOTEXIST ) ExitError("Failed to open directory to serve."); /* Reply 220 to user upon connection */ if ( send(controlSocket, replies[REPLY_220_BEGIN_SESSION], strlen(replies[REPLY_220_BEGIN_SESSION ]), 0) == -1 ) ExitError("Error sending reply."); while (1) { printf("Serving Directory: <%s>.\n", dir); int ret; /* Receive and parse the next command over the socket from the user. */ ret = GetControlConnectionCmd( controlSocket, msgBuf, msgBufLen, MSG_BUF_MAX_SIZE, cmdTokens, numCmdTokens ); if (ret == 1) // user has closed connection break; // break out of loop and end session /* Do the specified command */ /* USER command - We're not doing authentication. Just reply with a normal username okay message */ if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_USER]) == 0) { printf("Receivied USER command.\n"); send(controlSocket, replies[REPLY_331_USERNAME_OK], strlen(replies[REPLY_331_USERNAME_OK]), 0); } /* PASS command - Like with PASS we're not doing authentication. Just reply with a normal username okay message */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_PASS]) == 0) { printf("Receivied PASS command.\n"); send(controlSocket, replies[REPLY_230_PASS_ACCEPT], strlen(replies[REPLY_230_PASS_ACCEPT]), 0); } /* SYST command - Give a typical UNIX system response */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_SYST]) == 0) { printf("Receivied SYST command.\n"); send(controlSocket, replies[REPLY_215_SYST_RESPONSE], strlen(replies[REPLY_215_SYST_RESPONSE]), 0); } /* CWD command - Print out the current working directory. */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_CWD]) == 0) { printf("Receivied CWD command.\n"); char* dirToChangeTo = cmdTokens[1]; if ( strcmp( "." , dirToChangeTo ) == 0 ) { // change to current directory, so don't change anything and reply with success send(controlSocket, replies[REPLY_250_DIRCHANGE_SUCCESS], strlen(replies[REPLY_250_DIRCHANGE_SUCCESS]), 0); continue; } /* handle ".." CWD command */ if ( strcmp( ".." , dirToChangeTo ) == 0 ) { int len = strlen( dir ); assert( dir[len-1] == '/' ); // all dirs should have slash at end if ( strcmp( dir , properRootDir ) == 0 ) { printf("User tried to go above root directory.\n"); send(controlSocket, replies[REPLY_550_DIRCHANGE_FAILURE], strlen(replies[REPLY_550_DIRCHANGE_FAILURE]), 0); continue; } /* chomp the last dir off the end */ for (int i = len - 2; ; i--) { assert ( i > 0 ); if (dir[i] == '/') { dir[i+1] = '\0'; break; } } send(controlSocket, replies[REPLY_250_DIRCHANGE_SUCCESS], strlen(replies[REPLY_250_DIRCHANGE_SUCCESS]), 0); continue; } /* make sure dirToChange is a subdirectory of the current directory to prevent the user from jumping multiple directories with the dirToChangeTo string (this check especially important to the prevent the use of ".."s somewhere in the string which might allow the user to navigate above the root directory). */ DIR *dp; struct dirent *ep; bool entryExistsInCurrentDir; dp = opendir(dir); if (dp != NULL) { while ( ep = readdir(dp) ) if ( strcmp( ep->d_name, dirToChangeTo ) == 0) entryExistsInCurrentDir = true; closedir(dp); } else ExitError("For some reason the current directory doesn't exist, or opendir() failed for some other reason."); if ( entryExistsInCurrentDir == false ) { send(controlSocket, replies[REPLY_550_DIRCHANGE_FAILURE], strlen(replies[REPLY_550_DIRCHANGE_FAILURE]), 0); continue; } /* Finally, we have to make sure the file entry we found is actually a directory, not a regular file. */ sprintf(pathBuf, "%s%s%s", dir, dirToChangeTo, "/"); int fileInfo = GetFileInfo( pathBuf ); if ( fileInfo == FILEINFO_DIR ) { strcpy( dir, pathBuf ); send(controlSocket, replies[REPLY_250_DIRCHANGE_SUCCESS], strlen(replies[REPLY_250_DIRCHANGE_SUCCESS]), 0); } else { send(controlSocket, replies[REPLY_550_DIRCHANGE_FAILURE], strlen(replies[REPLY_550_DIRCHANGE_FAILURE]), 0); } } /* PASV command - Reply over the the control connection with the IP and port info of the data transfer connection listening IP and port, and then fork off the data transfer process (DTP) which will get a command from the control connection while listening for a connection from the user on the data transfer connection. Once the DTP gets the command over the control connectionit will do the specified command over the data connection once the user connects. */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_PASV]) == 0) { printf("Receivied PASV command.\n"); /* Create new listening socket */ const int DTP_MAX_BACKLOG_CONNECTIONS = 1; const uint16_t RANDOM_DTP_LISTEN_PORT = 49064; // HACK: for our random listening port we're just going to make a port number up int dataTransferListenSocket = CreateListenSocket( DTP_MAX_BACKLOG_CONNECTIONS, RANDOM_DTP_LISTEN_PORT, false, true ); /* Say Bert.CS.UIC.edu is 131.193.40.32 to the outside world. We want to get that address. */ char localHostName[MAXHOSTNAMELEN]; gethostname(localHostName, MAXHOSTNAMELEN); struct hostent* hostEntry = gethostbyname(localHostName); struct in_addr hostIPAddr = *(struct in_addr *)*hostEntry->h_addr_list;// TODO: make sure the first item in the list isn't 127.0.0.1 or something char* localIPString = inet_ntoa( hostIPAddr ); // points to the first entry in the list printf("PASV found IP: %s.\n", localIPString); /* Create the port string */ unsigned char h1, h2, h3, h4; unsigned char p1, p2; // HACK HACK: this stuff is not endian safe unsigned char* bytePtr = (unsigned char*)&hostIPAddr; h1 = bytePtr[0]; h2 = bytePtr[1]; h3 = bytePtr[2]; h4 = bytePtr[3]; bytePtr = (unsigned char*)&RANDOM_DTP_LISTEN_PORT; p2 = bytePtr[0]; // high byte p1 = bytePtr[1]; // low byte // port = p1 * 256 + p2 char pasvPortString[30]; // (xxx,yyy,zzz,www,ppp,nnn) sprintf(pasvPortString, "(%i,%i,%i,%i,%i,%i)", h1, h2, h3, h4, p1, p2); printf("Port value test: p1*256+p2 ?= port :: %d ?= %d.\n", p1*256+p2, RANDOM_DTP_LISTEN_PORT); printf("PASV string: %s.\n", pasvPortString); /* Send the PASV reply */ char pasvReply[200]; sprintf(pasvReply, replies[REPLY_227_PASSIVE_MODE], pasvPortString); send(controlSocket, pasvReply, strlen(pasvReply), 0); int dtp_pid = fork(); if ( !dtp_pid ) { /* Data Transfer Process (DTP) code */ printf("Created data transfer process.\n"); /* Get the next command from the control connection (RETR, STOR, LIST) */ ret = GetControlConnectionCmd( controlSocket, msgBuf, msgBufLen, MSG_BUF_MAX_SIZE, cmdTokens, numCmdTokens ); if (ret == 1) // control socket was closed for some reason { close(dataTransferListenSocket); // done with the listen socket exit(EXIT_FAILURE); } /* Accept the user connection */ struct sockaddr_in remoteAddr; int dataTransferSessionSocket = AcceptConnectionFromListenSocket(dataTransferListenSocket, &remoteAddr); printf("Data transfer process (DTP) received connection from %s\n", inet_ntoa(remoteAddr.sin_addr)); FTPDataTransferSession(controlSocket, dataTransferSessionSocket); close(dataTransferSessionSocket); // when done with the session close the socket close(dataTransferListenSocket); // close the listen socket too printf("Closing data transfer process.\n"); exit(EXIT_SUCCESS); // exit with success code } /* parent continues here */ close(dataTransferListenSocket); // parent doesn't need the this socket /* wait for the child process to complete */ waitpid( dtp_pid, NULL, 0 ); // TODO: check for things other than normal termination printf("Server-PI resuming execution.\n"); } /* TYPE command */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_TYPE]) == 0) { if ( strcmp(cmdTokens[1], "I") == 0 ) // binary { send(controlSocket, replies[REPLY_200_TYPE_SET_TO_I], strlen(replies[REPLY_200_TYPE_SET_TO_I]), 0); } else if ( strcmp(cmdTokens[1], "A") == 0 ) // ASCII { send(controlSocket, replies[REPLY_200_TYPE_SET_TO_A], strlen(replies[REPLY_200_TYPE_SET_TO_A]), 0); } else { // TODO: handle other stuff } } /* QUIT command */ else if (strcmp(cmdTokens[0], ftpCmds[FTPCMD_QUIT]) == 0) { printf("Receivied QUIT command.\n"); send(controlSocket, replies[REPLY_221_END_SESSION], strlen(replies[REPLY_221_END_SESSION]), 0); break; // break out of the loop } /* Unknown command */ else { printf("Receivied unknown command.\n"); send(controlSocket, replies[REPLY_500_UNKNOWN_COMMAND], strlen(replies[REPLY_500_UNKNOWN_COMMAND]), 0); } } /* Done */ printf("Ended FTP session from %s\n", inet_ntoa(remoteAddr.sin_addr)); }
/* Get the next command on the control connection socket (blocking until it comes), and parses the command */ int GetControlConnectionCmd(int controlSocket, char msgBuf[], int& msgBufLen, int MSG_BUF_MAX_SIZE, char* cmdTokens[], int& numCmdTokens) { /* Receive the next message on the control connection (blocks until next message is received). */ if ( ( msgBufLen = recv(controlSocket, msgBuf, MSG_BUF_MAX_SIZE, 0 ) ) == -1 ) ExitError("Error receiving control connection data."); if ( msgBufLen == 0 ) // recv() returns 0 if the remote side has closed the connection */ return 1; printf("Received Data:"); for (int i = 0; i < msgBufLen; i++) { //printf("byte %i: " i); printf(" '"); if (msgBuf[i] == '\n') printf("<LF>"); else if (msgBuf[i] == '\r') printf("<CR>"); else if (msgBuf[i] < 32 || msgBuf[i] > 126) printf("<0x%x>", msgBuf[i]); else putchar(msgBuf[i]); printf("'"); } printf(".\n"); /* Get rid of the trailing CR LF for processing the commands */ msgBuf[msgBufLen-2] = '\0'; msgBufLen--; printf("Command: %s\n", msgBuf); /* Tokenize strings */ char* token = strtok(msgBuf, " "); if (token == NULL) // found no delimiter to tokenize { /* if there are no space delimiters it must be a one word command */ cmdTokens[0] = msgBuf; numCmdTokens = 1; } else { /* there are space delimeters so we add all the tokens to our array of tokens */ cmdTokens[0] = token; numCmdTokens = 1; while ( (token = strtok(NULL, " ")) != NULL ) { cmdTokens[numCmdTokens] = token; numCmdTokens++; } } printf("Command tokens:"); for (int i = 0; i < numCmdTokens; i++) { printf(" \""); printf("%s", cmdTokens[i]); printf("\""); } printf(".\n"); return 0; }