From dc4bb1af967d2c53e90349f2f37324c622e714f5 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Mon, 3 Jan 2005 22:46:15 +0000 Subject: [PATCH] Add support for win32. Edit win32/config.mk to set the paths to your openssl and zlib headers and libraries. Then, from the root of the tree: nmake -f NMakefile voila. --- .cvsignore | 9 +++++++++ NMakefile | 16 ++++++++++++++++ include/libssh2.h | 16 +++++++++------- include/libssh2_priv.h | 2 ++ src/.cvsignore | 9 +++++++++ src/NMakefile | 18 ++++++++++++++++++ src/channel.c | 2 ++ src/packet.c | 41 ++++++++++++++++++++++++++++++++++++----- src/session.c | 7 ++++--- src/sftp.c | 32 ++++++++++++++++---------------- ssh2_sample.c | 31 ++++++++++++++++++++++++++----- win32/.cvsignore | 9 +++++++++ win32/config.mk | 24 ++++++++++++++++++++++++ win32/libssh2_config.h | 31 +++++++++++++++++++++++++++++++ win32/rules.mk | 15 +++++++++++++++ 15 files changed, 226 insertions(+), 36 deletions(-) create mode 100644 .cvsignore create mode 100644 NMakefile create mode 100644 src/.cvsignore create mode 100644 src/NMakefile create mode 100644 win32/.cvsignore create mode 100644 win32/config.mk create mode 100644 win32/libssh2_config.h create mode 100644 win32/rules.mk diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..075cebc --- /dev/null +++ b/.cvsignore @@ -0,0 +1,9 @@ +*.lib +*.pdb +*.dll +*.exe +*.obj +.*.swp +Debug +Release +*.exp diff --git a/NMakefile b/NMakefile new file mode 100644 index 0000000..446ccb7 --- /dev/null +++ b/NMakefile @@ -0,0 +1,16 @@ +!include "win32/config.mk" + +SUBDIRS=src + +all: all-sub ssh2_sample.exe + +ssh2_sample.exe: ssh2_sample.c + $(CC) $(CFLAGS) -DWIN32 -o ssh2_sample.exe ssh2_sample.c libssh2$(SUFFIX).lib $(LIBS) + +all-sub: + -for %D in ($(SUBDIRS)) do $(MAKE) /nologo /f %D/NMakefile BUILD=$(BUILD) SUBDIR=%D all-sub + +clean: + rmdir /s/q $(TARGET) + + diff --git a/include/libssh2.h b/include/libssh2.h index fc50bdf..551a29d 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -43,14 +43,16 @@ #include #ifdef LIBSSH2_WIN32 -#ifdef LIBSSH2_LIBRARY -#define LIBSSH2_API __declspec(dllexport) +# ifdef LIBSSH2_LIBRARY +# define LIBSSH2_API __declspec(dllexport) +# else +# define LIBSSH2_API __declspec(dllimport) +# endif +# ifndef _MSC_VER +# include +# endif #else -#define LIBSSH2_API __declspec(dllimport) -#endif -#include -#else -#define LIBSSH2_API +# define LIBSSH2_API #endif #define LIBSSH2_VERSION "0.4" diff --git a/include/libssh2_priv.h b/include/libssh2_priv.h index 4b90f07..50bff0a 100644 --- a/include/libssh2_priv.h +++ b/include/libssh2_priv.h @@ -42,7 +42,9 @@ #include "libssh2_config.h" #include "libssh2.h" +#ifndef WIN32 #include +#endif #include #define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract) diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..075cebc --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,9 @@ +*.lib +*.pdb +*.dll +*.exe +*.obj +.*.swp +Debug +Release +*.exp diff --git a/src/NMakefile b/src/NMakefile new file mode 100644 index 0000000..e18b2d8 --- /dev/null +++ b/src/NMakefile @@ -0,0 +1,18 @@ +!include "win32/config.mk" + +CFLAGS=$(CFLAGS) + +OBJECTS = $(INTDIR)\channel.obj $(INTDIR)\comp.obj $(INTDIR)\crypt.obj \ + $(INTDIR)\hostkey.obj $(INTDIR)\kex.obj $(INTDIR)\mac.obj \ + $(INTDIR)\misc.obj $(INTDIR)\packet.obj $(INTDIR)\scp.obj \ + $(INTDIR)\session.obj $(INTDIR)\sftp.obj $(INTDIR)\userauth.obj + +DLL=libssh2$(SUFFIX).dll + +$(DLL): $(OBJECTS) + $(CC) -o $(DLL) $(DLLFLAGS) $(OBJECTS) $(LIBS) + +all: $(DLL) + +!include "win32/rules.mk" + diff --git a/src/channel.c b/src/channel.c index 1a1d76b..669b2d3 100644 --- a/src/channel.c +++ b/src/channel.c @@ -36,7 +36,9 @@ */ #include "libssh2_priv.h" +#ifndef WIN32 #include +#endif /* {{{ libssh2_channel_nextid * Determine the next channel ID we can use at our end diff --git a/src/packet.c b/src/packet.c index 75057d7..fe42d4e 100644 --- a/src/packet.c +++ b/src/packet.c @@ -38,7 +38,9 @@ #include "libssh2_priv.h" #include #include +#ifndef WIN32 #include +#endif #include #include @@ -412,8 +414,17 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s while (bytes_read < count) { int ret; - ret = read(session->socket_fd, buf + bytes_read, count - bytes_read); + ret = recv(session->socket_fd, buf + bytes_read, count - bytes_read, 0); if (ret < 0) { +#ifdef WIN32 + switch (WSAGetLastError()) { + case WSAEWOULDBLOCK: errno = EAGAIN; + case WSAENOTCONN: + case WSAENOTSOCK: + case WSAECONNABORTED: errno = EBADF; + case WSAEINTR: errno = EINTR; + } +#endif if (errno == EAGAIN) { if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) { return -1; @@ -452,7 +463,14 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) return 0; } +#ifndef WIN32 fcntl(session->socket_fd, F_SETFL, O_NONBLOCK); +#else + { + u_long non_block = TRUE; + ioctlsocket(session->socket_fd, FIONBIO, &non_block); + } +#endif if (session->newkeys) { /* Temporary Buffer * The largest blocksize (currently) is 32, the largest MAC (currently) is 20 @@ -473,7 +491,7 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) if (should_block) { read_len = libssh2_blocking_read(session, block, blocksize); } else { - read_len = read(session->socket_fd, block, 1); + read_len = recv(session->socket_fd, block, 1, 0); if (read_len <= 0) { return 0; } @@ -598,7 +616,7 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) if (should_block) { buf_len = libssh2_blocking_read(session, buf, 5); } else { - buf_len = read(session->socket_fd, buf, 1); + buf_len = recv(session->socket_fd, buf, 1, 0); if (buf_len <= 0) { return 0; } @@ -618,8 +636,13 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1; } while (padding_length) { + int l; /* Flush padding */ - padding_length -= libssh2_blocking_read(session, buf, padding_length); + l = libssh2_blocking_read(session, buf, padding_length); + if (l > 0) + padding_length -= l; + else + break; } /* MACs don't exist in non-encrypted mode */ @@ -726,7 +749,15 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned } } +#ifndef WIN32 fcntl(session->socket_fd, F_SETFL, 0); +#else + { + u_long non_block = FALSE; + ioctlsocket(session->socket_fd, FIONBIO, &non_block); + } +#endif + packet_length = data_len + 1; /* padding_length(1) -- MAC doesn't count -- Padding to be added soon */ padding_length = block_size - ((packet_length + 4) % block_size); if (padding_length < 4) { @@ -785,7 +816,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned session->local.seqno++; /* Send It */ - ret = ((4 + packet_length + session->local.mac->mac_len) == write(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len)) ? 0 : -1; + ret = ((4 + packet_length + session->local.mac->mac_len) == send(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len, 0)) ? 0 : -1; /* Cleanup environment */ LIBSSH2_FREE(session, encbuf); diff --git a/src/session.c b/src/session.c index e13e329..0c016d6 100644 --- a/src/session.c +++ b/src/session.c @@ -37,7 +37,9 @@ #include "libssh2_priv.h" #include +#ifndef WIN32 #include +#endif #include /* {{{ libssh2_default_alloc @@ -79,7 +81,7 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session) char c = '\0'; int ret; - ret = read(session->socket_fd, &c, 1); + ret = recv(session->socket_fd, &c, 1, 0); if ((ret < 0) && (ret != EAGAIN)) { /* Some kinda error, but don't break for non-blocking issues */ @@ -124,7 +126,7 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session) banner = session->local.banner; } - return (write(session->socket_fd, banner, banner_len) == banner_len) ? 0 : 1; + return (send(session->socket_fd, banner, banner_len, 0) == banner_len) ? 0 : 1; } /* }}} */ @@ -247,7 +249,6 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket) session->socket_fd = socket; /* TODO: Liveness check */ - if (libssh2_banner_receive(session)) { /* Unable to receive banner from remote */ libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE, "Timeout waiting for banner", 0); diff --git a/src/sftp.c b/src/sftp.c index c5d9664..22e5d82 100644 --- a/src/sftp.c +++ b/src/sftp.c @@ -83,7 +83,7 @@ struct _LIBSSH2_SFTP { LIBSSH2_SFTP_HANDLE *handles; - unsigned long errno; + unsigned long last_errno; }; #define LIBSSH2_SFTP_HANDLE_FILE 0 @@ -542,7 +542,7 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char * if (data[0] == SSH_FXP_STATUS) { libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file", 0); - sftp->errno = libssh2_ntohu32(data + 5); + sftp->last_errno = libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); return NULL; } @@ -627,7 +627,7 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, switch (data[0]) { case SSH_FXP_STATUS: - sftp->errno = libssh2_ntohu32(data + 5); + sftp->last_errno = libssh2_ntohu32(data + 5); libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); LIBSSH2_FREE(session, data); return -1; @@ -722,7 +722,7 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, if (retcode == LIBSSH2_FX_EOF) { return 0; } else { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -809,7 +809,7 @@ LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *b return count; } libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); - sftp->errno = retcode; + sftp->last_errno = retcode; return -1; } @@ -865,7 +865,7 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ if (retcode == LIBSSH2_FX_OK) { return 0; } else { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -938,7 +938,7 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) LIBSSH2_FREE(session, data); if (retcode != LIBSSH2_FX_OK) { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -1008,7 +1008,7 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f if (retcode == LIBSSH2_FX_OK) { return 0; } else { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -1066,17 +1066,17 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam break; case LIBSSH2_FX_FILE_ALREADY_EXISTS: libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "File already exists and SSH_FXP_RENAME_OVERWRITE not specified", 0); - sftp->errno = retcode; + sftp->last_errno = retcode; retcode = -1; break; case LIBSSH2_FX_OP_UNSUPPORTED: libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Operation Not Supported", 0); - sftp->errno = retcode; + sftp->last_errno = retcode; retcode = -1; break; default: libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); - sftp->errno = retcode; + sftp->last_errno = retcode; retcode = -1; } @@ -1131,7 +1131,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l return 0; } else { libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); - sftp->errno = retcode; + sftp->last_errno = retcode; return -1; } } @@ -1179,7 +1179,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l if (retcode == LIBSSH2_FX_OK) { return 0; } else { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -1245,7 +1245,7 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le if (retcode == LIBSSH2_FX_OK) { return 0; } else { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -1319,7 +1319,7 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in if (retcode == LIBSSH2_FX_OK) { return 0; } else { - sftp->errno = retcode; + sftp->last_errno = retcode; libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); return -1; } @@ -1347,6 +1347,6 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in */ LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp) { - return sftp->errno; + return sftp->last_errno; } /* }}} */ diff --git a/ssh2_sample.c b/ssh2_sample.c index 21063c5..0c9213d 100644 --- a/ssh2_sample.c +++ b/ssh2_sample.c @@ -1,11 +1,17 @@ #include "libssh2.h" -#include -#include + +#ifndef WIN32 +# include +# include +# include +#else +# include +#endif + #include #include #include #include -#include #include int main(int argc, char *argv[]) { @@ -14,16 +20,26 @@ int main(int argc, char *argv[]) { char *fingerprint; LIBSSH2_SESSION *session; LIBSSH2_CHANNEL *channel; +#ifdef WIN32 + WSADATA wsadata; + + WSAStartup(WINSOCK_VERSION, &wsadata); +#endif /* 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); +#ifndef WIN32 fcntl(sock, F_SETFL, 0); +#endif sin.sin_family = AF_INET; sin.sin_port = htons(22); sin.sin_addr.s_addr = htonl(0x7F000001); - connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)); + if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) { + fprintf(stderr, "failed to connect!\n"); + return -1; + } /* Create a session instance and start it up * This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers @@ -114,8 +130,13 @@ int main(int argc, char *argv[]) { libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing"); libssh2_session_free(session); +#ifdef WIN32 + Sleep(1000); + closesocket(sock); +#else sleep(1); close(sock); - +#endif +printf("all done\n"); return 0; } diff --git a/win32/.cvsignore b/win32/.cvsignore new file mode 100644 index 0000000..075cebc --- /dev/null +++ b/win32/.cvsignore @@ -0,0 +1,9 @@ +*.lib +*.pdb +*.dll +*.exe +*.obj +.*.swp +Debug +Release +*.exp diff --git a/win32/config.mk b/win32/config.mk new file mode 100644 index 0000000..46c1d21 --- /dev/null +++ b/win32/config.mk @@ -0,0 +1,24 @@ + +# Tweak these for your system +OPENSSLINC=\local\php\php_build\include +OPENSSLLIB=\local\php\php_build\lib + +ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I\local\php\php_build\include +ZLIBLIB=\local\php\php_build\lib + +CPPFLAGS=/nologo /GL /Zi /EHsc /MD /Iwin32 /Iinclude /I$(OPENSSLINC) $(ZLIBINC) -DLIBSSH2_WIN32 +CFLAGS=$(CPPFLAGS) +DLLFLAGS=$(CFLAGS) /LDd +LIBS=$(OPENSSLLIB)\libeay32.lib $(OPENSSLLIB)\ssleay32.lib ws2_32.lib $(ZLIBLIB)\zlib.lib + +!if "$(TARGET)" == "" +TARGET=Debug +!endif + +!if "$(TARGET)" == "Debug" +SUFFIX=_debug +!endif + +INTDIR=$(TARGET)\$(SUBDIR) + + diff --git a/win32/libssh2_config.h b/win32/libssh2_config.h new file mode 100644 index 0000000..cda2f3a --- /dev/null +++ b/win32/libssh2_config.h @@ -0,0 +1,31 @@ +#define WIN32 +#include +#include +#include + +/* same as WSABUF */ +struct iovec { + u_long iov_len; + char *iov_base; +}; + +#define inline __inline + +static inline int writev(int sock, struct iovec *iov, int nvecs) +{ + DWORD ret; + if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) { + return ret; + } + return -1; +} + +/* not really usleep, but safe for the way we use it in this lib */ +static inline int usleep(int udelay) +{ + Sleep(udelay / 1000); + return 0; +} + +#define snprintf _snprintf + diff --git a/win32/rules.mk b/win32/rules.mk new file mode 100644 index 0000000..bfb7784 --- /dev/null +++ b/win32/rules.mk @@ -0,0 +1,15 @@ + +all-sub: $(INTDIR) all + +clean-sub: clean + +$(INTDIR): +!if "$(SRCDIR)" == "" + @if not exist $(TARGET) mkdir $(TARGET) +!endif + @if not exist $(INTDIR) mkdir $(INTDIR) + +{$(SUBDIR)}.c{$(INTDIR)}.obj:: + $(CC) -c $(CFLAGS) /Fo"$(INTDIR)\\" $< + +