|
1 /* |
|
2 Socket.cpp |
|
3 |
|
4 Copyright (C) 2002-2004 René Nyffenegger |
|
5 |
|
6 This source code is provided 'as-is', without any express or implied |
|
7 warranty. In no event will the author be held liable for any damages |
|
8 arising from the use of this software. |
|
9 |
|
10 Permission is granted to anyone to use this software for any purpose, |
|
11 including commercial applications, and to alter it and redistribute it |
|
12 freely, subject to the following restrictions: |
|
13 |
|
14 1. The origin of this source code must not be misrepresented; you must not |
|
15 claim that you wrote the original source code. If you use this source code |
|
16 in a product, an acknowledgment in the product documentation would be |
|
17 appreciated but is not required. |
|
18 |
|
19 2. Altered source versions must be plainly marked as such, and must not be |
|
20 misrepresented as being the original source code. |
|
21 |
|
22 3. This notice may not be removed or altered from any source distribution. |
|
23 |
|
24 René Nyffenegger rene.nyffenegger@adp-gmbh.ch |
|
25 */ |
|
26 |
|
27 |
|
28 #include "Socket.h" |
|
29 #include <iostream> |
|
30 |
|
31 using namespace std; |
|
32 |
|
33 int Socket::nofSockets_= 0; |
|
34 |
|
35 void Socket::Start() { |
|
36 if (!nofSockets_) { |
|
37 WSADATA info; |
|
38 if (WSAStartup(MAKEWORD(2,0), &info)) { |
|
39 throw "Could not start WSA"; |
|
40 } |
|
41 } |
|
42 ++nofSockets_; |
|
43 } |
|
44 |
|
45 void Socket::End() { |
|
46 WSACleanup(); |
|
47 } |
|
48 |
|
49 Socket::Socket() : s_(0) { |
|
50 Start(); |
|
51 // UDP: use SOCK_DGRAM instead of SOCK_STREAM |
|
52 s_ = socket(AF_INET,SOCK_STREAM,0); |
|
53 |
|
54 if (s_ == INVALID_SOCKET) { |
|
55 throw "INVALID_SOCKET"; |
|
56 } |
|
57 |
|
58 refCounter_ = new int(1); |
|
59 } |
|
60 |
|
61 Socket::Socket(SOCKET s) : s_(s) { |
|
62 Start(); |
|
63 refCounter_ = new int(1); |
|
64 }; |
|
65 |
|
66 Socket::~Socket() { |
|
67 if (! --(*refCounter_)) { |
|
68 Close(); |
|
69 delete refCounter_; |
|
70 } |
|
71 |
|
72 --nofSockets_; |
|
73 if (!nofSockets_) End(); |
|
74 } |
|
75 |
|
76 Socket::Socket(const Socket& o) { |
|
77 refCounter_=o.refCounter_; |
|
78 (*refCounter_)++; |
|
79 s_ =o.s_; |
|
80 |
|
81 nofSockets_++; |
|
82 } |
|
83 |
|
84 Socket& Socket::operator=(Socket& o) { |
|
85 (*o.refCounter_)++; |
|
86 |
|
87 refCounter_=o.refCounter_; |
|
88 s_ =o.s_; |
|
89 |
|
90 nofSockets_++; |
|
91 |
|
92 return *this; |
|
93 } |
|
94 |
|
95 void Socket::Close() { |
|
96 closesocket(s_); |
|
97 } |
|
98 |
|
99 std::string Socket::ReceiveBytes() { |
|
100 std::string ret; |
|
101 char buf[1024]; |
|
102 |
|
103 while (1) { |
|
104 u_long arg = 0; |
|
105 if (ioctlsocket(s_, FIONREAD, &arg) != 0) |
|
106 break; |
|
107 |
|
108 if (arg == 0) |
|
109 break; |
|
110 |
|
111 if (arg > 1024) arg = 1024; |
|
112 |
|
113 int rv = recv (s_, buf, arg, 0); |
|
114 if (rv <= 0) break; |
|
115 |
|
116 std::string t; |
|
117 |
|
118 t.assign (buf, rv); |
|
119 ret += t; |
|
120 } |
|
121 |
|
122 return ret; |
|
123 } |
|
124 |
|
125 std::string Socket::ReceiveLine() { |
|
126 std::string ret; |
|
127 while (1) { |
|
128 char r; |
|
129 |
|
130 switch(recv(s_, &r, 1, 0)) { |
|
131 case 0: // not connected anymore; |
|
132 // ... but last line sent |
|
133 // might not end in \n, |
|
134 // so return ret anyway. |
|
135 return ret; |
|
136 case -1: |
|
137 return ""; |
|
138 // if (errno == EAGAIN) { |
|
139 // return ret; |
|
140 // } else { |
|
141 // // not connected anymore |
|
142 // return ""; |
|
143 // } |
|
144 } |
|
145 |
|
146 if (r == '\n') return ret; |
|
147 ret += r; |
|
148 } |
|
149 } |
|
150 |
|
151 void Socket::SendLine(std::string s) { |
|
152 s += '\n'; |
|
153 send(s_,s.c_str(),s.length(),0); |
|
154 } |
|
155 |
|
156 void Socket::SendBytes(const std::string& s) { |
|
157 send(s_,s.c_str(),s.length(),0); |
|
158 } |
|
159 |
|
160 SocketServer::SocketServer(int port, int connections, TypeSocket type) { |
|
161 sockaddr_in sa; |
|
162 |
|
163 memset(&sa, 0, sizeof(sa)); |
|
164 |
|
165 sa.sin_family = PF_INET; |
|
166 sa.sin_port = htons(port); |
|
167 s_ = socket(AF_INET, SOCK_STREAM, 0); |
|
168 if (s_ == INVALID_SOCKET) { |
|
169 throw "INVALID_SOCKET"; |
|
170 } |
|
171 |
|
172 if(type==NonBlockingSocket) { |
|
173 u_long arg = 1; |
|
174 ioctlsocket(s_, FIONBIO, &arg); |
|
175 } |
|
176 |
|
177 /* bind the socket to the internet address */ |
|
178 if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) { |
|
179 closesocket(s_); |
|
180 throw "INVALID_SOCKET"; |
|
181 } |
|
182 |
|
183 listen(s_, connections); |
|
184 } |
|
185 |
|
186 Socket* SocketServer::Accept() { |
|
187 SOCKET new_sock = accept(s_, 0, 0); |
|
188 if (new_sock == INVALID_SOCKET) { |
|
189 int rc = WSAGetLastError(); |
|
190 if(rc==WSAEWOULDBLOCK) { |
|
191 return 0; // non-blocking call, no request pending |
|
192 } |
|
193 else { |
|
194 throw "Invalid Socket"; |
|
195 } |
|
196 } |
|
197 |
|
198 Socket* r = new Socket(new_sock); |
|
199 return r; |
|
200 } |
|
201 |
|
202 SocketClient::SocketClient(const std::string& host, int port) : Socket() { |
|
203 std::string error; |
|
204 |
|
205 hostent *he; |
|
206 if ((he = gethostbyname(host.c_str())) == 0) { |
|
207 error = strerror(errno); |
|
208 throw error; |
|
209 } |
|
210 |
|
211 sockaddr_in addr; |
|
212 addr.sin_family = AF_INET; |
|
213 addr.sin_port = htons(port); |
|
214 addr.sin_addr = *((in_addr *)he->h_addr); |
|
215 memset(&(addr.sin_zero), 0, 8); |
|
216 |
|
217 if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) { |
|
218 error = strerror(WSAGetLastError()); |
|
219 throw error; |
|
220 } |
|
221 } |
|
222 |
|
223 SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) { |
|
224 FD_ZERO(&fds_); |
|
225 FD_SET(const_cast<Socket*>(s1)->s_,&fds_); |
|
226 if(s2) { |
|
227 FD_SET(const_cast<Socket*>(s2)->s_,&fds_); |
|
228 } |
|
229 |
|
230 TIMEVAL tval; |
|
231 tval.tv_sec = 0; |
|
232 tval.tv_usec = 1; |
|
233 |
|
234 TIMEVAL *ptval; |
|
235 if(type==NonBlockingSocket) { |
|
236 ptval = &tval; |
|
237 } |
|
238 else { |
|
239 ptval = 0; |
|
240 } |
|
241 |
|
242 if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR) |
|
243 throw "Error in select"; |
|
244 } |
|
245 |
|
246 bool SocketSelect::Readable(Socket const* const s) { |
|
247 if (FD_ISSET(s->s_,&fds_)) return true; |
|
248 return false; |
|
249 } |