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

익명 사용자의 이미지

세그맨테이션 결함뜨는게 뭐가 문제일까요..

#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);
 
 
}

익명 사용자의 이미지

memset, read, fgets, write함수를 사용하실 때 인자로 쓰여진 변수의 바이트 길이가 정확한 지 의심해 보세요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.