aboutsummaryrefslogtreecommitdiff
path: root/libssh/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/connect.c')
-rw-r--r--libssh/connect.c118
1 files changed, 57 insertions, 61 deletions
diff --git a/libssh/connect.c b/libssh/connect.c
index d1e8bf59..afe1dadf 100644
--- a/libssh/connect.c
+++ b/libssh/connect.c
@@ -22,6 +22,7 @@ MA 02111-1307, USA. */
#include <netdb.h>
#include <string.h>
+#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
@@ -33,11 +34,6 @@ MA 02111-1307, USA. */
#include <fcntl.h>
#include "libssh/priv.h"
-#ifndef HAVE_GETHOSTBYNAME
-#ifndef HAVE_GETHOSTBYADDR
-#error "your system doesn't have gethostbyname nor gethostbyaddr"
-#endif
-#endif
#ifndef HAVE_SELECT
#error "Your system must have select()"
#endif
@@ -49,71 +45,67 @@ static void sock_set_blocking(int sock){
fcntl(sock,F_SETFL,0);
}
+static int getai(const char *host, int port, struct addrinfo **ai)
+{
+ struct addrinfo hints;
+ char *service=NULL;
+ char s_port[10];
+
+ memset(&hints,0,sizeof(hints));
+ hints.ai_protocol=IPPROTO_TCP;
+ hints.ai_socktype=SOCK_STREAM;
+ if(port==0){
+ hints.ai_flags=AI_PASSIVE;
+ } else {
+ snprintf(s_port,sizeof(s_port),"%hu",port);
+ service=s_port;
+ }
+ return getaddrinfo(host,service,&hints,ai);
+}
+
/* connect_host connects to an IPv4 (or IPv6) host */
/* specified by its IP address or hostname. */
/* output is the file descriptor, <0 if failed. */
int ssh_connect_host(SSH_SESSION *session, const char *host, const char
*bind_addr, int port,long timeout, long usec){
- struct sockaddr_in sa;
- struct sockaddr_in bindsa;
- struct hostent *hp=NULL;
- static int count=0; /* for reentrencity */
int s;
- while(++count>1)
- --count;
+ int my_errno;
+ struct addrinfo *ai;
-#ifdef HAVE_GETHOSTBYNAME
- hp=gethostbyname(host);
-#endif
- if(!hp){
- --count;
- ssh_set_error(session,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno));
+ my_errno=getai(host, port, &ai);
+ if (my_errno){
+ ssh_set_error(session,SSH_FATAL,"Failed to resolve hostname %s (%d)",host,my_errno);
return -1;
}
- memset(&sa,0,sizeof(sa));
- memcpy(&sa.sin_addr,hp->h_addr,hp->h_length);
- sa.sin_family=hp->h_addrtype;
- sa.sin_port=htons((unsigned short)port);
- --count;
- if(bind_addr){
- ssh_say(2,"resolving %s\n",bind_addr);
- hp=NULL;
- while(++count>1)
- --count;
-#ifdef HAVE_GETHOSTBYADDR
- hp=gethostbyaddr(bind_addr,4,AF_INET);
-#endif
-#ifdef HAVE_GETHOSTBYNAME
- if(!hp)
- hp=gethostbyname(bind_addr);
-#endif
- if(!hp){
- --count;
- ssh_set_error(session,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno));
- return -1;
- }
- }
- memset(&bindsa,0,sizeof(bindsa));
/* create socket */
- s=socket(sa.sin_family,SOCK_STREAM,0);
+ s=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol);
if(s<0){
- if(bind_addr)
- --count;
ssh_set_error(session,SSH_FATAL,"socket : %s",strerror(errno));
+ freeaddrinfo(ai);
return s;
}
if(bind_addr){
- memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length);
- bindsa.sin_family=hp->h_addrtype;
- --count;
- if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){
+ struct addrinfo *bind_ai;
+
+ ssh_say(2,"resolving %s\n",bind_addr);
+ my_errno=getai(host,0,&bind_ai);
+ if (my_errno){
+ ssh_set_error(session,SSH_FATAL,"Failed to resolve bind address %s (%d)",bind_addr,my_errno);
+ freeaddrinfo(ai);
+ return -1;
+ }
+
+ if(bind(s,bind_ai->ai_addr,bind_ai->ai_addrlen)<0){
ssh_set_error(session,SSH_FATAL,"Binding local address : %s",strerror(errno));
+ freeaddrinfo(ai);
+ freeaddrinfo(bind_ai);
close(s);
return -1;
}
+ freeaddrinfo(bind_ai);
}
if(timeout){
struct timeval to;
@@ -123,7 +115,8 @@ int ssh_connect_host(SSH_SESSION *session, const char *host, const char
to.tv_sec=timeout;
to.tv_usec=usec;
sock_set_nonblocking(s);
- connect(s,(struct sockaddr* )&sa,sizeof(sa));
+ connect(s,ai->ai_addr,ai->ai_addrlen);
+ freeaddrinfo(ai);
FD_ZERO(&set);
FD_SET(s,&set);
ret=select(s+1,NULL,&set,NULL,&to);
@@ -150,11 +143,12 @@ int ssh_connect_host(SSH_SESSION *session, const char *host, const char
sock_set_blocking(s);
return s;
}
- if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){
- close(s);
+ if(connect(s,ai->ai_addr,ai->ai_addrlen)<0){
ssh_set_error(session,SSH_FATAL,"connect: %s",strerror(errno));
- return -1;
+ close(s);
+ s=-1;
}
+ freeaddrinfo(ai);
return s;
}
@@ -220,13 +214,15 @@ int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *read
j=0;
// polls every channel.
for(i=0;channels[i];i++){
- if(channel_poll(channels[i],0)>0){
- outchannels[j]=channels[i];
- j++;
- } else
- if(channel_poll(channels[i],1)>0){
- outchannels[j]=channels[i];
- j++;
+ if(channels[i]->session->alive){
+ if(channel_poll(channels[i],0)>0){
+ outchannels[j]=channels[i];
+ j++;
+ } else
+ if(channel_poll(channels[i],1)>0){
+ outchannels[j]=channels[i];
+ j++;
+ }
}
}
outchannels[j]=NULL;
@@ -261,13 +257,13 @@ int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *read
}
/* set the data_to_read flag on each session */
for(i=0;channels[i];i++)
- if(FD_ISSET(channels[i]->session->fd,&localset))
+ if(channels[i]->session->alive && FD_ISSET(channels[i]->session->fd,&localset))
channels[i]->session->data_to_read=1;
/* now, test each channel */
j=0;
for(i=0;channels[i];i++){
- if(FD_ISSET(channels[i]->session->fd,&localset))
+ if(channels[i]->session->alive && FD_ISSET(channels[i]->session->fd,&localset))
if((channel_poll(channels[i],0)>0) || (channel_poll(channels[i],1)>0)){
outchannels[j]=channels[i];
j++;