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