root/lang/cplusplus/llv8call/branches/unixsocket/ext/socket/socket.cc @ 21244

Revision 21244, 13.7 kB (checked in by tokuhirom, 5 years ago)

bug fixed....

Line 
1// The MIT License
2//
3// Copyright (c) 2008 Tokuhiro Matsuno
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22
23#include <v8.h>
24#include <cstdio>
25#include <cstdlib>
26#include <memory.h>
27#include <errno.h>
28#include "v8ext.h"
29#include <llv8-macros.h>
30#ifndef _WIN32
31#  include <sys/socket.h>
32#  include <sys/types.h>
33#  include <netinet/in.h>
34#  include <arpa/inet.h>
35#  include <sys/un.h>
36#  include <unistd.h>
37#  include <sys/param.h>
38#  include <netdb.h>
39#endif
40
41typedef union sock_addr {
42    struct sockaddr_in in;
43#ifdef AF_UNIX
44    struct sockaddr_un un;
45#endif
46} sock_addr_t;
47
48/** DESCRIPTION:
49 *
50 * low level socket class.
51 *
52 * Design of this class is inspired from python's socket class.
53 *
54 */
55
56#define EXTERNAL_SOCKET() int sock = (int) args.This()->GetInternalField(0)->Int32Value()
57
58using namespace v8;
59
60static inline Handle<Value> throw_stderr(const char *msg) {
61    std::string buf(msg);
62    buf += " error: ";
63    buf += strerror(errno);
64    return ThrowException(String::New(buf.c_str()));
65}
66
67static inline v8::Handle<v8::Object> socket_namespace() {
68        return v8::Context::GetCurrent()->Global()
69                      ->Get(v8::String::New("org"))->ToObject()
70                      ->Get(v8::String::New("coderepos"))->ToObject()
71                      ->Get(v8::String::New("socket"))->ToObject();
72}
73
74// TODO: support AF_UNIX
75static inline Handle<Array> _makeaddr(sockaddr & addr) {
76    Handle<Array> ret = Array::New(2);
77    switch (addr.sa_family) {
78#if defined(AF_UNIX)
79    case AF_UNIX:
80        {
81            sockaddr_un * addr_un = (sockaddr_un*)&addr;
82            ret->Set(Int32::New(0), String::New(addr_un->sun_path));
83        }
84        break;
85#endif
86    case AF_INET:
87        {
88            char buf[NI_MAXHOST];
89            if (getnameinfo(&addr, sizeof(sockaddr_in), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST)) {
90                throw_stderr(__func__);
91                return ret;
92            }
93            sockaddr_in * addr_in = (sockaddr_in*)&addr;
94            ret->Set(Int32::New(0), String::New(buf));
95            ret->Set(Int32::New(1), Int32::New(ntohs(addr_in->sin_port)));
96        }
97        break;
98    default:
99        ThrowException(String::New("This family does not supported yet"));
100        return ret;
101    }
102    return ret;
103}
104
105// TODO: support unix domain socket
106// TODO: support inet6
107static inline void _gen_sockaddr(Handle<Array> &args, int family, sock_addr_t* addr_ret, socklen_t * len) {
108    switch (family) {
109#if defined(AF_UNIX)
110    case AF_UNIX:
111        {
112            if (args->Length() != 1) {
113                ThrowException(String::New("invalid args: AF_UNIX => (socket file)"));
114                return;
115            }
116            struct sockaddr_un *addr = (struct sockaddr_un*)addr_ret;
117            memset(addr, 0, sizeof(sockaddr_un)); // clear
118
119            String::Utf8Value path(args->Get(Int32::New(0)));
120            if ((unsigned int)path.length() >= sizeof(addr->sun_path)) {
121                ThrowException(String::New("path too long"));
122                return;
123            }
124            addr->sun_family = AF_UNIX;
125            memcpy(addr->sun_path, *path, path.length());
126            addr->sun_path[path.length()] = '\0';
127            *len = path.length() + (sizeof(*addr) - sizeof(addr->sun_path));
128        }
129        break;
130#endif
131    case AF_INET:
132        {
133            if (args->Length() != 2) {
134                ThrowException(String::New("invalid args: AF_INET => (host, port)"));
135                return;
136            }
137            String::Utf8Value host(args->Get(Int32::New(0)));
138            int32_t port = args->Get(Int32::New(1))->Int32Value();
139
140            struct sockaddr_in *addr = (struct sockaddr_in*)addr_ret;
141            memset(addr, 0, sizeof(*addr)); // clear
142            addr->sin_family = AF_INET;
143            in_addr_t hostinfo = inet_addr(*host);
144            if (hostinfo == INADDR_NONE) {
145                ThrowException(String::New("invalid ip"));
146                return;
147            }
148            addr->sin_addr.s_addr = hostinfo;
149            addr->sin_port = htons((short)port);
150            *len = sizeof(*addr);
151        }
152        break;
153    default:
154        fprintf(stderr, "unknown family");
155        abort();
156    }
157}
158
159
160FUNCTION(_open)
161    // USAGE: new Socket(Socket.AF_INET, Socket.SOCK_STREAM)
162    if (args.Length() == 2 && args[0]->IsExternal()) {
163        args.This()->SetInternalField(0, args[1]);
164        args.This()->Set(String::New("family"), args[2]);
165        args.This()->Set(String::New("type"),   args[3]);
166        args.This()->Set(String::New("proto"),  args[4]);
167        return args.This();
168    } else {
169        ARG_BETWEEN(0, 3);
170        ARG_int(family, 0);
171        ARG_int(type,   1);
172        ARG_int(protocol,  2);
173
174        if (args.Length() < 1) {
175            family = AF_INET;
176        }
177        if (args.Length() < 2) {
178            type = SOCK_STREAM;
179        }
180        if (args.Length() < 3) {
181            protocol = 0;
182        }
183
184        int desc = socket(family, type, protocol);
185        if (desc != -1) {
186            args.This()->SetInternalField(0, Int32::New(desc));
187            args.This()->Set(String::New("family"), Int32::New(family));
188            args.This()->Set(String::New("type"),   Int32::New(type));
189            args.This()->Set(String::New("proto"),  Int32::New(protocol));
190            return args.This();
191        } else {
192            return ThrowException(String::New("cannot open socket"));
193        }
194    }
195END
196
197FUNCTION(_bind)
198    EXTERNAL_SOCKET();
199    sock_addr_t addr;
200    socklen_t len;
201    int family = args.This()->Get(String::New("family"))->Int32Value();
202    ARG_array(addrsrc, 0);
203    _gen_sockaddr(addrsrc, family, &addr, &len);
204    if (bind(sock, (sockaddr*)&addr, len) == 0) {
205        return Undefined();
206    } else {
207        return throw_stderr("bind error: ");
208    }
209END
210
211FUNCTION(_listen)
212    EXTERNAL_SOCKET();
213    ARG_COUNT(1);
214    ARG_int(backlog, 0);
215    if (listen(sock, backlog) == 0) {
216        return Undefined();
217    } else {
218        return throw_stderr("listen error: ");
219    }
220END
221
222FUNCTION(_gethostname)
223    ARG_COUNT(0);
224    char * buf = new char [_POSIX_HOST_NAME_MAX+1];
225    if (gethostname(buf, _POSIX_HOST_NAME_MAX) == 0) {
226        Handle<String> str = String::New(buf);
227        delete [] buf;
228        return str;
229    } else {
230        delete [] buf;
231        return throw_stderr("gethostname error: ");
232    }
233END
234
235FUNCTION(_accept)
236    EXTERNAL_SOCKET();
237    ARG_COUNT(0);
238    struct sockaddr addr;
239    socklen_t len = sizeof(addr);
240    int newsock = accept(sock, &addr, &len);
241    if (newsock >= 0) {
242        Handle<Value> argv[2];
243        argv[0] = External::New(&len);
244        argv[1] = Int32::New(newsock);
245        argv[2] = args.This()->Get(String::New("family"));
246        argv[3] = args.This()->Get(String::New("type"));
247        argv[4] = args.This()->Get(String::New("proto"));
248        return Handle<Function>::Cast( socket_namespace()->Get(String::New("Socket")) )->NewInstance(2, argv);
249    } else {
250        return throw_stderr("accept error: ");
251    }
252END
253
254FUNCTION(_connect)
255    EXTERNAL_SOCKET();
256    sock_addr_t addr;
257    socklen_t len;
258    int family = args.This()->Get(String::New("family"))->Int32Value();
259    ARG_array(addrsrc, 0);
260    _gen_sockaddr(addrsrc, family, &addr, &len);
261    if (connect(sock, (sockaddr*)&addr, len) == 0) {
262        return Undefined();
263    } else {
264        return throw_stderr("connect error: ");
265    }
266END
267
268FUNCTION(_recv)
269    EXTERNAL_SOCKET();
270    ARG_BETWEEN(1, 2);
271    ARG_int(len, 0);
272    int _flags = 0;
273    if (args.Length() == 2) {
274        ARG_int(flags, 1);
275        _flags = flags;
276    }
277    char * buf = new char [len+1];
278    assert(sock);
279    ssize_t size = recv(sock, buf, len, _flags);
280    if (size >= 0) {
281        Handle<String> res = String::New(buf, size);
282        delete [] buf;
283        return res;
284    } else {
285        delete [] buf;
286        return throw_stderr("recv error: ");
287    }
288END
289
290FUNCTION(_recvfrom)
291    EXTERNAL_SOCKET();
292    ARG_BETWEEN(1, 2);
293    ARG_int(buflen, 0);
294    int _flags = 0;
295    if (args.Length() == 2) {
296        ARG_int(flags, 1);
297        _flags = flags;
298    }
299    char * buf = new char [buflen];
300    struct sockaddr addr;
301    socklen_t addrlen = sizeof(sockaddr);
302    ssize_t size = recvfrom(sock, buf, buflen, _flags, &addr, &addrlen);
303    if (size >= 0) {
304        Handle<Array> ret = Array::New(2);
305        ret->Set(Int32::New(0), String::New(buf, size));
306        ret->Set(Int32::New(1), _makeaddr(addr));
307        delete [] buf;
308        return ret;
309    } else {
310        delete [] buf;
311        return throw_stderr("recvfrom error: ");
312    }
313END
314
315FUNCTION(_send)
316    // @ret Returns the number of bytes sent.
317    EXTERNAL_SOCKET();
318    ARG_BETWEEN(1, 2);
319    ARG_str(str, 0);
320    int _flags = 0;
321    if (args.Length() == 2) {
322        ARG_int(flags, 1);
323        _flags = flags;
324    }
325    ssize_t size = send(sock, *str, str.length(), _flags);
326    if (size >= 0) {
327        return Int32::New(size);
328    } else {
329        return throw_stderr("send error: ");
330    }
331END
332
333FUNCTION(_sendto)
334    // @prototype sock.sendto(str, [flags, ] addr);
335    // @ret Returns the number of bytes sent.
336    EXTERNAL_SOCKET();
337    ARG_BETWEEN(2, 3);
338    ARG_str(str, 0);
339    int _flags = 0;
340    Handle<Array> addrsrc;
341    if (args.Length() == 3) {
342        ARG_int(flags, 1);
343        _flags = flags;
344        addrsrc = Handle<Array>::Cast(args[2]);
345    } else {
346        addrsrc = Handle<Array>::Cast(args[1]);
347    }
348    sock_addr_t addr;
349    socklen_t len;
350    int family = args.This()->Get(String::New("family"))->Int32Value();
351    _gen_sockaddr(addrsrc, family, &addr, &len);
352    ssize_t size = sendto(sock, *str, str.length(), _flags, (sockaddr*)&addr, len);
353    if (size >= 0) {
354        return Int32::New(size);
355    } else {
356        return throw_stderr("send error: ");
357    }
358END
359
360FUNCTION(_getsockname)
361    EXTERNAL_SOCKET();
362    ARG_COUNT(0);
363    sockaddr addr;
364    socklen_t len = sizeof(sockaddr);
365    if (getsockname(sock, &addr, &len) == 0) {
366        return _makeaddr(addr);
367    } else {
368        return throw_stderr("getsockname");
369    }
370END
371
372FUNCTION(_getpeername)
373    EXTERNAL_SOCKET();
374    ARG_COUNT(0);
375    sockaddr addr;
376    socklen_t len = sizeof(sockaddr);
377    if (getpeername(sock, &addr, &len) == 0) {
378        return _makeaddr(addr);
379    } else {
380        return throw_stderr("getpeername");
381    }
382END
383
384FUNCTION(_fileno)
385    EXTERNAL_SOCKET();
386    ARG_COUNT(0);
387    return Uint32::New(sock);
388END
389
390FUNCTION(_close)
391    EXTERNAL_SOCKET();
392    ARG_COUNT(0);
393    if (close(sock) >= 0) {
394        return Undefined();
395    } else {
396        return throw_stderr("close error: ");
397    }
398END
399
400FUNCTION(_inet_aton)
401    ARG_COUNT(1);
402    ARG_str(ip, 0);
403    in_addr addr;
404    if (inet_aton(*ip, &addr) == 1) {
405        return Uint32::New(addr.s_addr);
406    } else {
407        return throw_stderr("inet_aton");
408    }
409END
410
411FUNCTION(_inet_ntoa)
412    ARG_COUNT(1);
413    ARG_uint(ip, 0);
414    in_addr addr;
415    addr.s_addr = ip;
416    char * buf = inet_ntoa(addr);
417    if (buf) {
418        return String::New(buf);
419    } else {
420        return throw_stderr("inet_ntoa");
421    }
422END
423
424MODULE()
425    {
426        CLASS_WITH_CONSTRUCTOR(_open);
427
428        BIND_CI("SOCK_STREAM",    SOCK_STREAM);
429        BIND_CI("SOCK_DGRAM",     SOCK_DGRAM);
430        BIND_CI("SOCK_RAW",       SOCK_RAW);
431        BIND_CI("SOCK_RDM",       SOCK_RDM);
432        BIND_CI("SOCK_SEQPACKET", SOCK_SEQPACKET);
433
434#if defined(AF_UNIX)
435        BIND_CI("AF_UNIX",        AF_UNIX);
436#endif
437        BIND_CI("AF_INET",        AF_INET);
438        BIND_CI("AF_INET6",       AF_INET6);
439
440        BIND_CM("gethostname",    _gethostname);
441        BIND_CM("inet_aton",      _inet_aton);
442        BIND_CM("inet_ntoa",      _inet_ntoa);
443
444        BIND_IM("bind",           _bind);
445        BIND_IM("listen",         _listen);
446        BIND_IM("accept",         _accept);
447        BIND_IM("connect",        _connect);
448        BIND_IM("recv",           _recv);
449        BIND_IM("recvfrom",       _recvfrom);
450        BIND_IM("send",           _send);
451        BIND_IM("sendto",         _sendto);
452        BIND_IM("getsockname",    _getsockname);
453        BIND_IM("getpeername",    _getpeername);
454        BIND_IM("fileno",         _fileno);
455        BIND_IM("close",          _close);
456        // rest function is: 29
457        // getaddrinfo
458        // getfqdn
459        // gethostbyname
460        // gethostbyaddr
461        // getnameinfo
462        // getprotobyname
463        // getservbyname
464        // getservbyport
465        // socketpair
466        // fromfd
467        // ntohl
468        // ntohs
469        // htonl
470        // htons
471        // inet_pton
472        // inet_ntop
473        // getdefaulttimeout
474        // setdefaulttimeout
475        // getsockopt
476        // ioctl
477        // makefile
478        // recvfrom_into
479        // recv_into
480        // sendall
481        // setblocking
482        // settimeout
483        // gettimeout
484        // setsockopt
485        // shutdown
486
487        INTERNALCOUNT(1);
488
489        EXPORT_CLASS("Socket");
490    }
491ENDMODULE
492
Note: See TracBrowser for help on using the browser.