[asterisk-commits] kpfleming: branch 1.4 r67270 - /branches/1.4/channels/chan_iax2.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Jun 5 07:35:53 MST 2007


Author: kpfleming
Date: Tue Jun  5 09:35:52 2007
New Revision: 67270

URL: http://svn.digium.com/view/asterisk?view=rev&rev=67270
Log:
ensure that a burst of full frames (AST_FRAME_DTMF being the prime example) will not be processed out of order... this is a brute force fix, but seems to be the safest fix for now (thanks to the Digium PQ department for finding this bug)


Modified:
    branches/1.4/channels/chan_iax2.c

Modified: branches/1.4/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/channels/chan_iax2.c?view=diff&rev=67270&r1=67269&r2=67270
==============================================================================
--- branches/1.4/channels/chan_iax2.c (original)
+++ branches/1.4/channels/chan_iax2.c Tue Jun  5 09:35:52 2007
@@ -703,6 +703,12 @@
 	time_t checktime;
 	ast_mutex_t lock;
 	ast_cond_t cond;
+	unsigned short ffcallno;		/* if this thread is processing a full frame, the
+						   callno for that frame will be here, so we can
+						   avoid dispatching any more full frames for that
+						   callno to other threads */
+	struct sockaddr_in ffsin;		/* remember the peer IP/port number for a full frame
+						   in process */
 };
 
 /* Thread lists */
@@ -879,6 +885,11 @@
 		}
 		AST_LIST_UNLOCK(&dynamic_list);
 	}
+
+	/* this thread is not processing a full frame (since it is idle),
+	   so ensure that the field for the full frame call number is empty */
+	thread->ffcallno = 0;
+	memset(&thread->ffsin, 0, sizeof(thread->ffsin));
 
 	return thread;
 }
@@ -6260,37 +6271,68 @@
 	struct iax2_thread *thread;
 	socklen_t len;
 	time_t t;
-	static time_t last_errtime=0;
-
-	thread = find_idle_thread();
-	if (thread) {
-		len = sizeof(thread->iosin);
-		thread->iofd = fd;
-		thread->iores = recvfrom(fd, thread->buf, sizeof(thread->buf), 0,(struct sockaddr *) &thread->iosin, &len);
-		if (thread->iores < 0) {
-			if (errno != ECONNREFUSED && errno != EAGAIN)
-				ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
-			handle_error();
-			insert_idle_thread(thread);
-			return 1;
-		}
-		if (test_losspct && ((100.0 * ast_random() / (RAND_MAX + 1.0)) < test_losspct)) { /* simulate random loss condition */
-			insert_idle_thread(thread);
-			return 1;
-		}
-		/* Mark as ready and send on its way */
-		thread->iostate = IAX_IOSTATE_READY;
-#ifdef DEBUG_SCHED_MULTITHREAD
-		ast_copy_string(thread->curfunc, "socket_process", sizeof(thread->curfunc));
-#endif
-		signal_condition(&thread->lock, &thread->cond);
-	} else {
+	static time_t last_errtime = 0;
+	struct ast_iax2_full_hdr *fh;
+
+	if (!(thread = find_idle_thread())) {
 		time(&t);
 		if (t != last_errtime)
 			ast_log(LOG_NOTICE, "Out of idle IAX2 threads for I/O, pausing!\n");
 		last_errtime = t;
 		usleep(1);
-	}
+		return 1;
+	}
+
+	len = sizeof(thread->iosin);
+	thread->iofd = fd;
+	thread->iores = recvfrom(fd, thread->buf, sizeof(thread->buf), 0, (struct sockaddr *) &thread->iosin, &len);
+	if (thread->iores < 0) {
+		if (errno != ECONNREFUSED && errno != EAGAIN)
+			ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
+		handle_error();
+		insert_idle_thread(thread);
+		return 1;
+	}
+	if (test_losspct && ((100.0 * ast_random() / (RAND_MAX + 1.0)) < test_losspct)) { /* simulate random loss condition */
+		insert_idle_thread(thread);
+		return 1;
+	}
+	
+	/* Determine if this frame is a full frame; if so, and any thread is currently
+	   processing a full frame for the same callno from this peer, then drop this
+	   frame (and the peer will retransmit it) */
+	fh = (struct ast_iax2_full_hdr *) thread->buf;
+	if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
+		struct iax2_thread *cur = NULL;
+		
+		AST_LIST_LOCK(&active_list);
+		AST_LIST_TRAVERSE(&active_list, cur, list) {
+			if ((cur->ffcallno == ntohs(fh->scallno)) &&
+			    !memcmp(&cur->ffsin, &thread->iosin, sizeof(cur->ffsin)))
+				break;
+		}
+		AST_LIST_UNLOCK(&active_list);
+		if (cur) {
+			/* we found another thread processing a full frame for this call,
+			   so we can't accept this frame */
+			ast_log(LOG_WARNING, "Dropping full frame from %s (callno %d) received too rapidly\n",
+				ast_inet_ntoa(thread->iosin.sin_addr), cur->ffcallno);
+			insert_idle_thread(thread);
+			return 1;
+		} else {
+			/* this thread is going to process this frame, so mark it */
+			thread->ffcallno = ntohs(fh->scallno);
+			memcpy(&thread->ffsin, &thread->iosin, sizeof(thread->ffsin));
+		}
+	}
+	
+	/* Mark as ready and send on its way */
+	thread->iostate = IAX_IOSTATE_READY;
+#ifdef DEBUG_SCHED_MULTITHREAD
+	ast_copy_string(thread->curfunc, "socket_process", sizeof(thread->curfunc));
+#endif
+	signal_condition(&thread->lock, &thread->cond);
+
 	return 1;
 }
 



More information about the asterisk-commits mailing list