Browse code

- tcp receiver concerted to the new io_wait.h - epoll: close() not always removing the fd from set bug workarround - sigio_rt: reset O_ASYNC (sigio bug workarround) - more tcp related fixes

Andrei Pelinescu-Onciul authored on 05/07/2005 19:18:01
Showing 4 changed files
... ...
@@ -57,7 +57,7 @@ MAIN_NAME=ser
57 57
 VERSION = 0
58 58
 PATCHLEVEL = 10
59 59
 SUBLEVEL =   99
60
-EXTRAVERSION = -dev10
60
+EXTRAVERSION = -dev11-tcp
61 61
 
62 62
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
63 63
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
... ...
@@ -297,13 +297,19 @@ inline static int io_watch_add(	io_wait_h* h,
297 297
 	int n;
298 298
 	struct epoll_event ep_event;
299 299
 #endif
300
-#ifdef HAVE_SIGIO_RT
301
-	static char buf[65536];
302
-#endif
303 300
 #ifdef HAVE_DEVPOLL
304 301
 	struct pollfd pfd;
305 302
 #endif
303
+#if defined(HAVE_SIGIO_RT) || defined (HAVE_EPOLL)
304
+	int idx;
305
+	int check_io;
306
+	struct pollfd pf;
306 307
 	
308
+	check_io=0; /* set to 1 if we need to check for pre-existiing queued
309
+				   io/data on the fd */
310
+	idx=-1;
311
+#endif
312
+	e=0;
307 313
 	if (fd==-1){
308 314
 		LOG(L_CRIT, "BUG: io_watch_add: fd is -1!\n");
309 315
 		goto error;
... ...
@@ -344,6 +350,10 @@ inline static int io_watch_add(	io_wait_h* h,
344 350
 #ifdef HAVE_SIGIO_RT
345 351
 		case POLL_SIGIO_RT:
346 352
 			fd_array_setup;
353
+			/* re-set O_ASYNC might be needed, if not done from 
354
+			 * io_watch_del (or if somebody wants to add a fd which has
355
+			 * already O_ASYNC/F_SETSIG set on a dupplicate)
356
+			 */
347 357
 			/* set async & signal */
348 358
 			if (fcntl(fd, F_SETOWN, my_pid())==-1){
349 359
 				LOG(L_ERR, "ERROR: io_watch_add: fnctl: SETOWN"
... ...
@@ -362,9 +372,13 @@ inline static int io_watch_add(	io_wait_h* h,
362 372
 					fd,  h->signo, my_pid());
363 373
 #endif
364 374
 			/* empty socket receive buffer, if buffer is already full
365
-			 * (e.g. early media), no more space to put packets
366
-			 * => no more signals are ever generated -- andrei */
367
-			while(recv(fd, buf, sizeof(buf), 0)>=0);
375
+			 * no more space to put packets
376
+			 * => no more signals are ever generated
377
+			 * also when moving fds, the freshly moved fd might have
378
+			 *  already some bytes queued, we want to get them now
379
+			 *  and not later -- andrei */
380
+			idx=h->fd_no;
381
+			check_io=1;
368 382
 			break;
369 383
 #endif
370 384
 #ifdef HAVE_EPOLL
... ...
@@ -392,6 +406,8 @@ again2:
392 406
 					strerror(errno), errno);
393 407
 				goto error;
394 408
 			}
409
+			idx=-1;
410
+			check_io=1;
395 411
 			break;
396 412
 #endif
397 413
 #ifdef HAVE_KQUEUE
... ...
@@ -424,8 +440,23 @@ again_devpoll:
424 440
 	
425 441
 	h->fd_no++; /* "activate" changes, for epoll/kqueue/devpoll it
426 442
 				   has only informative value */
443
+#if defined(HAVE_SIGIO_RT) || defined (HAVE_EPOLL)
444
+	if (check_io){
445
+		/* handle possible pre-existing events */
446
+		pf.fd=fd;
447
+		pf.events=POLLIN;
448
+check_io_again:
449
+		while( ((n=poll(&pf, 1, 0))>0) && (handle_io(e, idx)>0));
450
+		if (n==-1){
451
+			if (errno==EINTR) goto check_io_again;
452
+			LOG(L_ERR, "ERROR: io_watch_add: check_io poll: %s [%d]\n",
453
+						strerror(errno), errno);
454
+		}
455
+	}
456
+#endif
427 457
 	return 0;
428 458
 error:
459
+	if (e) unhash_fd_map(e);
429 460
 	return -1;
430 461
 #undef fd_array_setup
431 462
 #undef set_fd_flags 
... ...
@@ -469,14 +500,17 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags)
469 500
 #ifdef HAVE_DEVPOLL
470 501
 	struct pollfd pfd;
471 502
 #endif
503
+#ifdef HAVE_SIGIO_RT
504
+	int fd_flags;
505
+#endif
472 506
 	
473 507
 	if ((fd<0) || (fd>=h->max_fd_no)){
474 508
 		LOG(L_CRIT, "BUG: io_watch_del: invalid fd %d, not in [0, %d) \n",
475 509
 						fd, h->fd_no);
476 510
 		goto error;
477 511
 	}
478
-	DBG("DBG: io_watch_del (%p, %d, %d) fd_no=%d called\n",
479
-			h, fd, idx, h->fd_no);
512
+	DBG("DBG: io_watch_del (%p, %d, %d, 0x%x) fd_no=%d called\n",
513
+			h, fd, idx, flags, h->fd_no);
480 514
 	e=get_fd_map(h, fd);
481 515
 	/* more sanity checks */
482 516
 	if (e==0){
... ...
@@ -509,25 +543,47 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags)
509 543
 #ifdef HAVE_SIGIO_RT
510 544
 		case POLL_SIGIO_RT:
511 545
 			fix_fd_array;
512
-			/* FIXME: re-set ASYNC? (not needed if the fd is/will be closed
513
-			 *        but might cause problems if the fd is "moved")
514
-			 *        update: probably not needed, the fd_map type!=0
515
-			 *        check should catch old queued signals or in-transit fd
516
-			 *        (so making another syscall to reset ASYNC is not 
517
-			 *         necessary)*/
546
+			/* the O_ASYNC flag must be reset all the time, the fd
547
+			 *  can be changed only if  O_ASYNC is reset (if not and
548
+			 *  the fd is a duplicate, you will get signals from the dup. fd
549
+			 *  and not from the original, even if the dup. fd wa closed
550
+			 *  and the signals re-set on the original) -- andrei
551
+			 */
552
+			/*if (!(flags & IO_FD_CLOSING)){*/
553
+				/* reset ASYNC */
554
+				fd_flags=fcntl(fd, F_GETFL); 
555
+				if (fd_flags==-1){ 
556
+					LOG(L_ERR, "ERROR: io_watch_del: fnctl: GETFL failed:" 
557
+							" %s [%d]\n", strerror(errno), errno); 
558
+					goto error; 
559
+				} 
560
+				if (fcntl(fd, F_SETFL, fd_flags&(~O_ASYNC))==-1){ 
561
+					LOG(L_ERR, "ERROR: io_watch_del: fnctl: SETFL" 
562
+								" failed: %s [%d]\n", strerror(errno), errno); 
563
+					goto error; 
564
+				} 
518 565
 			break;
519 566
 #endif
520 567
 #ifdef HAVE_EPOLL
521 568
 		case POLL_EPOLL_LT:
522 569
 		case POLL_EPOLL_ET:
570
+			/* epoll doesn't seem to automatically remove sockets,
571
+			 * if the socket is a dupplicate/moved and the original
572
+			 * is still open. The fd is removed from the epoll set
573
+			 * only when the original (and all the  copies?) is/are 
574
+			 * closed. This is probably a bug in epoll. --andrei */
575
+#ifdef EPOLL_NO_CLOSE_BUG
523 576
 			if (!(flags & IO_FD_CLOSING)){
577
+#endif
524 578
 				n=epoll_ctl(h->epfd, EPOLL_CTL_DEL, fd, &ep_event);
525 579
 				if (n==-1){
526 580
 					LOG(L_ERR, "ERROR: io_watch_del: removing fd from epoll "
527 581
 							"list failed: %s [%d]\n", strerror(errno), errno);
528 582
 					goto error;
529 583
 				}
584
+#ifdef EPOLL_NO_CLOSE_BUG
530 585
 			}
586
+#endif
531 587
 			break;
532 588
 #endif
533 589
 #ifdef HAVE_KQUEUE
... ...
@@ -659,8 +715,10 @@ again:
659 715
 		if (n==-1){
660 716
 			if (errno==EINTR) goto again; /* signal, ignore it */
661 717
 			else{
662
-				LOG(L_ERR, "ERROR:io_wait_loop_epoll: epoll_wait:"
663
-						" %s [%d]\n", strerror(errno), errno);
718
+				LOG(L_ERR, "ERROR:io_wait_loop_epoll: "
719
+						"epoll_wait(%d, %p, %d, %d): %s [%d]\n", 
720
+						h->epfd, h->ep_array, h->fd_no, t*1000,
721
+						strerror(errno), errno);
664 722
 				goto error;
665 723
 			}
666 724
 		}
... ...
@@ -1174,10 +1174,11 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
1174 1174
 				tcpconn_destroy(tcpconn);
1175 1175
 				break;
1176 1176
 			}
1177
-			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1178 1177
 			/* update the timeout*/
1179 1178
 			tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
1180 1179
 			tcpconn_put(tcpconn);
1180
+			/* must be after the de-ref*/
1181
+			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1181 1182
 			DBG("handle_tcp_child: CONN_RELEASE  %p refcnt= %d\n", 
1182 1183
 											tcpconn, tcpconn->refcnt);
1183 1184
 			break;
... ...
@@ -1309,9 +1310,9 @@ inline static int handle_ser_child(struct process_table* p, int fd_i)
1309 1310
 			tcpconn->s=fd;
1310 1311
 			/* add tcpconn to the list*/
1311 1312
 			tcpconn_add(tcpconn);
1312
-			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1313 1313
 			/* update the timeout*/
1314 1314
 			tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT;
1315
+			io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn);
1315 1316
 			break;
