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 } |