12 # include <winsock2.h>
\r
14 #if defined(_MSC_VER)
\r
15 #pragma comment(lib,"WS2_32.lib")
\r
18 # define EINPROGRESS WSAEINPROGRESS
\r
19 # define EWOULDBLOCK WSAEWOULDBLOCK
\r
20 # define ETIMEDOUT WSAETIMEDOUT
\r
21 # define EAGAIN WSAEWOULDBLOCK
\r
22 # define EINTR WSAEINTR
\r
25 # include <unistd.h>
\r
26 # include <sys/types.h>
\r
27 # include <sys/socket.h>
\r
28 # include <netinet/in.h>
\r
35 #include "sockets.hpp"
\r
37 std::map<std::string, in_addr_t> Socket::dns_map;
\r
41 static void initWinSock()
\r
43 static bool wsInit = false;
\r
46 WORD wVersionRequested = MAKEWORD( 2, 0 );
\r
48 WSAStartup(wVersionRequested, &wsaData);
\r
55 #define initWinSock()
\r
60 // These errors are not considered fatal for an IO operation; the operation will be re-tried.
\r
65 int err = Socket::get_error_code();
\r
66 return (err == EINPROGRESS || err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
\r
75 return (int) ::socket(AF_INET, SOCK_STREAM, 0);
\r
80 Socket::close(int fd)
\r
93 Socket::set_non_blocking(int fd)
\r
96 unsigned long flag = 1;
\r
97 return (ioctlsocket((SOCKET)fd, FIONBIO, &flag) == 0);
\r
99 return (fcntl(fd, F_SETFL, O_NONBLOCK) == 0);
\r
105 Socket::set_reuse_addr(int fd)
\r
107 // Allow this port to be re-bound immediately so server re-starts are not delayed
\r
109 return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&sflag, sizeof(sflag)) == 0);
\r
113 // Bind to a specified port
\r
115 Socket::bind(int fd, int port)
\r
117 struct sockaddr_in saddr;
\r
118 memset(&saddr, 0, sizeof(saddr));
\r
119 saddr.sin_family = AF_INET;
\r
120 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
\r
121 saddr.sin_port = htons((u_short) port);
\r
122 return (::bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0);
\r
126 // Set socket in listen mode
\r
127 bool Socket::listen(int fd, int backlog)
\r
129 return (::listen(fd, backlog) == 0);
\r
133 int Socket::accept(int fd)
\r
135 struct sockaddr_in addr;
\r
136 #if defined(_WIN32)
\r
141 addrlen = sizeof(addr);
\r
143 return (int) ::accept(fd, (struct sockaddr*)&addr, &addrlen);
\r
146 gboolean Socket::dns_main_thread_cb(gpointer data)
\r
148 DnsQueryData *query_data = (DnsQueryData *)data;
\r
149 if (query_data->resolved) {
\r
150 dns_map[query_data->host] = query_data->sa;
\r
152 query_data->func(query_data->data, query_data->resolved, query_data->sa);
\r
157 gpointer Socket::dns_thread(gpointer data)
\r
159 DnsQueryData *query_data = (DnsQueryData *)data;
\r
160 struct hostent *phost;
\r
162 struct hostent hostinfo;
\r
165 if (!gethostbyname_r(query_data->host.c_str(), &hostinfo, buf,
\r
166 sizeof(buf), &phost, &ret)) {
\r
167 query_data->sa = ((in_addr*)(hostinfo.h_addr))->s_addr;
\r
168 query_data->resolved = true;
\r
170 query_data->resolved = false;
\r
173 //static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
\r
174 //g_static_mutex_lock (&mutex);
\r
175 if (isalpha(query_data->host[0])) {
\r
176 phost = gethostbyname(query_data->host.c_str());
\r
179 addr = inet_addr(query_data->host.c_str());
\r
180 phost = gethostbyaddr((char *)&addr, 4, AF_INET);
\r
183 query_data->sa = ((in_addr*)(phost->h_addr))->s_addr;
\r
184 query_data->resolved = true;
\r
186 query_data->resolved = false;
\r
188 //g_static_mutex_unlock (&mutex);
\r
190 /* back to main thread */
\r
191 g_idle_add(dns_main_thread_cb, query_data);
\r
195 void Socket::resolve(std::string& host, gpointer data, on_resolved_func func)
\r
198 std::map<std::string, in_addr_t>::iterator iter;
\r
199 iter = dns_map.find(host);
\r
200 if (iter != dns_map.end()) {
\r
201 func(data, true, iter->second);
\r
204 DnsQueryData *query_data = new DnsQueryData();
\r
205 query_data->host = host;
\r
206 query_data->data = data;
\r
207 query_data->func = func;
\r
208 g_thread_create(dns_thread, query_data, FALSE, NULL);
\r
211 void Socket::connect(int socket, in_addr_t sa, int port, gpointer data, on_connected_func func)
\r
213 ConnectData *connect_data = new ConnectData();
\r
214 connect_data->sd = socket;
\r
215 connect_data->sa = sa;
\r
216 connect_data->port = port;
\r
217 connect_data->data = data;
\r
218 connect_data->func = func;
\r
219 g_thread_create(connect_thread, connect_data, FALSE, NULL);
\r
222 gpointer Socket::connect_thread(gpointer data)
\r
224 ConnectData *connect_data = (ConnectData *)data;
\r
225 struct sockaddr_in saddr;
\r
226 memset(&saddr, 0, sizeof(saddr));
\r
227 saddr.sin_family = AF_INET;
\r
228 saddr.sin_addr.s_addr = connect_data->sa;
\r
229 saddr.sin_port = htons((u_short) connect_data->port);
\r
231 // For asynch operation, this will return EWOULDBLOCK (windows) or
\r
232 // EINPROGRESS (linux) and we just need to wait for the socket to be writable...
\r
233 int result = ::connect(connect_data->sd, (struct sockaddr *)&saddr, sizeof(saddr));
\r
234 connect_data->succeeded = (result == 0);
\r
236 /* back to main thread */
\r
237 g_idle_add(connect_main_thread_cb, connect_data);
\r
241 gboolean Socket::connect_main_thread_cb(gpointer data)
\r
243 ConnectData *connect_data = (ConnectData *)data;
\r
244 connect_data->func(connect_data->data, connect_data->succeeded);
\r
245 delete connect_data;
\r
249 // Read available text from the specified socket. Returns false on error.
\r
250 bool Socket::nb_read(int fd, std::string& s, bool *eof)
\r
252 const int READ_SIZE = 4096; // Number of bytes to attempt to read at a time
\r
253 char readBuf[READ_SIZE];
\r
255 bool wouldBlock = false;
\r
258 while ( ! wouldBlock && ! *eof) {
\r
259 #if defined(_WIN32)
\r
260 int n = recv(fd, readBuf, READ_SIZE-1, 0);
\r
262 int n = read(fd, readBuf, READ_SIZE-1);
\r
264 g_debug("Socket::nbRead: read/recv returned %d.", n);
\r
269 s.append(readBuf, n);
\r
270 } else if (n == 0) {
\r
272 } else if (nonFatalError()) {
\r
275 return false; // Error
\r
282 // Write text to the specified socket. Returns false on error.
\r
283 bool Socket::nb_write(int fd, std::string& s, int *bytesSoFar)
\r
285 int nToWrite = int(s.length()) - *bytesSoFar;
\r
286 char *sp = const_cast<char*>(s.c_str()) + *bytesSoFar;
\r
287 bool wouldBlock = false;
\r
289 while ( nToWrite > 0 && ! wouldBlock ) {
\r
290 #if defined(_WIN32)
\r
291 int n = send(fd, sp, nToWrite, 0);
\r
293 int n = write(fd, sp, nToWrite);
\r
295 g_debug("Socket::nbWrite: send/write returned %d.", n);
\r
301 } else if (nonFatalError()) {
\r
304 return false; // Error
\r
311 // Returns last errno
\r
312 int Socket::get_error_code()
\r
314 #if defined(_WIN32)
\r
315 return WSAGetLastError();
\r
322 // Returns message corresponding to last errno
\r
323 std::string Socket::get_error_msg()
\r
325 //Actually works on windows, but may be better use FormatMessage?
\r
326 return strerror(get_error_code());
\r