1316 1317
 		default:
1317 1318
 			LOG(L_CRIT, "BUG: handle_ser_child: unknown cmd %d\n", cmd);
... ...
@@ -33,6 +33,7 @@
33 33
  * 2003-07-01  tcp_read & friends take no a single tcp_connection 
34 34
  *              parameter & they set c->state to S_CONN_EOF on eof (andrei)
35 35
  * 2003-07-04  fixed tcp EOF handling (possible infinite loop) (andrei)
36
+ * 2005-07-05  migrated to the new io_wait code (andrei)
36 37
  */
37 38
 
38 39
 #ifdef USE_TCP
... ...
@@ -62,6 +63,17 @@
62 63
 #include "tls/tls_server.h"
63 64
 #endif
64 65
 
66
+#define HANDLE_IO_INLINE
67
+#include "io_wait.h"
68
+#include <fcntl.h> /* must be included after io_wait.h if SIGIO_RT is used */
69
+
70
+/* types used in io_wait* */
71
+enum fd_types { F_NONE, F_TCPMAIN, F_TCPCONN };
72
+
73
+/* list of tcp connections handled by this process */
74
+static struct tcp_connection* tcp_conn_lst=0;
75
+static io_wait_h io_w; /* io_wait handler*/
76
+static int tcpmain_sock=-1;
65 77
 
