Bug fix: memory used by GRS records wasn't freed.
[ir-tcl-moved-to-github.git] / ir-tcl.c
index f18c248..21e8100 100644 (file)
--- a/ir-tcl.c
+++ b/ir-tcl.c
@@ -5,7 +5,20 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: ir-tcl.c,v $
- * Revision 1.81  1996-02-26 18:38:32  adam
+ * Revision 1.83  1996-03-05 09:21:09  adam
+ * Bug fix: memory used by GRS records wasn't freed.
+ * Rewrote some of the error handling code - the connection is always
+ * closed before failback is called.
+ * If failback is defined the send APDU methods (init, search, ...) will
+ * return OK but invoke failback (as is the case if the write operation
+ * fails).
+ * Bug fix: ref_count in assoc object could grow if fraction of PDU was
+ * read.
+ *
+ * Revision 1.82  1996/02/29  15:30:21  adam
+ * Export of IrTcl functionality to extensions.
+ *
+ * Revision 1.81  1996/02/26  18:38:32  adam
  * Work on export of set methods.
  *
  * Revision 1.80  1996/02/23  17:31:39  adam
 #include "ir-tclp.h"
 
 static void ir_deleteDiags (IrTcl_Diagnostic **dst_list, int *dst_num);
-static int do_disconnect (void *obj, Tcl_Interp *interp, 
-                          int argc, char **argv);
 
 static void ir_select_notify (ClientData clientData, int r, int w, int e);
 
@@ -324,6 +335,28 @@ void ir_select_remove_write (int fd, void *obj)
     ir_tcl_select_set (ir_select_notify, fd, obj, 1, 0, 0);
 }
 
+static void delete_IR_record (IrTcl_RecordList *rl)
+{
+    switch (rl->which)
+    {
+    case Z_NamePlusRecord_databaseRecord:
+        switch (rl->u.dbrec.type)
+        {
+        case VAL_GRS1:
+            ir_tcl_grs_del (&rl->u.dbrec.u.grs1);
+            break;
+        default:
+        }
+        free (rl->u.dbrec.buf);
+        break;
+    case Z_NamePlusRecord_surrogateDiagnostic:
+        ir_deleteDiags (&rl->u.surrogateDiagnostics.list,
+                        &rl->u.surrogateDiagnostics.num);
+        break;
+    }
+    free (rl->elements);
+}
+
 static IrTcl_RecordList *new_IR_record (IrTcl_SetObj *setobj, 
                                         int no, int which, 
                                         const char *elements)
@@ -337,18 +370,7 @@ static IrTcl_RecordList *new_IR_record (IrTcl_SetObj *setobj,
         if (no == rl->no && (!rl->elements || !elements ||
                              !strcmp(elements, rl->elements)))
         {
-            free (rl->elements);
-            switch (rl->which)
-            {
-            case Z_NamePlusRecord_databaseRecord:
-                free (rl->u.dbrec.buf);
-                rl->u.dbrec.buf = NULL;
-                break;
-            case Z_NamePlusRecord_surrogateDiagnostic:
-                ir_deleteDiags (&rl->u.surrogateDiagnostics.list,
-                                &rl->u.surrogateDiagnostics.num);
-                break;
-            }
+            delete_IR_record (rl);
             break;
         }
     }
@@ -372,6 +394,7 @@ int ir_tcl_eval (Tcl_Interp *interp, const char *command)
     char *tmp = ir_tcl_malloc (strlen(command)+1);
     int r;
 
+    logf (LOG_DEBUG, "Invoking %.17s ...", command);
     strcpy (tmp, command);
     r = Tcl_Eval (interp, tmp);
     if (r == TCL_ERROR)
@@ -428,16 +451,7 @@ static void delete_IR_records (IrTcl_SetObj *setobj)
 
     for (rl = setobj->record_list; rl; rl = rl1)
     {
-        switch (rl->which)
-        {
-        case Z_NamePlusRecord_databaseRecord:
-            free (rl->u.dbrec.buf);
-            break;
-        case Z_NamePlusRecord_surrogateDiagnostic:
-            ir_deleteDiags (&rl->u.surrogateDiagnostics.list,
-                            &rl->u.surrogateDiagnostics.num);
-            break;
-        }
+        delete_IR_record (rl);
         rl1 = rl->next;
         free (rl);
     }
