1 // ----------------------------------------------------------------------------
2 //
3 // flxmlrpc Copyright (c) 2015 by W1HKJ, Dave Freese <iam_w1hkj@w1hkj.com>
4 //
5 // XmlRpc++ Copyright (c) 2002-2008 by Chris Morley
6 //
7 // This file is part of fldigi
8 //
9 // flxmlrpc is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Lesser General Public License as published by
11 // the Free Software Foundation; either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 // ----------------------------------------------------------------------------
17 
18 #include <config.h>
19 
20 #include "XmlRpcSocket.h"
21 #include "XmlRpcUtil.h"
22 
23 
24 #if defined(_WINDOWS)
25 # include <stdio.h>
26 # include <winsock2.h>
27 //# pragma lib(WS2_32.lib)
28 
29 # define EINPROGRESS	WSAEINPROGRESS
30 # define EWOULDBLOCK	WSAEWOULDBLOCK
31 # define ETIMEDOUT	    WSAETIMEDOUT
32 
33 typedef int socklen_t;
34 
35 #include "compat.h"
36 
37 #else
38 extern "C" {
39 # include <unistd.h>
40 # include <stdio.h>
41 # include <string.h>
42 # include <sys/types.h>
43 # include <sys/socket.h>
44 # include <netinet/in.h>
45 # include <netdb.h>
46 # include <errno.h>
47 # include <fcntl.h>
48 # include <signal.h>
49 }
50 #endif  // _WINDOWS
51 
52 using namespace XmlRpc;
53 // One-time initializations
54 static bool initialized = false;
55 
initialize()56 static void initialize()
57 {
58     initialized = true;
59 
60 #if defined(_WINDOWS)
61     {
62         WORD wVersionRequested = MAKEWORD( WSA_MAJOR, WSA_MINOR );
63         WSADATA wsaData;
64         WSAStartup(wVersionRequested, &wsaData);
65        	atexit((void(*)(void)) WSACleanup);
66     }
67 #else
68     {
69         // Ignore SIGPIPE
70         (void) signal(SIGPIPE, SIG_IGN);
71     }
72 #endif // _WINDOWS
73 }
74 
75 // These errors are not considered fatal for an IO operation; the operation will be re-tried.
76 bool
nonFatalError()77 XmlRpcSocket::nonFatalError()
78 {
79   int err = XmlRpcSocket::getError();
80   return (err == EINPROGRESS ||
81 #if defined(EAGAIN)
82           err == EAGAIN ||
83 #endif
84 #if defined(EINTR)
85           err == EINTR ||
86 #endif
87           err == EWOULDBLOCK);
88 }
89 
90 
91 XmlRpcSocket::Socket
socket()92 XmlRpcSocket::socket()
93 {
94   if ( ! initialized) initialize();
95   return ::socket(AF_INET, SOCK_STREAM, 0);
96 }
97 
98 void
close(XmlRpcSocket::Socket fd)99 XmlRpcSocket::close(XmlRpcSocket::Socket fd)
100 {
101   XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd);
102 #if defined(_WINDOWS)
103   closesocket(fd);
104 #else
105   ::close(fd);
106 #endif // _WINDOWS
107 }
108 
109 
110 
111 
112 bool
setNonBlocking(XmlRpcSocket::Socket fd)113 XmlRpcSocket::setNonBlocking(XmlRpcSocket::Socket fd)
114 {
115 #if defined(_WINDOWS)
116   unsigned long flag = 1;
117   return (ioctlsocket(fd, FIONBIO, &flag) == 0);
118 #else
119   return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
120 #endif // _WINDOWS
121 }
122 
123 
124 bool
setReuseAddr(XmlRpcSocket::Socket fd)125 XmlRpcSocket::setReuseAddr(XmlRpcSocket::Socket fd)
126 {
127   // Allow this port to be re-bound immediately so server re-starts are not delayed
128   int sflag = 1;
129   return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
130 }
131 
132 
133 // Bind to a specified port
134 bool
bind(XmlRpcSocket::Socket fd,int port)135 XmlRpcSocket::bind(XmlRpcSocket::Socket fd, int port)
136 {
137   struct sockaddr_in saddr;
138   memset(&saddr, 0, sizeof(saddr));
139   saddr.sin_family = AF_INET;
140   saddr.sin_addr.s_addr = htonl(INADDR_ANY);
141   saddr.sin_port = htons((u_short) port);
142   return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0);
143 }
144 
145 
146 // Set socket in listen mode
147 bool
listen(XmlRpcSocket::Socket fd,int backlog)148 XmlRpcSocket::listen(XmlRpcSocket::Socket fd, int backlog)
149 {
150   return (::listen(fd, backlog) == 0);
151 }
152 
153 
154 XmlRpcSocket::Socket
accept(XmlRpcSocket::Socket fd)155 XmlRpcSocket::accept(XmlRpcSocket::Socket fd)
156 {
157   struct sockaddr_in addr;
158   socklen_t addrlen = sizeof(addr);
159 
160   return ::accept(fd, (struct sockaddr*)&addr, &addrlen);
161 }
162 
163 
164 
165 // Connect a socket to a server (from a client)
166 bool
connect(XmlRpcSocket::Socket fd,std::string & host,int port)167 XmlRpcSocket::connect(XmlRpcSocket::Socket fd, std::string& host, int port)
168 {
169   struct sockaddr_in saddr;
170   memset(&saddr, 0, sizeof(saddr));
171   saddr.sin_family = AF_INET;
172 
173   struct hostent *hp = gethostbyname(host.c_str());
174   if (hp == 0) return false;
175 
176   saddr.sin_family = hp->h_addrtype;
177   memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
178   saddr.sin_port = htons((u_short) port);
179 
180   // For asynch operation, this will return EWOULDBLOCK (windows) or
181   // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
182   int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
183   return result == 0 || nonFatalError();
184 }
185 
186 
187 
188 // Get the port of a bound socket
189 int
getPort(XmlRpcSocket::Socket socket)190 XmlRpcSocket::getPort(XmlRpcSocket::Socket socket)
191 {
192   struct sockaddr_in saddr;
193   socklen_t saddr_len = sizeof(saddr);
194   int port;
195 
196   int result = ::getsockname(socket, (sockaddr*) &saddr, &saddr_len);
197 
198   if (result != 0) {
199     port = -1;
200   } else {
201     port = ntohs(saddr.sin_port);
202   }
203   return port;
204 }
205 
206 
207 // Returns last errno
208 int
getError()209 XmlRpcSocket::getError()
210 {
211 #if defined(_WINDOWS)
212   return WSAGetLastError();
213 #else
214   return errno;
215 #endif
216 }
217 
218 
219 // Returns message corresponding to last errno
220 std::string
getErrorMsg()221 XmlRpcSocket::getErrorMsg()
222 {
223   return getErrorMsg(getError());
224 }
225 
226 // Returns message corresponding to errno... well, it should anyway
227 std::string
getErrorMsg(int error)228 XmlRpcSocket::getErrorMsg(int error)
229 {
230   char err[60];
231   snprintf(err,sizeof(err),"error %d", error);
232   return std::string(err);
233 }
234 
235 
236