summaryrefslogtreecommitdiff
path: root/ext/socket/rubysocket.h
blob: d39de0ab1a1776f0dc872a49c5c78ea5fb97358c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
#ifndef RUBY_SOCKET_H
#define RUBY_SOCKET_H 1

#include "ruby/ruby.h"
#include "ruby/io.h"
#include "ruby/thread.h"
#include "ruby/util.h"
#include "internal.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif

#ifdef HAVE_SYS_UIO_H
#  include <sys/uio.h>
#endif

#ifdef HAVE_XTI_H
#  include <xti.h>
#endif

#ifdef _WIN32
#  if defined(_MSC_VER)
#    undef HAVE_TYPE_STRUCT_SOCKADDR_DL
#  endif
#else
#  if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
#    include <net/socket.h>
#  else
#    include <sys/socket.h>
#  endif
#  include <netinet/in.h>
#  ifdef HAVE_NETINET_IN_SYSTM_H
#    include <netinet/in_systm.h>
#  endif
#  ifdef HAVE_NETINET_TCP_H
#    include <netinet/tcp.h>
#  endif
#  ifdef HAVE_NETINET_TCP_FSM_H
#    include <netinet/tcp_fsm.h>
#  endif
#  ifdef HAVE_NETINET_UDP_H
#    include <netinet/udp.h>
#  endif
#  ifdef HAVE_ARPA_INET_H
#    include <arpa/inet.h>
#  endif
#  include <netdb.h>
#endif

#ifdef HAVE_NETPACKET_PACKET_H
#  include <netpacket/packet.h>
#endif
#ifdef HAVE_NET_ETHERNET_H
#  include <net/ethernet.h>
#endif

#include <errno.h>

#ifdef HAVE_SYS_UN_H
#  include <sys/un.h>
#endif

#if defined(HAVE_FCNTL)
#  ifdef HAVE_SYS_SELECT_H
#    include <sys/select.h>
#  endif
#  ifdef HAVE_SYS_TYPES_H
#    include <sys/types.h>
#  endif
#  ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#  endif
#  ifdef HAVE_FCNTL_H
#    include <fcntl.h>
#  endif
#endif

#ifdef HAVE_IFADDRS_H
#  ifdef __HAIKU__
#    define _BSD_SOURCE
#  endif
#  include <ifaddrs.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#  include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
#  include <sys/sockio.h>
#endif
#ifdef HAVE_NET_IF_H
#  include <net/if.h>
#endif

#ifdef HAVE_SYS_PARAM_H
#  include <sys/param.h>
#endif
#ifdef HAVE_SYS_UCRED_H
#  include <sys/ucred.h>
#endif
#ifdef HAVE_UCRED_H
#  include <ucred.h>
#endif
#ifdef HAVE_NET_IF_DL_H
#  include <net/if_dl.h>
#endif

#ifndef HAVE_TYPE_SOCKLEN_T
typedef int socklen_t;
#endif

#ifdef NEED_IF_INDEXTONAME_DECL
char *if_indextoname(unsigned int, char *);
#endif
#ifdef NEED_IF_NAMETOINDEX_DECL
unsigned int if_nametoindex(const char *);
#endif

#define SOCKLEN_MAX \
  (0 < (socklen_t)-1 ? \
   ~(socklen_t)0 : \
   (((((socklen_t)1) << (sizeof(socklen_t) * CHAR_BIT - 2)) - 1) * 2 + 1))

#ifndef RSTRING_SOCKLEN
#  define RSTRING_SOCKLEN (socklen_t)RSTRING_LENINT
#endif

#ifndef EWOULDBLOCK
#  define EWOULDBLOCK EAGAIN
#endif

/*
 * workaround for NetBSD, OpenBSD and etc.
 * The problem is since 4.4BSD-Lite.
 * FreeBSD fix the problem at FreeBSD 2.2.0.
 * NetBSD fix the problem at NetBSD 3.0 by kern/29624.
 * OpenBSD fix the problem at OpenBSD 3.8.
 */
#define pseudo_AF_FTIP pseudo_AF_RTIP

#ifndef HAVE_GETADDRINFO
#  include "addrinfo.h"
#endif

#include "sockport.h"

#ifndef NI_MAXHOST
#  define NI_MAXHOST 1025
#endif
#ifndef NI_MAXSERV
#  define NI_MAXSERV 32
#endif

#ifdef AF_INET6
#  define IS_IP_FAMILY(af) ((af) == AF_INET || (af) == AF_INET6)
#else
#  define IS_IP_FAMILY(af) ((af) == AF_INET)
#endif

#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
#  define IN6_IS_ADDR_UNIQUE_LOCAL(a) (((a)->s6_addr[0] == 0xfc) || ((a)->s6_addr[0] == 0xfd))
#endif

#ifndef HAVE_TYPE_STRUCT_SOCKADDR_STORAGE
/*
 * RFC 2553: protocol-independent placeholder for socket addresses
 */
