赞
踩
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的ALL_Build.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.
但是如果想要二次封装为自己的dll的话,就需要还原原来的add_library(libssh2 ${SOURCES}),来使用libssh2.lib进行使用。
这里想要将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。
改进1:
Dll無法直接改名!
將文件名改为需要的如XXX.c,然后替换Cmakelists.txt:
- 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(XXX PRIVATE ${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})
将其中的XXX 改为自己的文件名即可,就会在libssh2-libssh2-1.10.0\build\example\Release生成对应的dll
改进2:
提供用户包含libcrypto-3-x64.dll文件,显得不专业。
在VS添加指定的lib进行重新编译:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。