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