#  define _SS_MAXSIZE     128
#  define _SS_ALIGNSIZE   (sizeof(double))
#  define _SS_PAD1SIZE    (_SS_ALIGNSIZE - sizeof(unsigned char) * 2)
#  define _SS_PAD2SIZE    (_SS_MAXSIZE - sizeof(unsigned char) * 2 - \
                                _SS_PAD1SIZE - _SS_ALIGNSIZE)

struct sockaddr_storage {
#  ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
        unsigned char ss_len;           /* address length */
        unsigned char ss_family;        /* address family */
#  else
        unsigned short ss_family;
#  endif
        char    __ss_pad1[_SS_PAD1SIZE];
        double  __ss_align;     /* force desired structure storage alignment */
        char    __ss_pad2[_SS_PAD2SIZE];
};
#endif

typedef union {
  struct sockaddr addr;
  struct sockaddr_in in;
#ifdef AF_INET6
  struct sockaddr_in6 in6;
#endif
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
  struct sockaddr_un un;
#endif
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_DL
  struct sockaddr_dl dl; /* AF_LINK */
#endif
  struct sockaddr_storage storage;
  char place_holder[2048]; /* sockaddr_storage is not enough for Unix domain sockets on SunOS and Darwin. */
} union_sockaddr;

#ifdef __APPLE__
/*
 * CMSG_ macros are broken on 64bit darwin, because __DARWIN_ALIGN
 * aligns up to __darwin_size_t which is 64bit, but CMSG_DATA is
 * 32bit-aligned.
 */
#  undef __DARWIN_ALIGNBYTES
#  define __DARWIN_ALIGNBYTES (sizeof(unsigned int) - 1)
#endif

#if defined(_AIX)
#  ifndef CMSG_SPACE
#    define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
#  endif
#  ifndef CMSG_LEN
#    define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#  endif
#endif

#ifdef __BEOS__
#  undef close
#  define close closesocket
#endif

#define INET_CLIENT 0
#define INET_SERVER 1
#define INET_SOCKS  2

extern int rsock_do_not_reverse_lookup;
extern int rsock_cmsg_cloexec_state;
#define FMODE_NOREVLOOKUP 0x100

/* common socket families only */
#define FMODE_UNIX        0x00200000
#define FMODE_INET        0x00400000
#define FMODE_INET6       0x00800000
#define FMODE_SOCK        (FMODE_UNIX|FMODE_INET|FMODE_INET6)

extern VALUE rb_cBasicSocket;
extern VALUE rb_cIPSocket;
extern VALUE rb_cTCPSocket;
extern VALUE rb_cTCPServer;
extern VALUE rb_cUDPSocket;
#ifdef HAVE_SYS_UN_H
extern VALUE rb_cUNIXSocket;
extern VALUE rb_cUNIXServer;
#endif
extern VALUE rb_cSocket;
extern VALUE rb_cAddrinfo;
extern VALUE rb_cSockOpt;

extern VALUE rb_eSocket;

#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
#  ifdef SOCKS5
#    include <socks.h>
#  else
void SOCKSinit();
int Rconnect();
#  endif
#endif

#include "constdefs.h"

#define BLOCKING_REGION_FD(func, arg) (long)rb_thread_io_blocking_region((func), (arg), (arg)->fd)

#define SockAddrStringValue(v) rsock_sockaddr_string_value(&(v))
#define SockAddrStringValuePtr(v) rsock_sockaddr_string_value_ptr(&(v))
#define SockAddrStringValueWithAddrinfo(v, rai_ret) rsock_sockaddr_string_value_with_addrinfo(&(v), &(rai_ret))
VALUE rsock_sockaddr_string_value(volatile VALUE *);
char *rsock_sockaddr_string_value_ptr(volatile VALUE *);
VALUE rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *ai_ret);

VALUE rb_check_sockaddr_string_type(VALUE);

NORETURN(void rsock_raise_socket_error(const char *, int));

int rsock_family_arg(VALUE domain);
int rsock_socktype_arg(VALUE type);
int rsock_level_arg(int family, VALUE level);
int rsock_optname_arg(int family, int level, VALUE optname);
int rsock_cmsg_type_arg(int family, int level, VALUE type);
int rsock_shutdown_how_arg(VALUE how);

int rsock_getfamily(rb_io_t *fptr);

struct rb_addrinfo {
  struct addrinfo *ai;
  int allocated_by_malloc;
};
int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct rb_addrinfo **res);
void rb_freeaddrinfo(struct rb_addrinfo *ai);
VALUE rsock_freeaddrinfo(VALUE arg);
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
int rsock_fd_family(int fd);
struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags);
struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);

VALUE rsock_addrinfo_new(struct sockaddr *addr, socklen_t len, int family, int socktype, int protocol, VALUE canonname, VALUE inspectname);
VALUE rsock_addrinfo_inspect_sockaddr(VALUE rai);

VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen);
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup);
VALUE rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t));
VALUE rsock_inspect_sockaddr(struct sockaddr *addr, socklen_t socklen, VALUE ret);
socklen_t rsock_sockaddr_len(struct sockaddr *addr);
VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len);

int rsock_revlookup_flag(VALUE revlookup, int *norevlookup);

