]> git.tdb.fi Git - libs/net.git/blob - source/streamsocket.cpp
Style update: spaces around assignments
[libs/net.git] / source / streamsocket.cpp
1 #ifndef WIN32
2 #include <sys/socket.h>
3 #endif
4 #include <cerrno>
5 #include <msp/io/poll.h>
6 #include <msp/strings/formatter.h>
7 #include "streamsocket.h"
8
9 namespace Msp {
10 namespace Net {
11
12 /**
13 Used by StreamListenSocket to construct a new socket from accept.
14 */
15 StreamSocket::StreamSocket(SocketHandle h, const SockAddr &paddr):
16         Socket(h, paddr),
17         connecting(false)
18 {
19 #ifdef WIN32
20         WSAEventSelect(handle, event, FD_READ|FD_CLOSE);
21 #endif
22         set_events(IO::P_INPUT);
23 }
24
25 /**
26 Constructs a new StreamSocket.
27 */
28 StreamSocket::StreamSocket(Family af, int proto):
29         Socket(af, SOCK_STREAM, proto),
30         connecting(false)
31 { }
32
33 /**
34 Checks the status of an ongoing connection attempt.  If the connection fails
35 with an error, an exception is thrown.
36
37 @return  0 if the connection finished, 1 if not
38 */
39 int StreamSocket::poll_connect(const Time::TimeDelta &timeout)
40 {
41         check_state(false);
42         if(!connecting)
43                 throw InvalidState("No connection attempt going on");
44
45         int res = poll(*this, IO::P_OUTPUT, timeout);
46         if(res==-1)
47 #ifdef WIN32
48                 throw Exception(format("Connection polling failed: %d", WSAGetLastError()));
49 #else
50                 throw SystemError("Connection polling failed", errno);
51 #endif
52         else if(res>0)
53         {
54                 connecting = false;
55
56                 int err;
57                 socklen_t len = sizeof(int);
58                 get_option(SOL_SOCKET, SO_ERROR, &err, &len);
59
60                 if(err!=0)
61                 {
62                         set_events(IO::P_NONE);
63 #ifdef WIN32
64                         throw Exception(format("Connection failed: %d", err));
65 #else
66                         throw SystemError("Connection failed", err);
67 #endif
68                 }
69
70 #ifdef WIN32
71                 WSAEventSelect(handle, event, FD_READ|FD_CLOSE);
72 #endif
73                 set_events(IO::P_INPUT);
74
75                 connected = true;
76
77                 return 0;
78         }
79
80         return 1;
81 }
82
83 /**
84 Connects the socket to a remote address.  In non-blocking mode, this function
85 may return before the connection is finished.  The caller must then use either
86 the poll_connect function or an EventDispatcher to determine when the
87 connection is finished.
88
89 @return  0 if the connection finished, 1 if it is in progress
90 */
91 int StreamSocket::connect(const SockAddr &addr)
92 {
93         check_state(false);
94
95         if(connected)
96                 throw InvalidState("Socket is already connected");
97
98         sockaddr_storage sa;
99         socklen_t size = addr.fill_sockaddr(sa);
100
101 #ifdef WIN32
102         int err = WSAConnect(handle, reinterpret_cast<sockaddr *>(&sa), size, 0, 0, 0, 0);
103         if(err==SOCKET_ERROR)
104         {
105                 int err_code = WSAGetLastError();
106                 if(err_code==WSAEWOULDBLOCK)
107                 {
108                         connecting = true;
109                         WSAEventSelect(handle, event, FD_CONNECT);
110                         set_events(IO::P_OUTPUT);
111                 }
112                 else
113                         throw Exception(format("Unable to connect: %d", err_code));
114         }
115 #else
116         int err = ::connect(handle, reinterpret_cast<sockaddr *>(&sa), size);
117         if(err==-1)
118         {
119                 if(errno==EINPROGRESS)
120                 {
121                         connecting = true;
122                         set_events(IO::P_OUTPUT);
123                 }
124                 else
125                         throw SystemError("Unable to connect", errno);
126         }
127 #endif
128
129         delete peer_addr;
130         peer_addr = addr.copy();
131
132         delete local_addr;
133         size = sizeof(sockaddr_storage);
134         getsockname(handle, reinterpret_cast<sockaddr *>(&sa), &size);
135         local_addr = SockAddr::create(sa);
136
137         if(err==0)
138         {
139                 connected = true;
140                 set_events(IO::P_INPUT);
141                 signal_connect_finished.emit(0);
142         }
143
144         return (err==0)?0:1;
145 }
146
147 void StreamSocket::on_event(IO::PollEvent ev)
148 {
149         //cout<<"StreamSocket::on_event "<<ev<<'\n';
150         if((ev&(IO::P_OUTPUT|IO::P_ERROR)) && connecting)
151         {
152                 int err;
153                 socklen_t len = sizeof(err);
154                 get_option(SOL_SOCKET, SO_ERROR, &err, &len);
155
156                 connecting = false;
157                 connected = (err==0);
158                 signal_connect_finished.emit(err);
159
160                 if(err!=0)
161                 {
162                         delete peer_addr;
163                         peer_addr = 0;
164                 }
165
166 #ifdef WIN32
167                 WSAEventSelect(handle, event, FD_READ|FD_CLOSE);
168 #endif
169                 set_events((err==0) ? IO::P_INPUT : IO::P_NONE);
170         }
171 }
172
173 } // namespace Net
174 } // namespace Msp