Changeset - e66e47801d87
[Not reviewed]
default
0 3 0
Nathan Brink (binki) - 16 years ago 2010-03-18 00:44:31
ohnobinki@ohnopublishing.net
support mingw32
3 files changed with 25 insertions and 4 deletions:
0 comments (0 inline, 0 general)
src/common/execio.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca
 

	
 
  This file is a part of DistRen.
 

	
 
  DistRen is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU Affero General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  DistRen is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU Affero General Public License for more details.
 

	
 
  You should have received a copy of the GNU Affero General Public License
 
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "execio.h"
 

	
 
#include <unistd.h>
 
#include <sys/types.h>
 
#ifndef _WIN32
 
#include <sys/wait.h>
 
#endif
 
#include <signal.h>
 
#include <malloc.h>
 
#include <fcntl.h>
 
#include <stdio.h>
 
#include <errno.h>
 

	
 
int execio_open(struct execio **rem, const char *progname, char *const argv[])
 
{
 
  /* pipe used to write to child */
 
  int pipe_write[2];
 
  /* pipe used to read from child */
 
  int pipe_read[2];
 

	
 
  pid_t child;
 

	
 
  /* for wait(2) if needed */
 
  int childstatus;
 
  
 
  int counter;
 
  int counter2;
 
  int maxfds;
 

	
 
  /* create two pipes to facilitate communication with child */
 
  if(pipe(pipe_write))
 
    return 1;
 
  if(pipe(pipe_read))
 
    {
 
      close(pipe_write[0]);
 
      close(pipe_write[1]);
 
      return 1;
 
    }
 
  
 
  /* parent */
 
  child = fork();
 
  if(child == -1)
 
    {
 
      close(pipe_write[0]);
 
      close(pipe_write[1]);
 
      close(pipe_read[0]);
 
      close(pipe_read[1]);
 
      return 1;
 
    }
 
  if(child)
 
    /* the parent proc: */
 
    {
 
      /* close sides of pipe we won't use */
 
      close(pipe_write[0]);
 
      close(pipe_read[1]);
 
      
 
      /* setup execio struct */
 
      (*rem) = malloc(sizeof(struct execio));
 
      if(!(*rem))
 
	{
 
	  /* we should tell the child we're dead - use wait and close our end of the pipes! */
 
	  close(pipe_write[1]);
 
	  close(pipe_read[0]);
 
	  /* we should probably pass of the wait() call to a thread that just does boring things like that. Especially for when the server tries to connect to other servers... */
 
	  /* maybe we should just kill instead of term the child */
 
	  kill(child, SIGTERM);
 
	  /* the waitpid(2) seems to indicate that only when the child is terminated will this wait return. */
 
	  waitpid(child, &childstatus, 0); 
 
	}
 
      (*rem)->pipe_write = pipe_write[1];
 
      (*rem)->pipe_read = pipe_read[0];
 
      (*rem)->state = 0;
 
      (*rem)->child = child;
 
      
 
      return 0;
 
    }
 
  
 
  /* child */
 
  else
 
    {
 
      /* close unused pipes */
 
      close(pipe_write[1]);
 
      close(pipe_read[0]);
 

	
 
      /*
 
	reset stdin, stdout, and stderr to the appropriate files. OK, not stderr :-) 
 
      */
 
      dup2(pipe_read[1], STDOUT_FILENO);
 
      dup2(pipe_write[0], STDIN_FILENO);
 
      /*
 
	close the fds that were dup'd
 
       */
 
      close(pipe_read[1]);
 
      close(pipe_write[0]);
 

	
 
      /* 
 
	 close all other file descriptors. We want to keep 0, 1, and 2 open. We don't know that the last open() or pipe() always gives the highest fd number. However, I will assume that it does. Maybe this is a bad idea:
 
       */
 
      counter = pipe_write[0];
 
      if(counter < pipe_write[1])
 
	counter = pipe_write[1];
 
      if(counter < pipe_read[0])
 
	counter = pipe_read[0];
 
      if(counter < pipe_read[1])
 
	counter = pipe_read[1];
 
      counter2 = 0;
 
      maxfds = counter;
 
      while(counter > 2)
 
	{
 
	  if(!close(counter))
 
	    counter2 ++; /* record how many descriptors we still had open :-) */
 
	  counter --;
 
	}
 
      
 
      /* stderr is the only stream we haven't confiscated atm - just for fun - I will confiscate it later, though, to support parsing error messages */
 
      fprintf(stderr, "closed %d/%d fds before execing \"%s\"\n", counter2, maxfds, progname);
 

	
 
      /*
 
	now exec: execvp uses interpreter to find the file to exec
 
       */
 
      execvp(progname, argv);
 

	
 
      return 1; /* this line should never be reached because we exec -- unless if the exec returns something bad. Then we'd have to tell execio over the pipe about that somehow... */
 
      /* in fact, maybe we should abort() here because if we returned, a monster of a distren client would exist! */
 
    }
 
}
 

	
 