@@ -445,9 +459,9 @@ static void delete_IR_records (IrTcl_SetObj *setobj)
 }
 
 /*
- * get_set_int: Set/get integer value
+ * ir_tcl_get_set_int: Set/get integer value
  */
-static int get_set_int (int *val, Tcl_Interp *interp, int argc, char **argv)
+int ir_tcl_get_set_int (int *val, Tcl_Interp *interp, int argc, char **argv)
 {
     char buf[20];
     
@@ -464,7 +478,8 @@ static int get_set_int (int *val, Tcl_Interp *interp, int argc, char **argv)
 /*
  * ir_tcl_method: Search for method in table and invoke method handler
  */
-int ir_tcl_method (Tcl_Interp *interp, int argc, char **argv, IrTcl_Methods *tab)
+int ir_tcl_method (Tcl_Interp *interp, int argc, char **argv,
+                   IrTcl_Methods *tab, int *ret)
 {
     IrTcl_Methods *tab_i = tab;
     IrTcl_Method *t;
@@ -478,7 +493,10 @@ int ir_tcl_method (Tcl_Interp *interp, int argc, char **argv, IrTcl_Methods *tab
             }
             else
                 if (!strcmp (t->name, argv[1]))
-                    return (*t->method)(tab_i->obj, interp, argc, argv);
+                {
+                    *ret = (*t->method)(tab_i->obj, interp, argc, argv);
+                    return TCL_OK;
+                }
 
     if (argc <= 0)
         return TCL_OK;
@@ -489,14 +507,15 @@ int ir_tcl_method (Tcl_Interp *interp, int argc, char **argv, IrTcl_Methods *tab
         for (t = tab_i->tab; t->name; t++)
             Tcl_AppendResult (interp, " ", t->name, NULL);
 #endif
+    *ret = TCL_ERROR;
     return TCL_ERROR;
 }
 
 /*
- *  ir_named_bits: get/set named bits
+ *  ir_tcl_named_bits: get/set named bits
  */
-int ir_named_bits (struct ir_named_entry *tab, Odr_bitmask *ob,
-                   Tcl_Interp *interp, int argc, char **argv)
+int ir_tcl_named_bits (struct ir_named_entry *tab, Odr_bitmask *ob,
+                       Tcl_Interp *interp, int argc, char **argv)
 {
     struct ir_named_entry *ti;
     if (argc > 0)
@@ -689,7 +708,7 @@ static int do_options (void *obj, Tcl_Interp *interp,
         ODR_MASK_SET (&p->options, 14);
         return TCL_OK;
     }
-    return ir_named_bits (options_tab, &p->options, interp, argc-2, argv+2);
+    return ir_tcl_named_bits (options_tab, &p->options, interp, argc-2, argv+2);
 }
 
 /*
@@ -795,7 +814,7 @@ static int do_preferredMessageSize (void *obj, Tcl_Interp *interp,
         p->preferredMessageSize = 30000;
         return TCL_OK;
     }
-    return get_set_int (&p->preferredMessageSize, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->preferredMessageSize, interp, argc, argv);
 }
 
 /*
@@ -811,7 +830,7 @@ static int do_maximumRecordSize (void *obj, Tcl_Interp *interp,
         p->maximumRecordSize = 30000;
         return TCL_OK;
     }
-    return get_set_int (&p->maximumRecordSize, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->maximumRecordSize, interp, argc, argv);
 }
 
 /*
@@ -824,7 +843,7 @@ static int do_initResult (void *obj, Tcl_Interp *interp,
    
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->initResult, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->initResult, interp, argc, argv);
 }
 
 
@@ -1066,7 +1085,7 @@ static int do_connect (void *obj, Tcl_Interp *interp,
         if ((r=cs_connect (p->cs_link, addr)) < 0)
         {
             interp->result = "connect fail";
-            do_disconnect (p, NULL, 2, NULL);
+            ir_tcl_disconnect (p);
             return TCL_ERROR;
         }
        logf(LOG_DEBUG, "cs_connect() returned %d fd=%d", r,
@@ -1098,25 +1117,11 @@ static int do_connect (void *obj, Tcl_Interp *interp,
     return TCL_OK;
 }
 
-/*
- * do_disconnect: disconnect method on IR object
+/* 
+ * ir_tcl_disconnect: close connection
  */
-static int do_disconnect (void *obj, Tcl_Interp *interp,
-                          int argc, char **argv)
+void ir_tcl_disconnect (IrTcl_Obj *p)
 {
-    IrTcl_Obj *p = obj;
-
-    if (argc == 0)
-    {
-        p->state = IR_TCL_R_Idle;
-        p->eventType = NULL;
-        p->hostname = NULL;
-        p->cs_link = NULL;
-#if IRTCL_GENERIC_FILES
-        p->csFile = 0;
-#endif
-        return TCL_OK;
-    }
     if (p->hostname)
     {
        logf(LOG_DEBUG, "Closing connection to %s", p->hostname);
@@ -1153,6 +1158,28 @@ static int do_disconnect (void *obj, Tcl_Interp *interp,
         ir_tcl_del_q (p);
     }
     assert (!p->cs_link);
+}
+
+/*
+ * do_disconnect: disconnect method on IR object
+ */
+static int do_disconnect (void *obj, Tcl_Interp *interp,
+                          int argc, char **argv)
+{
+    IrTcl_Obj *p = obj;
+
+    if (argc == 0)
+    {
+        p->state = IR_TCL_R_Idle;
+        p->eventType = NULL;
+        p->hostname = NULL;
+        p->cs_link = NULL;
+#if IRTCL_GENERIC_FILES
+        p->csFile = 0;
+#endif
+        return TCL_OK;
+    }
+    ir_tcl_disconnect (p);
     return TCL_OK;
 }
 
@@ -1423,7 +1450,7 @@ static int do_replaceIndicator (void *obj, Tcl_Interp *interp,
         p->replaceIndicator = 1;
         return TCL_OK;
     }
-    return get_set_int (&p->replaceIndicator, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->replaceIndicator, interp, argc, argv);
 }
 
 /*
@@ -1480,7 +1507,7 @@ static int do_smallSetUpperBound (void *o, Tcl_Interp *interp,
         p->smallSetUpperBound = 0;
         return TCL_OK;
     }
-    return get_set_int (&p->smallSetUpperBound, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->smallSetUpperBound, interp, argc, argv);
 }
 
 /*
@@ -1496,7 +1523,7 @@ static int do_largeSetLowerBound (void *o, Tcl_Interp *interp,
         p->largeSetLowerBound = 2;
         return TCL_OK;
     }
-    return get_set_int (&p->largeSetLowerBound, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->largeSetLowerBound, interp, argc, argv);
 }
 
 /*
@@ -1512,7 +1539,7 @@ static int do_mediumSetPresentNumber (void *o, Tcl_Interp *interp,
         p->mediumSetPresentNumber = 0;
         return TCL_OK;
     }
-    return get_set_int (&p->mediumSetPresentNumber, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->mediumSetPresentNumber, interp, argc, argv);
 }
 
 /*
@@ -1708,6 +1735,7 @@ static int ir_obj_method (ClientData clientData, Tcl_Interp *interp,
 {
     IrTcl_Methods tab[3];
     IrTcl_Obj *p = clientData;
+    int r;
 
     if (argc < 2)
         return TCL_ERROR;
@@ -1718,7 +1746,8 @@ static int ir_obj_method (ClientData clientData, Tcl_Interp *interp,
     tab[1].obj = &p->set_inher;
     tab[2].tab = NULL;
     
-    return ir_tcl_method (interp, argc, argv, tab);
+    ir_tcl_method (interp, argc, argv, tab, &r);
+    return r;
 }
 
 /* 
@@ -1741,7 +1770,7 @@ static void ir_obj_delete (ClientData clientData)
     tab[1].obj = &obj->set_inher;
     tab[2].tab = NULL;
 
-    ir_tcl_method (NULL, -1, NULL, tab);
+    ir_tcl_method (NULL, -1, NULL, tab, NULL);
 
     ir_tcl_del_q (obj);
     odr_destroy (obj->odr_in);
@@ -1796,7 +1825,7 @@ int ir_obj_init (ClientData clientData, Tcl_Interp *interp,
     tab[1].obj = &obj->set_inher;
     tab[2].tab = NULL;
 
-    if (ir_tcl_method (interp, 0, NULL, tab) == TCL_ERROR)
+    if (ir_tcl_method (interp, 0, NULL, tab, NULL) == TCL_ERROR)
     {
         Tcl_AppendResult (interp, "Failed to initialize ", argv[1], NULL);
         return TCL_ERROR;
@@ -2054,7 +2083,7 @@ static int do_resultCount (void *o, Tcl_Interp *interp,
         obj->resultCount = 0;
         return TCL_OK;
     }
-    return get_set_int (&obj->resultCount, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->resultCount, interp, argc, argv);
 }
 
 /*
@@ -2067,7 +2096,7 @@ static int do_searchStatus (void *o, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&obj->searchStatus, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->searchStatus, interp, argc, argv);
 }
 
 /*
@@ -2080,7 +2109,7 @@ static int do_presentStatus (void *o, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&obj->presentStatus, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->presentStatus, interp, argc, argv);
 }
 
 /*
@@ -2097,7 +2126,8 @@ static int do_nextResultSetPosition (void *o, Tcl_Interp *interp,
         obj->nextResultSetPosition = 0;
         return TCL_OK;
     }
-    return get_set_int (&obj->nextResultSetPosition, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->nextResultSetPosition, interp,
+                               argc, argv);
 }
 
 /*
@@ -2136,7 +2166,8 @@ static int do_numberOfRecordsReturned (void *o, Tcl_Interp *interp,
         obj->numberOfRecordsReturned = 0;
         return TCL_OK;
     }
-    return get_set_int (&obj->numberOfRecordsReturned, interp, argc, argv);
+    return ir_tcl_get_set_int (&obj->numberOfRecordsReturned, interp,
+                               argc, argv);
 }
 
 /*
@@ -2605,6 +2636,7 @@ static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
 {
     IrTcl_Methods tabs[3];
     IrTcl_SetObj *p = clientData;
+    int r;
 
     if (argc < 2)
     {
@@ -2617,7 +2649,8 @@ static int ir_set_obj_method (ClientData clientData, Tcl_Interp *interp,
     tabs[1].obj = &p->set_inher;
     tabs[2].tab = NULL;
 
-    return ir_tcl_method (interp, argc, argv, tabs);
+    ir_tcl_method (interp, argc, argv, tabs, &r);
+    return r;
 }
 
 /* 
@@ -2636,7 +2669,7 @@ static void ir_set_obj_delete (ClientData clientData)
     tabs[1].obj = &p->set_inher;
     tabs[2].tab = NULL;
 
-    ir_tcl_method (NULL, -1, NULL, tabs);
+    ir_tcl_method (NULL, -1, NULL, tabs, NULL);
 
     free (p);
 }
@@ -2722,7 +2755,7 @@ static int ir_set_obj_init (ClientData clientData, Tcl_Interp *interp,
     tabs[0].obj = obj;
     tabs[1].tab = NULL;
 
-    if (ir_tcl_method (interp, 0, NULL, tabs) == TCL_ERROR)
+    if (ir_tcl_method (interp, 0, NULL, tabs, NULL) == TCL_ERROR)
         return TCL_ERROR;
 
     *subData = obj;
@@ -2883,7 +2916,7 @@ static int do_stepSize (void *obj, Tcl_Interp *interp,
         p->stepSize = 0;
         return TCL_OK;
     }
-    return get_set_int (&p->stepSize, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->stepSize, interp, argc, argv);
 }
 
 /*
@@ -2899,7 +2932,7 @@ static int do_numberOfTermsRequested (void *obj, Tcl_Interp *interp,
         p->numberOfTermsRequested = 20;
         return TCL_OK;
     }
-    return get_set_int (&p->numberOfTermsRequested, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->numberOfTermsRequested, interp, argc, argv);
 }
 
 
@@ -2916,7 +2949,8 @@ static int do_preferredPositionInResponse (void *obj, Tcl_Interp *interp,
         p->preferredPositionInResponse = 1;
         return TCL_OK;
     }
-    return get_set_int (&p->preferredPositionInResponse, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->preferredPositionInResponse, interp,
+                               argc, argv);
 }
 
 /*
@@ -2929,7 +2963,7 @@ static int do_scanStatus (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->scanStatus, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->scanStatus, interp, argc, argv);
 }
 
 /*
@@ -2942,7 +2976,8 @@ static int do_numberOfEntriesReturned (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->numberOfEntriesReturned, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->numberOfEntriesReturned, interp,
+                               argc, argv);
 }
 
 /*
@@ -2955,7 +2990,7 @@ static int do_positionOfTerm (void *obj, Tcl_Interp *interp,
 
     if (argc <= 0)
         return TCL_OK;
-    return get_set_int (&p->positionOfTerm, interp, argc, argv);
+    return ir_tcl_get_set_int (&p->positionOfTerm, interp, argc, argv);
 }
 
 /*
@@ -3035,6 +3070,7 @@ static int ir_scan_obj_method (ClientData clientData, Tcl_Interp *interp,
                                int argc, char **argv)
 {
     IrTcl_Methods tabs[2];
+    int r;
 
     if (argc < 2)
     {
@@ -3045,7 +3081,8 @@ static int ir_scan_obj_method (ClientData clientData, Tcl_Interp *interp,
     tabs[0].obj = clientData;
     tabs[1].tab = NULL;
 
-    return ir_tcl_method (interp, argc, argv, tabs);
+    ir_tcl_method (interp, argc, argv, tabs, &r);
+    return r;
 }
 
 /* 
@@ -3060,7 +3097,7 @@ static void ir_scan_obj_delete (ClientData clientData)
     tabs[0].obj = obj;
     tabs[1].tab = NULL;
 
-    ir_tcl_method (NULL, -1, NULL, tabs);
+    ir_tcl_method (NULL, -1, NULL, tabs, NULL);
     free (obj);
 }
 
@@ -3091,7 +3128,7 @@ static int ir_scan_obj_mk (ClientData clientData, Tcl_Interp *interp,
     tabs[0].obj = obj;
     tabs[1].tab = NULL;
 
-    if (ir_tcl_method (interp, 0, NULL, tabs) == TCL_ERROR)
+    if (ir_tcl_method (interp, 0, NULL, tabs, NULL) == TCL_ERROR)
         return TCL_ERROR;
     Tcl_CreateCommand (interp, argv[1], ir_scan_obj_method,
                        (ClientData) obj, ir_scan_obj_delete);
@@ -3254,7 +3291,7 @@ static void ir_handleRecords (void *o, Z_Records *zrs, IrTcl_SetObj *setobj,
                 else if (rl->u.dbrec.type == VAL_GRS1 && 
                          oe->which == Z_External_grs1)
                 {
-                    ir_tcl_read_grs (oe->u.grs1, &rl->u.dbrec.u.grs1);
+                    ir_tcl_grs_mk (oe->u.grs1, &rl->u.dbrec.u.grs1);
                     rl->u.dbrec.buf = NULL;
                 }
                 else
@@ -3455,6 +3492,7 @@ static void ir_select_read (ClientData clientData)
             return;
         }
         p->state = IR_TCL_R_Idle;
+        p->ref_count = 2;
 #if IRTCL_GENERIC_FILES
         ir_select_remove_write (p->csFile, p);
 #else
@@ -3463,30 +3501,37 @@ static void ir_select_read (ClientData clientData)
         if (r < 0)
         {
             logf (LOG_DEBUG, "cs_rcvconnect error");
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_CONNECT;
                 ir_tcl_eval (p->interp, p->failback);
             }
-            do_disconnect (p, NULL, 2, NULL);
+            ir_obj_delete (p);
             return;
         }
-        p->state = IR_TCL_R_Idle;
         if (p->callback)
             ir_tcl_eval (p->interp, p->callback);
-        if (p->cs_link && p->request_queue && p->state == IR_TCL_R_Idle)
+        if (p->ref_count == 2 && p->cs_link && p->request_queue
+            && p->state == IR_TCL_R_Idle)
             ir_tcl_send_q (p, p->request_queue, "x");
+        ir_obj_delete (p);
         return;
     }
     do
     {
-        /* signal one more use of ir object - callbacks must not
-           release the ir memory (p pointer) */
         p->state = IR_TCL_R_Reading;
-        ++(p->ref_count);
 
         /* read incoming APDU */
-        if ((r=cs_get (p->cs_link, &p->buf_in, &p->len_in)) <= 0)
+        if ((r=cs_get (p->cs_link, &p->buf_in, &p->len_in)) == 1)
+       {
+           logf(LOG_DEBUG, "PDU Fraction read");
+            return ;
+       }
+        /* signal one more use of ir object - callbacks must not
+           release the ir memory (p pointer) */
+        p->ref_count = 2;
+        if (r <= 0)
         {
             logf (LOG_DEBUG, "cs_get failed, code %d", r);
 #if IRTCL_GENERIC_FILES
@@ -3494,7 +3539,7 @@ static void ir_select_read (ClientData clientData)
 #else
             ir_select_remove (cs_fileno (p->cs_link), p);
 #endif
-            do_disconnect (p, NULL, 2, NULL);
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_READ;
@@ -3504,11 +3549,6 @@ static void ir_select_read (ClientData clientData)
             ir_obj_delete (p);
             return;
         }        
-        if (r == 1)
-       {
-           logf(LOG_DEBUG, "PDU Fraction read");
-            return ;
-       }
         /* got complete APDU. Now decode */
         p->apduLen = r;
         p->apduOffset = -1;
@@ -3518,7 +3558,7 @@ static void ir_select_read (ClientData clientData)
         {
             logf (LOG_DEBUG, "cs_get failed: %s",
                odr_errmsg (odr_geterror (p->odr_in)));
-            do_disconnect (p, NULL, 2, NULL);
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_IN_APDU;
@@ -3573,7 +3613,7 @@ static void ir_select_read (ClientData clientData)
             default:
                 logf (LOG_WARN, "Received unknown APDU type (%d)",
                       apdu->which);
-                do_disconnect (p, NULL, 2, NULL);
+                ir_tcl_disconnect (p);
                 if (p->failback)
                 {
                     p->failInfo = IR_TCL_FAIL_UNKNOWN_APDU;
@@ -3599,7 +3639,7 @@ static void ir_select_read (ClientData clientData)
             ir_obj_delete (p);
             return;
         }
-        --(p->ref_count);
+        ir_obj_delete (p);
     } while (p->cs_link && cs_more (p->cs_link));
     if (p->cs_link && p->request_queue && p->state == IR_TCL_R_Idle)
         ir_tcl_send_q (p, p->request_queue, "x");
@@ -3620,31 +3660,32 @@ static void ir_select_write (ClientData clientData)
        logf(LOG_DEBUG, "Connect handler");
         r = cs_rcvconnect (p->cs_link);
         if (r == 1)
+        {
+            logf (LOG_DEBUG, "cs_rcvconnect returned 1");
             return;
+        }
         p->state = IR_TCL_R_Idle;
-        if (r < 0)
-        {
-            logf (LOG_DEBUG, "cs_rcvconnect error");
+        p->ref_count = 2;
 #if IRTCL_GENERIC_FILES
-            ir_select_remove_write (p->csFile, p);
+        ir_select_remove_write (p->csFile, p);
 #else
-            ir_select_remove_write (cs_fileno (p->cs_link), p);
+        ir_select_remove_write (cs_fileno (p->cs_link), p);
 #endif
+        if (r < 0)
+        {
+            logf (LOG_DEBUG, "cs_rcvconnect error");
+            ir_tcl_disconnect (p);
             if (p->failback)
             {
                 p->failInfo = IR_TCL_FAIL_CONNECT;
                 ir_tcl_eval (p->interp, p->failback);
             }
-            do_disconnect (p, NULL, 2, NULL);
+            ir_obj_delete (p);
             return;
         }
-#if IRTCL_GENERIC_FILES
-        ir_select_remove_write (p->csFile, p);
-#else
-        ir_select_remove_write (cs_fileno (p->cs_link), p);
-#endif
         if (p->callback)
             ir_tcl_eval (p->interp, p->callback);
+        ir_obj_delete (p);
         return;
     }
     rq = p->request_queue;
@@ -3654,18 +3695,20 @@ static void ir_select_write (ClientData clientData)
     if ((r=cs_put (p->cs_link, rq->buf_out, rq->len_out)) < 0)
     {
         logf (LOG_DEBUG, "cs_put write fail");
+        p->ref_count = 2;
+        free (rq->buf_out);
+        rq->buf_out = NULL;
+        ir_tcl_disconnect (p);
         if (p->failback)
         {
             p->failInfo = IR_TCL_FAIL_WRITE;
             ir_tcl_eval (p->interp, p->failback);
         }
-        free (rq->buf_out);
-        rq->buf_out = NULL;
-        do_disconnect (p, NULL, 2, NULL);
+        ir_obj_delete (p);
     }
     else if (r == 0)            /* remove select bit */
     {
-       logf(LOG_DEBUG, "Write completed");
+       logf (LOG_DEBUG, "Write completed");
         p->state = IR_TCL_R_Waiting;
 #if IRTCL_GENERIC_FILES
         ir_select_remove_write (p->csFile, p);