linux c sftp二次封装库

前言

本项目是基于linux c ssh、openssl标准库来开发sftp软件通信模块

本项目是对ssh、openssl标准库进行一个高层封装,使得可以在 Linux 上非常容易的执行调用,方便开发者使用,实现sftp文件上传、下载等操作.

一、openssl编译

由于libssh编译时会引用到openssl的libcrypto.a、libssl.a开发库,所以先编译该开源库编译步骤如下所示:

1.模块configure配置

./Configure linux-aarch64 --cross-compile-prefix=/usr/bin/aarch64-linux-gnu- --prefix=/home/data/openssl

2.make & make install

二、libssh2编译

1.模块configure配置

引用openssl编译出来的库,设置库路径

./configure  CC=/usr/bin/aarch64-linux-gnu-gcc --prefix=/home/buildlib --host=aarch64-linux-gnu --with-libssl-prefix=/home/data/openssl LDFLAGS="-Wl,-rpath-link,/home/data/openssl/lib64"

2.make & make install

生成库在/home/buildlib下。

 三、sftp二次开发模块封装

1.头文件内容如下

#ifndef __SFTP_H__
#define __SFTP_H__

void *SFTP_Init(const char *pDstIp, int iPort, int *pSocket);
void *SFTP_Login(void *session, int iSocket, const char *pUserName, const char *pPassword);
int SFTP_PutFile(void *ssh2Session, void *sftpSession, int iSocket, 
		const char *pSrcpath, const char *pDstpath);
int SFTP_GetFile(void *ssh2Session, void *sftpSession, int Socket, 
		const char *pSrcpath, const char *pLocalpath);
void SFTP_SocketClose(int iSocket);
void SFTP_SftpSessionclose(void *sftpSession);
void SFTP_SshSessionClose(void *ssh2Session);
void SFTP_Exit();

#endif

2、函数体

函数体实现如下所示:

#include <stdio.h>
#include "libssh2.h"
#include "libssh2_sftp.h"
#include "libssh2_publickey.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>

#include "sftp.h"

static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
    struct timeval timeout;
    int rc;
    fd_set fd;
    fd_set *writefd = NULL;
    fd_set *readfd = NULL;
    int dir;
 
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;
 
    FD_ZERO(&fd);
 
    FD_SET(socket_fd, &fd);
 
    /* now make sure we wait in the correct direction */ 
    dir = libssh2_session_block_directions(session);

    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
        readfd = &fd;
 
    if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
        writefd = &fd;
 
    rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
 
    return rc;
}


void *SFTP_Init(const char *pDstIp, int iPort, int *pSocket)
{
	int iRet = -1;
	int iSocketFd = -1;

	int iErr = -1;
	fd_set writeSet, exceptSet;
	struct timeval wait;
	int iSocketError;
	socklen_t errorLen = sizeof(iSocketError);
	
	const char *fingerprint;
	struct sockaddr_in sin;
	LIBSSH2_SESSION *session;

	*pSocket = -1;
	iRet = libssh2_init(0);

    if(iRet != 0) {
        printf("[%s]libssh2 initialization failed (%d)\n", __FUNCTION__, iRet);
        return NULL;
    }

	 /*
     * The application code is responsible for creating the socket
     * and establishing the connection
     */ 
    iSocketFd = socket(AF_INET, SOCK_STREAM, 0);
	if(iSocketFd < 0)
	{
		printf("[%s]create socket failed!\n", __FUNCTION__);
		return NULL;
	}

	int flags = fcntl(iSocketFd, F_GETFL, 0);
	if(-1 == fcntl(iSocketFd, F_SETFL, flags | O_NONBLOCK))
	{
		perror("Set socket unblock failed!");
	}

	sin.sin_family = AF_INET;
    sin.sin_port = htons(iPort);
    sin.sin_addr.s_addr = inet_addr(pDstIp);
    if (connect(iSocketFd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
		// 返回以下的标识,标识这个连接正在等待服务器accept
		if((errno != EINPROGRESS)&&(errno != EWOULDBLOCK))/* connection in progress */
		{
			close(iSocketFd);
			return NULL;
		}

		FD_ZERO(&writeSet);
		FD_SET(iSocketFd, &writeSet);
		FD_SET(iSocketFd, &exceptSet);
		wait.tv_sec = 3;
		wait.tv_usec = 0;
		iErr = select(iSocketFd+1, NULL, &writeSet, &exceptSet, &wait);
		if (iErr <= 0)    //出错
		{
			close(iSocketFd);
			return NULL;
		}

		if (FD_ISSET(iSocketFd, &writeSet))
		{
			// 判断socket是否已经连接,如果已经连接iSocketError=0
			iErr = getsockopt(iSocketFd, SOL_SOCKET, SO_ERROR, (void *)&iSocketError, &errorLen); 								
			if((iErr == 0)&& (iSocketError == 0))
			{
				/* connect success! */	
			}
			else 
			{
				close(iSocketFd);
				return NULL;
			}
		}

		if (FD_ISSET(iSocketFd, &exceptSet))
		{
			close(iSocketFd);
			return NULL;
		}
    }
	
	/* Create a session instance
     */ 
    session = libssh2_session_init();
    if(!session)
    {
    	printf("[%s]libssh2_session_init failed!\n", __FUNCTION__);
		return NULL;
	}

	/* set non-blocking, tell ~0 blocking 0:non-blocking */ 
    libssh2_session_set_blocking(session, 0);
	
    /* ... start it up. This will trade welcome banners, exchange keys,
     * and setup crypto, compression, and MAC layers
     */ 
	while((iRet = libssh2_session_handshake(session, iSocketFd))
           == LIBSSH2_ERROR_EAGAIN);
    if(iRet) {
        libssh2_session_disconnect(session,
			"Normal Shutdown, Thank you for playing");
    	libssh2_session_free(session);
        printf("[%s]Failure establishing SSH session: %d\n",__FUNCTION__, iRet);
        return NULL;
    }
 
    /* At this point we havn't yet authenticated.  The first thing to do
     * is check the hostkey's fingerprint against our known hosts Your app
     * may have it hard coded, may go to a file, may present it to the
     * user, that's your call
     */ 
    fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);

    printf("Fingerprint: ");
	int i;
    for(i = 0; i < 20; i++) {
        printf("%02X ", (unsigned char)fingerprint[i]);
    }
    printf("\n");
	*pSocket = iSocketFd;
	return (void *)session;
}


