1 /* Written by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module sockchan
is aliced
;
22 // ////////////////////////////////////////////////////////////////////////// //
25 static struct UDSData
{
38 void decRef () nothrow @nogc {
40 auto uds
= cast(UDSData
*)udsp
;
42 import core
.stdc
.stdlib
: free
;
43 import core
.sys
.posix
.unistd
: close
;
44 if (!uds
.dontclose
) close(uds
.fd
);
51 this (this) nothrow @nogc { pragma(inline
, true); if (udsp
) ++(cast(UDSData
*)udsp
).rc
; }
52 ~this () nothrow @nogc { pragma(inline
, true); if (udsp
) close(); }
54 void opAssign (UDSocket sk
) {
56 if (sk
.udsp
) ++(cast(UDSData
*)sk
.udsp
).rc
;
61 @property bool isOpen () const nothrow @trusted @nogc { pragma(inline
, true); return (udsp
!= 0); }
62 @property int fd () const nothrow @trusted @nogc { pragma(inline
, true); return (udsp
!= 0 ?
(cast(UDSData
*)udsp
).fd
: -1); }
64 void close () nothrow @nogc { pragma(inline
, true); if (udsp
) decRef(); }
65 void create (const(char)[] name
) { doCC
!"server"(name
); }
66 void connect (const(char)[] name
) { doCC
!"client"(name
); }
68 @property uint bytesSent () const nothrow @trusted @nogc { pragma(inline
, true); return (udsp
!= 0 ?
(cast(UDSData
*)udsp
).bytesSent
: 0); }
69 @property uint bytesReceived () const nothrow @trusted @nogc { pragma(inline
, true); return (udsp
!= 0 ?
(cast(UDSData
*)udsp
).bytesReceived
: 0); }
71 @property void resetBytesSent () nothrow @trusted @nogc { pragma(inline
, true); if (udsp
!= 0) (cast(UDSData
*)udsp
).bytesSent
= 0; }
72 @property void resetBytesReceived () nothrow @trusted @nogc { pragma(inline
, true); if (udsp
!= 0) (cast(UDSData
*)udsp
).bytesReceived
= 0; }
75 if (!udsp
) throw new Exception("can't listen on closed socket");
76 auto uds
= cast(UDSData
*)udsp
;
78 import core
.sys
.posix
.sys
.socket
: listen
;
79 if (listen(uds
.fd
, 1) != 0) throw new Exception("listen failed");
86 auto uds
= cast(UDSData
*)udsp
;
87 assert(uds
.didlisten
);
88 import core
.sys
.posix
.sys
.socket
: accept
;
89 int cfd
= accept(uds
.fd
, null, null);
90 if (cfd
== -1) throw new Exception("accept failed");
98 if (!udsp
) throw new Exception("can't detach closed socket");
99 auto uds
= cast(UDSData
*)udsp
;
101 uds
.dontclose
= true;
106 void[] rawRead (void[] buf
) {
107 import core
.sys
.posix
.sys
.socket
: recv
;
108 if (!udsp
) throw new Exception("can't read from closed socket");
109 auto uds
= cast(UDSData
*)udsp
;
110 if (buf
.length
== 0) return buf
[];
111 auto rd
= recv(uds
.fd
, buf
.ptr
, buf
.length
, 0);
112 if (rd
< 0) throw new Exception("socket read error");
113 uds
.bytesReceived
+= rd
;
117 void rawWrite (const(void)[] buf
) {
118 import core
.sys
.posix
.sys
.socket
: send
, MSG_NOSIGNAL
;
119 if (!udsp
) throw new Exception("can't write to closed socket");
120 auto uds
= cast(UDSData
*)udsp
;
121 auto dp
= cast(const(ubyte)*)buf
.ptr
;
122 auto left
= buf
.length
;
124 auto wr
= send(uds
.fd
, dp
, left
, 0);
125 if (wr
<= 0) throw new Exception("socket write error");
133 void assignFD (int fd
) {
134 import core
.stdc
.stdlib
: malloc
;
135 import core
.stdc
.string
: memset
;
138 auto uds
= cast(UDSData
*)malloc(UDSData
.sizeof
);
140 import core
.sys
.posix
.unistd
: close
;
142 throw new Exception("out of memory"); // let's hope that we can do it
144 memset(uds
, 0, (*uds
).sizeof
);
147 udsp
= cast(usize
)uds
;
151 void doCC(string mode
) (const(char)[] name
) {
152 static assert(mode
== "client" || mode
== "server", "invalid mode");
153 import core
.stdc
.stdlib
: malloc
;
154 import core
.stdc
.string
: memset
;
156 int fd
= makeUADS
!mode(name
);
157 auto uds
= cast(UDSData
*)malloc(UDSData
.sizeof
);
159 import core
.sys
.posix
.unistd
: close
;
161 throw new Exception("out of memory"); // let's hope that we can do it
163 memset(uds
, 0, (*uds
).sizeof
);
166 udsp
= cast(usize
)uds
;
169 static int makeUADS(string mode
) (const(char)[] name
) {
170 static assert(mode
== "client" || mode
== "server", "invalid mode");
171 import core
.stdc
.string
: memset
;
172 import core
.sys
.posix
.sys
.socket
;
173 import core
.sys
.posix
.sys
.un
: sockaddr_un
;
174 import core
.sys
.posix
.unistd
: close
;
175 // max name length is 108, so be safe here
176 if (name
.length
== 0 || name
.length
> 100) throw new Exception("invalid name");
177 sockaddr_un sun
= void;
178 memset(&sun
, 0, sun
.sizeof
);
179 sun
.sun_family
= AF_UNIX
;
180 // create domain socket without FS inode (first byte of name buffer should be zero)
181 sun
.sun_path
[1..1+name
.length
] = cast(byte[])name
[];
182 int fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
183 if (fd
< 0) throw new Exception("can't create unix domain socket");
184 static if (mode
== "server") {
185 import core
.sys
.posix
.sys
.socket
: bind
;
186 if (bind(fd
, cast(sockaddr
*)&sun
, sun
.sizeof
) != 0) { close(fd
); throw new Exception("can't bind unix domain socket"); }
188 import core
.sys
.posix
.sys
.socket
: connect
;
189 if (connect(fd
, cast(sockaddr
*)&sun
, sun
.sizeof
) != 0) {
190 import core
.stdc
.errno
;
193 //{ import std.stdio; writeln("ERRNO: ", err); }
194 throw new Exception("can't connect to unix domain socket");