1 module database.postgresql.socket;
2 
3 import core.stdc.errno;
4 
5 import std.socket;
6 import std.exception;
7 import std.datetime;
8 
9 import database.postgresql.exception;
10 
11 struct Socket
12 {
13     void connect(const(char)[] host, ushort port)
14     {
15         socket_ = new TcpSocket();
16         socket_.connect(new InternetAddress(host, port));
17         socket_.setOption(SocketOptionLevel.SOCKET, SocketOption.KEEPALIVE, true);
18         socket_.setOption(SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, true);
19         socket_.setOption(SocketOptionLevel.SOCKET, SocketOption.SNDTIMEO, 30.seconds);
20         socket_.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, 30.seconds);
21     }
22 
23     bool connected() inout
24     {
25         return socket_ && socket_.isAlive();
26     }
27 
28     void close()
29     {
30         if (socket_) 
31         {
32             socket_.shutdown(SocketShutdown.BOTH);
33             socket_.close();
34             socket_ = null;
35         }
36     }
37 
38     void read(ubyte[] buffer)
39     {
40         long len;
41 
42         for (size_t off; off < buffer.length; off += len)
43         {
44             len = socket_.receive(buffer[off..$]);
45 
46             if (len > 0)
47             {
48                 continue;
49             }
50             else if (len == 0)
51             {
52                 throw new PgSQLConnectionException("Server closed the connection");
53             }
54             else
55             {
56                 if ((errno == EINTR) || (errno == EAGAIN)/* || (errno == EWOULDBLOCK)*/)
57                 {
58                     len = 0;
59                     continue;
60                 }
61 
62                 throw new PgSQLConnectionException("Received std.socket.Socket.ERROR: " ~ formatSocketError(errno));
63             }
64         }
65     }
66 
67     void write(in ubyte[] buffer)
68     {
69         long len;
70 
71         for (size_t off; off < buffer.length; off += len)
72         {
73             len = socket_.send(buffer[off..$]);
74 
75             if (len > 0)
76             {
77                 continue;
78             }
79             else if (len == 0)
80             {
81                 throw new PgSQLConnectionException("Server closed the connection");
82             }
83             else
84             {
85                 if ((errno == EINTR) || (errno == EAGAIN)/* || (errno == EWOULDBLOCK)*/)
86                 {
87                     len = 0;
88                     continue;
89                 }
90 
91                 throw new PgSQLConnectionException("Sent std.socket.Socket.ERROR: " ~ formatSocketError(errno));
92             }
93         }
94     }
95 
96 private:
97 
98     TcpSocket socket_;
99 }