1 // Socket.C -*- C++ -*-
2 // Copyright (C) 2002,2005 Clinton Ebadi
3 // Copyright (c) 1997, 1998 Etienne BERNARD
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
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
37 : remotePort(0), remoteAddress(0),
38 localPort(0), localAddress(0)
41 fd->fd = socket(AF_INET, SOCK_STREAM, 0);
44 Socket::Socket(int newfd, unsigned long newAddress, int newPort)
45 : remotePort(newPort), remoteAddress(newAddress),
46 localPort(0), localAddress(0)
52 Socket::Socket(const Socket &s)
53 : remotePort(s.remotePort), remoteAddress(s.remoteAddress),
54 localPort(s.localPort), localAddress(s.localAddress)
69 Socket::getRemotePort() const
75 Socket::getLocalPort() const
81 Socket::getFileDescriptor() const
93 Socket::setRemoteHostname(String hostname)
97 if ((host = gethostbyname(hostname.c_str ())) == 0)
100 memcpy(&remoteAddress, host->h_addr, host->h_length);
101 remoteAddress = ntohl(remoteAddress);
107 Socket::setRemoteIP(unsigned long address)
109 remoteAddress = address;
114 Socket::setRemotePort(int p)
122 Socket::setLocalHostname(String hostname)
124 struct hostent *host;
126 if ((host = gethostbyname(hostname.c_str ())) == 0)
129 memcpy(&localAddress, host->h_addr, host->h_length);
131 struct sockaddr_in local_addr;
132 local_addr.sin_family = AF_INET;
133 local_addr.sin_port = htons(localPort);
134 local_addr.sin_addr.s_addr = htonl(localAddress);
135 if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0)
142 Socket::setLocalIP(unsigned long address)
144 localAddress = address;
146 struct sockaddr_in local_addr;
147 local_addr.sin_family = AF_INET;
148 local_addr.sin_port = htons(localPort);
149 local_addr.sin_addr.s_addr = htonl(localAddress);
150 if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0)
157 Socket::setLocalPort(int p)
161 struct sockaddr_in local_addr;
162 local_addr.sin_family = AF_INET;
163 local_addr.sin_port = htons(localPort);
164 local_addr.sin_addr.s_addr = htonl(localAddress);
165 if (bind(fd->fd, (struct sockaddr *)(&local_addr), sizeof(local_addr)) < 0)
172 Socket::setNonBlocking(bool nonblock)
179 // We first get the file descriptor's flags
180 if (!fcntl(fd->fd, F_GETFL, &flags))
184 return fcntl(fd->fd, F_SETFL, flags | O_NONBLOCK);
186 return fcntl(fd->fd, F_SETFL, flags & ~O_NONBLOCK);
192 struct sockaddr_in addr;
193 memset(&addr, 0, sizeof(addr));
194 addr.sin_family = AF_INET;
195 addr.sin_addr.s_addr = htonl(remoteAddress);
196 addr.sin_port = htons(remotePort);
197 if (::connect(fd->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
199 // Bot::logLine (String("Socket Error: ")
200 // + strerror (errno) + String("\n"));
208 Socket::listen(int backlog)
210 return ::listen(fd->fd, backlog) == 0;
216 struct sockaddr_in addr;
217 socklen_t addrlen=sizeof(addr);
218 int newfd = ::accept(fd->fd, (sockaddr *)&addr, &addrlen);
220 return Socket(-1, 0, 0);
221 unsigned long newRemoteAddress = ntohl(addr.sin_addr.s_addr);
222 int newRemotePort = ntohs(addr.sin_port);
223 return Socket(newfd, newRemoteAddress, newRemotePort);
234 Socket::write(String s, bool m)
240 if (::write(fd->fd, s.c_str (), s.length()) +
241 ::write(fd->fd, "\n", 1) != s.length() + 1)
245 if (::write(fd->fd, s.c_str (), s.length()) +
246 ::write(fd->fd, "\r\n", 2) != s.length() + 2)
255 // fixme: this could probably be sped up (use some faster way of
256 // reading from the socket than reading a char at a time)
258 // We allocate the buffer statically to keep from having to overhead
259 // of reallocating a new buffer every time we call this (which is
260 // every time anything happens on IRC so the overhead of
261 // re-allocating a buffer every time is potentially too large).
263 // Since it is static, and the length of lines will differ for each
264 // read, an embedded \0 is inserted after the last character of the
265 // line and then a copy of the the c_str is returned as a String so
266 // that only the line that was just read is returned.
267 static std::string buf (512, ' ');
269 std::string::size_type pos = 0; // pos in buffer
270 int nb; // number of bytes read by ::read
271 char r; // temp var for storing output of read into
272 std::string::size_type length = buf.length ();
276 nb = ::read(fd->fd, &r, 1);
281 if (errno != EINTR && errno != EAGAIN)
291 buf.resize (length * 2);
292 length = buf.length ();
297 if (pos > 1 && buf[pos-2] == '\r')
300 return String (buf.substr (0, pos - 2));
305 return String (buf.substr (0, pos - 1));
314 nb = ::read(fd->fd, &r, 1);
319 if(errno != EINTR && errno != EAGAIN)
328 // // Here we use a circular buffer to read from the socket
330 // Socket::readLine()
332 // // The result string
334 // // Position in the result string
336 // // Number of chars read from the socket
339 // // First, we read from the socket
341 // if (end <= begin) {
342 // nb = ::read(fd->fd, buf+end, begin - end);
344 // nb = ::read(fd->fd, buf+end, 1024 - end);
347 // if (nb == -1 && errno != EINTR && errno != EAGAIN)
348 // return String("");
350 // end = (end + nb) % 1024;
352 // // Fine, now we read our string from the buffer
353 // while (buf[begin] != '\r' && buf[begin] != '\n') {
354 // result[pos++] = buf[begin++];
360 // result[pos] = '\0';
362 // // Now we skip the final '\r' and '\n'
363 // if (buf[begin] == '\r')
364 // begin = (begin + 1) % 1024;
365 // if (buf[begin] == '\n')
366 // begin = (begin + 1) % 1024;
368 // // And we return the result
369 // return String(result);
375 // cout << "DEBUG hasData = " << (begin != end) << endl;
376 // return begin != end;