1:下载源码:libssh2https://www.libssh2.org/
?
?2.OpenSSL安装
编译libssh2需要安装OpenSSL,这里自己编译库比较复杂,直接安装带库的包比较方便:
直接从?Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions?下载
注意,不要下载 light 版本,因为 light 版本不带库文件。
3.在根目录创建编译目录
mkdir build
cd build
cmake ..
如果环境正确:
-- Configuring done
-- Generating done
-- Build files have been written to: E:/libssh2-libssh2-1.10.0/build
执行:
cmake --build .
将会在E:\libssh2-libssh2-1.10.0\build\example\Debug中编译出各个例子的exe文件。
同样在E:\libssh2-libssh2-1.10.0\build\src\Debug中会生成libssh2.lib文件。
4.编译dll
双击上一级E:\libssh2-libssh2-1.10.0\build\example的example-ssh2.vcxproj(任何一个都行)
打开VS:
这里我将Debug模式改为了release,重新生成libssh2目录:
在E:\libssh2-libssh2-1.10.0\build\src\Release便生成新的release的lib.
修改libssh2文件夹下的CmakeLists.txt文件:
将
add_library(libssh2 ${SOURCES})
?改为:
add_library(libssh2 SHARED ${SOURCES})
重新编译:?
???目录: E:\libssh2-libssh2-1.10.0\build\src\Release
Mode ????????????????LastWriteTime ????????Length Name
---- ????????????????------------- ????????------ ----
-a---- ????????2021/9/26 ????10:29 ????????226304 libssh2.dll
-a---- ????????2021/9/26 ????10:29 ?????????19538 libssh2.exp
-a---- ????????2021/9/26 ????10:29 ?????????32788 libssh2.lib
这样就可以正常使用dll.
使用
这里想要将libssh2的功能二次封装为dll,提供简洁的调用。
为了减少工作量:
随便选取一个例子,如example-ssh2_exec,将包含的CMakeLists.txt的:
add_executable(example-${example} ${example}.c)
改为:
add_library(example-${example}?SHARED ${example}.c)
然后修改其中的Source File文件ssh2_exec.c:
#include "libssh2_config.h"
#include "libssh2.h"
#include "libssh2_sftp.h"
#ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
# ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
const char* username = "username";
const char* password = "password";
unsigned long hostaddr = 0;//inet_addr("192.168.3.1"); init in anyfunction
unsigned long getIP() {
if (!hostaddr)
{
return inet_addr("192.168.3.1");
}
return hostaddr;
}
int sftp_download(char* loclfile, char* sftppath)
{
unsigned long hostaddr = getIP();
int sock, i, auth_pw = 1;
struct sockaddr_in sin;
const char* fingerprint;
LIBSSH2_SESSION* session;
int rc;
FILE* local;
LIBSSH2_SFTP* sftp_session;
LIBSSH2_SFTP_HANDLE* sftp_handle;
LIBSSH2_SFTP_ATTRIBUTES attrs;
char mem[1024 * 100];
size_t nread;
char* ptr;
#ifdef WIN32
WSADATA wsadata;
int err;
err = WSAStartup(MAKEWORD(2, 0), &wsadata);
if (err) {
fprintf(stderr, "WSAStartup failed with error: %d\n", err);
return -1;
}
#endif
rc = libssh2_init(0);
if (rc) {
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
return -1;
}
local = fopen(loclfile, "rb");
if (!local) {
fprintf(stderr, "Can't open local file %s\n", loclfile);
return -1;
}
/*
* The application code is responsible for creating the socket
* and establishing the connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance
*/
session = libssh2_session_init();
if (!session)
return -1;
/* Since we have set non-blocking, tell libssh2 we are blocking */
libssh2_session_set_blocking(session, 1);
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
rc = libssh2_session_handshake(session, sock);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
if (auth_pw) {
/* We could authenticate via password */
if (libssh2_userauth_password(session, username, password)) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
}
sftp_session = libssh2_sftp_init(session);
if (!sftp_session) {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown;
}
/* Request a file via SFTP */
sftp_handle =
libssh2_sftp_open(sftp_session, sftppath,
LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE | LIBSSH2_FXF_READ,
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR |
LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
if (!sftp_handle) {
fprintf(stderr, "Unable to open file with SFTP\n");
goto shutdown;
}
if (libssh2_sftp_fstat_ex(sftp_handle, &attrs, 0) < 0) {
fprintf(stderr, "libssh2_sftp_fstat_ex failed\n");
goto shutdown;
}
else
libssh2_sftp_seek64(sftp_handle, attrs.filesize);
if (!sftp_handle) {
fprintf(stderr, "Unable to open file with SFTP\n");
goto shutdown;
}
//fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
do {
nread = fread(mem, 1, sizeof(mem), local);
if (nread <= 0) {
/* end of file */
break;
}
ptr = mem;
do {
/* write data in a loop until we block */
rc = libssh2_sftp_write(sftp_handle, ptr, nread);
if (rc < 0)
break;
ptr += rc;
nread -= rc;
} while (nread);
} while (rc > 0);
libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session);
shutdown:
libssh2_session_disconnect(session,
"Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
if (local)
fclose(local);
libssh2_exit();
return 0;
}
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;
}
int ssh_exec(char* commandline)
{
unsigned long hostaddr = getIP();
int sock;
struct sockaddr_in sin;
const char* fingerprint;
LIBSSH2_SESSION* session;
LIBSSH2_CHANNEL* channel;
int rc;
int exitcode;
char* exitsignal = (char*)"none";
int bytecount = 0;
size_t len;
LIBSSH2_KNOWNHOSTS* nh;
int type;
#ifdef WIN32
WSADATA wsadata;
int err;
err = WSAStartup(MAKEWORD(2, 0), &wsadata);
if (err != 0) {
fprintf(stderr, "WSAStartup failed with error: %d\n", err);
return -1;
}
#endif
rc = libssh2_init(0);
if (rc != 0) {
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
return -1;
}
/* Ultra basic "connect to port 22 on localhost"
* Your code is responsible for creating the socket establishing the
* connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance */
session = libssh2_session_init();
if (!session)
return -1;
/* tell libssh2 we want it all done 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 ((rc = libssh2_session_handshake(session, sock)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
nh = libssh2_knownhost_init(session);
if (!nh) {
/* eeek, do cleanup here */
return -2;
}
/* read all hosts from here */
libssh2_knownhost_readfile(nh, "known_hosts",
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
/* store all known hosts to here */
libssh2_knownhost_writefile(nh, "dumpfile",
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
libssh2_knownhost_free(nh);
if (1) {
/* We could authenticate via password */
while ((rc = libssh2_userauth_password(session, username, password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
}
#if 0
libssh2_trace(session, ~0);
#endif
/* Exec non-blocking on the remove host */
while ((channel = libssh2_channel_open_session(session)) == NULL &&
libssh2_session_last_error(session, NULL, NULL, 0) ==
LIBSSH2_ERROR_EAGAIN) {
waitsocket(sock, session);
}
if (channel == NULL) {
fprintf(stderr, "Error\n");
exit(1);
}
while ((rc = libssh2_channel_exec(channel, commandline)) ==
LIBSSH2_ERROR_EAGAIN) {
waitsocket(sock, session);
}
if (rc != 0) {
fprintf(stderr, "Error\n");
exit(1);
}
for (;;) {
/* loop until we block */
int rc;
do {
char buffer[0x4000];
rc = libssh2_channel_read(channel, buffer, sizeof(buffer));
if (rc > 0) {
int i;
bytecount += rc;
fprintf(stderr, "We read:\n");
for (i = 0; i < rc; ++i)
fputc(buffer[i], stderr);
fprintf(stderr, "\n");
}
else {
if (rc != LIBSSH2_ERROR_EAGAIN)
/* no need to output this for the EAGAIN case */
fprintf(stderr, "returned %d\n", rc);
}
} while (rc > 0);
/* this is due to blocking that would occur otherwise so we loop on
this condition */
if (rc == LIBSSH2_ERROR_EAGAIN) {
waitsocket(sock, session);
}
else
break;
}
exitcode = 127;
while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
waitsocket(sock, session);
if (rc == 0) {
exitcode = libssh2_channel_get_exit_status(channel);
libssh2_channel_get_exit_signal(channel, &exitsignal,
NULL, NULL, NULL, NULL, NULL);
}
if (exitsignal)
fprintf(stderr, "\nGot signal: %s\n", exitsignal);
else
fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
libssh2_channel_free(channel);
channel = NULL;
shutdown:
libssh2_session_disconnect(session,
"Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
libssh2_exit();
return 0;
}
__declspec(dllexport) download_file(char* loclfile)
{
char sftppath[512] = "/home/XXX/";
strcat(sftppath, loclfile);
return sftp_download(loclfile, sftppath);
}
__declspec(dllexport) int setip(char* IP)
{
hostaddr = inet_addr(IP);
return 0;
}
__declspec(dllexport) int my_exec(char *cmd)
{
ssh_exec(cmd);
return 0;
}
编译命令:
Clang main.c -lexample-ssh2_exec
注意在其他电脑中不仅需要拷贝本次编译的dll,在安装OpenSSL时的安装目录下的bin文件中包含其他的可能需要的dll,需要拷贝过来,如libcrypto-3-x64.dll。
注意:
Dll無法直接改名:
將其中一部分改爲,清理並重新生成才能單獨編譯該文件:
include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CopyRuntimeDependencies)
include(SocketLibraries)
append_needed_socket_libraries(LIBRARIES)
add_library(XXX SHARED XXX.c)
list(APPEND EXAMPLE_TARGETS XXX)
# to find generated header
target_include_directories(XXXPRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(XXX libssh2 ${LIBRARIES})
add_target_to_copy_dependencies(
TARGET copy_example_dependencies
DEPENDENCIES ${RUNTIME_DEPENDENCIES}
BEFORE_TARGETS ${EXAMPLE_TARGETS})
|