added session manager and support for an external login system
[TransparentIRC.git] / src / IOHandler.c
index b276272ec11a44480468f95e87bc8bae00855598..375bcea86e3a20e8196114a33cbf6f3bbdd47df2 100644 (file)
@@ -71,7 +71,7 @@ struct IODescriptor *iohandler_add(int sockfd, enum IOType type, iohandler_callb
     return descriptor;
 }
 
-static void iohandler_remove(struct IODescriptor *descriptor) {
+static void iohandler_remove(struct IODescriptor *descriptor, int engine_remove) {
     //remove IODescriptor from the list
     if(descriptor->prev)
         descriptor->prev->next = descriptor->next;
@@ -79,7 +79,8 @@ static void iohandler_remove(struct IODescriptor *descriptor) {
         first_descriptor = descriptor->next;
     if(descriptor->next)
         descriptor->next->prev = descriptor->prev;
-    engine->remove(descriptor);
+    if(engine_remove)
+        engine->remove(descriptor);
     if(descriptor->readbuf.buffer)
         free(descriptor->readbuf.buffer);
     if(descriptor->writebuf.buffer)
@@ -296,7 +297,7 @@ void iohandler_write(struct IODescriptor *iofd, const char *line) {
 }
 
 void iohandler_send(struct IODescriptor *iofd, const char *data, size_t datalen) {
-    if(iofd->type == IOTYPE_TIMER) return; //can not write to timer? :D
+    if(iofd->type == IOTYPE_TIMER || iofd->state == IO_CLOSED) return; //can not write to timer? :D
     if(iofd->writebuf.buflen < iofd->writebuf.bufpos + datalen) {
         iohandler_increase_iobuf(&iofd->writebuf, iofd->writebuf.bufpos + datalen);
         if(iofd->writebuf.buflen < iofd->writebuf.bufpos + datalen)
@@ -335,10 +336,24 @@ void iohandler_try_write(struct IODescriptor *iofd) {
 }
 
 void iohandler_close(struct IODescriptor *iofd) {
+    int engine_remove = 1;
+    if(iofd->writebuf.bufpos) {
+        //try to send everything before closing
+#if defined(F_GETFL)
+        flags = fcntl(sockfd, F_GETFL);
+        fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK);
+        flags = fcntl(sockfd, F_GETFD);
+        fcntl(sockfd, F_SETFD, flags|FD_CLOEXEC);
+#else
+        engine_remove = 0;
+        engine->remove(iofd);
+#endif
+        iohandler_try_write(iofd);
+    }
     //close IODescriptor
     if(iofd->type == IOTYPE_SERVER || iofd->type == IOTYPE_CLIENT || iofd->type == IOTYPE_STDIN)
         close(iofd->fd);
-    iohandler_remove(iofd);
+    iohandler_remove(iofd, engine_remove);
 }
 
 void iohandler_update(struct IODescriptor *iofd) {
@@ -360,11 +375,13 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
                 callback_event.type = IOEVENT_TIMEOUT;
             break;
         case IO_LISTENING:
-            callback_event.data.accept_fd = accept(iofd->fd, NULL, 0);
-            if(callback_event.data.accept_fd < 0) {
-                //error: could not accept
-            } else
-                callback_event.type = IOEVENT_ACCEPT;
+            if(readable) {
+                callback_event.data.accept_fd = accept(iofd->fd, NULL, 0);
+                if(callback_event.data.accept_fd < 0) {
+                    //error: could not accept
+                } else
+                    callback_event.type = IOEVENT_ACCEPT;
+            }
             break;
         case IO_CONNECTING:
             if(readable) { //could not connect
@@ -386,6 +403,7 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
                     int bytes = recv(iofd->fd, iofd->readbuf.buffer + iofd->readbuf.bufpos, iofd->readbuf.buflen - iofd->readbuf.bufpos, 0);
                     if(bytes <= 0) {
                         if (errno != EAGAIN) {
+                            iofd->state = IO_CLOSED;
                             callback_event.type = IOEVENT_CLOSED;
                             callback_event.data.errid = errno;
                         }
@@ -429,6 +447,8 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
             }
             break;
     }
+    if(callback_event.type == IOEVENT_IGNORE && !readable && !writeable) 
+        callback_event.type = IOEVENT_TIMEOUT;
     if(callback_event.type != IOEVENT_IGNORE)
         iohandler_trigger_event(&callback_event);
 }