66 78
 
67 79
 /* reads next available bytes
... ...
@@ -385,7 +397,7 @@ skip:
385 397
 
386 398
 
387 399
 
388
-int tcp_read_req(struct tcp_connection* con)
400
+int tcp_read_req(struct tcp_connection* con, int* bytes_read)
389 401
 {
390 402
 	int bytes;
391 403
 	int resp;
... ...
@@ -394,6 +406,7 @@ int tcp_read_req(struct tcp_connection* con)
394 406
 	int s;
395 407
 	char c;
396 408
 		
409
+		bytes=-1;
397 410
 		resp=CONN_RELEASE;
398 411
 		s=con->fd;
399 412
 		req=&con->req;
... ...
@@ -520,7 +533,7 @@ again:
520 533
 		
521 534
 		
522 535
 	end_req:
523
-		
536
+		if (bytes_read) *bytes_read=bytes;
524 537
 		return resp;
525 538
 }
526 539
 
... ...
@@ -543,7 +556,8 @@ void release_tcpconn(struct tcp_connection* c, long state, int unix_sock)
543 556
 }
544 557
 
545 558
 
546
-
559
+#ifdef DEBUG_TCP_RECEIVE
560
+/* old code known to work, kept arround for debuging */
547 561
 void tcp_receive_loop(int unix_sock)
548 562
 {
549 563
 	struct tcp_connection* list; /* list with connections in use */
... ...
@@ -680,15 +694,229 @@ skip:
680 694
 		
681 695
 	}
682 696
 }
