1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU Lesser General Public License as published
7 //  by the Free Software Foundation; either version 3.0 of the License, or
8 //  any later version.
9 //
10 //  The GPSTk is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with GPSTk; if not, write to the Free Software Foundation,
17 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 //  This software was developed by Applied Research Laboratories at the
20 //  University of Texas at Austin.
21 //  Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 //  This software was developed by Applied Research Laboratories at the
28 //  University of Texas at Austin, under contract to an agency or agencies
29 //  within the U.S. Department of Defense. The U.S. Government retains all
30 //  rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 //  Pursuant to DoD Directive 523024
33 //
34 //  DISTRIBUTION STATEMENT A: This software has been approved for public
35 //                            release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 #include <cstring>
40 
41 #include <sstream>
42 #include <errno.h>
43 #include <stdlib.h>
44 
45 #include <unistd.h>
46 #include <netdb.h>
47 #include <fcntl.h>
48 #include <sys/file.h>
49 
50 #include <stdio.h>
51 #if !defined(unix) && !defined(__unix__) && !defined(__APPLE__)
52 #include <winsock.h>
53 #else
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
58 #endif
59 
60 #include <arpa/inet.h>
61 
62 #include "TCPStreamBuff.hpp"
63 
64 using namespace std;
65 
66 namespace gpstk
67 {
68 //------------------------------------------------------------------------
IPaddress(const string & host_name)69    IPaddress::IPaddress(const string& host_name)
70    {
71       // If the address is in dotted quad notation, this will work.
72       address = inet_addr(host_name.c_str());
73       if ( address != (uint32_t)(-1) )
74          return;
75 
76       struct hostent *host_ptr = ::gethostbyname(host_name.c_str());
77       if( host_ptr == 0 )
78       {
79          cout << "Host name '" << host_name << "' cannot be resolved";
80          return;
81       }
82       if( host_ptr->h_addrtype != AF_INET )
83       {
84          cout << "Host name '" << host_name
85                    << "' isn't an AF_INET address" << endl;
86          return;
87       }
88 
89       memcpy(&address, host_ptr->h_addr, sizeof(address));
90    }
91 
92 
93 //------------------------------------------------------------------------
operator <<(ostream & os,const IPaddress addr)94    ostream& operator<<(ostream& os, const IPaddress addr)
95    {
96       struct hostent * const host_ptr =
97          ::gethostbyaddr((char *)&addr.address,
98                          sizeof(addr.address), AF_INET);
99       if( host_ptr != 0 )
100          return os << host_ptr->h_name;
101 
102       // Reverse DNS failed, print in the dot notation
103       char buffer[80];
104       const unsigned int native_addr = ntohl(addr.address);
105       sprintf(buffer,"%0d.%0d.%0d.%0d", (native_addr >> 24) & 0xff,
106               (native_addr >> 16) & 0xff, (native_addr >> 8) & 0xff,
107               native_addr & 0xff);
108       return os << buffer;
109    }
110 
111 //------------------------------------------------------------------------
SocketAddr(const IPaddress host,const short port_no)112    SocketAddr::SocketAddr(const IPaddress host, const short port_no)
113    {
114       sin_family = AF_INET;
115       sin_port = htons((short)port_no);
116       sin_addr.s_addr = host.net_addr();
117    }
118 
operator <<(ostream & os,const SocketAddr & addr)119    ostream& operator<<(ostream& os, const SocketAddr& addr)
120    {
121       return os << IPaddress(addr.sin_addr.s_addr) << ':'
122                 << (unsigned short)ntohs((short)addr.sin_port);
123    }
124 
125 
126 //------------------------------------------------------------------------
connect(const SocketAddr target_address)127    int TCPStreamBuff::connect(const SocketAddr target_address)
128    {
129       if (is_open())
130          return 0;
131 
132       handle = socket(AF_INET,SOCK_STREAM,0);
133       if (!handle)
134          return -1;
135 
136       //  set_blocking_io(false);
137 
138       int connect_status = -1;
139       for (int i=0; i<5 && connect_status != 0; i++)
140       {
141          connect_status = ::connect(handle, (sockaddr *)target_address,
142                                     sizeof(target_address));
143       }
144       if (connect_status !=0)
145          return connect_status;
146 
147       // We do our own buffering...
148       char off=0;
149       ::setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
150       return 0;
151    }
152 
153 
154 //------------------------------------------------------------------------
155 // Take a file handle (which is supposed to be a listening socket), accept
156 // a connection if any, and return a TCPStreamBuff for that connection. On exit,
157 // peeraddr would be an addr of the connected peer.
accept(int listening_socket,SocketAddr & peeraddr)158    int TCPStreamBuff::accept(int listening_socket, SocketAddr& peeraddr)
159    {
160       // do nothing if we are already connected
161       if (is_open())
162          return 0;
163 
164       for(;;)
165       {
166          socklen_t target_addr_size = sizeof(peeraddr);
167          handle = ::accept(listening_socket,(sockaddr *)peeraddr,
168                                   &target_addr_size);
169          if (handle >= 0)
170             break;			// Successfully accepted the connection
171          if (errno == EAGAIN || errno == EINTR)
172             cout << "to be implimented" << endl;
173          else
174             return 0;
175       }
176 
177       // We do our own buffering...
178       char off=0;
179       ::setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
180       return 0;
181    }
182 
183 } // end of namespace
184