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