[project @ 2002-08-02 04:31:30 by unknown_lamer]
[clinton/bobotpp.git] / source / Socket.C
CommitLineData
cb21075d 1// Socket.C -*- C++ -*-
439869bf 2// Copyright (C) 2002 Clinton Ebadi
cb21075d 3// Copyright (c) 1997, 1998 Etienne BERNARD
4
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// any later version.
9
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18
19#include "Socket.H"
fd7440f1 20#include <string>
cb21075d 21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netdb.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <string.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <errno.h>
31
32Socket::Socket()
33 : remotePort(0), remoteAddress(0),
34 localPort(0), localAddress(0)
35{
36 fd = new s_fd;
37 fd->fd = socket(AF_INET, SOCK_STREAM, 0);
38}
39
40Socket::Socket(int newfd, unsigned long newAddress, int newPort)
41 : remotePort(newPort), remoteAddress(newAddress),
42 localPort(0), localAddress(0)
43{
44 fd = new s_fd;
45 fd->fd = newfd;
46}
47
48Socket::Socket(const Socket &s)
49 : remotePort(s.remotePort), remoteAddress(s.remoteAddress),
50 localPort(s.localPort), localAddress(s.localAddress)
51{
52 s.fd->n++;
53 fd = s.fd;
54}
55
56Socket::~Socket()
57{
58 if (--fd->n == 0) {
59 close();
60 delete fd;
61 }
62}
63
64int
65Socket::getRemotePort() const
66{
67 return remotePort;
68}
69
70int
71Socket::getLocalPort() const
72{
73 return localPort;
74}
75
76int
77Socket::getFileDescriptor() const
78{
79 return fd->fd;
80}
81
82bool
83Socket::isConnected()
84{
85 return fd->fd != -1;
86}
87
88bool
89Socket::setRemoteHostname(String hostname)
90{
91 struct hostent *host;
92
93 if ((host = gethostbyname((const char *)hostname)) == 0)
94 return false;
95
96 memcpy(&remoteAddress, host->h_addr, host->h_length);
97 remoteAddress = ntohl(remoteAddress);
98
99 return true;
100}
101
102bool
103Socket::setRemoteIP(unsigned long address)
104{
105 remoteAddress = address;
106 return true;
107}
108
109bool
110Socket::setRemotePort(int p)
111{
112 remotePort = p;
113
114 return true;
115}
116
117bool
118Socket::setLocalHostname(String hostname)
119{
120 struct hostent *host;
121
122 if ((host = gethostbyname((const char *)hostname)) == 0)
123 return false;
124
125 memcpy(&localAddress, host->h_addr, host->h_length);
126
127 struct sockaddr_in local_addr;
128 local_addr.sin_family = AF_INET;
129 local_addr.sin_port = htons(localPort);
130 local_addr.sin_addr.s_addr = htonl(localAddress);
131 if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0)
132 return false;
133
134 return true;
135}
136
137bool
138Socket::setLocalIP(unsigned long address)
139{
140 localAddress = address;
141
142 struct sockaddr_in local_addr;
143 local_addr.sin_family = AF_INET;
144 local_addr.sin_port = htons(localPort);
145 local_addr.sin_addr.s_addr = htonl(localAddress);
146 if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0)
147 return false;
148
149 return true;
150}
151
152bool
153Socket::setLocalPort(int p)
154{
155 localPort = p;
156
157 struct sockaddr_in local_addr;
158 local_addr.sin_family = AF_INET;
159 local_addr.sin_port = htons(localPort);
160 local_addr.sin_addr.s_addr = htonl(localAddress);
161 if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0)
162 return false;
163
164 return true;
165}
166
167bool
168Socket::setNonBlocking(bool nonblock)
169{
170 long flags;
171
172 if (fd->fd == -1)
173 return false;
174
175 // We first get the file descriptor's flags
176 if (!fcntl(fd->fd, F_GETFL, &flags))
177 return false;
178
179 if (nonblock)
180 return fcntl(fd->fd, F_SETFL, flags | O_NONBLOCK);
181 else
182 return fcntl(fd->fd, F_SETFL, flags & ~O_NONBLOCK);
183}
184
185bool
186Socket::connect()
187{
188 struct sockaddr_in addr;
189 memset(&addr, 0, sizeof(addr));
190 addr.sin_family = AF_INET;
191 addr.sin_addr.s_addr = htonl(remoteAddress);
192 addr.sin_port = htons(remotePort);
193 if (::connect(fd->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
fd7440f1 194 {
195 // I'd rather log this to the log file
196 std::cerr << strerror (errno) << std::endl;
197 return false;
198 }
cb21075d 199
200 return true;
201}
202
203bool
204Socket::listen(int backlog)
205{
206 return ::listen(fd->fd, backlog) == 0;
207}
208
209Socket
210Socket::accept()
211{
212 struct sockaddr_in addr;
213 socklen_t addrlen=sizeof(addr);
214 int newfd = ::accept(fd->fd, (sockaddr *)&addr, &addrlen);
215 if (newfd == -1)
216 return Socket(-1, 0, 0);
217 unsigned long newRemoteAddress = ntohl(addr.sin_addr.s_addr);
218 int newRemotePort = ntohs(addr.sin_port);
219 return Socket(newfd, newRemoteAddress, newRemotePort);
220}
221
222void
223Socket::close()
224{
225 ::close(fd->fd);
226 fd->fd = -1;
227}
228
229bool
230Socket::write(String s, bool m)
231{
232 if (fd->fd == -1)
233 return false;
234
235 if (m) {
236 if (::write(fd->fd, (const char *)s, s.length()) +
237 ::write(fd->fd, "\n", 1) != s.length() + 1)
238 return false;
239 }
240 else
241 if (::write(fd->fd, (const char *)s, s.length()) +
242 ::write(fd->fd, "\r\n", 2) != s.length() + 2)
243 return false;
244
245 return true;
246}
247
248String
249Socket::readLine()
250{
fd7440f1 251 static std::string buf (512, ' ');
cb21075d 252 int pos = 0, nb;
253 char r;
fd7440f1 254 std::size_t length = buf.length ();
255
439869bf 256 do
257 {
258 nb = ::read(fd->fd, &r, 1);
259 switch (nb) {
260 case 0:
261 return String("");
262 case -1:
263 if (errno != EINTR && errno != EAGAIN)
264 return String("");
265 sleep(1);
266 }
267
268 if (nb != -1)
fd7440f1 269 if (pos < length)
270 buf[pos++] = r;
271 else
272 {
273 buf.resize (length * 2);
274 length = buf.length ();
275 buf[pos++] = r;
276 }
439869bf 277 } while (r != '\n');
cb21075d 278
439869bf 279if (pos > 1 && buf[pos-2] == '\r')
cb21075d 280 buf[pos-2] = '\0';
281 else
439869bf 282 buf[pos-1] = '\0';
cb21075d 283
284 return String(buf);
285}
286
287String
288Socket::readChar()
289{
290 char r[2];
291 int nb;
292 nb = ::read(fd->fd, &r, 1);
293 switch (nb) {
294 case 0:
295 return String("");
296 case -1:
297 if(errno != EINTR && errno != EAGAIN)
298 return String("");
299 sleep(1);
300 }
301 r[1] = '\0';
302 return String(r);
303}
304
305
306// // Here we use a circular buffer to read from the socket
307// String
308// Socket::readLine()
309// {
310// // The result string
311// char result[512];
312// // Position in the result string
313// int pos = 0;
314// // Number of chars read from the socket
315// int nb;
316
317// // First, we read from the socket
318// beginning:
319// if (end <= begin) {
320// nb = ::read(fd->fd, buf+end, begin - end);
321// } else {
322// nb = ::read(fd->fd, buf+end, 1024 - end);
323// }
324
325// if (nb == -1 && errno != EINTR && errno != EAGAIN)
326// return String("");
327
328// end = (end + nb) % 1024;
329
330// // Fine, now we read our string from the buffer
331// while (buf[begin] != '\r' && buf[begin] != '\n') {
332// result[pos++] = buf[begin++];
333// begin %= 1024;
334// if (begin == end)
335// goto beginning;
336// }
337
338// result[pos] = '\0';
339
340// // Now we skip the final '\r' and '\n'
341// if (buf[begin] == '\r')
342// begin = (begin + 1) % 1024;
343// if (buf[begin] == '\n')
344// begin = (begin + 1) % 1024;
345
346// // And we return the result
347// return String(result);
348// }
349
350// bool
351// Socket::hasData()
352// {
353// cout << "DEBUG hasData = " << (begin != end) << endl;
354// return begin != end;
355// }