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