1 /*
2  * OSCompatSocket.cpp - socket interfaces.
3  *
4  *   Copyright (c) 2009  Higepon(Taro Minowa)  <higepon@users.sourceforge.jp>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  $Id: OSCompatSocket.cpp 183 2008-07-04 06:19:28Z higepon $
30  */
31 
32 #include "scheme.h"
33 #include "Object.h"
34 #include "Object-inl.h"
35 #include "Pair.h"
36 #include "Pair-inl.h"
37 #include "UTF8Codec.h"
38 #include "Transcoder.h"
39 #include "OSCompat.h"
40 #include "OSCompatSocket.h"
41 
42 using namespace scheme;
43 
Socket(int fd,enum Type type,const ucs4string & address)44 Socket::Socket(int fd, enum Type type, const ucs4string& address) :
45     socket_(fd),
46     lastError_(0),
47     address_(address),
48     type_(type),
49     isSSL_(false)
50 {
51 }
52 
accept()53 Socket* Socket::accept()
54 {
55     MOSH_ASSERT(isOpen());
56 #ifdef MONA
57     struct sockaddr_in addr;
58 #else
59     struct sockaddr_storage addr;
60 #endif
61     socklen_t addrlen = sizeof(addr);
62 
63     int fd = -1;
64     for (;;) {
65         fd = ::accept(socket_, (sockaddr*)&addr, &addrlen);
66         if (-1 == fd) {
67             if (errno == EINTR) {
68                 continue;
69             } else {
70                 setLastError();
71                 return NULL;
72             }
73         } else {
74             break;
75         }
76     }
77     return new Socket(fd, Socket::SERVER, getAddressString((sockaddr*)&addr, addrlen));
78 }
79 
isOpen() const80 bool Socket::isOpen() const
81 {
82     return socket_ != -1;
83 }
84 
sslize()85 bool Socket::sslize()
86 {
87 #if HAVE_OPENSSL
88     if (isSSL_) {
89         return true;
90     }
91     ctx_ = SSL_CTX_new(SSLv23_client_method());
92     if (ctx_ == NULL) {
93         return false;
94     }
95     ssl_ = SSL_new(ctx_);
96     if (ssl_ == NULL) {
97         return false;
98     }
99 
100     if (SSL_set_fd(ssl_, socket_) == 0) {
101         return false;
102     }
103     RAND_poll();
104     while (RAND_status() == 0) {
105         unsigned short rand_ret = rand() % 65536;
106         RAND_seed(&rand_ret, sizeof(rand_ret));
107     }
108     if (SSL_connect(ssl_) == -1) {
109         return false;
110     }
111     isSSL_ = true;
112     return true;
113 #else
114     return false;
115 #endif
116 }
117 
shutdown(int how)118 void Socket::shutdown(int how)
119 {
120     if (!isOpen()) {
121         return;
122     }
123     ::shutdown(socket_, how);
124 }
125 
close()126 void Socket::close()
127 {
128     if (!isOpen()) {
129         return;
130     }
131 #if HAVE_OPENSSL
132     if (isSSL()) {
133         SSL_shutdown(ssl_);
134     }
135 #endif
136 #ifdef _WIN32
137     ::shutdown(socket_, SD_SEND);
138     ::closesocket(socket_);
139 #elif defined(MONA)
140     ::closesocket(socket_);
141 #else
142     ::close(socket_);
143 #endif
144 #if HAVE_OPENSSL
145     if (isSSL()) {
146         SSL_free(ssl_);
147         SSL_CTX_free(ctx_);
148     }
149 #endif
150     socket_ = -1;
151 
152 }
153 
getLastErrorMessage() const154 ucs4string Socket::getLastErrorMessage() const
155 {
156     return getLastErrorMessageInternal(lastError_);
157 }
158 
toString() const159 ucs4string Socket::toString() const
160 {
161     if (address_.empty()) {
162         return UC("<socket>");
163     } else {
164         ucs4string ret = UC("<socket ");
165         if (type_ == CLIENT) {
166             ret += UC("client ");
167         } else {
168             ret += UC("server ");
169         }
170         ret += address_;
171         ret += UC(">");
172         return ret;
173     }
174 }
175 
176 /**
177    read from socket
178    @param data [in] buffer to read
179    @param size [in] size to read
180    @param flags [in] flags
181    @retval >=0 read size
182    @retval -1 error
183 */
receive(uint8_t * data,int size,int flags)184 int Socket::receive(uint8_t* data, int size, int flags)
185 {
186     if (isSSL()) {
187 #if HAVE_OPENSSL
188         return SSL_read(ssl_, data, size);
189 #else
190         MOSH_ASSERT(false);
191         return -1;
192 #endif
193     } else {
194         MOSH_ASSERT(isOpen());
195 
196         for (;;) {
197             const int ret = recv(socket_, (char*)data, size, flags);
198             if (ret == -1 && errno == EINTR) {
199                 continue;
200             }
201             setLastError();
202             return ret;
203         }
204     }
205 }
206 
207 /**
208    write to socket
209    @param data [in] buffer to read
210    @param size [in] size to read
211    @param flags [in] flags
212    @retval >=0 written size
213    @retval -1 error
214 */
send(uint8_t * data,int size,int flags)215 int Socket::send(uint8_t* data, int size, int flags)
216 {
217     MOSH_ASSERT(isOpen());
218     if (isSSL()) {
219 #if HAVE_OPENSSL
220         return SSL_write(ssl_, data, size);
221 #else
222         MOSH_ASSERT(false);
223         return -1;
224 #endif
225     } else {
226         int rest = size;
227         int sizeSent = 0;
228         while (rest > 0) {
229             const int ret = ::send(socket_, (char*)data, size, flags);
230             if (ret == -1) {
231                 if (errno == EINTR) {
232                     continue;
233                 } else {
234                     setLastError();
235                     return ret;
236                 }
237             }
238             sizeSent += ret;
239             rest -= ret;
240             data += ret;
241             size -= ret;
242         }
243         return sizeSent;
244     }
245 }
246 
247 // Factories
createClientSocket(const char * node,const char * service,int ai_family,int ai_socktype,int ai_flags,int ai_protocol,bool & isErrorOccured,ucs4string & errorMessage)248 Socket* Socket::createClientSocket(const char* node,
249                                    const char* service,
250                                    int ai_family,
251                                    int ai_socktype,
252                                    int ai_flags,
253                                    int ai_protocol,
254                                    bool& isErrorOccured,
255                                    ucs4string& errorMessage)
256 {
257     struct addrinfo hints;
258     memset(&hints, 0, sizeof(struct addrinfo));
259     hints.ai_family = ai_family;
260     hints.ai_socktype = ai_socktype;
261     hints.ai_flags = ai_flags;
262     hints.ai_protocol = ai_protocol;
263     hints.ai_canonname = NULL;
264     hints.ai_addr = NULL;
265     hints.ai_next = NULL;
266     struct addrinfo* result;
267     int ret;
268     // TODO server socket?
269 #ifndef MONA
270     MOSH_ASSERT(!((ai_flags & AI_PASSIVE) && node == NULL));
271 #endif
272 
273     // check temporary failure
274     do {
275         ret = getaddrinfo(node, service, &hints, &result);
276     } while (EAI_AGAIN == ret);
277 
278     if (ret != 0) {
279         isErrorOccured = true;
280 #ifdef _WIN32
281         errorMessage = getLastErrorMessageInternal(WSAGetLastError());
282 #elif defined(MONA)
283         char buf[128];
284         snprintf(buf, 128, "getaddrinfo returns %d", ret);
285         errorMessage = ucs4string::from_c_str(buf);
286 #else
287         errorMessage = ucs4string::from_c_str(gai_strerror(ret));
288 #endif
289         return NULL;
290     }
291 
292     // there may be many addresses for one host
293     int lastError = 0;
294     for (struct addrinfo* p = result; p != NULL; p = p->ai_next) {
295         const int fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
296         if (-1 == fd) {
297 #ifdef _WIN32
298             lastError = WSAGetLastError();
299 #else
300             lastError = errno;
301 #endif
302             continue;
303         }
304         if (connect(fd, p->ai_addr, p->ai_addrlen) == 0) {
305 
306             ucs4string addressString = getAddressString(p);
307             freeaddrinfo(result);
308             return new Socket(fd, Socket::CLIENT, addressString);
309         } else {
310 #ifdef _WIN32
311             lastError = WSAGetLastError();
312 #else
313             lastError = errno;
314 #endif
315 #ifdef _WIN32
316             ::shutdown(fd, SD_SEND);
317             ::closesocket(fd);
318 #elif defined(MONA)
319             ::closesocket(fd);
320 #else
321             ::close(fd);
322 #endif
323         }
324     }
325     freeaddrinfo(result);
326     isErrorOccured = true;
327     errorMessage = getLastErrorMessageInternal(lastError);
328     return NULL;
329 }
330 #if !defined(__CYGWIN__) && !defined(MONA)
331 extern ucs4string my_utf16ToUtf32(const std::wstring& s);
332 #endif
createServerSocket(const char * service,int ai_family,int ai_socktype,int ai_protocol,bool & isErrorOccured,ucs4string & errorMessage)333 Socket* Socket::createServerSocket(const char* service,
334                                    int ai_family,
335                                    int ai_socktype,
336                                    int ai_protocol,
337                                    bool& isErrorOccured,
338                                    ucs4string& errorMessage)
339 {
340     struct addrinfo hints;
341     memset(&hints, 0, sizeof(struct addrinfo));
342     hints.ai_family = ai_family;
343     hints.ai_socktype = ai_socktype;
344 #ifndef MONA
345     hints.ai_flags = AI_PASSIVE;
346 #endif
347     hints.ai_protocol = ai_protocol;
348     hints.ai_canonname = NULL;
349     hints.ai_addr = NULL;
350     hints.ai_next = NULL;
351     struct addrinfo* result;
352     int ret;
353 
354     // check temporary failure
355     do {
356         ret = getaddrinfo(NULL, service, &hints, &result);
357     } while (EAI_AGAIN == ret);
358 
359     if (ret != 0) {
360         isErrorOccured = true;
361 #ifdef _WIN32
362         errorMessage = my_utf16ToUtf32(gai_strerror(ret));
363 #elif defined(MONA)
364         errorMessage = ucs4string::from_c_str("should be port lwip_strerr");
365 #else
366         errorMessage = ucs4string::from_c_str(gai_strerror(ret));
367 #endif
368         return NULL;
369     }
370     // there may be many addresses for one host
371     int lastError = 0;
372     for (struct addrinfo* p = result; p != NULL; p = p->ai_next) {
373         const int fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
374         if (-1 == fd) {
375             lastError = errno;
376             continue;
377         }
378 // Mona's lwip doesn't support SO_REUSEADDR.
379 #ifndef MONA
380         int optValue = 1;
381         if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optValue, sizeof(optValue)) == -1) {
382 #ifdef _WIN32
383             ::shutdown(fd, SD_SEND);
384             ::closesocket(fd);
385             lastError = WSAGetLastError();
386 #else
387             ::close(fd);
388             lastError = errno;
389 #endif
390             continue;
391         }
392 #endif
393 
394         if (bind(fd, p->ai_addr, p->ai_addrlen) == -1) {
395 #ifdef _WIN32
396             ::shutdown(fd, SD_SEND);
397             ::closesocket(fd);
398             lastError = WSAGetLastError();
399 #elif defined(MONA)
400             ::closesocket(fd);
401             lastError = errno;
402 #else
403             ::close(fd);
404             lastError = errno;
405 #endif
406             continue;
407         }
408         const int TRADITIONAL_BACKLOG = 5;
409         if (p->ai_socktype == SOCK_STREAM ) {
410             if (listen(fd, TRADITIONAL_BACKLOG) == -1) {
411 #ifdef _WIN32
412                 ::shutdown(fd, SD_SEND);
413                 ::closesocket(fd);
414                 lastError = WSAGetLastError();
415 #elif defined(MONA)
416             ::closesocket(fd);
417             lastError = errno;
418 #else
419                 ::close(fd);
420                 lastError = errno;
421 #endif
422 
423                 continue;
424             }
425         }
426         ucs4string addressString = getAddressString(p);
427         freeaddrinfo(result);
428         return new Socket(fd, Socket::SERVER, addressString);
429     }
430     freeaddrinfo(result);
431     isErrorOccured = true;
432     errorMessage = getLastErrorMessageInternal(lastError);
433     return NULL;
434 }
435 
getAddressString(const struct sockaddr * addr,socklen_t addrlen)436 ucs4string Socket::getAddressString(const struct sockaddr* addr, socklen_t addrlen)
437 {
438 #ifdef MONA
439     return ucs4string::from_c_str("getAddressString not supported");
440 #else
441     int ret;
442     char host[NI_MAXHOST];
443     char serv[NI_MAXSERV];
444     do {
445         ret = getnameinfo(addr,
446                           addrlen,
447                           host, sizeof(host),
448                           serv, sizeof(serv), NI_NUMERICSERV);
449     } while (EAI_AGAIN == ret);
450     char name[NI_MAXSERV + NI_MAXHOST + 1];
451     snprintf(name, sizeof(name), "%s:%s", host, serv);
452     return ucs4string::from_c_str(name);
453 #endif
454 }
getAddressString(const struct addrinfo * addr)455 ucs4string Socket::getAddressString(const struct addrinfo* addr)
456 {
457     return getAddressString(addr->ai_addr, addr->ai_addrlen);
458 }
459 
setLastError()460 void Socket::setLastError()
461 {
462 #ifdef _WIN32
463     lastError_ = WSAGetLastError();
464 #else
465     lastError_ = errno;
466 #endif
467 }
468