#ifdef HAVE_SYS_UN_H
VALUE rsock_unixpath_str(struct sockaddr_un *sockaddr, socklen_t len);
VALUE rsock_unixaddr(struct sockaddr_un *sockaddr, socklen_t len);
socklen_t rsock_unix_sockaddr_len(VALUE path);
#endif

int rsock_socket(int domain, int type, int proto);
int rsock_detect_cloexec(int fd);
VALUE rsock_init_sock(VALUE sock, int fd);
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type);
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);

struct rsock_send_arg {
    int fd, flags;
    VALUE mesg;
    struct sockaddr *to;
    socklen_t tolen;
};

VALUE rsock_sendto_blocking(void *data);
VALUE rsock_send_blocking(void *data);
VALUE rsock_bsock_send(int argc, VALUE *argv, VALUE sock);

enum sock_recv_type {
    RECV_RECV,                  /* BasicSocket#recv(no from) */
    RECV_IP,                    /* IPSocket#recvfrom */
    RECV_UNIX,                  /* UNIXSocket#recvfrom */
    RECV_SOCKET                 /* Socket#recvfrom */
};

VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
			        VALUE ex, enum sock_recv_type from);
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);

int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);

VALUE rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
VALUE rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
			      struct sockaddr *sockaddr, socklen_t *len);
VALUE rsock_sock_listen(VALUE sock, VALUE log);

VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data);

#if defined(HAVE_SENDMSG)
VALUE rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock);
VALUE rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock);
#else
#define rsock_bsock_sendmsg rb_f_notimplement
#define rsock_bsock_sendmsg_nonblock rb_f_notimplement
#endif

#if defined(HAVE_RECVMSG)
VALUE rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock);
VALUE rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock);
ssize_t rsock_recvmsg(int socket, struct msghdr *message, int flags);
#else
#define rsock_bsock_recvmsg rb_f_notimplement
#define rsock_bsock_recvmsg_nonblock rb_f_notimplement
#endif

#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
void rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p);
#endif

void rsock_init_basicsocket(void);
void rsock_init_ipsocket(void);
void rsock_init_tcpsocket(void);
void rsock_init_tcpserver(void);
void rsock_init_sockssocket(void);
void rsock_init_udpsocket(void);
void rsock_init_unixsocket(void);
void rsock_init_unixserver(void);
void rsock_init_socket_constants(void);
void rsock_init_ancdata(void);
void rsock_init_addrinfo(void);
void rsock_init_sockopt(void);
void rsock_init_sockifaddr(void);
void rsock_init_socket_init(void);

NORETURN(void rsock_syserr_fail_host_port(int err, const char *, VALUE, VALUE));
NORETURN(void rsock_syserr_fail_path(int err, const char *, VALUE));
NORETURN(void rsock_syserr_fail_sockaddr(int err, const char *mesg, struct sockaddr *addr, socklen_t len));
NORETURN(void rsock_syserr_fail_raddrinfo(int err, const char *mesg, VALUE rai));
NORETURN(void rsock_syserr_fail_raddrinfo_or_sockaddr(int err, const char *mesg, VALUE addr, VALUE rai));

NORETURN(void rsock_sys_fail_host_port(const char *, VALUE, VALUE));
NORETURN(void rsock_sys_fail_path(const char *, VALUE));
NORETURN(void rsock_sys_fail_sockaddr(const char *, struct sockaddr *addr, socklen_t len));
NORETURN(void rsock_sys_fail_raddrinfo(const char *, VALUE rai));
NORETURN(void rsock_sys_fail_raddrinfo_or_sockaddr(const char *, VALUE addr, VALUE rai));

/*
 * It is safe on Linux to attempt using a socket without waiting on it in
 * all cases.  For some syscalls (e.g. accept/accept4), blocking on the
 * syscall instead of relying on select/poll allows the kernel to use
 * "wake-one" behavior and avoid the thundering herd problem.
 * This is likely safe on all other *nix-like systems, so this whitelist
 * can be expanded by interested parties.
 */
#if defined(__linux__)
static inline int rsock_maybe_fd_writable(int fd) { return 1; }
static inline void rsock_maybe_wait_fd(int fd) { }
#  ifdef MSG_DONTWAIT
#    define MSG_DONTWAIT_RELIABLE 1
#  endif
#else /* some systems (mswin/mingw) need these.  ref: r36946 */
#  define rsock_maybe_fd_writable(fd) rb_thread_fd_writable((fd))
#  define rsock_maybe_wait_fd(fd) rb_thread_wait_fd((fd))
#endif

/*
 * some OSes may support MSG_DONTWAIT inconsistently depending on socket
 * type, we only expect Linux to support it consistently for all socket types.
 */
#ifndef MSG_DONTWAIT_RELIABLE
#  define MSG_DONTWAIT_RELIABLE 0
#endif

static inline int
rsock_opt_false_p(VALUE opt, VALUE sym)
{
    if (!NIL_P(opt) && Qfalse == rb_hash_lookup2(opt, sym, Qundef))
	return 1;
    return 0;
}

#endif