1 /*
2 * Sample showing how to do SFTP non-blocking write transfers.
3 *
4 * The sample code has default values for host name, user name, password
5 * and path to copy, but you can specify them on the command line like:
6 *
7 * "sftp 192.168.0.1 user password thisfile /tmp/storehere"
8 */
9
10 #include "libssh2_config.h"
11 #include <libssh2.h>
12 #include <libssh2_sftp.h>
13
14 #ifdef HAVE_WINSOCK2_H
15 # include <winsock2.h>
16 #endif
17 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
19 #endif
20 #ifdef HAVE_NETINET_IN_H
21 # include <netinet/in.h>
22 #endif
23 #ifdef HAVE_SYS_SELECT_H
24 # include <sys/select.h>
25 #endif
26 # ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_ARPA_INET_H
30 # include <arpa/inet.h>
31 #endif
32 #ifdef HAVE_SYS_TIME_H
33 # include <sys/time.h>
34 #endif
35
36 #include <sys/types.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <time.h>
42
waitsocket(int socket_fd,LIBSSH2_SESSION * session)43 static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
44 {
45 struct timeval timeout;
46 int rc;
47 fd_set fd;
48 fd_set *writefd = NULL;
49 fd_set *readfd = NULL;
50 int dir;
51
52 timeout.tv_sec = 10;
53 timeout.tv_usec = 0;
54
55 FD_ZERO(&fd);
56
57 FD_SET(socket_fd, &fd);
58
59 /* now make sure we wait in the correct direction */
60 dir = libssh2_session_block_directions(session);
61
62 if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
63 readfd = &fd;
64
65 if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
66 writefd = &fd;
67
68 rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
69
70 return rc;
71 }
72
main(int argc,char * argv[])73 int main(int argc, char *argv[])
74 {
75 unsigned long hostaddr;
76 int sock, i, auth_pw = 1;
77 struct sockaddr_in sin;
78 const char *fingerprint;
79 LIBSSH2_SESSION *session;
80 const char *username = "username";
81 const char *password = "password";
82 const char *loclfile = "sftp_write_nonblock.c";
83 const char *sftppath = "/tmp/sftp_write_nonblock.c";
84 int rc;
85 FILE *local;
86 LIBSSH2_SFTP *sftp_session;
87 LIBSSH2_SFTP_HANDLE *sftp_handle;
88 char mem[1024 * 100];
89 size_t nread;
90 char *ptr;
91 time_t start;
92 long total = 0;
93 int duration;
94
95 #ifdef WIN32
96 WSADATA wsadata;
97 int err;
98
99 err = WSAStartup(MAKEWORD(2, 0), &wsadata);
100 if(err != 0) {
101 fprintf(stderr, "WSAStartup failed with error: %d\n", err);
102 return 1;
103 }
104 #endif
105
106 if(argc > 1) {
107 hostaddr = inet_addr(argv[1]);
108 }
109 else {
110 hostaddr = htonl(0x7F000001);
111 }
112
113 if(argc > 2) {
114 username = argv[2];
115 }
116 if(argc > 3) {
117 password = argv[3];
118 }
119 if(argc > 4) {
120 loclfile = argv[4];
121 }
122 if(argc > 5) {
123 sftppath = argv[5];
124 }
125
126 rc = libssh2_init(0);
127 if(rc != 0) {
128 fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
129 return 1;
130 }
131
132 local = fopen(loclfile, "rb");
133 if(!local) {
134 fprintf(stderr, "Can't open local file %s\n", loclfile);
135 return -1;
136 }
137
138 /*
139 * The application code is responsible for creating the socket
140 * and establishing the connection
141 */
142 sock = socket(AF_INET, SOCK_STREAM, 0);
143
144 sin.sin_family = AF_INET;
145 sin.sin_port = htons(22);
146 sin.sin_addr.s_addr = hostaddr;
147 if(connect(sock, (struct sockaddr*)(&sin),
148 sizeof(struct sockaddr_in)) != 0) {
149 fprintf(stderr, "failed to connect!\n");
150 return -1;
151 }
152
153 /* Create a session instance
154 */
155 session = libssh2_session_init();
156 if(!session)
157 return -1;
158
159 /* Since we have set non-blocking, tell libssh2 we are non-blocking */
160 libssh2_session_set_blocking(session, 0);
161
162 /* ... start it up. This will trade welcome banners, exchange keys,
163 * and setup crypto, compression, and MAC layers
164 */
165 while((rc = libssh2_session_handshake(session, sock))
166 == LIBSSH2_ERROR_EAGAIN);
167 if(rc) {
168 fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
169 return -1;
170 }
171
172 /* At this point we havn't yet authenticated. The first thing to do is
173 * check the hostkey's fingerprint against our known hosts Your app may
174 * have it hard coded, may go to a file, may present it to the user,
175 * that's your call
176 */
177 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
178 fprintf(stderr, "Fingerprint: ");
179 for(i = 0; i < 20; i++) {
180 fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
181 }
182 fprintf(stderr, "\n");
183
184 if(auth_pw) {
185 /* We could authenticate via password */
186 while((rc = libssh2_userauth_password(session, username, password)) ==
187 LIBSSH2_ERROR_EAGAIN);
188 if(rc) {
189 fprintf(stderr, "Authentication by password failed.\n");
190 goto shutdown;
191 }
192 }
193 else {
194 /* Or by public key */
195 const char *pubkey = "/home/username/.ssh/id_rsa.pub";
196 const char *privkey = "/home/username/.ssh/id_rsa";
197 while((rc = libssh2_userauth_publickey_fromfile(session, username,
198 pubkey, privkey,
199 password)) ==
200 LIBSSH2_ERROR_EAGAIN);
201 if(rc) {
202 fprintf(stderr, "\tAuthentication by public key failed\n");
203 goto shutdown;
204 }
205 }
206
207 fprintf(stderr, "libssh2_sftp_init()!\n");
208 do {
209 sftp_session = libssh2_sftp_init(session);
210
211 if(!sftp_session &&
212 (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
213 fprintf(stderr, "Unable to init SFTP session\n");
214 goto shutdown;
215 }
216 } while(!sftp_session);
217
218 fprintf(stderr, "libssh2_sftp_open()!\n");
219 /* Request a file via SFTP */
220 do {
221 sftp_handle =
222 libssh2_sftp_open(sftp_session, sftppath,
223 LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|
224 LIBSSH2_FXF_TRUNC,
225 LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
226 LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
227 if(!sftp_handle &&
228 (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
229 fprintf(stderr, "Unable to open file with SFTP\n");
230 goto shutdown;
231 }
232 } while(!sftp_handle);
233
234 fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
235
236 start = time(NULL);
237
238 do {
239 nread = fread(mem, 1, sizeof(mem), local);
240 if(nread <= 0) {
241 /* end of file */
242 break;
243 }
244 ptr = mem;
245
246 total += nread;
247
248 do {
249 /* write data in a loop until we block */
250 while((rc = libssh2_sftp_write(sftp_handle, ptr, nread)) ==
251 LIBSSH2_ERROR_EAGAIN) {
252 waitsocket(sock, session);
253 }
254 if(rc < 0)
255 break;
256 ptr += rc;
257 nread -= rc;
258
259 } while(nread);
260 } while(rc > 0);
261
262 duration = (int)(time(NULL)-start);
263
264 fprintf(stderr, "%ld bytes in %d seconds makes %.1f bytes/sec\n",
265 total, duration, total/(double)duration);
266
267
268 fclose(local);
269 libssh2_sftp_close(sftp_handle);
270 libssh2_sftp_shutdown(sftp_session);
271
272 shutdown:
273
274 while(libssh2_session_disconnect(session, "Normal Shutdown")
275 == LIBSSH2_ERROR_EAGAIN);
276 libssh2_session_free(session);
277
278 #ifdef WIN32
279 closesocket(sock);
280 #else
281 close(sock);
282 #endif
283 fprintf(stderr, "all done\n");
284
285 libssh2_exit();
286
287 return 0;
288 }
289