1
2 #include "XmlRpcSocket.h"
3 #include "XmlRpcUtil.h"
4
5 #ifndef MAKEDEPEND
6
7 #if defined(_WINDOWS)
8 # include <stdio.h>
9 # include <winsock2.h>
10 //# pragma lib(WS2_32.lib)
11
12 # define EINPROGRESS WSAEINPROGRESS
13 # define EWOULDBLOCK WSAEWOULDBLOCK
14 # define ETIMEDOUT WSAETIMEDOUT
15 #else
16 extern "C" {
17 # include <unistd.h>
18 # include <stdio.h>
19 # include <sys/types.h>
20 # include <sys/socket.h>
21 # include <netinet/in.h>
22 # include <netdb.h>
23 # include <errno.h>
24 # include <fcntl.h>
25 }
26 #endif // _WINDOWS
27
28 #endif // MAKEDEPEND
29
30
31 using namespace XmlRpc;
32
33
34
35 #if defined(_WINDOWS)
36
initWinSock()37 static void initWinSock()
38 {
39 static bool wsInit = false;
40 if (! wsInit)
41 {
42 WORD wVersionRequested = MAKEWORD( 2, 0 );
43 WSADATA wsaData;
44 WSAStartup(wVersionRequested, &wsaData);
45 wsInit = true;
46 }
47 }
48
49 #else
50
51 #define initWinSock()
52
53 #endif // _WINDOWS
54
55
56 // These errors are not considered fatal for an IO operation; the operation will be re-tried.
57 static inline bool
nonFatalError()58 nonFatalError()
59 {
60 int err = XmlRpcSocket::getError();
61 return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
62 }
63
64
65
66 int
socket()67 XmlRpcSocket::socket()
68 {
69 initWinSock();
70 return (int) ::socket(AF_INET, SOCK_STREAM, 0);
71 }
72
73
74 void
close(int fd)75 XmlRpcSocket::close(int fd)
76 {
77 XmlRpcUtil::log(4, "XmlRpcSocket::close: fd %d.", fd);
78 #if defined(_WINDOWS)
79 closesocket(fd);
80 #else
81 ::close(fd);
82 #endif // _WINDOWS
83 }
84
85
86
87
88 bool
setNonBlocking(int fd)89 XmlRpcSocket::setNonBlocking(int fd)
90 {
91 #if defined(_WINDOWS)
92 unsigned long flag = 1;
93 return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0);
94 #else
95 return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
96 #endif // _WINDOWS
97 }
98
99
100 bool
setReuseAddr(int fd)101 XmlRpcSocket::setReuseAddr(int fd)
102 {
103 // Allow this port to be re-bound immediately so server re-starts are not delayed
104 int sflag = 1;
105 return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
106 }
107
108
109 // Bind to a specified port
110 bool
bind(int fd,int port)111 XmlRpcSocket::bind(int fd, int port)
112 {
113 struct sockaddr_in saddr;
114 memset(&saddr, 0, sizeof(saddr));
115 saddr.sin_family = AF_INET;
116 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
117 saddr.sin_port = htons((u_short) port);
118 return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0);
119 }
120
121
122 // Set socket in listen mode
123 bool
listen(int fd,int backlog)124 XmlRpcSocket::listen(int fd, int backlog)
125 {
126 return (::listen(fd, backlog) == 0);
127 }
128
129
130 int
accept(int fd)131 XmlRpcSocket::accept(int fd)
132 {
133 struct sockaddr_in addr;
134 #if defined(_WINDOWS)
135 int
136 #else
137 socklen_t
138 #endif
139 addrlen = sizeof(addr);
140
141 return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen);
142 }
143
144
145
146 // Connect a socket to a server (from a client)
147 bool
connect(int fd,std::string & host,int port)148 XmlRpcSocket::connect(int fd, std::string& host, int port)
149 {
150 struct sockaddr_in saddr;
151 memset(&saddr, 0, sizeof(saddr));
152 saddr.sin_family = AF_INET;
153
154 struct hostent *hp = gethostbyname(host.c_str());
155 if (hp == 0) return false;
156
157 saddr.sin_family = hp->h_addrtype;
158 memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
159 saddr.sin_port = htons((u_short) port);
160
161 // For asynch operation, this will return EWOULDBLOCK (windows) or
162 // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
163 int result = ::connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
164 return result == 0 || nonFatalError();
165 }
166
167
168
169 // Read available text from the specified socket. Returns false on error.
170 bool
nbRead(int fd,std::string & s,bool * eof)171 XmlRpcSocket::nbRead(int fd, std::string& s, bool *eof)
172 {
173 const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time
174 char readBuf[READ_SIZE];
175
176 bool wouldBlock = false;
177 *eof = false;
178
179 while ( ! wouldBlock && ! *eof) {
180 #if defined(_WINDOWS)
181 int n = recv(fd, readBuf, READ_SIZE-1, 0);
182 #else
183 int n = read(fd, readBuf, READ_SIZE-1);
184 #endif
185 XmlRpcUtil::log(5, "XmlRpcSocket::nbRead: read/recv returned %d.", n);
186
187 if (n > 0) {
188 readBuf[n] = 0;
189 s.append(readBuf, n);
190 } else if (n == 0) {
191 *eof = true;
192 } else if (nonFatalError()) {
193 wouldBlock = true;
194 } else {
195 return false; // Error
196 }
197 }
198 return true;
199 }
200
201
202 // Write text to the specified socket. Returns false on error.
203 bool
nbWrite(int fd,std::string & s,int * bytesSoFar)204 XmlRpcSocket::nbWrite(int fd, std::string& s, int *bytesSoFar)
205 {
206 int nToWrite = int(s.length()) - *bytesSoFar;
207 char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
208 bool wouldBlock = false;
209
210 while ( nToWrite > 0 && ! wouldBlock ) {
211 #if defined(_WINDOWS)
212 int n = send(fd, sp, nToWrite, 0);
213 #else
214 int n = write(fd, sp, nToWrite);
215 #endif
216 XmlRpcUtil::log(5, "XmlRpcSocket::nbWrite: send/write returned %d.", n);
217
218 if (n > 0) {
219 sp += n;
220 *bytesSoFar += n;
221 nToWrite -= n;
222 } else if (nonFatalError()) {
223 wouldBlock = true;
224 } else {
225 return false; // Error
226 }
227 }
228 return true;
229 }
230
231
232 // Returns last errno
233 int
getError()234 XmlRpcSocket::getError()
235 {
236 #if defined(_WINDOWS)
237 return WSAGetLastError();
238 #else
239 return errno;
240 #endif
241 }
242
243
244 // Returns message corresponding to last errno
245 std::string
getErrorMsg()246 XmlRpcSocket::getErrorMsg()
247 {
248 return getErrorMsg(getError());
249 }
250
251 // Returns message corresponding to errno... well, it should anyway
252 std::string
getErrorMsg(int error)253 XmlRpcSocket::getErrorMsg(int error)
254 {
255 char err[60];
256 snprintf(err,sizeof(err),"error %d", error);
257 return std::string(err);
258 }
259
260
261