1 #include <string.h>
2 
3 #include "memory_mgt.h"
4 #include "debug.h"
5 #include "tcp_send_buffer.h"
6 #include "tcp_sb_queue.h"
7 
8 #define MAX(a, b) ((a)>(b)?(a):(b))
9 #define MIN(a, b) ((a)<(b)?(a):(b))
10 
11 /*----------------------------------------------------------------------------*/
12 struct sb_manager
13 {
14 	size_t chunk_size;
15 	uint32_t cur_num;
16 	uint32_t cnum;
17 	mem_pool_t mp;
18 	sb_queue_t freeq;
19 
20 } sb_manager;
21 /*----------------------------------------------------------------------------*/
22 uint32_t
23 SBGetCurnum(sb_manager_t sbm)
24 {
25 	return sbm->cur_num;
26 }
27 /*----------------------------------------------------------------------------*/
28 sb_manager_t
29 SBManagerCreate(size_t chunk_size, uint8_t disable_rings, uint32_t concurrency)
30 {
31 	sb_manager_t sbm = (sb_manager_t)calloc(1, sizeof(sb_manager));
32 	if (!sbm) {
33 		TRACE_ERROR("SBManagerCreate() failed. %s\n", strerror(errno));
34 		return NULL;
35 	}
36 
37 	sbm->chunk_size = chunk_size;
38 	sbm->cnum = concurrency;
39 	sbm->mp = (mem_pool_t)MPCreate(chunk_size,
40 				       (uint64_t)chunk_size * (!disable_rings * concurrency),
41 				       0);
42 	if (!sbm->mp) {
43 		TRACE_ERROR("Failed to create mem pool for sb.\n");
44 		free(sbm);
45 		return NULL;
46 	}
47 
48 	sbm->freeq = CreateSBQueue(concurrency);
49 	if (!sbm->freeq) {
50 		TRACE_ERROR("Failed to create free buffer queue.\n");
51 		MPDestroy(sbm->mp);
52 		free(sbm);
53 		return NULL;
54 	}
55 
56 	return sbm;
57 }
58 /*----------------------------------------------------------------------------*/
59 struct tcp_send_buffer *
60 SBInit(sb_manager_t sbm, uint32_t init_seq)
61 {
62 	struct tcp_send_buffer *buf;
63 
64 	/* first try dequeue from free buffer queue */
65 	buf = SBDequeue(sbm->freeq);
66 	if (!buf) {
67 		buf = (struct tcp_send_buffer *)malloc(sizeof(struct tcp_send_buffer));
68 		if (!buf) {
69 			perror("calloc() for buf");
70 			return NULL;
71 		}
72 		buf->data = MPAllocateChunk(sbm->mp);
73 		if (!buf->data) {
74 			TRACE_ERROR("Failed to fetch memory chunk for data.\n");
75 			free(buf);
76 			return NULL;
77 		}
78 		sbm->cur_num++;
79 	}
80 
81 	buf->head = buf->data;
82 
83 	buf->head_off = buf->tail_off = 0;
84 	buf->len = buf->cum_len = 0;
85 	buf->size = sbm->chunk_size;
86 
87 	buf->init_seq = buf->head_seq = init_seq;
88 
89 	return buf;
90 }
91 /*----------------------------------------------------------------------------*/
92 void
93 SBFree(sb_manager_t sbm, struct tcp_send_buffer *buf)
94 {
95 	if (!buf)
96 		return;
97 
98 	SBEnqueue(sbm->freeq, buf);
99 }
100 /*----------------------------------------------------------------------------*/
101 size_t
102 SBPut(sb_manager_t sbm, struct tcp_send_buffer *buf, const void *data, size_t len)
103 {
104 	size_t to_put;
105 
106 	if (len <= 0)
107 		return 0;
108 
109 	/* if no space, return -2 */
110 	to_put = MIN(len, buf->size - buf->len);
111 	if (to_put <= 0) {
112 		return -2;
113 	}
114 
115 	if (buf->tail_off + to_put < buf->size) {
116 		/* if the data fit into the buffer, copy it */
117 		memcpy(buf->data + buf->tail_off, data, to_put);
118 		buf->tail_off += to_put;
119 	} else {
120 		/* if buffer overflows, move the existing payload and merge */
121 		memmove(buf->data, buf->head, buf->len);
122 		buf->head = buf->data;
123 		buf->head_off = 0;
124 		memcpy(buf->head + buf->len, data, to_put);
125 		buf->tail_off = buf->len + to_put;
126 	}
127 	buf->len += to_put;
128 	buf->cum_len += to_put;
129 
130 	return to_put;
131 }
132 /*----------------------------------------------------------------------------*/
133 size_t
134 SBRemove(sb_manager_t sbm, struct tcp_send_buffer *buf, size_t len)
135 {
136 	size_t to_remove;
137 
138 	if (len <= 0)
139 		return 0;
140 
141 	to_remove = MIN(len, buf->len);
142 	if (to_remove <= 0) {
143 		return -2;
144 	}
145 
146 	buf->head_off += to_remove;
147 	buf->head = buf->data + buf->head_off;
148 	buf->head_seq += to_remove;
149 	buf->len -= to_remove;
150 
151 	/* if buffer is empty, move the head to 0 */
152 	if (buf->len == 0 && buf->head_off > 0) {
153 		buf->head = buf->data;
154 		buf->head_off = buf->tail_off = 0;
155 	}
156 
157 	return to_remove;
158 }
159 /*---------------------------------------------------------------------------*/
160