697
+#else /* DEBUG_TCP_RECEIVE */
698
+
699
+
700
+
701
+/* handle io routine, based on the fd_map type
702
+ * (it will be called from io_wait_loop* )
703
+ * params:  fm  - pointer to a fd hash entry
704
+ *          idx - index in the fd_array (or -1 if not known)
705
+ * return: -1 on error, or when we are not interested any more on reads
706
+ *            from this fd (e.g.: we are closing it )
707
+ *          0 on EAGAIN or when by some other way it is known that no more 
708
+ *            io events are queued on the fd (the receive buffer is empty).
709
+ *            Usefull to detect when there are no more io events queued for
710
+ *            sigio_rt, epoll_et, kqueue.
711
+ *         >0 on successfull read from the fd (when there might be more io
712
+ *            queued -- the receive buffer might still be non-empty)
713
+ */
714
+inline static int handle_io(struct fd_map* fm, int idx)
715
+{	
716
+	int ret;
717
+	int n;
718
+	struct tcp_connection* con;
719
+	int s;
720
+	long resp;
721
+	
722
+	switch(fm->type){
723
+		case F_TCPMAIN:
724
+again:
725
+			ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0);
726
+			DBG("received n=%d con=%p, fd=%d\n", n, con, s);
727
+			if (n<0){
728
+				if (errno == EWOULDBLOCK || errno == EAGAIN){
729
+					ret=0;
730
+					break;
731
+				}else if (errno == EINTR) goto again;
732
+				else{
733
+					LOG(L_CRIT,"BUG: tcp_receive: handle_io: read_fd: %s \n",
734
+							strerror(errno));
735
+						abort(); /* big error*/
736
+				}
737
+			}
738
+			if (n==0){
739
+				LOG(L_ERR, "WARNING: tcp_receive: handle_io: 0 bytes read\n");
740
+				break;
741
+			}
742
+			if (con==0){
743
+					LOG(L_CRIT, "BUG: tcp_receive: handle_io null pointer\n");
744
+					break;
745
+			}
746
+			con->fd=s;
747
+			if (s==-1) {
748
+				LOG(L_ERR, "ERROR: tcp_receive: handle_io: read_fd:"
749
+									"no fd read\n");
750
+				goto con_error;
751
+			}
752
+			if (con==tcp_conn_lst){
753
+				LOG(L_CRIT, "BUG: tcp_receive: handle_io: duplicate"
754
+							" connection received: %p, id %d, fd %d, refcnt %d"
755
+							" state %d (n=%d)\n", con, con->id, con->fd,
756
+							con->refcnt, con->state, n);
757
+				release_tcpconn(con, CONN_ERROR, tcpmain_sock);
758
+				break; /* try to recover */
759
+			}
760
+			/* must be before io_watch_add, io_watch_add might catch some
761
+			 * already existing events => might call handle_io and
762
+			 * handle_io might decide to del. the new connection =>
763
+			 * must be in the list */
764
+			tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev);
765
+			con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
766
+			if (io_watch_add(&io_w, s, F_TCPCONN, con)<0){
767
+				LOG(L_CRIT, "ERROR: tcp_receive: handle_io: failed to add"
768
+						" new socket to the fd list\n");
769
+				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
770
+				goto con_error;
771
+			}
772
+			break;
773
+		case F_TCPCONN:
774
+			con=(struct tcp_connection*)fm->data;
775
+			resp=tcp_read_req(con, &ret);
776
+			if (resp<0){
777
+				ret=-1; /* some error occured */
778
+				io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING);
779
+				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
780
+				con->state=S_CONN_BAD;
781
+				release_tcpconn(con, resp, tcpmain_sock);
782
+			}else{
783
+				/* update timeout */
784
+				con->timeout=get_ticks()+TCP_CHILD_TIMEOUT;
785
+			}
786
+			break;
787
+		case F_NONE:
788
+			LOG(L_CRIT, "BUG: handle_io: empty fd map %p (%d): "
789
+						"{%d, %d, %p}\n", fm, (int)(fm-io_w.fd_hash),
790
+						fm->fd, fm->type, fm->data);
791
+			goto error;
792
+		default:
793
+			LOG(L_CRIT, "BUG: handle_io: uknown fd type %d\n", fm->type); 
794
+			goto error;
795
+	}
796
+	
797
+	return ret;
798
+con_error:
799
+	con->state=S_CONN_BAD;
800
+	release_tcpconn(con, CONN_ERROR, fm->fd);
801
+	return ret;
802
+error:
803
+	return -1;
804
+}
683 805
 
