5773050 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n connect.c
  1 /* connect.c */
  2 /* it handles connections to ssh servers */
  3 /*
  4 Copyright 2003 Aris Adamantiadis
  5 
  6 This file is part of the SSH Library
  7 
  8 The SSH Library is free software; you can redistribute it and/or modify
  9 it under the terms of the GNU Lesser General Public License as published by
 10 the Free Software Foundation; either version 2.1 of the License, or (at your
 11 option) any later version.
 12 
 13 The SSH Library is distributed in the hope that it will be useful, but
 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 16 License for more details.
 17 
 18 You should have received a copy of the GNU Lesser General Public License
 19 along with the SSH Library; see the file COPYING.  If not, write to
 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 21 MA 02111-1307, USA. */
 22 
 23 #include "libssh/priv.h"
 24 
 25 #ifdef HAVE_NETDB_H
 26 #include <netdb.h>
 27 #endif
 28 #include <string.h>
 29 #include <unistd.h>
 30 #include <stdlib.h>
 31 #include <errno.h>
 32 #include <sys/types.h>
 33 #ifdef HAVE_SYS_SOCKET_H
 34 #include <sys/socket.h>
 35 #endif
 36 #ifdef HAVE_SYS_SELECT_H
 37 #include <sys/select.h>
 38 #endif
 39 #include <sys/time.h>
 40 #ifdef HAVE_NETINET_IN_H
 41 #include <netinet/in.h>
 42 #endif
 43 #include <fcntl.h>
 44 #ifdef HAVE_SYS_POLL_H
 45 #include <sys/poll.h>
 46 #endif
 47 
 48 #define FIRST_CHANNEL 42
 49 static void sock_set_nonblocking(int sock) {
 50 #if defined(F_SETFL) && defined(O_NONBLOCK)
 51     fcntl(sock,F_SETFL,O_NONBLOCK);
 52 #endif
 53 }
 54 static void sock_set_blocking(int sock){
 55 #ifdef F_SETFL
 56     fcntl(sock,F_SETFL,0);
 57 #endif
 58 }
 59 
 60 int ssh_net_init(void) {
 61 #ifdef __WIN32__
 62    static int called = 0;
 63    WSADATA wsaData;
 64 
 65    if (called) {
 66        return(0);
 67    }
 68 
 69    if (WSAStartup(MAKEWORD(2, 0), &wsaData)!=0) {
 70     return(-1);
 71    }
 72    if (wsaData.wVersion!=MAKEWORD(2, 0)) {
 73     /* Cleanup Winsock stuff */
 74     WSACleanup();
 75     return(-1);
 76    }
 77 
 78    called = 1;
 79 #endif
 80    return(0);
 81 }
 82 
 83 /* connect_host connects to an IPv4 (or IPv6) host */
 84 /* specified by its IP address or hostname. */
 85 /* output is the file descriptor, <0 if failed. */
 86 
 87 int ssh_connect_host(const char *host, const char *bind_addr, int port,long timeout, long usec){
 88     struct sockaddr_in sa;
 89     struct sockaddr_in bindsa;
 90     struct hostent *hp=NULL;
 91     static int count=0; /* for reentrencity */
 92     int s;
 93 
 94     ssh_net_init();
 95 
 96     while(++count>1)
 97         --count;
 98 
 99 
100     sa.sin_family = AF_INET;
101 
102 #ifdef HAVE_INET_ATON
103    if (!inet_aton(host,&sa.sin_addr)) {
104 #else
105 #ifdef HAVE_INET_ADDR
106    if ( (sa.sin_addr.s_addr=inet_addr(host) )==-1) {
107 #else
108    {
109 #endif
110 #endif
111        hp = gethostbyname(host);
112 
113        if(!hp) {
114            --count;
115 #ifdef HAVE_HSTRERROR
116              ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno));
117 #else
118              ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,strerror(h_errno));
119 #endif
120              return -1;
121         }
122 
123         memcpy(&sa.sin_addr.s_addr,hp->h_addr_list[0],hp->h_length);
124         sa.sin_family=hp->h_addrtype;
125     }
126     sa.sin_port=htons((unsigned short)port);
127     --count;
128 
129     if(bind_addr){
130         ssh_say(2,"resolving %s\n",bind_addr);
131         hp=NULL;
132         while(++count>1)
133             --count;
134 #ifdef HAVE_GETHOSTBYADDR
135         hp=gethostbyaddr(bind_addr,4,AF_INET);
136 #endif
137 #ifdef HAVE_GETHOSTBYNAME
138         if(!hp)
139             hp=gethostbyname(bind_addr);
140 #endif
141         if(!hp){
142             --count;
143 #ifdef HAVE_HSTRERROR
144             ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno));
145 #else
146             ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,strerror(h_errno));
147 #endif
148             return -1;
149         }
150     }
151     memset(&bindsa,0,sizeof(bindsa));
152     /* create socket */
153     s=socket(sa.sin_family,SOCK_STREAM,0);
154     if(s<0){
155         if(bind_addr)
156             --count;
157         ssh_set_error(NULL,SSH_FATAL,"socket : %s",strerror(errno));
158         return s;
159     }
160 
161     if(bind_addr){
162         memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length);
163         bindsa.sin_family=hp->h_addrtype;
164         --count;
165         if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){
166             ssh_set_error(NULL,SSH_FATAL,"Binding local address : %s",strerror(errno));
167             close(s);
168             return -1;
169         }
170     }
171     if(timeout){
172         struct timeval to;
173         fd_set set;
174         int ret=0;
175         int len=sizeof(ret);
176         to.tv_sec=timeout;
177         to.tv_usec=usec;
178         sock_set_nonblocking(s);
179         connect(s,(struct sockaddr* )&sa,sizeof(sa));
180         FD_ZERO(&set);
181         FD_SET(s,&set);
182         ret=select(s+1,NULL,&set,NULL,&to);
183         if(ret==0){
184             /* timeout */
185             ssh_set_error(NULL,SSH_FATAL,"Timeout while connecting to %s:%d",host,port);
186             close(s);
187             return -1;
188         }
189         if(ret<0){
190             ssh_set_error(NULL,SSH_FATAL,"Select error : %s",strerror(errno));
191             close(s);
192             return -1;
193         }
194         /* get connect(2) return code. zero means no error */
195         getsockopt(s,SOL_SOCKET,SO_ERROR,&ret,&len);
196         if (ret!=0){
197             ssh_set_error(NULL,SSH_FATAL,"Connecting : %s",strerror(ret));
198             close(s);
199             return -1;
200         }
201         /* s is connected ? */
202         ssh_say(3,"socket connected with timeout\n");
203         sock_set_blocking(s);
204         return s;
205     }
206     if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){
207         close(s);
208         ssh_set_error(NULL,SSH_FATAL,"connect: %s",strerror(errno));
209         return -1;
210     }
211     return s;
212 }
213 
214 /* connection_new() returns a newly allocated SSH_SESSION structure pointer */
215 SSH_SESSION *ssh_session_new() {
216     SSH_SESSION *conn=malloc(sizeof (SSH_SESSION));
217     memset(conn,0,sizeof(SSH_SESSION));
218     conn->next_crypto=crypto_new();
219     conn->maxchannel=FIRST_CHANNEL;
220     return conn;
221 }
222 
223 
224 /* returns 1 if bytes are available on the stream, 0 instead */
225 int ssh_fd_poll(SSH_SESSION *session){
226 #ifdef HAVE_POLL
227     struct pollfd fdset;
228 #else
229     struct timeval sometime;
230     fd_set descriptor;
231 #endif
232     if(session->datatoread)
233         return(session->datatoread);
234 #ifdef HAVE_POLL
235     fdset.fd=session->fd;
236     fdset.events=POLLHUP|POLLIN|POLLPRI;
237     fdset.revents=0;
238     if(poll(&fdset,1,0)==0)
239         return 0;
240     if(fdset.revents & (POLLHUP|POLLIN|POLLPRI))
241         return (session->datatoread=1);
242     return 0;
243 #elif defined(HAVE_SELECT)
244     
245     /* Set to return immediately (no blocking) */
246     sometime.tv_sec = 0;
247     sometime.tv_usec = 0;
248 
249     /* Set up descriptor */
250     FD_ZERO(&descriptor);
251     FD_SET(session->fd, &descriptor);
252 
253     /* Make the call, and listen for errors */
254     if (select(session->fd + 1, &descriptor, NULL, NULL, &sometime) < 0) {
255         ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno));
256         return -1;
257     }
258     session->datatoread=FD_ISSET(session->fd,&descriptor);
259     return session->datatoread;
260 #else
261 #error This system does not have poll() or select(), so ssh_fd_poll() will not work correctly
262     return 0;
263 #endif
264 }
265 
266 /* this function is a complete wrapper for the select syscall. it does more than wrapping ... */
267 int ssh_select(CHANNEL **channels, CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout){
268     struct timeval zerotime;
269     fd_set localset, localset2;
270     int rep = 0;
271     int i, j;
272     int set;
273     int getc_ret;
274 
275     zerotime.tv_sec = 0;
276     zerotime.tv_usec = 1;
277 
278     /* first, poll the maxfd file descriptors from the user with a zero-second timeout. they have the bigger priority */
279     if (maxfd > 0) {
280         memcpy(&localset, readfds, sizeof(*readfds));
281         rep = select(maxfd, &localset, NULL, NULL, &zerotime);
282         // catch the eventual errors
283         if (rep == -1) {
284             FD_ZERO(&localset);
285             if (FD_ISSET(fileno(stdin), readfds)) {
286                 getc_ret = getc(stdin);
287                 if (getc_ret != EOF) {
288                     ungetc(getc_ret, stdin);
289                     FD_SET(fileno(stdin), &localset);
290                 }
291             }
292         }
293     }
294 
295     /* polls every channel. */
296     j = 0;
297     for (i = 0; channels[i]; i++) {
298         if (channel_poll(channels[i], 0) > 0) {
299             outchannels[j] = channels[i];
300             j++;
301         } else if (channel_poll(channels[i], 1) > 0) {
302             outchannels[j] = channels[i];
303             j++;
304         }
305     }
306     outchannels[j] = NULL;
307 
308     /* look into the localset for active fd */
309     set = 0;
310     for (i = 0; i < maxfd; i++) {
311         if (FD_ISSET(i, &localset)) {
312             set = 1;
313             break;
314         }
315     }
316 
317     /* j!=0 means a channel has data */
318     if ((j != 0) || (set != 0)) {
319         if (maxfd > 0) {
320             memcpy(readfds, &localset, sizeof(fd_set));
321         }
322         return 0;
323     }
324 
325     /* at this point, not any channel had any data ready for reading, nor any fd had data for reading */
326     memcpy(&localset, readfds, sizeof(fd_set));
327     for (i = 0; channels[i]; i++) {
328         if (channels[i]->session->alive) {
329             FD_SET(channels[i]->session->fd, &localset);
330             if (channels[i]->session->fd > (maxfd - 1)) {
331                 maxfd = channels[i]->session->fd + 1;
332             }
333         }
334     }
335 
336     rep = select(maxfd, &localset, NULL, NULL, timeout);
337     if (rep == -1 && errno == EINTR) {
338         return SSH_EINTR; /* interrupted by a signal */
339     }
340 
341     if (rep == -1) {
342         /* was the error due to a libssh's Channel or from a closed descriptor from the user ? user closed descriptors
	have been
343         caught in the first select and not closed since that moment. that case shouldn't occur at all */
344         FD_ZERO(&localset);
345         if (FD_ISSET(fileno(stdin), readfds)) {
346             getc_ret = getc(stdin);
347             if (getc_ret != EOF) {
348                 ungetc(getc_ret, stdin);
349                 FD_SET(fileno(stdin), &localset);
350             }
351         }
352     }
353 
354     /* set the data_to_read flag on each session */
355     for (i = 0; channels[i]; i++) {
356         if (FD_ISSET(channels[i]->session->fd, &localset)) {
357             channels[i]->session->datatoread = 1;
358         }
359     }
360 
361     /* now, test each channel */
362     j = 0;
363     for (i = 0; channels[i]; i++) {
364         if (FD_ISSET(channels[i]->session->fd, &localset)) {
365             if ((channel_poll(channels[i], 0) > 0) || (channel_poll(channels[i], 1) > 0)) {
366                 outchannels[j] = channels[i];
367                 j++;
368             }
369         }
370     }
371 
372     outchannels[j] = NULL;
373     FD_ZERO(&localset2);
374     for (i = 0; i < maxfd; i++) {
375         if (FD_ISSET(i, readfds) && FD_ISSET(i, &localset)) {
376             FD_SET(i, &localset2);
377         }
378     }
379 
380     memcpy(readfds, &localset2, sizeof(fd_set));
381     return 0;
382 }
5773051 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 17:46:50