int nfds;
int max_nfds;
}; // 실행된 커맨드들의 응답 대기를 위한 pool 구조체
ssh2_manager 구조체는 아래와 같이 초기화된다.
// addr : 원격 Server의 주소.
// cmd : 원격 Server에서 실행할 명령
// linkage : 별도의 데이터 저장이 필요한 경우 사용
struct ssh2_manager *ssh2_new_manager(unsigned long addr, char *cmd, void *linkage)
{
struct ssh2_manager *stm;
ssh2_manager 구조체를 초기화 한 후에, cmd로 입력된 명령을 원격 Server에서 실행하게 하는 명령이다.
int ssh2_execute(struct ssh2_manager *stm)
{
struct sockaddr_in sin;
int retval = 0;
stm->sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22); // 원격 port는 항상 22를 가정했다.
sin.sin_addr.s_addr = stm->addr;
if (connect(stm->sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) { // 원격 Server로 기본 socket을 연결한다.
return -1;
}
// libssh2의 초기화 과정에는 libssh와는 다르게, 이와 같이 별도로 Socket을 생성하여 원격 Server에 연결한 이후 해당 Socket을 입력받아 초기화를 수행한다.
stm->session = libssh2_session_init();
if (libssh2_session_startup(stm->session, stm->sock)) {
return -2;
}
// 별도로 제작한 인증 관련 함수이다. 각종 key와 관련된 사항들이 문자열로 입력된다.
if (libssh2_userauth_publickey_fromstring(stm->session, "root", PUBLIC_KEY_STRING, PUBLIC_KEY_STRING_LEN, PRIVATE_KEY_STRING, KEY_PASSWORD)) {
retval = -3;
goto shutdown;
}
// session에서 channel을 할당 받는다. 이 channel을 통하여 커맨드를 주고 받는다.
if (!(stm->channel = libssh2_channel_open_session(stm->session))) {
retval = -4;
goto shutdown;
}
// channel을 규정한다. vanilla는 terminal의 일종인듯 하다. (예제에서 그대로 복사한 것이다!)
if (libssh2_channel_request_pty(stm->channel, "vanilla")) {
retval = -5;
goto shutdown;
}
// channel을 nonblock 모드로 설정한다. (라고 알고 있다.)
libssh2_channel_set_blocking(stm->channel, 0); // channel을 통해서 명령을 내린다.
if (libssh2_channel_exec(stm->channel, stm->cmd)) {
retval = -6;
goto shutdown;
}
return retval;
shutdown:
ssh2_shutdown(stm);
return retval;
}
여기까지 명령을 내린 과정 되겠다. 이렇게 명령을 내린 이후에는 Interactive한 처리를 위해 결과가 필요하다. libssh2는 이를 위해 libssh2_poll이라는 함수를 제공한다.
명령을 내리고 응답을 기다리는 ssh2_manager 구조체들을 관리하고 응답이 왔는지 확인시켜주는 용도로 ssh2_poller라는 구조체를 초기화한다.
#define POLLER_NUMBER_GUIDE 10
struct ssh2_poller *ssh2_new_poller(struct ssh2_poller *stp, struct ssh2_manager *stm)
{
if (stp == NULL) { // 최초 stp가 NULL일 경우 초기화한다.
stp = (struct ssh2_poller *)malloc(sizeof(struct ssh2_poller));
stp->pollfds = (LIBSSH2_POLLFD *)malloc(sizeof(LIBSSH2_POLLFD) * POLLER_NUMBER_GUIDE);
memset((char *)stp->pollfds, 0, sizeof(LIBSSH2_POLLFD) * POLLER_NUMBER_GUIDE);
stp->nfds = 0;
stp->max_nfds = POLLER_NUMBER_GUIDE;
}
if ((stp->nfds + 1) >= stp->max_nfds) { // stp가 존재하고, 그 Capacity가 넘어갔을 경우, Capacity를 POLLER_NUMBER_GUIDE 만큼 증가시킨다.
LIBSSH2_POLLFD *newpollfds;
위 함수가 NULL이 아닌 응답을 주었다면, 해당 ssh2_manager 구조체를 통해 명령을 받은 원격 Server에서 메시지가 도착한 것이다. 해당 메시지를 받아보자.
// 역시 별로 코멘트가 필요하지 않다;
int ssh2_result(struct ssh2_manager *stm, char *so_buf, int so_len, char *se_buf, int se_len)
{
int retval = 0;
int readlen = 0;