Browse code

core/tcp: clone received message over tcp in local buffer

- receive_msg() got pointer inside tcp stream as rcv buffer, linking it to
msg->buf, but there are places where the content of msg->buf is
changed (topoh, msg_apply_changes) which can result in corruption of
tcp stream content
- added a wrapper function receive_tcp_msg() to clone the content and
have same behaviour as for udp or sctp
- reported by Hugh Waite, FS#185

Daniel-Constantin Mierla authored on 02/12/2011 12:05:55
Showing 1 changed files
... ...
@@ -848,6 +848,62 @@ skip:
848 848
 }
849 849
 
850 850
 
851
+/**
852
+ * @brief wrapper around receive_msg() to clone the tcpbuf content
853
+ *
854
+ * When receiving over TCP, tcpbuf points inside the TCP stream buffer, but during
855
+ * processing of config, msg->buf content might be changed and may corrupt
856
+ * the content of the stream. Safer, make a clone of buf content in a local
857
+ * buffer and give that to receive_msg() to link to msg->buf
858
+ */
859
+int receive_tcp_msg(char* tcpbuf, unsigned int len, struct receive_info* rcv_info)
860
+{
861
+#ifdef DYN_BUF
862
+	char *buf = NULL;
863
+#else
864
+	static char *buf = NULL;
865
+	static unsigned int bsize = 0;
866
+#endif
867
+	int blen;
868
+
869
+	/* min buffer size is BUF_SIZE */
870
+	blen = len;
871
+	if(blen < BUF_SIZE)
872
+		blen = BUF_SIZE;
873
+
874
+#ifdef DYN_BUF
875
+	buf=pkg_malloc(blen+1);
876
+	if (buf==0) {
877
+		LM_ERR("could not allocate receive buffer\n");
878
+		return -1;
879
+	}
880
+#else
881
+	/* allocate buffer when needed
882
+	 * - no buffer yet
883
+	 * - existing buffer too small (min size is BUF_SIZE - to accomodate most
884
+	 *   of SIP messages; expected larger for HTTP/XCAP)
885
+	 * - existing buffer too large (e.g., we got a too big message in the past,
886
+	 *   let's free it)
887
+	 *
888
+	 * - also, use system memory, not to eat from PKG (same as static buffer
889
+	 *   from PKG pov)
890
+	 */
891
+	if(buf==NULL || bsize < blen || blen < bsize/2) {
892
+		if(buf!=NULL)
893
+			free(buf);
894
+		buf=malloc(blen+1);
895
+		if (buf==0) {
896
+			LM_ERR("could not allocate receive buffer\n");
897
+			return -1;
898
+		}
899
+		bsize = blen;
900
+	}
901
+#endif
902
+
903
+	memcpy(buf, tcpbuf, len);
904
+	buf[len] = '\0';
905
+	return receive_msg(buf, len, rcv_info);
906
+}
851 907
 
852 908
 int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
853 909
 {
... ...
@@ -932,7 +988,7 @@ again:
932 932
 			/* if we are here everything is nice and ok*/
933 933
 			resp=CONN_RELEASE;
934 934
 #ifdef EXTRA_DEBUG
935
-			DBG("calling receive_msg(%p, %d, )\n",
935
+			DBG("receiving msg(%p, %d, )\n",
936 936
 					req->start, (int)(req->parsed-req->start));
937 937
 #endif
938 938
 			/* rcv.bind_address should always be !=0 */
... ...
@@ -970,12 +1026,12 @@ again:
970 970
 			if (unlikely(req->state==H_HTTP11_CHUNK_FINISH)){
971 971
 				/* http chunked request */
972 972
 				req->body[req->content_len] = 0;
973
-				ret = receive_msg(req->start,
973
+				ret = receive_tcp_msg(req->start,
974 974
 						req->body + req->content_len - req->start,
975 975
 						&con->rcv);
976 976
 			}else
977 977
 #endif
978
-				ret = receive_msg(req->start, req->parsed-req->start,
978
+				ret = receive_tcp_msg(req->start, req->parsed-req->start,
979 979
 									&con->rcv);
980 980
 				
981 981
 			if (unlikely(ret < 0)) {