1 /***************************************************************************
3 * Copyright (C) 2006 David Brodsky *
5 * This library is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU Library General Public *
7 * License as published by the Free Software Foundation and appearing *
8 * in the file LICENSE.LGPL included in the packaging of this file. *
10 * This library 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 GNU *
13 * Library General Public License for more details. *
15 ***************************************************************************/
21 #include <tairon/core/log.h>
27 #include "socketnotifier.h"
35 const size_t Socket::bufLength
= 65536;
37 /* {{{ Socket::Socket(Type) */
38 Socket::Socket(Type type
)
40 fd
= socket(PF_INET
, type
, 0);
42 throw SocketException("Cannot create socket", errno
);
48 /* {{{ Socket::Socket(int sd) */
49 Socket::Socket(int sd
) : fd(sd
)
51 if (fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
) == -1)
52 throw SocketException("Cannot set nonblocking socket", errno
);
56 notifier
->setReadyReadFunctor(Tairon::Core::methodFunctor(this, &Socket::readyRead
));
57 notifier
->setReadyWriteFunctor(Tairon::Core::methodFunctor(this, &Socket::readyWrite
));
61 /* {{{ Socket::~Socket() */
64 // deleting notifier also deletes all created functors
70 /* {{{ Socket::close() */
73 connectedSignal
.disable();
74 errorSignal
.disable();
75 readyReadSignal
.disable();
76 readyWriteSignal
.disable();
78 // this also removes socket from polling
81 Poll::self()->addDeleter(createDeleter(this));
85 /* {{{ Socket::connected() */
86 void Socket::connected()
88 DEBUG((const char *) String("Socket::connected " + String::number(fd
)));
90 Poll::self()->delSocketToWrite(fd
, notifier
);
91 delete notifier
->getReadyWriteFunctor();
92 notifier
->setReadyWriteFunctor(Tairon::Core::methodFunctor(this, &Socket::readyWrite
));
95 socklen_t len
= sizeof(err
);
96 getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
);
98 notifier
->setReadyReadFunctor(Tairon::Core::methodFunctor(this, &Socket::readyRead
));
99 Poll::self()->addSocketToRead(fd
, notifier
);
100 connectedSignal
.emit(this);
102 errorSignal
.emit(this, err
);
106 /* {{{ Socket::connect(const String &, uint16_t) */
107 void Socket::connect(const String
&address
, uint16_t port
)
109 if (fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
) == -1)
110 throw SocketException("Cannot set nonblocking socket", errno
);
112 struct hostent
*host
= gethostbyname(address
);
114 throw SocketException("Cannot resolve host name", h_errno
);
116 if (host
->h_addrtype
!= AF_INET
)
117 throw SocketException("Invalid address type", host
->h_addrtype
);
119 if (!(*host
->h_addr_list
))
120 throw SocketException("Zero length list of addresses", 0);
123 addr
.sin_family
= AF_INET
;
124 addr
.sin_port
= htons(port
);
125 memcpy(&(addr
.sin_addr
.s_addr
), *(host
->h_addr_list
), sizeof(addr
.sin_addr
.s_addr
));
127 int ret
= ::connect(fd
, (sockaddr
*) &addr
, sizeof(addr
));
128 if ((ret
== -1) && (errno
!= EINPROGRESS
))
129 throw SocketException("Error while connecting", errno
);
131 notifier
->setReadyWriteFunctor(Tairon::Core::methodFunctor(this, &Socket::connected
));
133 Poll::self()->registerSocketToWrite(fd
, notifier
);
137 /* {{{ Socket::error() */
141 socklen_t len
= sizeof(err
);
142 getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
);
143 Poll::self()->unregisterSocket(fd
);
144 errorSignal
.emit(this, err
);
148 /* {{{ Socket::init() */
151 inBuffer
= new char[bufLength
];
152 notifier
= new SocketNotifier(0, 0, Tairon::Core::methodFunctor(this, &Socket::error
));
156 /* {{{ Socket::read(size_t) */
157 String
Socket::read(size_t max
)
159 ssize_t len
= recv(fd
, inBuffer
, bufLength
< max
? bufLength
: max
, MSG_DONTWAIT
);
160 if (len
== 0) // connection has been closed
161 throw SocketException("Connection has been closed", 0);
163 if (errno
!= EAGAIN
) {
164 throw SocketException("Error while reading from socket", errno
);
167 Poll::self()->addSocketToRead(fd
, notifier
);
168 return String(inBuffer
, len
);
172 /* {{{ Socket::readyRead() */
173 void Socket::readyRead()
175 DEBUG((const char *) String("Socket::readyRead " + String::number((int) this)));
177 // don't make signal storm - if processing of the signals takes much time
178 // in another thread, then there can be new data and many new signals would
180 Poll::self()->delSocketToRead(fd
, notifier
);
181 readyReadSignal
.emit(this);
185 /* {{{ Socket::readTo(void *, size_t) */
186 size_t Socket::readTo(void *buf
, size_t length
)
188 size_t len
= recv(fd
, buf
, length
, MSG_DONTWAIT
);
189 if (len
== 0) // connection has been closed
190 throw SocketException("Connection has been closed", 0);
193 throw SocketException("Error while reading from socket", errno
);
196 Poll::self()->addSocketToRead(fd
, notifier
);
201 /* {{{ Socket::ready() */
204 Poll::self()->registerSocketToRead(fd
, notifier
);
208 /* {{{ Socket::readyWrite() */
209 void Socket::readyWrite()
211 Poll::self()->delSocketToWrite(fd
, notifier
);
212 readyWriteSignal
.emit(this);
216 /* {{{ Socket::write(const String &, bool) */
217 size_t Socket::write(const String
&data
, bool block
)
219 return write(data
.data(), data
.length(), block
);
223 /* {{{ Socket::write(const char *, size_t, bool) */
224 size_t Socket::write(const char *data
, size_t length
, bool block
)
226 ssize_t sent
= send(fd
, data
, length
, block
? 0 : MSG_DONTWAIT
);
229 throw SocketException("Error while writing to socket", errno
);
230 Poll::self()->addSocketToWrite(fd
, notifier
);
238 /* {{{ SocketException::SocketException(const String &, int) */
239 SocketException::SocketException(const String
&desc
, int err
) : Tairon::Core::Exception(desc
), errorNumber(err
)
241 DEBUG((const char *) String(desc
+ " (" + String::number(errorNumber
) + ")"));
249 // vim: ai sw=4 ts=4 noet fdm=marker