00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <stdio.h>
00038
00039 #include <sys/types.h>
00040 #include <sys/time.h>
00041 #include <sys/stat.h>
00042 #include <fcntl.h>
00043 #include <unistd.h>
00044 #include <errno.h>
00045 #include <time.h>
00046
00047 #include <FileDescriptor.h>
00048
00049 #define WANT_FD_DEBUG_MESSAGES 0
00050
00051 #ifndef MAX
00052 #define MAX(a, b) ((a > b) ? a : b)
00053 #endif
00054
00055 #ifndef MIN
00056 #define MIN(a, b) ((a < b) ? a : b)
00057 #endif
00058
00059
00060
00061 FileDescriptor::FileDescriptor(ref<FileDescriptorManager> const &_fdMgr, int _fd)
00062 : fdMgr(_fdMgr),
00063 fd(_fd),
00064 buflen(0),
00065 pos(0),
00066 readCallback(),
00067 writeCallback()
00068 {
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 #if WANT_FD_DEBUG_MESSAGES
00083 fprintf(stderr, "%u: FileDescriptor::FileDescriptor on fd %d\n", (unsigned) time(NULL), fd);
00084 #endif
00085 }
00086
00087 FileDescriptor::~FileDescriptor()
00088 {
00089 #if WANT_FD_DEBUG_MESSAGES
00090 if (fd == -1) {
00091
00092 fprintf(stderr, "%u: FileDescriptor::~FileDescriptor (already closed.)\n",
00093 (unsigned) time(NULL));
00094 } else {
00095 fprintf(stderr, "%u: FileDescriptor::~FileDescriptor on fd %d\n", (unsigned) time(NULL), fd);
00096 }
00097 #endif
00098 this->close();
00099 }
00100
00101
00102
00103 bool FileDescriptor::fillBuffer() {
00104 while (pos >= buflen) {
00105 int nread = lowlevel_read(fd, buf, sizeof(buf));
00106
00107
00108
00109 if (nread == 0) {
00110
00111 char buf[20];
00112 sprintf(buf, "%d", fd);
00113 throw EndOfFile("EOF (graceful) while reading fd " + string(buf));
00114 }
00115
00116 if (nread == -1) {
00117 switch (errno) {
00118 #ifndef __WIN32__
00119
00120 case ECONNRESET: {
00121 char buf[20];
00122 sprintf(buf, "%d", fd);
00123 throw EndOfFile("EOF (connection reset) while reading fd " + string(buf));
00124 }
00125 #endif
00126
00127 case EINTR:
00128 continue;
00129
00130 case EAGAIN:
00131 return false;
00132
00133 default:
00134 throw Exception("EOF due to error condition while reading", errno);
00135 }
00136 }
00137
00138 buflen = nread;
00139 pos = 0;
00140 }
00141
00142 return true;
00143 }
00144
00145 void FileDescriptor::block(bool forRead, bool forWrite) {
00146 fd_set fds;
00147 FD_ZERO(&fds);
00148 FD_SET(fd, &fds);
00149
00150 select(fd + 1, forRead ? &fds : NULL, forWrite ? &fds : NULL, &fds, NULL);
00151 }
00152
00153 void FileDescriptor::close() {
00154 if (isOpen()) {
00155 #if WANT_FD_DEBUG_MESSAGES
00156 fprintf(stderr, "FileDescriptor::close() - closing FD %d\n", fd);
00157 #endif
00158
00159 int oldfd = fd;
00160 fd = -1;
00161
00162 lowlevel_close(oldfd);
00163 fdMgr->remove(oldfd);
00164 fdMgr = 0;
00165 }
00166 }
00167
00168 bool FileDescriptor::setNonBlocking(bool on) {
00169 if (!isOpen())
00170 return false;
00171
00172 int status;
00173
00174 #ifdef __WIN32__
00175
00176 {
00177 int non_block = (on ? 1 : 0);
00178 ioctlsocket(fd, FIONBIO, (u_long FAR *) &non_block);
00179 }
00180 #else
00181
00182 if (on) {
00183 status = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
00184 } else {
00185 status = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
00186 }
00187 #endif
00188
00189 return (status != -1);
00190 }
00191
00192
00193
00194 void FileDescriptor::updateCallbacks() {
00195 fdMgr->update(this,
00196 readCallback.callback.valid(),
00197 writeCallback.callback.valid());
00198 }
00199
00200 void FileDescriptor::setReadCallback(ref<Callback> const &cb, Callback::Method cbm) {
00201 readCallback.callback = cb;
00202 readCallback.callbackMethod = cbm;
00203 updateCallbacks();
00204 }
00205
00206 void FileDescriptor::setWriteCallback(ref<Callback> const &cb, Callback::Method cbm) {
00207 writeCallback.callback = cb;
00208 writeCallback.callbackMethod = cbm;
00209 updateCallbacks();
00210 }
00211
00212 void FileDescriptor::clearReadCallback() {
00213 setReadCallback(0, 0);
00214 }
00215
00216 void FileDescriptor::clearWriteCallback() {
00217 setWriteCallback(0, 0);
00218 }
00219
00220 void FileDescriptor::fireReadCallback() {
00221 if (readCallback.callback.valid()) {
00222 ((readCallback.callback)->*(readCallback.callbackMethod))(this);
00223 }
00224 }
00225
00226 void FileDescriptor::fireWriteCallback() {
00227 if (writeCallback.callback.valid()) {
00228 ((writeCallback.callback)->*(writeCallback.callbackMethod))(this);
00229 }
00230 }
00231
00232
00233
00234 int FileDescriptor::lowlevel_read(int fd, char *buf, int len) {
00235 return ::read(fd, buf, len);
00236 }
00237
00238 int FileDescriptor::lowlevel_write(int fd, char const *buf, int len) {
00239 return ::write(fd, buf, len);
00240 }
00241
00242 int FileDescriptor::lowlevel_close(int fd) {
00243 return ::close(fd);
00244 }
00245
00246 ref<FileDescriptorManager> const &FileDescriptor::getFdMgr() const
00247 {
00248 return fdMgr;
00249 }
00250
00251 int FileDescriptor::read(char *inbuf, int len, bool complete = false) {
00252 int sofar = 0;
00253
00254 while (sofar < len) {
00255 int tocopy = MIN(len - sofar, buflen - pos);
00256
00257 if (tocopy == 0) {
00258 if (!fillBuffer()) {
00259 if (complete)
00260 block(true, false);
00261 else
00262 return sofar;
00263 }
00264 continue;
00265 }
00266
00267 memcpy(inbuf, buf, tocopy);
00268 inbuf += tocopy;
00269 sofar += tocopy;
00270 pos += tocopy;
00271 }
00272
00273 return sofar;
00274 }
00275
00276 int FileDescriptor::write(char const *outbuf, int len, bool complete = false) {
00277 int sofar = 0;
00278
00279 while (sofar < len) {
00280 int result = lowlevel_write(fd, outbuf, len - sofar);
00281
00282 if (result == -1) {
00283 if (errno == EINTR) {
00284 continue;
00285 }
00286
00287 if (errno == EAGAIN) {
00288 if (complete)
00289 block(false, true);
00290 else
00291 return sofar;
00292 continue;
00293 }
00294
00295 throw Exception("EOF due to error condition writing", errno);
00296 }
00297
00298 outbuf += result;
00299 sofar += result;
00300 }
00301
00302 return sofar;
00303 }
00304
00305
00306
00307 FileDescriptorManager::FileDescriptorManager()
00308 : allFds(),
00309 countRegistered(0),
00310 maxFd(-1)
00311 {
00312 FD_ZERO(&readFds);
00313 FD_ZERO(&writeFds);
00314 }
00315
00316 void FileDescriptorManager::update(ref<FileDescriptor> const &fd, bool forRead, bool forWrite)
00317 {
00318 int fdnum = fd->getFd();
00319
00320 if (fdnum != -1) {
00321 if (fdnum >= maxFd) {
00322 maxFd = fdnum;
00323 allFds.resize(maxFd + 1);
00324 }
00325
00326 if (allFds[fdnum].get() == 0)
00327 countRegistered++;
00328
00329 allFds[fdnum] = fd;
00330 if (forRead) FD_SET(fdnum, &readFds); else FD_CLR(fdnum, &readFds);
00331 if (forWrite) FD_SET(fdnum, &writeFds); else FD_CLR(fdnum, &writeFds);
00332 }
00333 }
00334
00335 void FileDescriptorManager::remove(int fdnum) {
00336
00337
00338
00339
00340 if (fdnum != -1 && fdnum <= maxFd && allFds[fdnum].valid()) {
00341 allFds[fdnum] = 0;
00342 countRegistered--;
00343
00344 FD_CLR(fdnum, &readFds);
00345 FD_CLR(fdnum, &writeFds);
00346 }
00347 }
00348
00349 void FileDescriptorManager::closeAll()
00350 {
00351 for (unsigned int fdnum = 0; fdnum < allFds.size(); fdnum++) {
00352 ref<FileDescriptor> &fd(allFds[fdnum]);
00353
00354 if (fd.valid()) {
00355 fd->close();
00356 allFds[fdnum] = 0;
00357 }
00358 }
00359
00360 FD_ZERO(&readFds);
00361 FD_ZERO(&writeFds);
00362 countRegistered = 0;
00363 maxFd = -1;
00364 }
00365
00366 void FileDescriptorManager::fillFdSet(fd_set *rfds, fd_set *wfds) const
00367 {
00368 for (unsigned int fdnum = 0; fdnum < allFds.size(); fdnum++) {
00369 if (allFds[fdnum].valid()) {
00370 if (FD_ISSET(fdnum, &readFds)) FD_SET(fdnum, rfds);
00371 if (FD_ISSET(fdnum, &writeFds)) FD_SET(fdnum, wfds);
00372 }
00373 }
00374 }
00375
00376 void FileDescriptorManager::processFdSet(fd_set *rfds, fd_set *wfds)
00377 {
00378 for (unsigned int fdnum = 0; fdnum < allFds.size(); fdnum++) {
00379 ref<FileDescriptor> &fd(allFds[fdnum]);
00380
00381 if (fd.valid()) {
00382 try {
00383 if (FD_ISSET(fdnum, rfds)) {
00384 fd->fireReadCallback();
00385 }
00386 } catch (FileDescriptor::Exception &fe) {
00387 fprintf(stderr, "processFdSet: fireReadCallback threw: %s (%d %s)\n",
00388 fe.what(), fe.getErrno(), strerror(fe.getErrno()));
00389 throw;
00390 }
00391
00392 try {
00393 if (FD_ISSET(fdnum, wfds)) {
00394 fd->fireWriteCallback();
00395 }
00396 } catch (FileDescriptor::Exception &fe) {
00397 fprintf(stderr, "processFdSet: fireWriteCallback threw: %s (%d %s)\n",
00398 fe.what(), fe.getErrno(), strerror(fe.getErrno()));
00399 throw;
00400 }
00401
00402 }
00403 }
00404 }
00405
00406 bool FileDescriptorManager::poll(struct timeval const *timeout) {
00407 fd_set rfds;
00408 fd_set wfds;
00409 fd_set efds;
00410
00411
00412 struct timeval _timeout;
00413 if (timeout != NULL) {
00414 _timeout = *timeout;
00415 }
00416
00417 if (countRegistered == 0) {
00418 throw FileDescriptor::Exception("poll() called on empty FileDescriptorManager");
00419 }
00420
00421 memcpy(&rfds, &readFds, sizeof(rfds));
00422 memcpy(&wfds, &writeFds, sizeof(wfds));
00423 memcpy(&efds, &readFds, sizeof(efds));
00424
00425 int selectResult = select(maxFd + 1, &rfds, &wfds, &efds, timeout ? &_timeout : NULL);
00426
00427 if (selectResult == -1) {
00428 int errnoCopy = errno;
00429 throw FileDescriptor::Exception("Error in select()", errnoCopy);
00430 }
00431
00432 if (selectResult == 0) {
00433
00434 return false;
00435 }
00436
00437
00438 processFdSet(&rfds, &wfds);
00439 return true;
00440 }
00441
00442 void FileDescriptorManager::mainloop() {
00443 while (true) {
00444 poll(NULL);
00445 }
00446 }