684 806
 
685
-#if 0
686
-int main(int argv, char** argc )
807
+
808
+/* releases expired connections and cleans up bad ones (state<0) */
809
+static inline void tcp_receive_timeout()
687 810
 {
688
-	printf("starting tests\n");
689
-	tcp_receive_loop();
811
+	struct tcp_connection* con;
812
+	struct tcp_connection* next;
813
+	int ticks;
814
+	
815
+	ticks=get_ticks();
816
+	for (con=tcp_conn_lst; con; con=next){
817
+		next=con->c_next; /* safe for removing */
818
+		if (con->state<0){   /* kill bad connections */ 
819
+			/* S_CONN_BAD or S_CONN_ERROR, remove it */
820
+			/* fd will be closed in release_tcpconn */
821
+			io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING);
822
+			tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
823
+			con->state=S_CONN_BAD;
824
+			release_tcpconn(con, CONN_ERROR, tcpmain_sock);
825
+			continue;
826
+		}
827
+		if (con->timeout<=ticks){
828
+			/* expired, return to "tcp main" */
829
+			DBG("tcp_receive_loop: %p expired (%d, %d)\n",
830
+					con, con->timeout, ticks);
831
+			/* fd will be closed in release_tcpconn */
832
+			io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING);
833
+			tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
834
+			release_tcpconn(con, CONN_RELEASE, tcpmain_sock);
835
+		}
836
+	}
690 837
 }
691 838
 
692
-#endif
693 839
 
840
+
841
+void tcp_receive_loop(int unix_sock)
842
+{
843
+	
844
+	/* init */
845
+	tcpmain_sock=unix_sock; /* init com. socket */
846
+	if (init_io_wait(&io_w, tcp_max_fd_no, tcp_poll_method)<0)
847
+		goto error;
848
+	/* add the unix socket */
849
+	if (io_watch_add(&io_w, tcpmain_sock, F_TCPMAIN, 0)<0){
850
+		LOG(L_CRIT, "ERROR: tcp_receive_loop: init: failed to add socket "
851
+							" to the fd list\n");
852
+		goto error;
853
+	}
854
+	/* main loop */
855
+	switch(io_w.poll_method){
856
+		case POLL_POLL:
857
+				while(1){
858
+					io_wait_loop_poll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
859
+					tcp_receive_timeout();
860
+				}
861
+				break;
862
+#ifdef HAVE_SELECT
863
+		case POLL_SELECT:
864
+			while(1){
865
+				io_wait_loop_select(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
866
+				tcp_receive_timeout();
867
+			}
868
+			break;
869
+#endif
870
+#ifdef HAVE_SIGIO_RT
871
+		case POLL_SIGIO_RT:
872
+			while(1){
873
+				io_wait_loop_sigio_rt(&io_w, TCP_CHILD_SELECT_TIMEOUT);
874
+				tcp_receive_timeout();
875
+			}
876
+			break;
877
+#endif
878
+#ifdef HAVE_EPOLL
879
+		case POLL_EPOLL_LT:
880
+			while(1){
881
+				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
882
+				tcp_receive_timeout();
883
+			}
884
+			break;
885
+		case POLL_EPOLL_ET:
886
+			while(1){
887
+				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 1);
888
+				tcp_receive_timeout();
889
+			}
890
+			break;
694 891
 #endif
892
+#ifdef HAVE_KQUEUE
893
+		case POLL_KQUEUE:
894
+			while(1){
895
+				io_wait_loop_kqueue(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
896
+				tcp_receive_timeout();
897
+			}
898
+			break;
899
+#endif
900
+#ifdef HAVE_DEVPOLL
901
+		case POLL_DEVPOLL:
902
+			while(1){
903
+				io_wait_loop_devpoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
904
+				tcp_receive_timeout();
905
+			}
906
+			break;
907
+#endif
908
+		default:
909
+			LOG(L_CRIT, "BUG: tcp_receive_loop: no support for poll method "
910
+					" %s (%d)\n", 
911
+					poll_method_name(io_w.poll_method), io_w.poll_method);
912
+			goto error;
913
+	}
914
+error:
915
+	destroy_io_wait(&io_w);
916
+	LOG(L_CRIT, "ERROR: tcp_receive_loop: exiting...");
917
+	exit(-1);
918
+}
919
+
920
+#endif /* DEBUG_TCP_RECEIVE */
921
+
922
+#endif /* USE_TCP */