* temporary tracing messages
[citadel.git] / webcit / tcp_sockets.c
1 /*
2  * $Id$
3  */
4
5 /*
6  * Uncomment this to log all communications with the Citadel server
7 #define SERV_TRACE 1
8  */
9
10
11 #include "webcit.h"
12 #include "webserver.h"
13
14 extern int DisableGzip;
15
16 /*
17  * register the timeout
18  */
19 RETSIGTYPE timeout(int signum)
20 {
21         lprintf(1, "Connection timed out; unable to reach citserver\n");
22         /* no exit here, since we need to server the connection unreachable thing. exit(3); */
23 }
24
25
26 /*
27  *  Connect a unix domain socket
28  *  sockpath where to open a unix domain socket
29  */
30 int uds_connectsock(char *sockpath)
31 {
32         struct sockaddr_un addr;
33         int s;
34
35         memset(&addr, 0, sizeof(addr));
36         addr.sun_family = AF_UNIX;
37         strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
38
39         s = socket(AF_UNIX, SOCK_STREAM, 0);
40         if (s < 0) {
41                 lprintf(1, "Can't create socket[%s]: %s\n",
42                         sockpath,
43                         strerror(errno));
44                 return(-1);
45         }
46
47         if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
48                 lprintf(1, "Can't connect [%s]: %s\n",
49                         sockpath,
50                         strerror(errno));
51                 close(s);
52                 return(-1);
53         }
54
55         return s;
56 }
57
58
59 /*
60  *  Connect a TCP/IP socket
61  *  host the host to connect to
62  *  service the service on the host to call
63  */
64 int tcp_connectsock(char *host, char *service)
65 {
66         int fdflags;
67         struct hostent *phe;
68         struct servent *pse;
69         struct protoent *ppe;
70         struct sockaddr_in sin;
71         int s;
72
73         memset(&sin, 0, sizeof(sin));
74         sin.sin_family = AF_INET;
75
76         pse = getservbyname(service, "tcp");
77         if (pse) {
78                 sin.sin_port = pse->s_port;
79         } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
80                 lprintf(1, "Can't get %s service entry\n", service);
81                 return (-1);
82         }
83         phe = gethostbyname(host);
84         if (phe) {
85                 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
86         } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
87                 lprintf(1, "Can't get %s host entry: %s\n",
88                         host, strerror(errno));
89                 return (-1);
90         }
91         if ((ppe = getprotobyname("tcp")) == 0) {
92                 lprintf(1, "Can't get TCP protocol entry: %s\n",
93                         strerror(errno));
94                 return (-1);
95         }
96
97         s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
98         if (s < 0) {
99                 lprintf(1, "Can't create socket: %s\n", strerror(errno));
100                 return (-1);
101         }
102
103         fdflags = fcntl(s, F_GETFL);
104         if (fdflags < 0)
105                 lprintf(1, "unable to get socket flags!  %s.%s: %s \n",
106                         host, service, strerror(errno));
107         fdflags = fdflags | O_NONBLOCK;
108         if (fcntl(s, F_SETFD, fdflags) < 0)
109                 lprintf(1, "unable to set socket nonblocking flags!  %s.%s: %s \n",
110                         host, service, strerror(errno));
111
112         signal(SIGALRM, timeout);
113         alarm(30);
114
115         if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
116                 lprintf(1, "Can't connect to %s.%s: %s\n",
117                         host, service, strerror(errno));
118                 close(s);
119                 return (-1);
120         }
121         alarm(0);
122         signal(SIGALRM, SIG_IGN);
123
124         fdflags = fcntl(s, F_GETFL);
125         if (fdflags < 0)
126                 lprintf(1, "unable to get socket flags!  %s.%s: %s \n",
127                         host, service, strerror(errno));
128         fdflags = fdflags | O_NONBLOCK;
129         if (fcntl(s, F_SETFD, fdflags) < 0)
130                 lprintf(1, "unable to set socket nonblocking flags!  %s.%s: %s \n",
131                         host, service, strerror(errno));
132         return (s);
133 }
134
135
136
137 /*
138  *  input string from pipe
139  */
140 int serv_getln(char *strbuf, int bufsize)
141 {
142         wcsession *WCC = WC;
143         int len;
144
145         *strbuf = '\0';
146         StrBuf_ServGetln(WCC->MigrateReadLineBuf);
147         len = StrLength(WCC->MigrateReadLineBuf);
148         if (len > bufsize)
149                 len = bufsize - 1;
150         memcpy(strbuf, ChrPtr(WCC->MigrateReadLineBuf), len);
151         FlushStrBuf(WCC->MigrateReadLineBuf);
152         strbuf[len] = '\0';
153 #ifdef SERV_TRACE
154         lprintf(9, "%3d>%s\n", WC->serv_sock, strbuf);
155 #endif
156         return len;
157 }
158
159
160 int StrBuf_ServGetln(StrBuf *buf)
161 {
162         wcsession *WCC = WC;
163         const char *ErrStr = NULL;
164         int rc;
165
166         rc = StrBufTCP_read_buffered_line_fast(buf, 
167                                                WCC->ReadBuf, 
168                                                &WCC->ReadPos, 
169                                                &WCC->serv_sock, 
170                                                5, 1, 
171                                                &ErrStr);
172         if (rc < 0)
173         {
174                 lprintf(1, "Server connection broken: %s\n",
175                         ErrStr);
176                 wc_backtrace();
177                 WCC->serv_sock = (-1);
178                 WCC->connected = 0;
179                 WCC->logged_in = 0;
180         }
181         return rc;
182 }
183
184 int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize)
185 {
186         wcsession *WCC = WC;
187         const char *Err;
188         int rc;
189         
190         rc = StrBufReadBLOBBuffered(buf, 
191                                     WCC->ReadBuf, 
192                                     &WCC->ReadPos,
193                                     &WCC->serv_sock, 
194                                     1, 
195                                     BlobSize, 
196                                     NNN_TERM,
197                                     &Err);
198         if (rc < 0)
199         {
200                 lprintf(1, "Server connection broken: %s\n",
201                         Err);
202                 wc_backtrace();
203                 WCC->serv_sock = (-1);
204                 WCC->connected = 0;
205                 WCC->logged_in = 0;
206         }
207         return rc;
208 }
209
210 int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize)
211 {
212         wcsession *WCC = WC;
213         const char *Err;
214         int rc;
215         
216         WCC->ReadPos = NULL;
217         rc = StrBufReadBLOB(buf, &WCC->serv_sock, 1, BlobSize, &Err);
218         if (rc < 0)
219         {
220                 lprintf(1, "Server connection broken: %s\n",
221                         Err);
222                 wc_backtrace();
223                 WCC->serv_sock = (-1);
224                 WCC->connected = 0;
225                 WCC->logged_in = 0;
226         }
227         return rc;
228 }
229
230 /*
231  *  send binary to server
232  *  buf the buffer to write to citadel server
233  *  nbytes how many bytes to send to citadel server
234  */
235 void serv_write(const char *buf, int nbytes)
236 {
237         wcsession *WCC = WC;
238         int bytes_written = 0;
239         int retval;
240
241         FlushStrBuf(WCC->ReadBuf);
242         WCC->ReadPos = NULL;
243         while (bytes_written < nbytes) {
244                 retval = write(WCC->serv_sock, &buf[bytes_written],
245                                nbytes - bytes_written);
246                 if (retval < 1) {
247                         lprintf(1, "Server connection broken: %s\n",
248                                 strerror(errno));
249                         close(WCC->serv_sock);
250                         WCC->serv_sock = (-1);
251                         WCC->connected = 0;
252                         WCC->logged_in = 0;
253                         return;
254                 }
255                 bytes_written = bytes_written + retval;
256         }
257 }
258
259
260 /*
261  *  send line to server
262  *  string the line to send to the citadel server
263  */
264 void serv_puts(const char *string)
265 {
266         wcsession *WCC = WC;
267 #ifdef SERV_TRACE
268         lprintf(9, "%3d<%s\n", WC->serv_sock, string);
269 #endif
270         FlushStrBuf(WCC->ReadBuf);
271         WCC->ReadPos = NULL;
272
273         serv_write(string, strlen(string));
274         serv_write("\n", 1);
275 }
276
277 /*
278  *  send line to server
279  *  string the line to send to the citadel server
280  */
281 void serv_putbuf(const StrBuf *string)
282 {
283         wcsession *WCC = WC;
284 #ifdef SERV_TRACE
285         lprintf(9, "%3d<%s\n", WC->serv_sock, ChrPtr(string));
286 #endif
287         FlushStrBuf(WCC->ReadBuf);
288         WCC->ReadPos = NULL;
289
290         serv_write(ChrPtr(string), StrLength(string));
291         serv_write("\n", 1);
292 }
293
294
295 /*
296  *  convenience function to send stuff to the server
297  *  format the formatstring
298  *  ... the entities to insert into format 
299  */
300 void serv_printf(const char *format,...)
301 {
302         wcsession *WCC = WC;
303         va_list arg_ptr;
304         char buf[SIZ];
305         size_t len;
306
307         FlushStrBuf(WCC->ReadBuf);
308         WCC->ReadPos = NULL;
309
310         va_start(arg_ptr, format);
311         vsnprintf(buf, sizeof buf, format, arg_ptr);
312         va_end(arg_ptr);
313
314         len = strlen(buf);
315         buf[len++] = '\n';
316         buf[len] = '\0';
317         serv_write(buf, len);
318 #ifdef SERV_TRACE
319         lprintf(9, "<%s", buf);
320 #endif
321 }
322
323
324
325
326 int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target)
327 {
328         const char *Error, *pch, *pchs;
329         int rlen, len, retval = 0;
330
331 #ifdef HAVE_OPENSSL
332         if (is_https) {
333                 int ntries = 0;
334                 if (StrLength(Hdr->ReadBuf) > 0) {
335                         pchs = ChrPtr(Hdr->ReadBuf);
336                         pch = strchr(pchs, '\n');
337                         if (pch != NULL) {
338                                 rlen = 0;
339                                 len = pch - pchs;
340                                 if (len > 0 && (*(pch - 1) == '\r') )
341                                         rlen ++;
342                                 StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
343                                 StrBufCutLeft(Hdr->ReadBuf, len + 1);
344                                 return len - rlen;
345                         }
346                 }
347
348                 while (retval == 0) { 
349                                 pch = NULL;
350                                 pchs = ChrPtr(Hdr->ReadBuf);
351                                 if (*pchs != '\0')
352                                         pch = strchr(pchs, '\n');
353                                 if (pch == NULL) {
354                                         retval = client_read_sslbuffer(Hdr->ReadBuf, SLEEPING);
355                                         pchs = ChrPtr(Hdr->ReadBuf);
356                                         pch = strchr(pchs, '\n');
357                                 }
358                                 if (retval == 0) {
359                                         sleeeeeeeeeep(1);
360                                         ntries ++;
361                                 }
362                                 if (ntries > 10)
363                                         return 0;
364                 }
365                 if ((retval > 0) && (pch != NULL)) {
366                         rlen = 0;
367                         len = pch - pchs;
368                         if (len > 0 && (*(pch - 1) == '\r') )
369                                 rlen ++;
370                         StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
371                         StrBufCutLeft(Hdr->ReadBuf, len + 1);
372                         return len - rlen;
373
374                 }
375                 else 
376                         return -1;
377         }
378         else 
379 #endif
380                 return StrBufTCP_read_buffered_line_fast(Target, 
381                                                          Hdr->ReadBuf,
382                                                          &Hdr->Pos,
383                                                          &Hdr->http_sock,
384                                                          5,
385                                                          1,
386                                                          &Error);
387 }
388
389 /* 
390  * This is a generic function to set up a master socket for listening on
391  * a TCP port.  The server shuts down if the bind fails.
392  *
393  * ip_addr      IP address to bind
394  * port_number  port number to bind
395  * queue_len    number of incoming connections to allow in the queue
396  */
397 int ig_tcp_server(char *ip_addr, int port_number, int queue_len)
398 {
399         struct protoent *p;
400         struct sockaddr_in sin;
401         int s, i;
402
403         memset(&sin, 0, sizeof(sin));
404         sin.sin_family = AF_INET;
405         if (ip_addr == NULL) {
406                 sin.sin_addr.s_addr = INADDR_ANY;
407         } else {
408                 sin.sin_addr.s_addr = inet_addr(ip_addr);
409         }
410
411         if (sin.sin_addr.s_addr == INADDR_NONE) {
412                 sin.sin_addr.s_addr = INADDR_ANY;
413         }
414
415         if (port_number == 0) {
416                 lprintf(1, "Cannot start: no port number specified.\n");
417                 exit(WC_EXIT_BIND);
418         }
419         sin.sin_port = htons((u_short) port_number);
420
421         p = getprotobyname("tcp");
422
423         s = socket(PF_INET, SOCK_STREAM, (p->p_proto));
424         if (s < 0) {
425                 lprintf(1, "Can't create a socket: %s\n", strerror(errno));
426                 exit(WC_EXIT_BIND);
427         }
428         /* Set some socket options that make sense. */
429         i = 1;
430         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
431
432         #ifndef __APPLE__
433         fcntl(s, F_SETFL, O_NONBLOCK); /* maide: this statement is incorrect
434                                           there should be a preceding F_GETFL
435                                           and a bitwise OR with the previous
436                                           fd flags */
437         #endif
438         
439         if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
440                 lprintf(1, "Can't bind: %s\n", strerror(errno));
441                 exit(WC_EXIT_BIND);
442         }
443         if (listen(s, queue_len) < 0) {
444                 lprintf(1, "Can't listen: %s\n", strerror(errno));
445                 exit(WC_EXIT_BIND);
446         }
447         return (s);
448 }
449
450
451
452 /*
453  * Create a Unix domain socket and listen on it
454  * sockpath - file name of the unix domain socket
455  * queue_len - Number of incoming connections to allow in the queue
456  */
457 int ig_uds_server(char *sockpath, int queue_len)
458 {
459         struct sockaddr_un addr;
460         int s;
461         int i;
462         int actual_queue_len;
463
464         actual_queue_len = queue_len;
465         if (actual_queue_len < 5) actual_queue_len = 5;
466
467         i = unlink(sockpath);
468         if ((i != 0) && (errno != ENOENT)) {
469                 lprintf(1, "webcit: can't unlink %s: %s\n",
470                         sockpath, strerror(errno));
471                 exit(WC_EXIT_BIND);
472         }
473
474         memset(&addr, 0, sizeof(addr));
475         addr.sun_family = AF_UNIX;
476         safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
477
478         s = socket(AF_UNIX, SOCK_STREAM, 0);
479         if (s < 0) {
480                 lprintf(1, "webcit: Can't create a socket: %s\n",
481                         strerror(errno));
482                 exit(WC_EXIT_BIND);
483         }
484
485         if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
486                 lprintf(1, "webcit: Can't bind: %s\n",
487                         strerror(errno));
488                 exit(WC_EXIT_BIND);
489         }
490
491         if (listen(s, actual_queue_len) < 0) {
492                 lprintf(1, "webcit: Can't listen: %s\n",
493                         strerror(errno));
494                 exit(WC_EXIT_BIND);
495         }
496
497         chmod(sockpath, 0777);
498         return(s);
499 }
500
501
502
503
504 /*
505  * Read data from the client socket.
506  *
507  * sock         socket fd to read from
508  * buf          buffer to read into 
509  * bytes        number of bytes to read
510  * timeout      Number of seconds to wait before timing out
511  *
512  * Possible return values:
513  *      1       Requested number of bytes has been read.
514  *      0       Request timed out.
515  *      -1      Connection is broken, or other error.
516  */
517 int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout)
518 {
519         const char *Error;
520         int retval = 0;
521
522 #ifdef HAVE_OPENSSL
523         if (is_https) {
524                 long bufremain;
525
526                 if (Hdr->Pos == NULL)
527                         Hdr->Pos = ChrPtr(Hdr->ReadBuf);
528                 bufremain = StrLength(Hdr->ReadBuf) - (Hdr->Pos - ChrPtr(Hdr->ReadBuf));
529
530                 if (bytes < bufremain)
531                         bufremain = bytes;
532                 StrBufAppendBufPlain(Target, Hdr->Pos, bufremain, 0);
533                 StrBufCutLeft(Hdr->ReadBuf, bufremain);
534
535                 if (bytes > bufremain) 
536                 {
537                         while ((StrLength(Hdr->ReadBuf) + StrLength(Target) < bytes) &&
538                                (retval >= 0))
539                                 retval = client_read_sslbuffer(Hdr->ReadBuf, timeout);
540                         if (retval >= 0) {
541                                 StrBufAppendBuf(Target, Hdr->ReadBuf, 0); /* todo: Buf > bytes? */
542 #ifdef HTTP_TRACING
543                                 write(2, "\033[32m", 5);
544                                 write(2, buf, bytes);
545                                 write(2, "\033[30m", 5);
546 #endif
547                                 return 1;
548                         }
549                         else {
550                                 lprintf(2, "client_read_ssl() failed\n");
551                                 return -1;
552                         }
553                 }
554                 else 
555                         return 1;
556         }
557 #endif
558
559         retval = StrBufReadBLOBBuffered(Target, 
560                                         Hdr->ReadBuf, 
561                                         &Hdr->Pos, 
562                                         &Hdr->http_sock, 
563                                         1, 
564                                         bytes,
565                                         O_TERM,
566                                         &Error);
567         if (retval < 0) {
568                 lprintf(2, "client_read() failed: %s\n",
569                         Error);
570                 return retval;
571         }
572
573 #ifdef HTTP_TRACING
574         write(2, "\033[32m", 5);
575         write(2, buf, bytes);
576         write(2, "\033[30m", 5);
577 #endif
578         return 1;
579 }
580
581
582 /*
583  * Begin buffering HTTP output so we can transmit it all in one write operation later.
584  */
585 void begin_burst(void)
586 {
587         if (WC->WBuf == NULL) {
588                 WC->WBuf = NewStrBufPlain(NULL, 32768);
589         }
590 }
591
592
593 /*
594  * Finish buffering HTTP output.  [Compress using zlib and] output with a Content-Length: header.
595  */
596 long end_burst(void)
597 {
598         wcsession *WCC = WC;
599         const char *ptr, *eptr;
600         long count;
601         ssize_t res;
602         fd_set wset;
603         int fdflags;
604
605         if (!DisableGzip && (WCC->Hdr->HR.gzip_ok) && CompressBuffer(WCC->WBuf))
606         {
607                 hprintf("Content-encoding: gzip\r\n");
608         }
609
610         if (WCC->Hdr->HR.prohibit_caching)
611                 hprintf("Pragma: no-cache\r\nCache-Control: no-store\r\nExpires:-1\r\n");
612         hprintf("Content-length: %d\r\n\r\n", StrLength(WCC->WBuf));
613
614         ptr = ChrPtr(WCC->HBuf);
615         count = StrLength(WCC->HBuf);
616         eptr = ptr + count;
617
618 #ifdef HAVE_OPENSSL
619         if (is_https) {
620                 client_write_ssl(WCC->HBuf);
621                 client_write_ssl(WCC->WBuf);
622                 return (count);
623         }
624 #endif
625
626         
627 #ifdef HTTP_TRACING
628         
629         write(2, "\033[34m", 5);
630         write(2, ptr, StrLength(WCC->WBuf));
631         write(2, "\033[30m", 5);
632 #endif
633         fdflags = fcntl(WC->Hdr->http_sock, F_GETFL);
634
635         while (ptr < eptr) {
636                 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
637                         FD_ZERO(&wset);
638                         FD_SET(WCC->Hdr->http_sock, &wset);
639                         if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
640                                 lprintf(2, "client_write: Socket select failed (%s)\n", strerror(errno));
641                                 return -1;
642                         }
643                 }
644
645                 if ((res = write(WCC->Hdr->http_sock, 
646                                  ptr,
647                                  count)) == -1) {
648                         lprintf(2, "client_write: Socket write failed (%s)\n", strerror(errno));
649                         wc_backtrace();
650                         return res;
651                 }
652                 count -= res;
653                 ptr += res;
654         }
655
656         ptr = ChrPtr(WCC->WBuf);
657         count = StrLength(WCC->WBuf);
658         eptr = ptr + count;
659
660 #ifdef HTTP_TRACING
661         
662         write(2, "\033[34m", 5);
663         write(2, ptr, StrLength(WCC->WBuf));
664         write(2, "\033[30m", 5);
665 #endif
666
667         while (ptr < eptr) {
668                 if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
669                         FD_ZERO(&wset);
670                         FD_SET(WCC->Hdr->http_sock, &wset);
671                         if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) {
672                                 lprintf(2, "client_write: Socket select failed (%s)\n", strerror(errno));
673                                 return -1;
674                         }
675                 }
676
677                 if ((res = write(WCC->Hdr->http_sock, 
678                                  ptr,
679                                  count)) == -1) {
680                         lprintf(2, "client_write: Socket write failed (%s)\n", strerror(errno));
681                         wc_backtrace();
682                         return res;
683                 }
684                 count -= res;
685                 ptr += res;
686         }
687
688         return StrLength(WCC->WBuf);
689 }
690
691
692 /*
693  * lingering_close() a`la Apache. see
694  * http://www.apache.org/docs/misc/fin_wait_2.html for rationale
695  */
696 int lingering_close(int fd)
697 {
698         char buf[SIZ];
699         int i;
700         fd_set set;
701         struct timeval tv, start;
702
703         gettimeofday(&start, NULL);
704         shutdown(fd, 1);
705         do {
706                 do {
707                         gettimeofday(&tv, NULL);
708                         tv.tv_sec = SLEEPING - (tv.tv_sec - start.tv_sec);
709                         tv.tv_usec = start.tv_usec - tv.tv_usec;
710                         if (tv.tv_usec < 0) {
711                                 tv.tv_sec--;
712                                 tv.tv_usec += 1000000;
713                         }
714                         FD_ZERO(&set);
715                         FD_SET(fd, &set);
716                         i = select(fd + 1, &set, NULL, NULL, &tv);
717                 } while (i == -1 && errno == EINTR);
718
719                 if (i <= 0)
720                         break;
721
722                 i = read(fd, buf, sizeof buf);
723         } while (i != 0 && (i != -1 || errno == EINTR));
724
725         return close(fd);
726 }
727
728 void
729 HttpNewModule_TCPSOCKETS
730 (ParsedHttpHdrs *httpreq)
731 {
732
733         httpreq->ReadBuf = NewStrBufPlain(NULL, SIZ * 4);
734 }
735
736 void
737 HttpDetachModule_TCPSOCKETS
738 (ParsedHttpHdrs *httpreq)
739 {
740
741         FlushStrBuf(httpreq->ReadBuf);
742         ReAdjustEmptyBuf(httpreq->ReadBuf, 4 * SIZ, SIZ);
743 }
744
745 void
746 HttpDestroyModule_TCPSOCKETS
747 (ParsedHttpHdrs *httpreq)
748 {
749
750         FreeStrBuf(&httpreq->ReadBuf);
751 }
752
753
754 void
755 SessionNewModule_TCPSOCKETS
756 (wcsession *sess)
757 {
758         sess->CLineBuf = NewStrBuf();
759         sess->MigrateReadLineBuf = NewStrBuf();
760 }
761
762 void 
763 SessionDestroyModule_TCPSOCKETS
764 (wcsession *sess)
765 {
766         FreeStrBuf(&sess->CLineBuf);
767         FreeStrBuf(&sess->ReadBuf);
768         FreeStrBuf(&sess->MigrateReadLineBuf);
769         if (sess->serv_sock > 0)
770                 close(sess->serv_sock);
771 }