5772780 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11/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 <netdb.h>
 24 #include <string.h>
 25 #include <unistd.h>
 26 #include <stdlib.h>
 27 #include <errno.h>
 28 #include <sys/types.h>
 29 #include <sys/socket.h>
 30 #include <sys/select.h>
 31 #include <sys/time.h>
 32 #include <netinet/in.h>
 33 #include <fcntl.h>
 34 #include "libssh/priv.h"
 35 #ifdef HAVE_SYS_POLL_H
 36 #include <sys/poll.h>
 37 #endif
 38 
 39 #ifndef HAVE_GETHOSTBYNAME
 40 #ifndef HAVE_GETHOSTBYADDR
 41 #error "your system doesn't have gethostbyname nor gethostbyaddr"
 42 #endif
 43 #endif
 44 #define FIRST_CHANNEL 42
 45 static void sock_set_nonblocking(int sock) {
 46     fcntl(sock,F_SETFL,O_NONBLOCK);
 47 }
 48 static void sock_set_blocking(int sock){
 49     fcntl(sock,F_SETFL,0);
 50 }
 51 
 52 /* connect_host connects to an IPv4 (or IPv6) host */
 53 /* specified by its IP address or hostname. */
 54 /* output is the file descriptor, <0 if failed. */
 55 
 56 int ssh_connect_host(const char *host, const char *bind_addr, int port,long timeout, long usec){
 57     struct sockaddr_in sa;
 58     struct sockaddr_in bindsa;
 59     struct hostent *hp=NULL;
 60     static int count=0; /* for reentrencity */
 61     int s;
 62     while(++count>1)
 63         --count;
 64 #ifdef HAVE_GETHOSTBYADDR
 65     hp=gethostbyaddr(host,4,AF_INET);
 66 #endif
 67 #ifdef HAVE_GETHOSTBYNAME
 68     if(!hp)
 69         hp=gethostbyname(host);
 70 #endif
 71     if(!hp){
 72         --count;
 73         ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno));
 74         return -1;
 75     }
 76     memset(&sa,0,sizeof(sa));
 77     memcpy(&sa.sin_addr,hp->h_addr,hp->h_length);
 78     sa.sin_family=hp->h_addrtype;
 79     sa.sin_port=htons((unsigned short)port);
 80     --count;
 81     
 82     if(bind_addr){
 83         ssh_say(2,"resolving %s\n",bind_addr);
 84         hp=NULL;
 85         while(++count>1)
 86             --count;
 87 #ifdef HAVE_GETHOSTBYADDR
 88         hp=gethostbyaddr(bind_addr,4,AF_INET);
 89 #endif
 90 #ifdef HAVE_GETHOSTBYNAME
 91         if(!hp)
 92             hp=gethostbyname(bind_addr);
 93 #endif
 94         if(!hp){
 95             --count;
 96             ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno));
 97             return -1;
 98         }
 99     }