/*
 
  returns 1 if child has exited, 
 
  returns 0 if child is still alive
 
 */
 
int _execio_checkpid(struct execio *eio)
 
{
 
  int childstatus;
 
  
 
#ifdef _WIN32
 
  waitpid(eio->child, &childstatus, 0);
 
#else
 
  waitpid(eio->child, &childstatus, WNOHANG);
 
#endif
 
  /* perror()? */
 

	
 
  return WIFEXITED(childstatus);
 
}
 

	
 

	
 
int execio_read(struct execio *eio, void *buf, size_t len, size_t *bytesread)
 
{
 
  /*
 
    TODO: detect NULL eio? 
 
    TODO: errno?
 
    update status of eio for execio_status/to be able to cleanup subproc??
 

	
 
    whenever read() returns 0, it means EOF
 
   */
 
  (*bytesread) = read(eio->pipe_read, buf, len);
 
  if(!*bytesread)
 
    {
 
      /* should also be able to figure out if is bad fd and should set EXECIO_STATE_ERROR instead of _EOF */
 
      eio->state = EXECIO_STATE_EOF;
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
int execio_write(struct execio *eio, void *buf, size_t len, size_t *bytesread)
 
{
 
  errno = 0;
 
  (*bytesread) = write(eio->pipe_write, buf, len);
 
  if(!*bytesread)
 
    {
 
      switch(errno)
 
	{
 
	case EPIPE:
 
	  /* 
 
	     the program closed the pipe (died)
 
	  */
 
	fprintf(stderr, "execio_write: the child program closed its stdin pipe\n");
 
	eio->state = EXECIO_STATE_EOF;
 
	break;
 
	
 
	default:
 
	  fprintf(stderr, "execio_write: unhandled error writing to an fd: \n");
 
	  perror("write");
 
	  eio->state = EXECIO_STATE_ERROR;
 
	  break;
 
	  
 
	}
 
      
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 

	
 
enum execio_state execio_state(struct execio *eio)
 
{
 
  return eio->state;
 
}
 

	
 

	
 
int execio_close(struct execio *eio)
 
{
 
  int childstatus;
 

	
 
  close(eio->pipe_read);
 
  close(eio->pipe_write);
 

	
 
  /* maybe we should just kill rather than term the child */
 
  kill(eio->child, SIGTERM);
 
  /* 
 
     the waitpid(2) seems to indicate that only when the child is terminated will this wait return. 
 
     This are of code will probably need improving - the ability to seng SIGKILL after a timeout? So we'll output a debug line before running waitpid
 
  */
 
  fprintf(stderr, "execio_close: running waitpid\n");
 
  waitpid(eio->child, &childstatus, 0);
 

	
 
  free(eio);
 
  
 
  return 0;
 
}
 

	
src/common/misc.c
Show inline comments
 
/*
 
  Copyright 2010 Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 

	
 
  This file is a part of DistRen.
 

	
 
  DistRen is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU Affero General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  DistRen is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU Affero General Public License for more details.
 

	
 
  You should have received a copy of the GNU Affero General Public License
 
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "common/misc.h"
 

	
 
#include <errno.h>
 
#include <malloc.h>
 
#include <unistd.h>
 
#include <stddef.h>
 

	
 
char *distren_getcwd()
 
{
 
  char *mycwd;
 
  size_t counter;
 
  
 
  /**
 
     This is completely wrong, feel free to rewrite with
 
     pathconf() in mind.
 
   */
 
  for(counter = 128; ; counter +=32)
 
    {
 
      mycwd = malloc(counter);
 

	
 
      errno = 0;
 
      if(getcwd(mycwd, counter))
 
	return mycwd;
 

	
 
      /** ERANGE means that counter is too small */
 
      if(errno != ERANGE)
 
	return (char *)NULL;
 

	
 
      free(mycwd);
 
    }
 
  return (char *)NULL;
 
}
src/common/remoteio.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 

	
 
  This file is a part of DistRen.
 

	
 
  DistRen is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU Affero General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  DistRen is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU Affero General Public License for more details.
 

	
 
  You should have received a copy of the GNU Affero General Public License
 
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
*/
 

	
 
#include "libremoteio.h"
 
#include "execio.h"
 
#include "asprintf.h"
 

	
 
#include <errno.h>
 
#ifndef _WIN32
 
#include <netdb.h>
 
#endif
 
#include <stdlib.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <sys/types.h>
 
#ifdef _WIN32
 
#include <winsock2.h>
 
#include <ws2tcpip.h>
 
#else
 
#include <sys/socket.h>
 
#endif
 
#include <unistd.h>
 

	
 
#ifndef WINDOWS
 
#ifndef _WIN32
 
#include <sys/un.h>
 
#endif
 

	
 
/* local */
 

	
 
#define REMOTEIO_DEFAULT_PORT "4050"
 

	
 
int _remoteio_ssh_open(struct remoteio *rem, struct remoteio_server *server);
 
int _remoteio_ssh_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
int _remoteio_ssh_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten);
 
int _remoteio_ssh_close(struct remoteio *rem);
 

	
 
#ifndef WINDOWS
 
#ifndef _WIN32
 
int _remoteio_sock_open(struct remoteio *rem, struct remoteio_server *server);
 
int _remoteio_sock_close(struct remoteio *rem);
 
#endif
 
int _remoteio_sock_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
int _remoteio_sock_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten);
 

	
 
int _remoteio_tcp_open(struct remoteio *rem, struct remoteio_server *server);
 
int _remoteio_tcp_close(struct remoteio *rem);
 

	
 
/**
 
  lookup table for different methods of remoteio:
 
  the enum remoteio_method is the index of the entry to use for that method. 
 
  Regardless, a NULL terminator is required because the configuration function
 
  searches through this table for the method specified in the config file.
 
*/
 
struct remoteio_method_funcmap funcmap[] = 
 
  {
 
    /* [REMOTEIO_METHOD_SSH] */
 
    {REMOTEIO_METHOD_SSH, &_remoteio_ssh_open, &_remoteio_ssh_read, &_remoteio_ssh_write, &_remoteio_ssh_close, "ssh"},
 
#ifndef WINDOWS
 
#ifndef _WIN32
 
    {REMOTEIO_METHOD_UNIX, &_remoteio_sock_open, &_remoteio_sock_read, &_remoteio_sock_write, &_remoteio_sock_close, "unix"},
 
#endif
 
    {REMOTEIO_METHOD_TCP, &_remoteio_tcp_open, &_remoteio_sock_read, &_remoteio_sock_write, &_remoteio_tcp_close, "tcp"},
 
    {REMOTEIO_METHOD_MAX, NULL, NULL, NULL, NULL, NULL}
 
  };
 

	
 
struct remoteio_server *remoteio_getserver(const struct remoteio_opts *opts, const char *servername);
 

	
 
int remoteio_config(cfg_t *cfg, struct remoteio_opts *opts)
 
{
 
  size_t numservers;
 
  size_t counter;
 
  static int haslisted_methods = 0;
 
  
 
  struct remoteio_server *aserver;
 

	
 
  opts->servers = malloc(sizeof(struct remoteio_server));
 
  if(!opts->servers)
 
    {
 
      fprintf(stderr, "@todo cleanup!\n");
 
      abort();
 
    }
 
  
 
  aserver = opts->servers;
 
  
 
  numservers = cfg_size(cfg, "server"); 
 
  for(counter = 0; counter < numservers; counter ++)
 
    {
 
      cfg_t *cfg_aserver;
 
      char *method;
 
      
 
      cfg_aserver = cfg_getnsec(cfg, "server", counter);
 
      
 
      if(!aserver) /*< if the malloc in the previous loop failed */
 
	abort();
 
      
 
      aserver->name = strdup(cfg_title(cfg_aserver));
 
      aserver->hostname = strdup(cfg_getstr(cfg_aserver, "hostname"));
 
      aserver->username = strdup(cfg_getstr(cfg_aserver, "username"));
 

	
 
      aserver->method = REMOTEIO_METHOD_MAX;
 
      method = cfg_getstr(cfg_aserver, "method");
 
      for(counter = 0; funcmap[counter].name; counter ++)
 
	if(strcmp(method, funcmap[counter].name) == 0)
 
	  aserver->method = REMOTEIO_METHOD_SSH;
 
      if(aserver->method == REMOTEIO_METHOD_MAX)
 
	{
 
	  fprintf(stderr, "No such method as %s\n", method);
 
	  if(!haslisted_methods)
 
	    {
 
	      fprintf(stderr, "Available methods:\n");
 
	      for(counter = 0; funcmap[counter].name; counter ++)
 
		fprintf(stderr, "\t%s\n", funcmap[counter].name);
 
	      
 
	      haslisted_methods ++;
 
	    }
 
	  abort();
 
	}
 
      
 
      if(counter < numservers - 1)
 
	{
 
	  aserver->next = malloc(sizeof(struct remoteio_server));
 
	  aserver = aserver->next;
 
	}
 
    }
 
  aserver->next = NULL;
 
  
 
  return 0;
 
}
 

	
 

	
 

	
 
int remoteio_open(struct remoteio **remoteio, struct remoteio_opts *opts, const char *servername)
 
{
 
  struct remoteio_server *theserver;
 
  struct remoteio *rem;
 

	
 
  int tmp;
 

	
 
  if(!opts)
 
    {
 
      fprintf(stderr, "%s:%d: no null opts!\n\tThis is a bug, please report it (after making sure it isn't already reported)\n", __FILE__, __LINE__);
 
      return 1;
 
    }
 

	
 
  theserver = remoteio_getserver(opts, servername);
 
  if(!theserver)
 
    {
 
      fprintf(stderr, "%s:%d: Could not find server named ``%s''\n", __FILE__, __LINE__, servername);
 
      return 1;
 
    }
 

	
 
  if(theserver->method >= REMOTEIO_METHOD_MAX
 
     || theserver->method < 0)
 
    {
 
      fprintf(stderr, "%s:%d: Unsupported remoteio method %d\n\tThis is a bug, probably indicating memory corruption. This is, of course, probably my fault (not your hardware's) ;-)\n", __FILE__, __LINE__, theserver->method);
 
@@ -184,297 +191,303 @@ int remoteio_open(struct remoteio **remo
 
    }
 
  
 
  return 0;
 
}
 

	
 
int remoteio_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread)
 
{
 
  return funcmap[rem->method].read_func(rem, buf, len, bytesread);
 
}
 

	
 
int remoteio_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten)
 
