#include "winsock2.h"
#include "stdio.h"

#pragma comment( lib, "ws2_32.lib" )

#define BUFMAX 256

void err_handler(char *);
DWORD WINAPI Connection(LPVOID);

int main(int argc, char **argv)
{
  int retval;        // 임시로 값을 받을 정수형 변수
  HANDLE hThread;      // 스레드를 받을 핸들
  DWORD ThreadId;      // 스레드 ID를 받을 변수
 
  // 윈속 초기화
  // WSAStartup을 통해서 ws2_32.dll을 로딩하여 윈속을 사용할 수 있도록 초기화 함.
  WSADATA wsa;
  if( WSAStartup( MAKEWORD(2, 2), &wsa ) != 0)
  {
    return -1;            // 윈속 초기화 실패시 종료(-1)
  }
 
  // 소켓 생성 socket()
  SOCKET serv_sock = socket(AF_INET, SOCK_STREAM, 0);
  if( serv_sock == INVALID_SOCKET ) err_handler("socket()");
 
  // bind()
  SOCKADDR_IN serv_addr;
  ZeroMemory( &serv_addr, sizeof(serv_addr) );
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(9000);
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
  retval = bind(serv_sock, (SOCKADDR *)&serv_addr, sizeof(serv_addr));
  if( retval == SOCKET_ERROR ) err_handler("bind()");
 
  // listen()
  retval = listen( serv_sock, SOMAXCONN );
  if(retval == SOCKET_ERROR) err_handler("listen()");
 
  // 클라이언트에 사용될 변수 선언
  SOCKET clnt_sock;
  SOCKADDR_IN clnt_addr;
  int clnt_addr_size;
 
  while(TRUE)
  {
    //accept()
    clnt_addr_size = sizeof(clnt_addr);
    clnt_sock = accept( (SOCKET)serv_sock, (SOCKADDR *)&clnt_addr, &clnt_addr_size );
    if( clnt_sock == INVALID_SOCKET )
    {
      err_handler("accept()");
      continue;        // accept 실패하면 다시 accept에서 대기
    }
   
    // Thread 생성
    hThread = CreateThread( NULL, 0, Connection, (LPVOID)clnt_sock, 0, &ThreadId );
    if( hThread == NULL ) err_handler("Could not create Thread.");
  }
 
  // 소켓 닫기
  closesocket( serv_sock );
 
  // WSA 닫기
  WSACleanup();
 
  return 0;
}

void err_handler(char *msg)
{
  printf("%s에서 에러가 발생하였습니다!\n", msg);
}

