The DejaVU Framework -- hush 3.0
[.] Papers Tutorials Examples Manuals Interfaces Sources Packages Resources ?

source: udp.c hush-3.0b4/auxiliary/net/cs


[.] - [up] [top] - index README make include source scripts configure
  // udp.cc
  
  include <net/cs/udp/dataconn.h>
  include <net/cs/udp/listenconn.h>
  include <net/cs/udp/client.h>
  include <net/cs/udp/clientimp.h>
  include <net/cs/udp/server.h>
  include <net/cs/udp/serverimp.h>
  include <net/cs/csserver.h>
  include <net/cs/dataconn.h>
  include <net/cs/listenconn.h>
  include <net/cs/csaddress.h>
  include <net/cs/inetaddr.h>
  include <net/cs/cs.h>
  include <net/cs/samlib.h>
  
  include <errno.h>
  include <unistd.h>
  include <string.h>
  include <sys/types.h>
  include <sys/time.h>
  include <sys/socket.h>
  include <netinet/in.h>
  include <arpa/inet.h>
  include <netdb.h>
  include <stdio.h>
  include <signal.h>
  include <fcntl.h>
  include <sys/fcntl.h>
  include <stdlib.h>
  
  
************************************************************************
  IMPLEMENTATION NOTE: 
  man socket states that SIGPIPE will be raised if a process writes to a
  broken pipe (when the other side has hung up). So for robustness, this
  signal has to be handled.
  
  ANOTHER NOTE: 
  UDP is a connectionless protocol so a very tiny hack has to be used: if the
  listen-connection receives a message, it _must_ be a connect-message, since
  it will be lost. For each message that arrives at the listen-connection, a
  new data-connection will be created which will receive all further messages
  from the client, but the message will be lost to the data-connection.
  Therefore, the first message sent to the server _must_ be a connect-message,
  so a data-connection is created at the serverside.
  
  **************************************************************************/
  
  const char connect_string[] = "CS++:Connect";
  
  //---------------------------- udpsocket implementation -------------------
  
  int udpsocket::_got_sigpipe = 0;
  int udpsocket::_handler_installed = 0;
  void (*udpsocket::_old_sigpipe_handler)(int) = NULL;
  
  void udpsocket::sigpipe_handler(int signr)
  {
      signal(SIGPIPE, sigpipe_handler);
      _got_sigpipe = 1;
  
      if (_old_sigpipe_handler != NULL)
          (*_old_sigpipe_handler)(signr);
  
      if (cs_trace)
          printf("udpsocket::sigpipe_handler(%d)\n", signr);
  }
  
  udpsocket::udpsocket()
  {
      if (!_handler_installed)
      {
          _old_sigpipe_handler = signal(SIGPIPE, sigpipe_handler);
          _handler_installed = 1;
      }
  
      _portnr = -1;
      _name.sin_family = 0;
      _name.sin_port = 0;
      _name.sin_addr.s_addr = 0;
      _sd = -1;
  }
  
  int udpsocket::portnr() const
  {
      struct sockaddr addr;
      int addrlen;
  // hack to keep this function 'const'
      udpsocket* uptr = (udpsocket*) this;
  
      if (_portnr != -1)
          return _portnr;             // portnumber already known
  
      addrlen = sizeof(addr);
      if (getsockname(_sd, &addr, &addrlen) < 0)
      {
          warn("udp_listenconn::portnr : getsockname failed (%s)", 
               strerror(errno));
          return -1;
      }
  
      struct sockaddr_in* ptr = (struct sockaddr_in*) &addr;
      uptr -> _portnr = ntohs(ptr -> sin_port);
  
      return uptr -> _portnr;
  }
  
  void udpsocket::close()
  {
      ::close(_sd);
      _sd = -1;
  }
  
  //--------------------------- udp_dataconn implementation --------------------
  
  // constructor for client-side
  udp_dataconn::udp_dataconn(const csaddress* addr)
             :udpsocket(), data_connection(addr)
  {
      char buf[128];
      sockaddr_in dst;
      int dstlen = sizeof(dst);
  
      if (addr == NULL)
      {
          warn("udp_dataconn::udp_dataconn : addr = NULL");
          return;
      }
  
  // make socket connection
      struct hostent* hp;
      inet_address* a = (inet_address*) addr;
      char* hname = (char*) a -> hostname();
  
      if (cs_trace)
          printf("hname = %s, portnr = %d\n", a -> hostname(), a -> portnr());
  
      if ((_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
      {
          warn("udp_dataconn::udp_dataconn : couldn't create socket (%s)",
               strerror(errno));
          return;
      }
  
      _name.sin_family = AF_INET;
      _name.sin_port = htons(a -> portnr());
  
      if ((hname == NULL) || (strlen(hname) == 0))
      {
          warn("udp_dataconn::udp_dataconn : hostname = NULL or \"\"");
          ::close(_fd);
          return;
      }
      else
      {
          hp = gethostbyname(hname);
          if (hp == NULL)
              hp = gethostbyaddr(hname, strlen(hname), AF_INET);
          if (hp == NULL)
          {
              warn("udp_dataconn::udp_dataconn : unknown host %s", hname);
              ::close(_fd);
              return;
          }
          memcpy(&_name.sin_addr.s_addr, hp -> h_addr, hp -> h_length);
      }
  
      if (sendto(_fd, connect_string, strlen(connect_string)+1, 0, 
                 (struct sockaddr*) &_name, sizeof(_name)) < 0)
      {
          perror("INET Domain sendto");
          exit(2);
      }
  
  // wait for reply from server
      fd_set readfds;
      FD_ZERO(&readfds);
      FD_SET(_fd, &readfds);
      timeval tv;
      tv.tv_sec = 3;
      tv.tv_usec = 0;
      int got_data = 0;
  
      if (cs_trace)
          printf("waiting for reply...\n");
      do
      {
          if (select(_fd+1, &readfds, NULL, NULL, &tv) > 0)
              got_data = 1;
      }
      while ((tv.tv_usec != 0) || (tv.tv_sec != 0));
  
      if (!got_data)
      {
          warn("udp_dataconn::udp_dataconn : didn't get connection ACK");
          ::close(_fd);
          return;
      }
  
      recvfrom(_fd, buf, sizeof(buf), 0, (sockaddr*) &dst, &dstlen);
      if (cs_trace > 1)
          printf("received: %s\n", buf);
  
      if (connect(_fd, (struct sockaddr*) &dst, dstlen) < 0)
      {
          warn("udp_dataconn::udp_dataconn : couldn't connect (%s)",
               strerror(errno));
          ::close(_fd);
          return;
      }
  
  // set socketdescriptor
      _sd = _fd;
      _connected = 1;
  }
  
  // constructor for server-side
  udp_dataconn::udp_dataconn(int fd)
             :udpsocket(), data_connection()
  {
      _fd = fd;
      _sd = fd;
  // since this constructor will be called by the receiving side of a
  // connection, the connection is already a fact
      _connected = 1;
  }
  
  udp_dataconn::~udp_dataconn()
  {
      close();
  }
  
  int udp_dataconn::readmsg(char* buf, int nrbytes)
  {
  //    return read(buf, nrbytes);
      return recv(_fd, buf, nrbytes, 0);
  }
  
  int udp_dataconn::writemsg(const char* buf, int nrbytes)
  {
  //    return write(buf, nrbytes);
      return send(_fd, buf, nrbytes, 0);
  }
  
  //------------------------ udp_listenconn implementation --------------------
  
  udp_listenconn::udp_listenconn(const csaddress* addr)
               :udpsocket(), listen_connection(addr)
  {
  /* DEBUG
  // make socket connection
      struct hostent* hp;
      inet_address* a = (inet_address*) _address;     // this should be tested!!!
      char* hname = NULL;
      
      if ((_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
      {
          warn("udp_listenconn::udp_listenconn : couldn't create socket (%s)",
               strerror(errno));
          return;
      }
  
      _name.sin_family = AF_INET;
      if (a != NULL)
      {
          hname = (char*) a -> hostname();
          _name.sin_port = htons(a -> portnr());
      }
      else
      {
          hname = NULL;
          _name.sin_port = 0;
      }
  
      if (hname == NULL)
          _name.sin_addr.s_addr = INADDR_ANY;
      else
      {
          hp = gethostbyname(hname);
          if (hp == NULL)
              hp = gethostbyaddr(hname, strlen(hname), AF_INET);
          if (hp == NULL)
          {
              warn("udp_listenconn::udp_listenconn : unknown host %s", hname);
              ::close(_fd);
              return;
          }
          memcpy(&_name.sin_addr.s_addr, hp -> h_addr, hp -> h_length);
      }
  
      if (bind(_fd, (struct sockaddr*) &_name, sizeof(_name)) < 0)
      {
          warn("udp_listenconn::udp_listenconn : couldn't bind socket (%s)",
               strerror(errno));
          ::close(_fd);
          return;
      }
  
  // set socketdescriptor
      _sd = _fd;
      _connected = 1;         // we're on the air now
  
   */
  
      if (cs_trace)
          printf("udp_listenconn::udp_listenconn\n");
      struct sockaddr_in name;
      int ld;
  
      if ((ld = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
      {
          perror("socket");
          exit(1);
      }
  
      name.sin_family = AF_INET;
      name.sin_port = 0;
      name.sin_addr.s_addr = INADDR_ANY;
  
      if ( bind( ld, (sockaddr*) &name, sizeof( name ) ) < 0 )
      {
         perror("INET Domain bind");
         exit(2);
      }
  
      _sd = ld;
      _fd = ld;
      _connected = 1;
  }
  
  udp_listenconn::~udp_listenconn()
  {
      close();
  }
  
  data_connection* udp_listenconn::waitconnect()
  {
      int new_sd;
      data_connection* new_conn = NULL;
      sockaddr from;
      int fromlen;
      char buf[256];
  
      if (cs_trace)
          printf("waitconnect\n");
  
  // every packet that arrives will come from a new client
      fromlen = sizeof(from);
  // message can't be forwarded to correct socket, so just read it (no peek)
      if (recvfrom(_fd, buf, sizeof(buf), 0, &from, &fromlen) < 0)
      {
          warn("udp_listenconn::waitconnect : could not receive (%s)",
               strerror(errno));
          return NULL;
      }
      
      if (strncmp(buf, connect_string, sizeof(connect_string)) != 0)
      {
          warn("udp_listenconn::waitconnect : received data message (%s), "
               "ignoring", buf);
      }
      else
          warn("udp_listenconn:waitconnect : got connect string");
      if ((new_sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
      {
          warn("udp_listenconn::waitconnect : couldn't create new socket (%s)",
               strerror(errno));
          return NULL;
      }
      if (connect(new_sd, &from, fromlen) != 0)
      {
          warn("udp_listenconn::waitconnect : couldn't connect (%s)",
               strerror(errno));
          return NULL;
      }
  
      if (sendto(new_sd, buf, strlen(buf)+1, 0, &from, fromlen) == -1)
          perror("sendto");
      else
      {
          if (cs_trace)
              printf("sent\n");
      }
  
      if (!(new_conn = new udp_dataconn(new_sd)))
      {
          warn("udp_listenconn::waitconnect : couldn't create new "
               "data_connection");
          return NULL;
      }
  
  // some questions here: has the data now moved from the listen-socket to
  //                      the data-socket? NO!!!
  //                      if so, will binding a handler to the data-socket
  //                      immediately cause the handler to be called as is
  //                      wanted? NO!!!
  // solution: always send a connection-message to make yourself known
  
      return new_conn;
  }
  
  //------------------------ udp_client implementation ---------------------
  
  udp_client::udp_client()
            :csclient(_udpimp = new udp_clientimp())
  {
      _inetaddr = NULL;
  }
  
  udp_client::udp_client(const char* hostname, int portnr)
            :csclient(_udpimp = new udp_clientimp(), 
                      _inetaddr = new inet_address(hostname, portnr))
  {
  }
  
  udp_client::~udp_client()
  {
      if (_inetaddr != NULL)
          delete _inetaddr;
      delete _udpimp;
  }
  
  int udp_client::connect(const char* hostname, int portnr)
  {
      if (_inetaddr != NULL)
          delete _inetaddr;
      _inetaddr = new inet_address(hostname, portnr);
  
  write_to_log("udp_client::connect with %s at port %d", hostname, portnr);
      return csclient::connect(_inetaddr);
  }
  
  //------------------------ udp_server implementation ---------------------
  
  udp_server::udp_server()
            :csserver(_udpimp = new udp_serverimp())
  {
  }
  
  udp_server::~udp_server()
  {
      delete _udpimp;
  }
  
  int udp_server::portnr() const
  {
      udp_listenconn* tlc = (udp_listenconn*) listenconn();
  
      if (tlc != NULL)
          return tlc -> portnr();
      else
          return -1;
  }
  
  //--------------------- udp_clientimp implementation -----------------------
   
  udp_clientimp::udp_clientimp()
  {
  }
   
   
  data_connection* udp_clientimp::createdata(const csaddress* addr) const
  {
      return new udp_dataconn(addr);
  }
   
   
  //------------------------- udp_serverimp ------------------------------
   
  udp_serverimp::udp_serverimp()
  {
  }
   
   
  listen_connection* udp_serverimp::createlisten(const csaddress* addr) const
  {
      return new udp_listenconn(addr);
  }
  
  

[.] Papers Tutorials Examples Manuals Interfaces Sources Packages Resources ?
Hush Online Technology
hush@cs.vu.nl
09/09/98