source: branches/prototype-v0/zoo-project/zoo-kernel/sshapi.c @ 822

Last change on this file since 822 was 822, checked in by djay, 7 years ago

Commit the minimal requirements for remote HPC support

  • Property svn:keywords set to Id
File size: 16.9 KB
Line 
1/*
2 *
3 * Author : Gérald FENOY
4 *
5 * Copyright 2017 GeoLabs SARL. All rights reserved.
6 *
7 * This work was supported by public funds received in the framework of GEOSUD,
8 * a project (ANR-10-EQPX-20) of the program "Investissements d'Avenir" managed
9 * by the French National Research Agency
10 *
11 * permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 */
29
30#include "sshapi.h"
31
32SSHCON *sessions[MAX_PARALLEL_SSH_CON];
33
34/**
35 * Wait until one or more file descriptor has been changed for the socket for a
36 * time defined by timeout
37 * @param socket_fd int defining the sockket file descriptor
38 * @param session an exeisting LIBSSH2_SESSION
39 */ 
40int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
41{
42    struct timeval timeout;
43    int rc;
44    fd_set fd;
45    fd_set *writefd = NULL;
46    fd_set *readfd = NULL;
47    int dir;
48 
49    timeout.tv_sec = 10;
50    timeout.tv_usec = 0;
51 
52    FD_ZERO(&fd);
53 
54    FD_SET(socket_fd, &fd);
55 
56    /* now make sure we wait in the correct direction */ 
57    dir = libssh2_session_block_directions(session);
58
59 
60    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
61        readfd = &fd;
62 
63    if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
64        writefd = &fd;
65 
66    rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
67 
68    return rc;
69}
70
71/**
72 * Connect to a remote host using SSH protocol
73 * @param conf maps The main configuration maps
74 * @return the libssh2 sessions pointer or NULL in case any failure occured.
75 */
76SSHCON *ssh_connect(maps* conf){
77  unsigned long hostaddr;
78  int i, use_pw = 1;
79  struct sockaddr_in sin;
80  const char *fingerprint;
81  SSHCON *result=(SSHCON*)malloc((2*sizeof(int))+sizeof(LIBSSH2_SESSION*)+sizeof(LIBSSH2_SFTP*));
82  result->sock_id=NULL;
83  result->index=NULL;
84  result->session=NULL;
85  result->sftp_session=NULL;
86  const char *user;
87  const char *password=NULL;
88  const char *public_key;
89  char *private_key;
90  int rc;
91  FILE *local;
92  char mem[1024 * 1000];
93  char error[1024];
94  int port=22;
95
96  fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
97  fflush(stderr);
98
99  map* hpc_host=getMapFromMaps(conf,"HPC","host");
100  map* hpc_port=getMapFromMaps(conf,"HPC","port");
101  map* hpc_user=getMapFromMaps(conf,"HPC","user");
102  map* hpc_password=getMapFromMaps(conf,"HPC","password");
103  map* hpc_public_key=getMapFromMaps(conf,"HPC","key");
104
105  fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
106  fflush(stderr);
107
108#ifdef WIN32
109  WSADATA wsadata;
110  int err;
111  err = WSAStartup(MAKEWORD(2,0), &wsadata);
112  if (err != 0) {
113    sprintf(error, "WSAStartup failed with error: %d\n", err);
114    setMapInMaps(conf,"lenv","message",error);
115    return NULL;
116  }
117#endif
118
119  // TODO: fetch ip address for the hostname
120  if (hpc_host != NULL) {
121    hostaddr = inet_addr(hpc_host->value);
122  } else {
123    setMapInMaps(conf,"lenv","message","No host parameter found in your main.cfg file!\n");
124    return NULL;
125  }
126
127  // Default port is 22
128  if(hpc_port!=NULL){
129    port=atoi(hpc_port->value);
130  }
131
132  // In case there is no HPC > user the it must failed
133  if (hpc_user != NULL) {
134    user = hpc_user->value;
135  }else{
136    setMapInMaps(conf,"lenv","message","No user parameter found in your main.cfg file!");
137    return NULL;
138  }
139
140  // TODO: in case password is available but there is also the public key
141  // defined, then we can consider this password as the pass phrase.
142  if (hpc_password != NULL) {
143    password = hpc_password->value;
144  }else{
145    use_pw=-1;
146    if (hpc_public_key != NULL) {
147      public_key = hpc_public_key->value;
148      private_key = strdup(hpc_public_key->value);
149      private_key[strlen(public_key)-4]=0;
150    }else{
151      setMapInMaps(conf,"lenv","message","No method found to authenticate!");
152      return NULL;
153    }
154  }
155
156  rc = libssh2_init (0);
157  if (rc != 0) {
158    sprintf (error, "libssh2 initialization failed (%d)\n", rc);
159    setMapInMaps(conf,"lenv","message",error);
160    return NULL;
161  }
162
163  result->sock_id = socket(AF_INET, SOCK_STREAM, 0);
164  sin.sin_family = AF_INET;
165  sin.sin_port = htons(port);
166  sin.sin_addr.s_addr = hostaddr;
167  if (connect(result->sock_id, (struct sockaddr*)(&sin),sizeof(struct sockaddr_in)) != 0) {
168    setMapInMaps(conf,"lenv","message","Failed to connect to remote host!");
169    return NULL;
170  }
171
172  result->session = libssh2_session_init();
173  result->sftp_session = NULL;
174  map* tmp=getMapFromMaps(conf,"lenv","nb_sessions");
175  if(tmp!=NULL){
176    char nb_sessions[10];
177    int nb_sess=atoi(tmp->value);
178    sprintf(nb_sessions,"%d",nb_sess+1);
179    setMapInMaps(conf,"lenv","nb_sessions",nb_sessions);
180    result->index=nb_sess+1;
181    sessions[nb_sess+1]=result;
182  }else{
183    setMapInMaps(conf,"lenv","nb_sessions","0");
184    sessions[0]=result;
185    result->index=0;
186  }
187
188  if (!result->session)
189    return NULL;
190
191  libssh2_session_set_blocking(result->session, 0);
192
193  while ((rc = libssh2_session_handshake(result->session, result->sock_id))
194         == LIBSSH2_ERROR_EAGAIN);
195
196  if (rc) {
197    sprintf(error, "Failure establishing SSH session: %d\n", rc);
198    setMapInMaps(conf,"lenv","message",error);
199    return NULL;
200  }
201
202  fingerprint = libssh2_hostkey_hash(result->session, LIBSSH2_HOSTKEY_HASH_SHA1);
203 
204  if (use_pw>0) {
205    while ((rc = libssh2_userauth_password(result->session, user, password)) ==
206           LIBSSH2_ERROR_EAGAIN);
207    if (rc) {
208      setMapInMaps(conf,"lenv","message","Authentication by password failed.");
209      ssh_close(conf);
210      return NULL;
211    }
212  } else {
213    while ((rc = libssh2_userauth_publickey_fromfile(result->session, user,
214                                                     public_key,
215                                                     private_key,
216                                                     password)) ==
217           LIBSSH2_ERROR_EAGAIN);
218    if (rc) {
219      setMapInMaps(conf,"lenv","message","Authentication by public key failed");
220      ssh_close(conf);
221      return NULL;
222    }
223    free(private_key);
224  }
225
226  return result;
227
228}
229
230/**
231 * Get the number of opened SSH connections
232 * @param conf maps pointer to the main configuration maps
233 * @return the number of opened SSH connections
234 */
235int ssh_get_cnt(maps* conf){
236  int result=0;
237  map* myMap=getMapFromMaps(conf,"lenv","cnt_session");
238  if(myMap!=NULL){
239    result=atoi(myMap->value);
240  }
241  return result;
242}
243
244/**
245 * Verify if a file exists on the remote host
246 * @param conf maps pointer to the main configuration maps
247 * @param targetPath const char* defining the path for storing the file on the
248 * remote host
249 * @return true in case of success, false if failure occured
250 */
251size_t ssh_file_exists(maps* conf,const char* targetPath){
252  size_t result=-1;
253  int cnt=ssh_get_cnt(conf);
254  if(cnt>0)
255    cnt-=1;
256  int rc;
257  LIBSSH2_SFTP_ATTRIBUTES attrs;
258  LIBSSH2_SFTP_HANDLE *sftp_handle;
259  do{
260    sftp_handle =
261      libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath, LIBSSH2_FXF_READ,
262                        LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
263                        LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
264    if (!sftp_handle) {
265      fprintf(stderr, "Unable to open file with SFTP: %d %ld\n",__LINE__,
266              libssh2_sftp_last_error(sessions[cnt]->sftp_session));
267      return 0;
268    }
269  }while(!sftp_handle);
270  fprintf(stderr, "libssh2_sftp_open() is done, get file information\n");
271  do {
272  rc = libssh2_sftp_stat_ex(sessions[cnt]->sftp_session, targetPath, strlen(targetPath),
273                            LIBSSH2_SFTP_LSTAT, &attrs );
274  if (rc<0 &&
275      (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN))
276    {
277      fprintf(stderr, "error trying to fstat_ex, returned %d\n", rc);
278      break;
279    }
280  else
281    {
282      fprintf(stderr, "Stat Data: RetCode=%d\n", rc);
283      fprintf(stderr, "Stat Data: Size=%llu\n", attrs.filesize);
284      fprintf(stderr, "Stat Data: Perm=%lx\n",  attrs.permissions);
285      fprintf(stderr, "Stat Data: mtime=%lu\n",  attrs.mtime);
286      if(rc==0)
287        break;
288      result=attrs.filesize;
289    }
290  } while (true);
291  libssh2_sftp_close(sftp_handle);
292  //libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
293
294  return result;
295}
296
297/**
298 * Upload a file over an opened SSH connection
299 * @param conf maps pointer to the main configuration maps
300 * @param localPath const char* defining the local path for accessing the file
301 * @param targetPath const char* defining the path for storing the file on the
302 * remote host
303 * @return true in case of success, false if failure occured
304 */
305bool ssh_copy(maps* conf,const char* localPath,const char* targetPath){
306  char mem[1024 * 1000];
307  size_t nread;
308  size_t memuse=0;
309  time_t start;
310  long total = 0;
311  int duration;
312  int cnt=ssh_get_cnt(conf);
313  int rc;
314  LIBSSH2_SFTP_HANDLE *sftp_handle;
315  //map* myMap=getMapFromMaps(conf,"lenv","cnt_session");
316  if(getMapFromMaps(conf,"lenv","cnt_session")!=NULL){
317    char tmp[10];
318    sprintf(tmp,"%d",cnt+1);
319    setMapInMaps(conf,"lenv","cnt_session",tmp);
320  }else
321    setMapInMaps(conf,"lenv","cnt_session","0");
322  FILE *local = fopen(localPath, "rb");
323  if (!local) {
324    fprintf(stderr, "Can't open local file %s\n", localPath);
325    return -1;
326  }
327
328  do {
329    sessions[cnt]->sftp_session = libssh2_sftp_init(sessions[cnt]->session);
330    if (!sessions[cnt]->sftp_session &&
331        (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
332     
333      fprintf(stderr, "Unable to init SFTP session\n");
334      return false;
335    }
336  } while (!sessions[cnt]->sftp_session);
337
338  do {
339    sftp_handle =
340      libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath,
341                       
342                        LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
343                        LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
344                        LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
345
346    if (!sftp_handle &&
347        (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
348     
349      fprintf(stderr, "Unable to open file with SFTP\n");
350      return false;
351    }
352  } while (!sftp_handle);
353  start = time(NULL);
354 
355  do {
356    nread = fread(&mem[memuse], 1, sizeof(mem)-memuse, local);
357    if (nread <= 0) {
358      if (memuse > 0)
359        nread = 0;
360      else
361        break;
362    }
363    memuse += nread;
364    total += nread;
365   
366    while ((rc = libssh2_sftp_write(sftp_handle, mem, memuse)) ==
367           LIBSSH2_ERROR_EAGAIN) {
368      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
369    }
370    if(rc < 0)
371      break;
372   
373    if(memuse - rc) {
374      memmove(&mem[0], &mem[rc], memuse - rc);
375      memuse -= rc;
376    }
377    else
378      memuse = 0;
379   
380  } while (rc > 0);
381 
382  duration = (int)(time(NULL)-start);
383  fclose(local);
384  libssh2_sftp_close(sftp_handle);
385
386  libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
387  return true;
388}
389
390/**
391 * Download a file over an opened SSH connection
392 * @param conf maps pointer to the main configuration maps
393 * @param localPath const char* defining the local path for storing the file
394 * @param targetPath const char* defining the path for accessing the file on the
395 * remote host
396 * @return true in case of success, false if failure occured
397 */
398int ssh_fetch(maps* conf,const char* localPath,const char* targetPath){
399  char mem[1024];
400  size_t nread;
401  size_t memuse=0;
402  time_t start;
403  long total = 0;
404  int duration;
405  int cnt=ssh_get_cnt(conf);
406  int rc;
407  LIBSSH2_SFTP_HANDLE *sftp_handle;
408  FILE *local = fopen(localPath, "wb");
409  if (!local) {
410    fprintf(stderr, "Can't open local file %s\n", localPath);
411    return -1;
412  }
413
414  do {
415    sessions[cnt]->sftp_session = libssh2_sftp_init(sessions[cnt]->session);
416    if (!sessions[cnt]->sftp_session &&
417        (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN)) {
418     
419      fprintf(stderr, "Unable to init SFTP session\n");
420      return false;
421    }
422  } while (!sessions[cnt]->sftp_session);
423    do {
424        sftp_handle = libssh2_sftp_open(sessions[cnt]->sftp_session, targetPath,
425
426                                        LIBSSH2_FXF_READ, 0);
427 
428        if (!sftp_handle) {
429            if (libssh2_session_last_errno(sessions[cnt]->session) != LIBSSH2_ERROR_EAGAIN) {
430
431                fprintf(stderr, "Unable to open file with SFTP\n");
432                return -1;
433            }
434            else {
435                fprintf(stderr, "non-blocking open\n");
436                waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session); 
437            }
438        }
439    } while (!sftp_handle);
440 
441    int result=1;
442    do {
443        do {
444            rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
445            fprintf(stderr, "libssh2_sftp_read returned %d\n",
446                    rc);
447 
448            if(rc > 0) {
449                write(2, mem, rc);
450                fwrite(mem, rc, 1, local);
451            }
452        } while (rc > 0);
453 
454        if(rc != LIBSSH2_ERROR_EAGAIN) {
455          result=-1;
456          break;
457        }
458
459        struct timeval timeout;
460        fd_set fd;
461        timeout.tv_sec = 10;
462        timeout.tv_usec = 0;
463 
464        FD_ZERO(&fd);
465 
466        FD_SET(sessions[cnt]->sock_id, &fd);
467 
468        rc = select(sessions[cnt]->sock_id+1, &fd, &fd, NULL, &timeout);
469        if(rc <= 0) {
470          if(rc==0)
471            fprintf(stderr, "SFTP download timed out: %d\n", rc);
472          else
473            fprintf(stderr, "SFTP download error: %d\n", rc);
474          result=-1;
475          break;
476        }
477 
478    } while (1);
479  duration = (int)(time(NULL)-start);
480  fclose(local);
481  libssh2_sftp_close(sftp_handle);
482
483  libssh2_sftp_shutdown(sessions[cnt]->sftp_session);
484  return 0;
485}
486
487/**
488 * Execute a command over an opened SSH connection
489 * @param conf maps pointer to the main configuration maps
490 * @param command const char pointer to the command to be executed
491 * @return bytecount resulting from the execution of the command
492 */
493int ssh_exec(maps* conf,const char* command){
494  int cnt=ssh_get_cnt(conf);
495  LIBSSH2_CHANNEL *channel;
496  int rc;
497  int bytecount = 0;
498  int exitcode;
499  char *exitsignal=(char *)"none";
500  while( (channel = libssh2_channel_open_session(sessions[cnt]->session)) == NULL &&
501         libssh2_session_last_error(sessions[cnt]->session,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN ) {
502      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
503  }
504  if( channel == NULL ){
505    fprintf(stderr,"Error\n");
506    return 1;
507  }
508  while( (rc = libssh2_channel_exec(channel, command)) == LIBSSH2_ERROR_EAGAIN ) {
509    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
510  }
511  if( rc != 0 ) {
512    fprintf(stderr,"Error\n");
513    return -1;
514  }
515
516  map* tmpPath=getMapFromMaps(conf,"main","tmpPath");
517  map* uuid=getMapFromMaps(conf,"lenv","usid");
518  char *logPath=(char*)malloc((strlen(tmpPath->value)+strlen(uuid->value)+11)*sizeof(char));
519  sprintf(logPath,"%s/exec_out_%s",tmpPath->value,uuid->value);
520  FILE* logFile=fopen(logPath,"wb");
521  while(true){
522    int rc;
523    do {
524      char buffer[0x4000];
525      rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
526     
527      if( rc > 0 ){
528        int i;
529        bytecount += rc;
530        buffer[rc]=0;
531        fprintf(logFile,"%s",buffer);
532        fflush(logFile);
533      }
534    }
535    while( rc > 0 );
536   
537    if( rc == LIBSSH2_ERROR_EAGAIN ) {
538      waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
539    }
540    else
541      break;
542  }
543  fclose(logFile);
544  exitcode = 127;
545  while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
546    waitsocket(sessions[cnt]->sock_id, sessions[cnt]->session);
547 
548  if( rc == 0 ) {
549    exitcode = libssh2_channel_get_exit_status( channel );
550    libssh2_channel_get_exit_signal(channel, &exitsignal,
551                                    NULL, NULL, NULL, NULL, NULL);
552  }
553 
554  if (exitsignal)
555    fprintf(stderr, "\nGot signal: %s\n", exitsignal);
556  else
557    fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
558 
559  libssh2_channel_free(channel);
560
561  return bytecount;
562}
563
564/**
565 * Close an opened SSH connection
566 * @param conf maps pointer to the main configuration maps
567 * @param con SSHCON pointer to the SSH connection
568 * @return true in case of success, false if failure occured
569 */
570bool ssh_close_session(maps* conf,SSHCON* con){
571  while (libssh2_session_disconnect(con->session, "Normal Shutdown, Thank you for using the ZOO-Project sshapi")
572         == LIBSSH2_ERROR_EAGAIN);
573  libssh2_session_free(con->session);
574#ifdef WIN32
575  closesocket(con->sock_id);
576#else
577  close(con->sock_id);
578#endif
579  return true;
580}
581
582/**
583 * Close all the opened SSH connections
584 * @param conf maps pointer to the main configuration maps
585 * @return true in case of success, false if failure occured
586 */
587bool ssh_close(maps* conf){
588  int i,nb_sessions;
589  map* tmp=getMapFromMaps(conf,"lenv","nb_sessions");
590  if(tmp!=NULL){
591    nb_sessions=atoi(tmp->value);
592    for(i=0;i<nb_sessions;i++)
593      ssh_close_session(conf,sessions[i]);
594  }
595  libssh2_exit();
596  return true;
597}
Note: See TracBrowser for help on using the repository browser.

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png