void *SFTP_Login(void *session, int iSocket, const char *pUserName, const char *pPassword)
{
	int rc = 0;
	int iRet = 0;
	LIBSSH2_SFTP *sftp_session;
	LIBSSH2_SESSION *sshSession = (LIBSSH2_SESSION *)session;
	
	if(NULL == session)	
	{
		printf("[%s] ssh session is null!\n", __FUNCTION__);
		return NULL;
	}

	 while((rc = libssh2_userauth_password(session, pUserName, pPassword))
               == LIBSSH2_ERROR_EAGAIN);
	 if(rc) {
	    printf("[%s] libssh2_userauth_password failed!\n", __FUNCTION__);
        return NULL;
    }

    do {
		sftp_session = libssh2_sftp_init(session);
		if(!sftp_session) {
		    if(libssh2_session_last_errno(session) ==
		       LIBSSH2_ERROR_EAGAIN) {
		        printf("non-blocking libssh2_sftp_init now we wait\n");
		        iRet = waitsocket(iSocket, session); 		/* now we wait */ 
				if(iRet <= 0)
				{
					printf("[%s] waitsocket time out\n", __FUNCTION__);
					return NULL;
				}
					
		    }
		    else {
		        printf("[%s] Unable to init SFTP session, libssh2_sftp_init failed\n", __FUNCTION__);
		    	return NULL;
		    }
		}
	} while(!sftp_session);

	return(void *)sftp_session;
}

int SFTP_PutFile(void *ssh2Session, void *sftpSession, int iSocket, 
		const char *pSrcpath, const char *pDstpath)
{
    /**略*/
}

int SFTP_GetFile(void *ssh2Session, void *sftpSession, int iSocket, 
			const char *pSrcpath, const char *pLocalpath)
{
     /**略*/
}

void SFTP_SocketClose(int iSocket)
{
	if(iSocket > 0)
		close(iSocket);
}

void SFTP_SftpSessionclose(void *sftpSession)
{
	LIBSSH2_SFTP *sftp_Session = sftpSession;
		
	if(sftp_Session)
	{
		libssh2_sftp_shutdown(sftp_Session);
//		sftp_Session = NULL;
	}
}


void SFTP_SshSessionClose(void *ssh2Session)
{
	LIBSSH2_SESSION *ssh2_Session = ssh2Session;

	if(ssh2_Session)
	{
	    libssh2_session_disconnect(ssh2_Session,
                           "Normal Shutdown, Thank you for playing");
		libssh2_session_free(ssh2_Session);	
		ssh2_Session = NULL;
	}
}

void SFTP_Exit()
{
	libssh2_exit();
}

总结

SFTP_GetFile、SFTP_PutFile接口直接到本人博客资源文件中下载查看即可。

本文主要对libssh开源库进行二次开发,封装成可供直接调用的函数库,并且对原开发库做了以下优化:

1、解决原开源库api接口在网络异常环境中阻塞问题;

2、实现逻辑流程优化,功能api接口函数划分清晰!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flypig哗啦啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值