{
 
  return funcmap[rem->method].write_func(rem, buf, len, byteswritten);
 
}
 

	
 
int remoteio_close(struct remoteio *rem)
 
{
 
  int rtn;
 
  
 
  rtn = funcmap[rem->method].close_func(rem);
 
  free(rem);
 
  
 
  return rtn;
 
}
 

	
 

	
 
struct remoteio_server *remoteio_getserver(const struct remoteio_opts *opts, const char *servername)
 
{
 
  struct remoteio_server *aserver;
 
  
 
  for(aserver = opts->servers;
 
      aserver;
 
      aserver = aserver->next)
 
    if(!strcmp(servername, aserver->name))
 
      return aserver;
 

	
 
  return (struct remoteio_server *)NULL;
 
}
 

	
 

	
 

	
 

	
 
/**
 
   different remoteio methods' implementations:
 
 */
 

	
 
/*
 
  SSH, via execio
 
*/
 

	
 
int _remoteio_ssh_open(struct remoteio *rem, struct remoteio_server *server)
 
{
 
  char *userhost;
 
  char *sshargs[] = {rem->opts->ssh_command, NULL /* userhost */, "distrend", "-d", (char *)NULL};
 

	
 
  int rtn;
 

	
 
  if(server->username)
 
    _distren_asprintf(&userhost, "%s@%s", server->username, server->hostname);
 
  else
 
    userhost = strdup(server->hostname);
 
  sshargs[1] = userhost;
 

	
 
  rtn = execio_open( &rem->execio, "ssh", sshargs);
 
  if(rtn)
 
    {
 
      fprintf(stderr, "error opening remoteio channel to ssh userhost ``%s''\n" , userhost);
 
      free(userhost);
 
      return 1;
 
    }
 
  free(userhost);
 
  
 
  return 0;
 
}
 

	
 
