소켓 ftp 세그멘테이션 결함뜹니다.

글쓴이: 익명 사용자 / 작성시간: 화, 2013/04/16 - 2:46오후
세그맨테이션 결함뜨는게 뭐가 문제일까요..
#include <netinet/in.h> #include <arpa/inet.h> #include <strings.h> #include <unistd.h> #include <stdio.h> #include <pthread.h> #include <netdb.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /* 접속 FTP Sever 포트 설정 */ #define FTP_PORT 21 void* send_data_thread(void* sockfd); void* recv_ctrl_thread(void* sockfd); void* recv_data_thread(void* sockfd); void help(); void get_remote_port(char * message); void parse_filename(char * temp_buff, char * buff); void parse_commandname(char * temp_buff, char * buff); struct sockaddr_in ftp_send_addr; struct sockaddr_in ftp_recv_data_addr; int ftp_send_sockfd; /* 현재 진행명령에 대한 인덱스 : ls(1), put(2), get(3), cd(4) */ int command_index; /* 다운로드나 업로드 할 파일 이름 */ char file_name[1024]; char command_name[1024]; int main(int argc, char* argv[]) { pthread_t recv_thread; char cmd_ctrl_buff[1024] = {0}; char temp_buff[1024] = {0}; /* FTP Server에 대한 주소 및 포트 설정 */ ftp_send_addr.sin_family = AF_INET; ftp_send_addr.sin_port = htons(FTP_PORT); ftp_send_addr.sin_addr.s_addr = inet_addr(argv[1]); memset(&(ftp_send_addr.sin_zero), 0, 8); /* 서버 접속 소켓 생성 */ ftp_send_sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 서버 접속 및 초기 서버 응답 데이타 수신 */ connect(ftp_send_sockfd, (struct sockaddr*)&ftp_send_addr, sizeof(struct sockaddr_in)); memset(temp_buff, '\0', sizeof(temp_buff)); read(ftp_send_sockfd, temp_buff, sizeof(temp_buff)); printf("**Connect>%s\n", temp_buff); /* FTP서버 로그인 : 로그인 실패시 계속 로그인 시도 3번까지 가능함. 이후는 서버에서 파이프를 끊음 */ while(1) { printf("User Name:"); memset(temp_buff, '\0', sizeof(temp_buff)); fgets(temp_buff, sizeof(temp_buff), stdin); sprintf(cmd_ctrl_buff,"USER %s", temp_buff); /* FTP Command : USER 유저명 */ write(ftp_send_sockfd, cmd_ctrl_buff, strlen(cmd_ctrl_buff)); memset(temp_buff, '\0', sizeof(temp_buff)); read(ftp_send_sockfd, temp_buff, sizeof(temp_buff)); printf("**userlog id>%s\n", temp_buff); printf("Password:"); memset(temp_buff, '\0', sizeof(temp_buff)); fgets(temp_buff, sizeof(temp_buff), stdin); memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); /* FTP Command : PASS 패스워드 */ sprintf(cmd_ctrl_buff, "PASS %s", temp_buff); write(ftp_send_sockfd, cmd_ctrl_buff, strlen(cmd_ctrl_buff)); memset(temp_buff, '\0', sizeof(temp_buff)); read(ftp_send_sockfd, temp_buff, sizeof(temp_buff)); printf("**user login pass>%s\n", temp_buff); if (strncmp(temp_buff, "530", 3) == 0) continue; else break; } pthread_create(&recv_thread, NULL, recv_ctrl_thread, (void*)ftp_send_sockfd); help(); while(1) { memset(temp_buff, '\0', sizeof(temp_buff)); memset(cmd_ctrl_buff, '\0',sizeof(cmd_ctrl_buff)); printf("Command:"); /* 사용자로부터의 명령 입력 */ fgets(temp_buff, sizeof(temp_buff), stdin); /* ls 명령 처리 : 데이타 커넥션 생성 */ if (strncmp(temp_buff, "ls", 2) == 0 || strncmp(temp_buff, "dir", 3) == 0) { memset(temp_buff, '\0', sizeof(temp_buff)); /* passive 모드설정 */ sprintf(temp_buff, "pasv\n"); write(ftp_send_sockfd, temp_buff, strlen(temp_buff)); command_index = 1; memset(temp_buff, '\0', sizeof(temp_buff)); /* 접속된 현재의 디렉토리의 파일 리스트에 대한 명령 */ sprintf(temp_buff, "list -a\n"); write(ftp_send_sockfd, temp_buff, strlen(temp_buff)); sleep(1); } /* put 명령 처리 : 데이타 커넥션 생성 */ else if(strncmp(temp_buff, "put", 3) == 0) { /* 업로드할 파일명 파싱 */ temp_buff[strlen(temp_buff)-1] = '\0'; memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); parse_filename(temp_buff, cmd_ctrl_buff); memset(file_name, '\0', sizeof(file_name)); sprintf(file_name, "%s", cmd_ctrl_buff); memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); command_index = 2; /* passive 모드 설정 */ sprintf(cmd_ctrl_buff, "pasv\n"); write(ftp_send_sockfd, cmd_ctrl_buff, strlen(cmd_ctrl_buff)); sleep(1); } /* get 명령 처리 : 데이타 커넥션 생성 */ else if(strncmp(temp_buff, "get", 3) == 0) { temp_buff[strlen(temp_buff)-1] = '\0'; memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); /* passive 모드 설정 */ sprintf(cmd_ctrl_buff, "pasv\n"); write(ftp_send_sockfd, cmd_ctrl_buff, strlen(cmd_ctrl_buff)); command_index = 3; /* 다운로드할 파일명 파싱 */ memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); parse_filename(temp_buff, cmd_ctrl_buff); memset(file_name, '\0', sizeof(file_name)); sprintf(file_name, "%s", cmd_ctrl_buff); memset(temp_buff, '\0', sizeof(temp_buff)); /* 서버로의 명령 전달 retr 다운로드 파일명 */ sprintf(temp_buff, "retr %s\n", cmd_ctrl_buff); write(ftp_send_sockfd, temp_buff, strlen(temp_buff)); sleep(1); } /* help메뉴 */ else if (strncmp(temp_buff, "help", 4) == 0) { help(); } /* FTP 종료 */ else if (strncmp(temp_buff, "bye", 3) == 0) { memset(temp_buff, '\0', sizeof(temp_buff)); sprintf(temp_buff, "quit\n"); write(ftp_send_sockfd, temp_buff, strlen(temp_buff)); exit(0); } else if(strncmp(temp_buff, "cd", 2) == 0) { temp_buff[strlen(temp_buff)-1] = '\0'; memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); /* passive 모드 설정 */ sprintf(cmd_ctrl_buff, "pasv\n"); write(ftp_send_sockfd, cmd_ctrl_buff, strlen(cmd_ctrl_buff)); command_index = 4; memset(cmd_ctrl_buff, '\0', sizeof(cmd_ctrl_buff)); parse_commandname(temp_buff, cmd_ctrl_buff); printf("commandname is %s \n", temp_buff); memset(command_name, '\0', sizeof(command_name)); sprintf(command_name, "%s", cmd_ctrl_buff); memset(temp_buff, '\0', sizeof(temp_buff)); sprintf(temp_buff, "cd %s\n", cmd_ctrl_buff); write(ftp_send_sockfd, temp_buff, strlen(temp_buff)); sleep(1); } /* 그외 명령어 처리 : PWD, CWD */ else { write(ftp_send_sockfd, temp_buff, strlen(temp_buff)); sleep(1); } } return 0; } /* 사용자 입력으로 부터 파일명 파싱 ex)get lib.h => lib.h를 문자열로 저장 */ void parse_filename(char * temp_buff, char * buff) { int index = 3; int count = 0; for (; index < strlen(temp_buff); index++) { if (temp_buff<ol> </ol> == ' ') { continue; } else { buff[count] = temp_buff<ol> </ol> ; count++; } } } /* */ void parse_commandname(char * temp_buff, char * buff) { int index = 2; int count = 0; for (; index < strlen(temp_buff); index++) { if (temp_buff<ol> </ol> == ' ') { continue; } else { buff[count] = temp_buff<ol> </ol> ; count++; } } } /* 업로드 파일 전송 stor 업로드 파일 업로드할 파일을 열어 해당 파일을 data_buff에 담아서 서버로 전송 한번의 연결후 소켓 종료 */ void * send_data_thread(void* sockfd) { int fd; char data_buff[4096] = {0}; int data_size; fd = open(file_name, O_RDONLY); if (fd == -1) printf("send_data_thread**>no exist file\n"); else { sprintf(data_buff, "stor %s\n", file_name); write(ftp_send_sockfd,data_buff, strlen(data_buff)); while(1) { memset(data_buff, '\0', sizeof(data_buff)); data_size = read(fd, data_buff, sizeof(data_buff)); if (data_size == 0) break; else write((int)sockfd, data_buff, data_size); } } close((int)sockfd); close(fd); } /* 서버에서 수신되는 컨트롤 메세지가 아닌 실제 데이타에 대한 수신 처리 한번의 연결후 소켓 종료 */ void * recv_data_thread(void* sockfd) { int fd; char data_buff[4096] = {0}; int data_size; if (command_index == 3) fd = open(file_name, O_WRONLY|O_CREAT,0644); while(1) { memset(data_buff, '\0', sizeof(data_buff)); data_size = read((int)sockfd, data_buff, sizeof(data_buff)); if (data_size == 0) { break; } else { if (command_index == 1 || command_index ==4 ) printf("recv_data_thread**>%s\n", data_buff); else if (command_index == 3) { write(fd, data_buff, data_size); } } } close((int)sockfd); if (command_index == 3) close(fd); } /* 서버로 부터 수신되는 컨트롤 메세지 */ void * recv_ctrl_thread(void* sockfd) { char ctrl_buff[1024] = {0}; int msg_size; int temp_port; while(1) { memset(ctrl_buff, '\0', sizeof(ctrl_buff)); msg_size = read((int)sockfd, ctrl_buff, sizeof(ctrl_buff)); if (msg_size <= 0) continue; /* passive모드 설정을 위해서 227응답과 함께 서버로부터 해당 IP와 PORT가 전달된다. 클라이언트는 해당 IP와 PORT를 파싱하여 그쪽으로 접속을 한다. 이후 실제 데이타는 현재 연결된 커넥션으로 수신 및 송신된다 */ if (strncmp(ctrl_buff, "227", 3) == 0) { printf("122**>%s\n", ctrl_buff); get_remote_port(ctrl_buff); } /* 데이타 다운로드 실패응답 코드 실제 클라이언트에서는 다운로드시 먼저 로컬에 해당 파일을 생성하는데 다운로드 실패시는 해당 파일을 삭제하는 코드 */ else if (strncmp(ctrl_buff, "550", 3) == 0 && command_index == 3) { printf("recv_ctrl_fail**>%s\n", ctrl_buff); memset(ctrl_buff, '\0', sizeof(ctrl_buff)); sprintf(ctrl_buff, "rm -f %s", file_name); system(ctrl_buff); } else printf("*recv_ctrl_thread*>%s\n", ctrl_buff); } close((int)sockfd); printf("Exit Thread"); exit(0); } /* 도움말 */ void help() { printf("#########################################################\n"); printf("# #\n"); printf("# FTP Client Command #\n"); printf("# #\n"); printf("# 1. ls or dir : Show Directory File List #\n"); printf("# 2. get remote file name : Download File FTP Server #\n"); printf("# 3. put local file name?: Upload File FTP Server #\n"); printf("# 4. pwd : current location #\n"); printf("# 5. cwd : change directory location #\n"); printf("# 6. bye : quit FTP client #\n"); printf("# 7. help : Show Help Menu #\n"); printf("#########################################################\n"); } /* pasv명령시 서버로부터 227응답과 함께 서버의 IP와 PORT를 보내주는 데 이함수는 이 IP와 PORT를 파싱하여 해당 서버로 접속하는 역할을 한다 */ void get_remote_port(char * message) { pthread_t t; int index; int parse_start = 0; char ip_buff[512] = {0}; char port_buff1[10] = {0}; char port_buff2[10] = {0}; char cport_number[2]; int iport_number; char * ref_number; int comma_count = 0; int buff_count = 0; struct sockaddr_in connect_addr; int connect_fd; int connect_result; for (index = 0; index < strlen(message); index++) { if (message<ol> </ol> == '(') { parse_start = 1; continue; } else if (message<ol> </ol> == ')') break; if (parse_start == 1)/* addr process */ { if (message<ol> </ol> == ',') { comma_count++; if (comma_count == 4) { buff_count = 0; parse_start = 2; continue; } else { ip_buff[buff_count] = '.'; buff_count++; } } else { ip_buff[buff_count] = message<ol> </ol> ; buff_count++; } } if (parse_start == 2)/* port process */ { if (message<ol> </ol> == ',') { comma_count++; buff_count = 0; } else { if (comma_count == 5) { port_buff2[buff_count] = message<ol> </ol> ; buff_count++; } else { port_buff1[buff_count] = message<ol> </ol> ; buff_count++; } } } } /* 전달된 포트는 상위바이트와 하위 바이트가 뒤바뀐채로 온다. 여기에서 바로 잡아주는 역할을 한다 */ iport_number = (atoi(port_buff1)<<8) + atoi(port_buff2); /* 데이타를 전달을 위한 서버 접속 */ connect_addr.sin_family = AF_INET; connect_addr.sin_port = htons(iport_number); connect_addr.sin_addr.s_addr = inet_addr(ip_buff); memset(&(connect_addr.sin_zero), 0, 8); connect_fd = socket(AF_INET, SOCK_STREAM, 0); connect_result = connect(connect_fd, (struct sockaddr*)&connect_addr, sizeof(connect_addr)); /* 데이타 커넥션후 각 명령에 따라 서버로부터 수신을 전용으로 하는 쓰레드 서버로부터 송신을 전용으로하는 쓰레드가 따로 호출된다 ls 명령의 경우 수신 쓰레드, get명령의 경우 수신 쓰레더 put명령의 경우 송신 쓰레드 생성 */ if (command_index == 1 || command_index == 3 || command_index == 4) pthread_create(&t, NULL,recv_data_thread, (void*)connect_fd); else if (command_index == 2) pthread_create(&t, NULL,send_data_thread, (void*)connect_fd); }
Forums:
memset, read, fgets, write함수를
memset, read, fgets, write함수를 사용하실 때 인자로 쓰여진 변수의 바이트 길이가 정확한 지 의심해 보세요.
댓글 달기