LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-20-2009, 07:30 AM   #1
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Need critique of C++ Socket class


Over the course of the years, I have pieced together a C++ OO socket library that I use (successfully) for TCP and UDP communications. When I bind() to a socket, and a hostname or IP address is given, I use gethostbyname().

Through a little research this morning, I discovered that the gethostbyname() function is considered "obsolete", and instead getaddrinfo() should be used. Is this correct?

The example code I have seen that describes the usage of getaddrinfo() does not work well with the design of the socket library I developed, namely because an attempt is made to create a socket using information returned by getaddrinfo(). In my code, the socket has already been created before I ever attempt to bind() to a socket.

Below is a snippet of my code, which employs gethostbyname(). Can someone please provide some ideas as to how I should approach incorporating the getaddrinfo() into my code, or even if I should?

Should I defer opening/creating the socket until the server application calls bind()? Or in the case of a client application, until that application calls connect()?

I am not too keen on defering the opening of the socket from the Socket() constructor, and thus I wonder if the implementation I have is acceptable?

Anyhow, any comments are appreciated -- but please keep them in layman's terms!

Code:
////////////////////////////////////////////////////////////////////////////////
//
// Method:  Socket (constructor)
//
////////////////////////////////////////////////////////////////////////////////
Socket::Socket(int domain, int type, int protocol) :
               m_Domain(domain),
               m_Type(type),
               m_Protocol(protocol)
{
  if ((m_Socket = socket(m_Domain, m_Type, m_Protocol)) < 0)
  {
    throw std::runtime_error("Could not create socket!");
  }
}

...

////////////////////////////////////////////////////////////////////////////////
//
// Method:  Bind
//
////////////////////////////////////////////////////////////////////////////////
void
Socket::Bind(const std::string& address, unsigned short port)
{
  sockaddr_in addr;

  FillAddress(address, port, addr);

  if (bind(m_Socket, (sockaddr*) &addr, sizeof(sockaddr_in)) < 0)
  {
    throw std::runtime_error("Could not bind to socket!");
  }
}


////////////////////////////////////////////////////////////////////////////////
//
// Method:  FillAddress
//
////////////////////////////////////////////////////////////////////////////////
void
Socket::FillAddress(const std::string& address, unsigned short port, sockaddr_in& addr)
{
  hostent* host = gethostbyname(address.c_str());

  if (host == 0)
  {
    throw std::runtime_error("Could not get hostname from given address!");
  }

  memset(&addr, 0, sizeof(addr));

  addr.sin_family      = m_Domain;
  addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
  addr.sin_port        = htons(port);
}
I have a TCPServerSocket, a TCPSocket (for clients), and a UDPSocket that subclass from Socket. Here's how I would typically use the TCPServerSocket in an application:
Code:
...

  const unsigned short port = 9100;
  TCPServerSocket      server;

  server.Bind("192.168.6.128", port);
  server.Listen();
  server.EnableReuseAddress();

...

Last edited by dwhitney67; 02-20-2009 at 07:32 AM.
 
Old 02-21-2009, 12:29 AM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Maybe this? Sorry, I didn't have a chance to compile or test it, but it's based on something I use.
Code:
Socket::FillAddress(const std::string& address, unsigned short port, sockaddr_in& addr)
{
  struct addrinfo *host_info = NULL;

  if ( getaddrinfo(address.c_str(), NULL, NULL, &host_info) != 0 ||
       !host_info || !host_info->ai_addr || host_info->ai_family != AF_INET )
  {
    if (host_info) freeaddrinfo(host_info);
    throw std::runtime_error("Could not get hostname from given address!");
  }

  memcpy(&addr, host_info->ai_addr, sizeof(struct sockaddr_in));
  addr.sin_port = htons(port);

  freeaddrinfo(host_info);
}
I'd avoid sizeof addr because of its ambiguity, although I'm not up on how the standard deals with sizes of references. Also, sizeof has parentheses with type names but not with variable names.
Quote:
Originally Posted by dwhitney67 View Post
Should I defer opening/creating the socket until the server application calls bind()? Or in the case of a client application, until that application calls connect()?
I'm not sure what you mean by this. Addressing doesn't take place during socket creation; only during binding and connecting.

Do you think throwing an exception is appropriate? I know that's how things are dealt with in Java, but with something that incorporates low-level C it might not be wise. Also, it creates additional overhead and the inconvenience of try/catch when you could just be returning false.

In all, though, I think it's a good idea to have a socket class. I generally just use the same 20 lines of socket code in each new place. I use C whenever possible for that sort of thing, though, so a class isn't really an option for me.

I've never actually worked with an IPv6 network before; however, using getaddrinfo would make adding it as a consideration very simple. You might be able to get away with not using a template if you go about it C-style and use sockaddr* and sizes as private-function arguments.
Kevin Barry

Last edited by ta0kira; 02-21-2009 at 12:47 AM.
 
Old 02-23-2009, 07:15 AM   #3
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Original Poster
Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
ta0kira

Thank you very much. I employed the code you provided in your previous post within the my FillAddress() method, and it worked as expected.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Can I access class A and class C ip address using one ethernet card? fakhrul Linux - Networking 4 10-21-2007 01:34 AM
C++ templated Node class: pointers to different instantated class types jhwilliams Programming 3 08-20-2007 06:20 PM
Derived class inside parent class array, possible? xemous Programming 3 10-17-2006 11:35 AM
Does derivated class inherit base class destructor (constructor)? kornerr Programming 2 08-23-2006 08:05 AM
Which C++ editor in Linux has the class view/class browser feature imaginationworks Programming 7 05-21-2006 11:09 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:27 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration