/*! accept PASV connection for ftp session * * @param[in] session ftp session * * @returns -1 for failure */ static int ftp_session_accept(ftp_session_t *session) { int rc, new_fd; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); if(session->flags & SESSION_PASV) { /* clear PASV flag */ session->flags &= ~SESSION_PASV; /* tell the peer that we're ready to accept the connection */ ftp_send_response(session, 150, "Ready\r\n"); /* accept connection from peer */ new_fd = accept(session->pasv_fd, (struct sockaddr*)&addr, &addrlen); if(new_fd < 0) { console_print(RED "accept: %d %s\n" RESET, errno, strerror(errno)); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 425, "Failed to establish connection\r\n"); return -1; } rc = ftp_set_socket_nonblocking(new_fd); if(rc != 0) { ftp_closesocket(new_fd, 1); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 425, "Failed to establish connection\r\n"); return -1; } console_print(CYAN "accepted connection from %s:%u\n" RESET, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); ftp_session_set_state(session, DATA_TRANSFER_STATE); session->data_fd = new_fd; return 0; } else { /* peer didn't send PASV command */ ftp_send_response(session, 503, "Bad sequence of commands\r\n"); return -1; } }
static int store_transfer(ftp_session_t *session) { ssize_t rc; if(session->bufferpos == session->buffersize) { rc = recv(session->data_fd, session->buffer, sizeof(session->buffer), 0); if(rc <= 0) { if(rc < 0) { if(errno == EWOULDBLOCK) return -1; console_print(RED "recv: %d %s\n" RESET, errno, strerror(errno)); } ftp_session_close_file(session); ftp_session_set_state(session, COMMAND_STATE); if(rc == 0) { ftp_send_response(session, 226, "OK\r\n"); } else ftp_send_response(session, 426, "Connection broken during transfer\r\n"); return -1; } session->bufferpos = 0; session->buffersize = rc; } rc = ftp_session_write_file(session); if(rc <= 0) { ftp_session_close_file(session); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 451, "Failed to write file\r\n"); return -1; } session->bufferpos += rc; return 0; }
static int retrieve_transfer(ftp_session_t *session) { ssize_t rc; if(session->bufferpos == session->buffersize) { rc = ftp_session_read_file(session); if(rc <= 0) { ftp_session_close_file(session); ftp_session_set_state(session, COMMAND_STATE); if(rc < 0) ftp_send_response(session, 451, "Failed to read file\r\n"); else ftp_send_response(session, 226, "OK\r\n"); return -1; } session->bufferpos = 0; session->buffersize = rc; } rc = send(session->data_fd, session->buffer + session->bufferpos, session->buffersize - session->bufferpos, 0); if(rc <= 0) { if(rc < 0) { if(errno == EWOULDBLOCK) return -1; console_print(RED "send: %d %s\n" RESET, errno, strerror(errno)); } else console_print(YELLOW "send: %d %s\n" RESET, ECONNRESET, strerror(ECONNRESET)); ftp_session_close_file(session); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 426, "Connection broken during transfer\r\n"); return -1; } session->bufferpos += rc; return 0; }
int main(int argc, char **argv){ WSADATA wsa_data; SOCKET srv_soc = 0, acpt_soc; /* socket 句柄 */ struct sockaddr_in serv_addr; /* 服务器地址 */ struct sockaddr_in from_addr; /* 客户端地址 */ char recv_buf[FTP_BUF_SIZE]; unsigned short port = FTP_DEF_PORT; int from_len = sizeof(from_addr); int result = 0, recv_len; if (argc == 2) /* 端口号 */ port = atoi(argv[1]); WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 资源 */ srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */ if (srv_soc == INVALID_SOCKET) { printf("[FTP] socket() Fails, error = %d\n", WSAGetLastError()); return -1; } /* 服务器地址 */ serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (result == SOCKET_ERROR) /* 绑定失败 */ { closesocket(srv_soc); printf("[FTP Server] Fail to bind, error = %d\n", WSAGetLastError()); return -1; } result = listen(srv_soc, SOMAXCONN); printf("[FTP] The server is running ... ...\n"); //printf("%d\n",SOMAXCONN); while (1) { acpt_soc = accept(srv_soc, (struct sockaddr *) &from_addr, &from_len); if (acpt_soc == INVALID_SOCKET) /* 接受失败 */ { printf("[FTP] Fail to accept, error = %d\n", WSAGetLastError()); break; } printf("[FTP] Accepted address:[%s], port:[%d]\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port)); recv_len = recv(acpt_soc, recv_buf, FTP_BUF_SIZE, 0); char temp[1] ={'a'}; send(acpt_soc, temp, 1, 0); //getchar(); if (recv_len == SOCKET_ERROR) /* 接收失败 */ { // getchar(); closesocket(acpt_soc); printf("[FTP] Fail to recv, error = %d\n", WSAGetLastError()); break; } recv_buf[recv_len] = 0; /* 向客户端发送响应数据 */ result = ftp_send_response(acpt_soc, recv_buf, recv_len); closesocket(acpt_soc); } closesocket(srv_soc); WSACleanup(); printf("[FTP] The server is stopped.\n"); return 0; }
int main(int argc, char **argv) { WSADATA wsa_data; WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 资源 */ //web SOCKET web_srv_soc = 0; unsigned short web_port = HTTP_DEF_PORT; web_srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */ if (web_srv_soc == INVALID_SOCKET) { printf("[Web] socket() Fails, error = %d\n", WSAGetLastError()); return -1; } struct sockaddr_in web_serv_addr; /* 服务器地址 */ web_serv_addr.sin_family = AF_INET; web_serv_addr.sin_port = htons(web_port); web_serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); int result; result = bind(web_srv_soc, (struct sockaddr *) &web_serv_addr, sizeof(web_serv_addr)); if (result == SOCKET_ERROR) /* 绑定失败 */ { closesocket(web_srv_soc); printf("[Web Server] Fail to bind, error = %d\n", WSAGetLastError()); return -1; } result = listen(web_srv_soc, SOMAXCONN); printf("[Web] The server is running ... ...\n"); //FTP SOCKET ftp_srv_soc = 0; unsigned short ftp_port = FTP_DEF_PORT; ftp_srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */ if (ftp_srv_soc == INVALID_SOCKET) { printf("[FTP] socket() Fails, error = %d\n", WSAGetLastError()); return -1; } struct sockaddr_in ftp_serv_addr; /* 服务器地址 */ ftp_serv_addr.sin_family = AF_INET; ftp_serv_addr.sin_port = htons(ftp_port); ftp_serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); result = bind(ftp_srv_soc, (struct sockaddr *) &ftp_serv_addr, sizeof(ftp_serv_addr)); if (result == SOCKET_ERROR) /* 绑定失败 */ { closesocket(ftp_srv_soc); printf("[FTP Server] Fail to bind, error = %d\n", WSAGetLastError()); return -1; } result = listen(ftp_srv_soc, SOMAXCONN); printf("[FTP] The server is running ... ...\n"); fd_set afds; FD_ZERO(&afds); FD_SET(web_srv_soc, &afds); FD_SET(ftp_srv_soc, &afds); fd_set rfds; SOCKET web_conn_soc; SOCKET ftp_conn_soc; while(1) { FD_ZERO(&rfds); memcpy(&rfds, &afds, sizeof(rfds)); if(select(FD_SETSIZE, &rfds, (fd_set*)0, (fd_set*)0, (struct timeval *)0)== SOCKET_ERROR) printf("select error\n"); if(FD_ISSET(web_srv_soc, &rfds)) { struct sockaddr_in conn_addr; /* 客户端地址 */ int conn_addr_len = sizeof(conn_addr); web_conn_soc = accept(web_srv_soc, (struct sockaddr*)&conn_addr,&conn_addr_len); if(web_conn_soc == INVALID_SOCKET) { printf("[Web] Fail to accept, error = %d\n", WSAGetLastError()); break; } printf("[Web] Accepted address:[%s], port:[%d]\n", inet_ntoa(conn_addr.sin_addr), ntohs(conn_addr.sin_port)); char recv_buf[BUF_SIZE]; int recv_len; recv_len = recv(web_conn_soc, recv_buf, BUF_SIZE, 0); if (recv_len == SOCKET_ERROR) /* 接收失败 */ { closesocket(web_conn_soc); printf("[Web] Fail to recv, error = %d\n", WSAGetLastError()); break; } recv_buf[recv_len] = 0; /* 向客户端发送响应数据 */ http_send_response(web_conn_soc, recv_buf, recv_len); closesocket(web_conn_soc); } if(FD_ISSET(ftp_srv_soc, &rfds)) { struct sockaddr_in conn_addr; /* 客户端地址 */ int conn_addr_len = sizeof(conn_addr); ftp_conn_soc = accept(ftp_srv_soc, (struct sockaddr*)&conn_addr,&conn_addr_len); if(ftp_conn_soc == INVALID_SOCKET) { printf("[FTP] Fail to accept, error = %d\n", WSAGetLastError()); break; } printf("[FTP] Accepted address:[%s], port:[%d]\n", inet_ntoa(conn_addr.sin_addr), ntohs(conn_addr.sin_port)); char recv_buf[BUF_SIZE]; int recv_len; recv_len = recv(ftp_conn_soc, recv_buf, BUF_SIZE, 0); if (recv_len == SOCKET_ERROR) /* 接收失败 */ { closesocket(ftp_conn_soc); printf("[FTP] Fail to recv, error = %d\n", WSAGetLastError()); break; } recv_buf[recv_len] = 0; /* 向客户端发送响应数据 */ ftp_send_response(ftp_conn_soc, recv_buf, recv_len); closesocket(ftp_conn_soc); } } closesocket(web_srv_soc); closesocket(ftp_srv_soc); WSACleanup(); printf("[web] The server is stopped.\n"); printf("[FTP] The server is stopped.\n"); return 0; }
/*! poll sockets for ftp session * * @param[in] session ftp session * * @returns next session */ static ftp_session_t* ftp_session_poll(ftp_session_t *session) { int rc; struct pollfd pollinfo; switch(session->state) { case COMMAND_STATE: /* we are waiting to read a command */ pollinfo.fd = session->cmd_fd; pollinfo.events = POLLIN; pollinfo.revents = 0; break; case DATA_CONNECT_STATE: /* we are waiting for a PASV connection */ pollinfo.fd = session->pasv_fd; pollinfo.events = POLLIN; pollinfo.revents = 0; break; case DATA_TRANSFER_STATE: /* we need to transfer data */ pollinfo.fd = session->data_fd; if(session->flags & SESSION_RECV) pollinfo.events = POLLIN; else pollinfo.events = POLLOUT; pollinfo.revents = 0; break; } /* poll the selected socket */ rc = poll(&pollinfo, 1, 0); if(rc < 0) console_print(RED "poll: %d %s\n" RESET, errno, strerror(errno)); else if(rc > 0) { if(pollinfo.revents != 0) { /* handle event */ switch(session->state) { case COMMAND_STATE: if(pollinfo.revents & POLL_UNKNOWN) console_print(YELLOW "cmd_fd: revents=0x%08X\n" RESET, pollinfo.revents); /* we need to read a new command */ if(pollinfo.revents & (POLLERR|POLLHUP)) ftp_session_close_cmd(session); else if(pollinfo.revents & POLLIN) ftp_session_read_command(session); break; case DATA_CONNECT_STATE: if(pollinfo.revents & POLL_UNKNOWN) console_print(YELLOW "pasv_fd: revents=0x%08X\n" RESET, pollinfo.revents); /* we need to accept the PASV connection */ if(pollinfo.revents & (POLLERR|POLLHUP)) { ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 426, "Data connection failed\r\n"); } else if(pollinfo.revents & POLLIN) { if(ftp_session_accept(session) != 0) ftp_session_set_state(session, COMMAND_STATE); } break; case DATA_TRANSFER_STATE: if(pollinfo.revents & POLL_UNKNOWN) console_print(YELLOW "data_fd: revents=0x%08X\n" RESET, pollinfo.revents); /* we need to transfer data */ if(pollinfo.revents & (POLLERR|POLLHUP)) { ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 426, "Data connection failed\r\n"); } else if(pollinfo.revents & (POLLIN|POLLOUT)) ftp_session_transfer(session); break; } } } /* still connected to peer; return next session */ if(session->cmd_fd >= 0) return session->next; /* disconnected from peer; destroy it and return next session */ return ftp_session_destroy(session); }
/*! read command for ftp session * * @param[in] session ftp session */ static void ftp_session_read_command(ftp_session_t *session) { static char buffer[CMD_BUFFERSIZE]; ssize_t rc; char *args; ftp_command_t key, *command; memset(buffer, 0, sizeof(buffer)); /* retrieve command */ rc = recv(session->cmd_fd, buffer, sizeof(buffer), 0); if(rc < 0) { /* error retrieving command */ console_print(RED "recv: %d %s\n" RESET, errno, strerror(errno)); ftp_session_close_cmd(session); return; } if(rc == 0) { /* peer closed connection */ ftp_session_close_cmd(session); return; } else { /* split into command and arguments */ /* TODO: support partial transfers */ buffer[sizeof(buffer)-1] = 0; args = buffer; while(*args && *args != '\r' && *args != '\n') ++args; *args = 0; args = buffer; while(*args && !isspace((int)*args)) ++args; if(*args) *args++ = 0; /* look up the command */ key.name = buffer; command = bsearch(&key, ftp_commands, num_ftp_commands, sizeof(ftp_command_t), ftp_command_cmp); /* execute the command */ if(command == NULL) { ftp_send_response(session, 502, "invalid command -> %s %s\r\n", key.name, args); } else { /* clear RENAME flag for all commands except RNTO */ if(strcasecmp(command->name, "RNTO") != 0) session->flags &= ~SESSION_RENAME; command->handler(session, args); } } }
/*! allocate new ftp session * * @param[in] listen_fd socket to accept connection from */ static void ftp_session_new(int listen_fd) { ssize_t rc; int new_fd; ftp_session_t *session; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); /* accept connection */ new_fd = accept(listen_fd, (struct sockaddr*)&addr, &addrlen); if(new_fd < 0) { console_print(RED "accept: %d %s\n" RESET, errno, strerror(errno)); return; } console_print(CYAN "accepted connection from %s:%u\n" RESET, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); /* allocate a new session */ session = (ftp_session_t*)malloc(sizeof(ftp_session_t)); if(session == NULL) { console_print(RED "failed to allocate session\n" RESET); ftp_closesocket(new_fd, 1); return; } /* initialize session */ memset(session->cwd, 0, sizeof(session->cwd)); strcpy(session->cwd, "/"); session->peer_addr.sin_addr.s_addr = INADDR_ANY; session->cmd_fd = new_fd; session->pasv_fd = -1; session->data_fd = -1; session->flags = 0; session->state = COMMAND_STATE; session->next = NULL; session->prev = NULL; session->transfer = NULL; /* link to the sessions list */ if(sessions == NULL) { sessions = session; session->prev = session; } else { sessions->prev->next = session; session->prev = sessions->prev; sessions->prev = session; } /* copy socket address to pasv address */ addrlen = sizeof(session->pasv_addr); rc = getsockname(new_fd, (struct sockaddr*)&session->pasv_addr, &addrlen); if(rc != 0) { console_print(RED "getsockname: %d %s\n" RESET, errno, strerror(errno)); ftp_send_response(session, 451, "Failed to get connection info\r\n"); ftp_session_destroy(session); return; } session->cmd_fd = new_fd; /* send initiator response */ rc = ftp_send_response(session, 200, "Hello!\r\n"); if(rc <= 0) ftp_session_destroy(session); }
static int list_transfer(ftp_session_t *session) { ssize_t rc; if(session->bufferpos == session->buffersize) { struct stat st; struct dirent *dent = readdir(session->dp); if(dent == NULL) { ftp_session_close_cwd(session); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 226, "OK\r\n"); return -1; } if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) return 0; if(strcmp(session->cwd, "/") == 0) snprintf(session->buffer, sizeof(session->buffer), "/%s", dent->d_name); else snprintf(session->buffer, sizeof(session->buffer), "%s/%s", session->cwd, dent->d_name); rc = lstat(session->buffer, &st); if(rc != 0) { console_print(RED "stat '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno)); ftp_session_close_cwd(session); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 550, "unavailable\r\n"); return -1; } session->buffersize = sprintf(session->buffer, "%crwxrwxrwx 1 3DS 3DS %llu Jan 1 1970 %s\r\n", S_ISDIR(st.st_mode) ? 'd' : S_ISLNK(st.st_mode) ? 'l' : '-', (unsigned long long)st.st_size, dent->d_name); session->bufferpos = 0; } rc = send(session->data_fd, session->buffer + session->bufferpos, session->buffersize - session->bufferpos, 0); if(rc <= 0) { if(rc < 0) { if(errno == EWOULDBLOCK) return -1; console_print(RED "send: %d %s\n" RESET, errno, strerror(errno)); } else console_print(YELLOW "send: %d %s\n" RESET, ECONNRESET, strerror(ECONNRESET)); ftp_session_close_cwd(session); ftp_session_set_state(session, COMMAND_STATE); ftp_send_response(session, 426, "Connection broken during transfer\r\n"); return -1; } session->bufferpos += rc; return 0; }