100     memset(&bindsa,0,sizeof(bindsa));
101     /* create socket */
102     s=socket(sa.sin_family,SOCK_STREAM,0);
103     if(s<0){
104         if(bind_addr)
105             --count;
106         ssh_set_error(NULL,SSH_FATAL,"socket : %s",strerror(errno));
107         return s;
108     }
109 
110     if(bind_addr){
111         memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length);
112         bindsa.sin_family=hp->h_addrtype;
113         --count;
114         if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){
115             ssh_set_error(NULL,SSH_FATAL,"Binding local address : %s",strerror(errno));
116             close(s);
117             return -1;
118         }
119     }
120     if(timeout){
121         struct timeval to;
122         fd_set set;
123         int ret=0;
124         int len=sizeof(ret);
125         to.tv_sec=timeout;
126         to.tv_usec=usec;
127         sock_set_nonblocking(s);
128         connect(s,(struct sockaddr* )&sa,sizeof(sa));
129         FD_ZERO(&set);
130         FD_SET(s,&set);
131         ret=select(s+1,NULL,&set,NULL,&to);
132         if(ret==0){
133             /* timeout */
134             ssh_set_error(NULL,SSH_FATAL,"Timeout while connecting to %s:%d",host,port);
135             close(s);
136             return -1;
137         }
138         if(ret<0){
139             ssh_set_error(NULL,SSH_FATAL,"Select error : %s",strerror(errno));
140             close(s);
141             return -1;
142         }
143         /* get connect(2) return code. zero means no error */
144         getsockopt(s,SOL_SOCKET,SO_ERROR,&ret,&len);
145         if (ret!=0){
146             ssh_set_error(NULL,SSH_FATAL,"Connecting : %s",strerror(ret));
147             close(s);
148             return -1;
149         }
150         /* s is connected ? */
151         ssh_say(3,"socket connected with timeout\n");
152         sock_set_blocking(s);
153         return s;
154     }
155     if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){
156         close(s);
157         ssh_set_error(NULL,SSH_FATAL,"connect: %s",strerror(errno));
158         return -1;
159     }
160     return s;
161 }
162 
163 /* connection_new() returns a newly allocated SSH_SESSION structure pointer */
164 SSH_SESSION *ssh_session_new() {
165     SSH_SESSION *conn=malloc(sizeof (SSH_SESSION));
166     memset(conn,0,sizeof(SSH_SESSION));
167     conn->next_crypto=crypto_new();
168     conn->maxchannel=FIRST_CHANNEL;
169     return conn;
170 }
171 
172 
173 /* returns 1 if bytes are available on the stream, 0 instead */
174 int ssh_fd_poll(SSH_SESSION *session){
175 #ifdef HAVE_POLL
176     struct pollfd fdset;
177 #else
178     struct timeval sometime;
179     fd_set descriptor;
180 #endif
181     if(session->datatoread)
182         return(session->datatoread);
183 #ifdef HAVE_POLL
184     fdset.fd=session->fd;
185     fdset.events=POLLHUP|POLLIN|POLLPRI;
186     fdset.revents=0;
187     if(poll(&fdset,1,0)==0)
188         return 0;
189     if(fdset.revents & (POLLHUP|POLLIN|POLLPRI))
190         return (session->datatoread=1);
191     return 0;
192 #elif HAVE_SELECT
193     
194     /* Set to return immediately (no blocking) */
195     sometime.tv_sec = 0;
196     sometime.tv_usec = 0;
197     
198     /* Set up descriptor */
199     FD_ZERO(&descriptor);
200     FD_SET(session->fd, &descriptor);
201     
202     /* Make the call, and listen for errors */
203     if (select(session->fd + 1, &descriptor, NULL, NULL, &sometime) < 0) {
204         ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno));
205         return -1;
206     }
207     session->datatoread=FD_ISSET(session->fd,&descriptor);
208     return session->datatoread;
209 #else
210 #error This system does not have poll() or select(), so ssh_fd_poll() will not work correctly
211     return 0;
212 #endif
213 }
214 
215 /* this function is a complete wrapper for the select syscall. it does more than wrapping ... */
216 int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout){
217     struct timeval zerotime;
218     fd_set localset,localset2;
219     int rep;
220     int i,j;
221     int set;
222 
223     zerotime.tv_sec=0;
224     zerotime.tv_usec=0;
225     /* first, poll the maxfd file descriptors from the user with a zero-second timeout. they have the bigger priority */
226     if(maxfd>0){
227         memcpy(&localset,readfds, sizeof(fd_set));
228         rep=select(maxfd,&localset,NULL,NULL,&zerotime);
229         // catch the eventual errors
230         if(rep==-1)
231             return -1;
232     }
233     j=0;
234     // polls every channel.
235     for(i=0;channels[i];i++){
236         if(channel_poll(channels[i],0)>0){
237             outchannels[j]=channels[i];
238             j++;
239         } else
240         if(channel_poll(channels[i],1)>0){
241             outchannels[j]=channels[i];
242             j++;
243         }
244     }
245     outchannels[j]=NULL;
246     /* look into the localset for active fd */
247     set=0;
248     for(i=0;(i<maxfd) && !set;i++)
249         if(FD_ISSET(i,&localset))
250             set=1;
251     // j!=0 means a channel has data
252     if( (j!=0) || (set!=0)){
253         if(maxfd>0)
254             memcpy(readfds,&localset,sizeof(fd_set));
255         return 0;
256     }
257     /* at this point, not any channel had any data ready for reading, nor any fd had data for reading */
258     memcpy(&localset,readfds,sizeof(fd_set));
259     for(i=0;channels[i];i++){
260         if(channels[i]->session->alive){
261             FD_SET(channels[i]->session->fd,&localset);
262             if(channels[i]->session->fd>maxfd-1)
263                 maxfd=channels[i]->session->fd+1;
264         }
265     }
266     rep=select(maxfd,&localset,NULL,NULL,timeout);
267     if(rep==-1 && errno==EINTR){
268         return SSH_EINTR; /* interrupted by a signal */
269     }
270     if(rep==-1){
271         /* was the error due to a libssh's Channel or from a closed descriptor from the user ? user closed descriptors
	have been
272         caught in the first select and not closed since that moment. that case shouldn't occur at all */
273         return -1;
274     }
275     /* set the data_to_read flag on each session */
276     for(i=0;channels[i];i++)
277         if(FD_ISSET(channels[i]->session->fd,&localset))
278             channels[i]->session->datatoread=1;
279             
280     /* now, test each channel */
281     j=0;
282     for(i=0;channels[i];i++){
283         if(FD_ISSET(channels[i]->session->fd,&localset))
284             if((channel_poll(channels[i],0)>0) || (channel_poll(channels[i],1)>0)){
285                 outchannels[j]=channels[i];
286                 j++;
287             }
288     }
289     outchannels[j]=NULL;
290     FD_ZERO(&localset2);
291     for(i=0;i<maxfd;i++)
292         if(FD_ISSET(i,readfds) && FD_ISSET(i,&localset))
293             FD_SET(i,&localset2);
294     memcpy(readfds,&localset2,sizeof(fd_set));
295     return 0;
296 }
5772781 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59