int _remoteio_ssh_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread)
 
{
 
  return execio_read(rem->execio, buf, len, bytesread);
 
}
 

	
 
int _remoteio_ssh_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten)
 
{
 
  return execio_write(rem->execio, buf, len, byteswritten);
 
}
 

	
 
int _remoteio_ssh_close(struct remoteio *rem)
 
{
 
  int rtn;
 
  
 
  rtn = execio_close(rem->execio);
 
  if(rtn)
 
    fprintf(stderr, "%s:%d: error closing execio\n", __FILE__, __LINE__);
 
  
 
  return rtn;
 
}
 

	
 
#ifndef WINDOWS
 
#ifndef _WIN32
 
/*
 
  local sockets implementation (``named pipes''), unix-only
 
 */
 
int _remoteio_sock_open(struct remoteio *rem, struct remoteio_server *server)
 
{
 
  int sock;
 
  struct sockaddr_un sockaddr;
 

	
 
  /*
 
    The POSIX docs pretty much say that I can't depend on sockpath being able to be longer than 
 
    some proprietary length. So, if the compiler specifies a long path for RUNSTATEDIR, it could
 
    cause a buffer overflow.
 
   */
 
  char *sockpath = RUNSTATEDIR "/distrend.sock";
 
  unsigned int sockaddr_len;
 

	
 
  sock = socket(AF_UNIX, SOCK_STREAM, 0);
 
  if(sock == -1)
 
    {
 
      perror("socket");
 
      return 1;
 
    }
 

	
 
  sockaddr.sun_family = AF_UNIX;
 
  /*
 
    The terminating NULL should not be included in what's copied to sun_path,
 
    although it won't hurt as long as strlen(sockpath) < max socket length
 
   */
 
  for(sockaddr_len = 0; sockpath[sockaddr_len]; sockaddr_len ++)
 
    sockaddr.sun_path[sockaddr_len] = sockpath[sockaddr_len];
 

	
 
  if(connect(sock, (struct sockaddr *)&sockaddr, sockaddr_len) == -1)
 
    {
 
      perror("connect");
 
      close(sock);
 
      return 1;
 
    }
 

	
 
  rem->sock = sock;
 

	
 
  return 0;
 
}
 

	
 