DWORD WINAPI Connection(LPVOID arg)
{
  SOCKET clnt_sock = (SOCKET)arg;
  int retval = 0;            // 임시로 결과값을 저장하기 위한 변수
  bool onoff = false;          // 서버를 시작하는데 필요한 변수(onoff 스위치)
  char buffer[BUFMAX+1] = {0};    // 소켓에서 사용할 버퍼
  char bufpw[BUFMAX+1] = {0};      // 패스워드와 명령어를 임시적으로 저장하기 위한 버퍼
  char file_buffer[BUFMAX+1] = {0}// 파일 전송을 위해 사용할 버퍼
 
  // clnt_sock <- 클라이언트 소켓만 가지고 getpeername을 이용해서
  // 클라이언트의 아이피와 포트번호를 알아낸다.
  SOCKADDR_IN clnt_addr;
  int clnt_addr_size = sizeof( clnt_addr );
 
  ZeroMemory( &clnt_addr, clnt_addr_size );
  getpeername( clnt_sock, (SOCKADDR *)&clnt_addr, &clnt_addr_size );
 
  // 패스워드 묻는 과정을 3번하기 위한 for 문장
  for( int i = 0; i < 3; i++ )
  {
    ZeroMemory( bufpw, sizeof(bufpw) );    // 패스워드를 받기 위한 버퍼 초기화
   
    printf("%s:%d에 패스워드를 요청합니다.\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
   
    // 패스워드 묻는 프롬프트 출력(-> 클라이언트 화면)
    strcpy( buffer, "\r\npassword : " );
    retval = send( clnt_sock, buffer, BUFMAX, 0 );
    if( retval == SOCKET_ERROR )
    {
      err_handler("send()");        // 에러출력 함수에 send() 값 전달
      closesocket( clnt_sock );
      return -1;
    }
   
    // 클라이언트에서 패스워드를 받아서 bufpw에 담는 부분
    while( TRUE )
    {
      retval = recv( clnt_sock, buffer, BUFMAX, 0 );
      if( retval == SOCKET_ERROR ) err_handler("passwd recv()");
     
      if( buffer[retval-1] == '\n' ) break;        // 엔터를 입력하면 빠져 나감.
      else strncat( bufpw, buffer, retval );
    }
   
    printf("패스워드를 입력받습니다 : %s\n", bufpw);
   
    // 입력받은 패스워드 비교 부분
    char *password = "mypass";
    int password_size = (int)strlen(password);
    int bufpw_size = (int)strlen(bufpw);
   
    // 길이를 먼저 비교해보고 맞으면 길이만큼 패스워드 비교
    // 패스워드가 맞으면 onoff = true 넣어주고, 틀리면 계속 진행
    // printf("bufpw %d, password %d\n", bufpw_size, password_size);
    if( !((bufpw_size == password_size) && (strncmp(bufpw, password, password_size) == 0)) ) continue;
    else
    {
      onoff = true;            // 서버를 시작하기 위해 true 값을 설정
      break;                    // 패스워드 3회 체크 for문 탈출
    }
   
  } // for 패스워드 3회 비교 부분
 
  // 서버 시작부분 if 문
  if( onoff == true )
  {
    // 클라이언트측에 환영 메시지 표시
    char *welcome = "\r\nWelcome to Telnet server!\r\n";
    retval = send(clnt_sock, welcome, (int)strlen(welcome), 0);
    if( retval == SOCKET_ERROR ) err_handler("send to client end of line()");
   
    // bufpw 버퍼를 명령어 버퍼로 재활용합니다.
    ZeroMemory( bufpw, sizeof(bufpw) );
   
    while( TRUE )
    {
      // buffer 버퍼를 초기화합니다.(초기화하지 않으면 쓰레기값이 많음)
      ZeroMemory( buffer, sizeof(buffer) );
     
      // recv()
      retval = recv( clnt_sock, buffer, BUFMAX, 0 );
      if( retval == SOCKET_ERROR )
      {
        err_handler("recv()");        // 에러출력 함수에 recv() 전달
        break;
      }
      else if(retval == 0) break;        // (retval == 0 정상 소켓 종료)
     
      buffer[retval] = '\0';            // ZeroMemory 해서 하지 않아도 되지만 정석으로 하는 과정임.
     
      //------------------------------------------------------//
      // 위의 패스워드 입력 버퍼 복사 부분처럼                //
      // while 문으로 쓰지 않아도 아래 if 문장이 엔터 입력을    //
      // 받지 않으면 루프 반복되어서 while문을 따로 쓰지 않음.//
      //------------------------------------------------------//
     
      // buffer를 bufpw(명령어버퍼)에 복사한다.
      strncat( bufpw, buffer, retval );
     
      printf("%s", buffer);
     
      // ---------------------------------------------------------------- //
      // 엔터가 입력되면 네트워크로 \r\n 패킷이 온다.                        //
      // 엔터 패킷만 왔을때에는 buffer[0]='\r', buffer[1]='\n'이 된다.    //
      // ---------------------------------------------------------------- //
      if( buffer[retval-1] == '\n' )
      {
        // 엔터명령을 받은후 명령어 출력
        printf( "입력받은 명령어 : %s", bufpw );
       
        // 명령어 해석 / 실행 / 결과 전송
        if( strncmp(bufpw, "exit", 4) == 0)
        {
          strcat( buffer, "<exit 명령어 실행 완료>" );    // 메시지 설정
         
          strcat( buffer, "\r\n" );        // 클라이언트로 보낼 버퍼에 완료 메시지
          printf( "%s\n", buffer );        // 서버에 완료 메시지 출력
          retval = (int)strlen( buffer );    // 메시지 사이즈에 버퍼 크기를 맞춘다.
         
          closesocket( clnt_sock );    // 소켓을 닫는다.
          break;
        } // if (exit 명령)
       
        else if( strncmp(bufpw, "netstat", 7) == 0)
        {
          ShellExecute( NULL, "open", "cmd.exe", "/c netstat -an > netstat.txt", "c:\\", SW_HIDE );
          strcat( buffer, "<netstat 명령어 실행 완료>" );    // 메시지 설정
         
          strcat( buffer, "\r\n" );        // 클라이언트로 보낼 버퍼에 완료 메시지
          printf( "%s\n", buffer );        // 서버에 완료 메시지 출력
          retval = (int)strlen(buffer);    // 메시지 사이즈에 버퍼 크기를 맞춘다.
         
          FILE *read_file = fopen( "c:\\netstat.txt", "r" );// 읽을 파일의 포인터 선언
         
          Sleep(1000);    // 1초간 딜레이를 두어서 파일이 생성되기를 기다린다.
         
          // 파일이 생성되지 않았을때 클라이언트에 메시지 출력
          if (read_file == NULL)
          {
            char *msg = "결과 파일이 생성에 실패하였습니다.\r\n다시 시도해 주십시오.\r\n";
            retval = send(clnt_sock, msg, (int)strlen(msg), 0);
            if(retval == SOCKET_ERROR)
            {
              err_handler("netstat()");
              break;
            }
          }
          // 파일이 생성되었을 경우에 파일 내용을 보냄
          else
          {
            while( (fgets(file_buffer, BUFMAX, read_file) != 0) )
            {
              strcat( file_buffer, "\r" );    // 한 라인이 끝나고 줄바꿈 표시
             
              retval = send( clnt_sock, file_buffer, (int)strlen(file_buffer), 0 );
              if( retval == SOCKET_ERROR )
              {
                err_handler("netstat()");
                break;
              }
             
            } // while (fgets)
           
          } // if_else 문장(파일 유무에 따른 절차)
         
          fclose(read_file);
         
        } // else if (netstat 명령)
       
        //--------------------------------------------------//
        // 명령어 수행 후 명령어 버퍼 초기화 및 계속 진행  //
        // while() 시작에 초기화를 하면 되지만,        //
        // 이해를 돕기위해 명령어 수행 후 바로 버퍼 초기화  //
        //--------------------------------------------------//
        ZeroMemory( bufpw, sizeof(bufpw) );
      }
     
      // send()
      retval = send( clnt_sock, buffer, retval, 0 );
      if( retval == SOCKET_ERROR )
      {
        err_handler("send()");
        break;
      }
     
    } // while문 recv() send()

  } // if onoff 서버 본문

  printf( "%s:%d에서의 클라이언트 연결을 끊습니다.\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port) );
  closesocket( clnt_sock );

  return 0;
}

 
2006/05/13 23:17 2006/05/13 23:17

글 걸기 주소 : 이 글에는 트랙백을 보낼 수 없습니다

덧글을 달아 주세요