1 module yu.asyncsocket.transport;
2 
3 import yu.eventloop;
4 public import yu.memory.allocator;
5 
6 enum TransportType : short {
7     ACCEPT,
8     TCP,
9     UDP
10 }
11 
12 __gshared size_t TCP_READ_BUFFER_SIZE = 16 * 1024;
13 __gshared size_t UDP_READ_BUFFER_SIZE = 16 * 1024;
14 
15 abstract class AsyncTransport {
16     this(EventLoop loop, TransportType type) {
17         _loop = loop;
18     }
19 
20     void close();
21     bool start();
22     @property bool isAlive() @trusted;
23     @property int fd();
24 
25     final @property transportType() {
26         return _type;
27     }
28 
29     final @property eventLoop() {
30         return _loop;
31     }
32 
33 protected:
34     EventLoop _loop;
35     TransportType _type;
36 }
37 
38 static if (IOMode == IO_MODE.epoll) {
39     version (X86) {
40 
41         enum SO_REUSEPORT = 15;
42     } else version (X86_64) {
43         enum SO_REUSEPORT = 15;
44     } else version (MIPS32) {
45         enum SO_REUSEPORT = 0x0200;
46 
47     } else version (MIPS64) {
48         enum SO_REUSEPORT = 0x0200;
49     } else version (PPC) {
50         enum SO_REUSEPORT = 15;
51     } else version (PPC64) {
52         enum SO_REUSEPORT = 15;
53     } else version (ARM) {
54         enum SO_REUSEPORT = 15;
55     }
56 } else static if (IOMode == IO_MODE.kqueue) {
57     enum SO_REUSEPORT = 0x0200;
58 }
59 
60 mixin template TransportSocketOption() {
61     import std.functional;
62     import std.datetime;
63     import core.stdc.stdint;
64     import std.socket;
65 
66     version (Windows) import SOCKETOPTIONS = core.sys.windows.winsock2;
67 
68     version (Posix) import SOCKETOPTIONS = core.sys.posix.sys.socket;
69 
70     /// Get a socket option.
71     /// Returns: The number of bytes written to $(D result).
72     //returns the length, in bytes, of the actual result - very different from getsockopt()
73     pragma(inline) final int getOption(SocketOptionLevel level, SocketOption option,
74         void[] result) @trusted {
75 
76         return _socket.getOption(level, option, result);
77     }
78 
79     /// Common case of getting integer and boolean options.
80     pragma(inline) final int getOption(SocketOptionLevel level,
81         SocketOption option, ref int32_t result) @trusted {
82         return _socket.getOption(level, option, result);
83     }
84 
85     /// Get the linger option.
86     pragma(inline) final int getOption(SocketOptionLevel level, SocketOption option,
87         ref Linger result) @trusted {
88         return _socket.getOption(level, option, result);
89     }
90 
91     /// Get a timeout (duration) option.
92     pragma(inline) final void getOption(SocketOptionLevel level,
93         SocketOption option, ref Duration result) @trusted {
94         _socket.getOption(level, option, result);
95     }
96 
97     /// Set a socket option.
98     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option,
99         void[] value) @trusted {
100         return _socket.setOption(forward!(level, option, value));
101     }
102 
103     /// Common case for setting integer and boolean options.
104     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option,
105         int32_t value) @trusted {
106         return _socket.setOption(forward!(level, option, value));
107     }
108 
109     /// Set the linger option.
110     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option,
111         Linger value) @trusted {
112         return _socket.setOption(forward!(level, option, value));
113     }
114 
115     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option,
116         Duration value) @trusted {
117         return _socket.setOption(forward!(level, option, value));
118     }
119 
120     // you should be yDel the Address
121     final @property @trusted Address remoteAddress() {
122         Address addr = createAddress();
123         SOCKETOPTIONS.socklen_t nameLen = addr.nameLen;
124         if (Socket.ERROR == SOCKETOPTIONS.getpeername(_socket.handle, addr.name, &nameLen))
125             throw new SocketOSException("Unable to obtain remote socket address");
126         if (nameLen > addr.nameLen)
127             throw new SocketParameterException("Not enough socket address storage");
128         assert(addr.addressFamily == _socket.addressFamily);
129         return addr;
130     }
131 
132     // you should be yDel the Address
133     final @property @trusted Address localAddress() {
134         Address addr = createAddress();
135         SOCKETOPTIONS.socklen_t nameLen = addr.nameLen;
136         if (Socket.ERROR == SOCKETOPTIONS.getsockname(_socket.handle, addr.name, &nameLen))
137             throw new SocketOSException("Unable to obtain local socket address");
138         if (nameLen > addr.nameLen)
139             throw new SocketParameterException("Not enough socket address storage");
140         assert(addr.addressFamily == _socket.addressFamily);
141         return addr;
142     }
143 
144     protected final Address createAddress() {
145         enum ushort DPORT = 0;
146         if (AddressFamily.INET == _socket.addressFamily)
147             return yNew!InternetAddress(DPORT);
148         else if (AddressFamily.INET6 == _socket.addressFamily)
149             return yNew!Internet6Address(DPORT);
150         else
151             throw new AddressException(
152                 "NOT SUPPORT addressFamily. It only can be AddressFamily.INET or AddressFamily.INET6");
153     }
154 }