int _remoteio_sock_close(struct remoteio *rem)
 
{
 
  close(rem->sock);
 

	
 
  return 0;
 
}
 

	
 
#endif
 

	
 
int _remoteio_sock_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread)
 
{
 
  ssize_t readrtn;
 

	
 
  readrtn = read(rem->sock, buf, len);
 
  /*
 
    The following is valid for blocking sockets:
 
   */
 
  if(readrtn == -1)
 
    {
 
      /*
 
	in this case, we may have been interrupted by a signal and errno == EINTR
 
	or the connection was reset and errno = ECONNRESET
 

	
 
	Some of these are not error conditions:
 
       */
 
      perror("read");
 
      *bytesread = 0;
 

	
 
      if(errno != EINTR)
 
	{
 
	  fprintf(stderr, "error reading socket in remoteio_sock_read\n");
 
	  return 1;
 
	}
 

	
 
      return 0;
 
    }
 

	
 
  *bytesread = readrtn;
 
  if(!readrtn)
 
    {
 
      /*
 
	means EOF except when FD is in ``message-nondiscard'' or ``message-discard''
 
	modes.
 
       */
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
int _remoteio_sock_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten)
 
{
 
  ssize_t writertn;
 

	
 
  writertn = write(rem->sock, buf, len);
 

	
 
  if(writertn == -1)
 
    {
 
      perror("write");
 
      if(errno != EINTR)
 
	{
 
	  fprintf(stderr, "error writing to socket in remoteio_sock_write()\n");
 
	  return 1;
 
	}
 
    }
 

	
 
  *byteswritten = writertn;
 
  if(!writertn)
 
    {
 
      /*
 
	should we consider this an error? I'm pretty
 
	sure we should :-/
 
       */
 
      fprintf(stderr, "write() returned 0 in remoteio_sock_write()\n");
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
/**
 
   TCP, taking advantage of the two generic socks read/write functions:
 
 */
 
int _remoteio_tcp_open(struct remoteio *rem, struct remoteio_server *server)
 
{
 
  int tmp;
 
  int tmp2;
 

	
 
  int sock;
 

	
 
  char *hostname;
 
  char *port;
 

	
 
  struct addrinfo addrinfo_hints;
 
  struct addrinfo *addrinfo_res;
 

	
 
  /**
 
     only hostname should be free()-ed, not port,
 
     because both are from the same block of malloc()-ed
 
     memory
 
   */
 
  hostname = strdup(server->hostname);
 
  for(port = hostname;
 
      *port && *port != ':';
 
      port ++)
 
    ;
 
  if(*port)
 
    {
 
      *port = '\0';
 
      port ++;
 
    }
 
  else
 
    port = REMOTEIO_DEFAULT_PORT;
 

	
 
  memset(&addrinfo_hints, '\0', sizeof(struct addrinfo));
 
  addrinfo_hints.ai_family = AF_UNSPEC;
 
#ifdef _WIN32
 
  /* windows lacks stuff documented in POSIX, I guess :-( */
 
  addrinfo_hints.ai_flags = 0;
 
#else
 
  addrinfo_hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
 
#endif
 
  addrinfo_hints.ai_socktype = SOCK_STREAM;
 

	
 
  tmp = getaddrinfo(server->hostname, port, &addrinfo_hints, &addrinfo_res);
 
  if(tmp)
 
    fprintf(stderr, "error resolving %s:%s: %s\n", server->hostname, port, gai_strerror(tmp));
 
  fprintf(stderr, "connecting to %s[%s]:%s\n", server->hostname, addrinfo_res->ai_canonname, port);
 

	
 
  free(hostname);
 

	
 
  sock = socket(addrinfo_res->ai_family, SOCK_STREAM, addrinfo_res->ai_protocol);
 
  if(sock == -1)
 
    {
 
      perror("socket");
 
      freeaddrinfo(addrinfo_res);
 
  
 
      return 1;
 
    }
 

	
 
  tmp = connect(sock, addrinfo_res->ai_addr, addrinfo_res->ai_addrlen);
 
  tmp2 = errno;
 
  freeaddrinfo(addrinfo_res);
 
  errno = tmp2;
 
  if(tmp == -1)
 
    {
 
      perror("connect");
 
      close(sock);
 

	
 
      return 1;
 
    }
 

	
 
  rem->sock = sock;
 

	
 
  return 0;
 
}
 

	
 
int _remoteio_tcp_close(struct remoteio *rem)
 
{
 
  close(rem->sock);
 

	
 
  return 0;
 
}
0 comments (0 inline, 0 general)