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
SBGetCurnum(sb_manager_t sbm)23 SBGetCurnum(sb_manager_t sbm)
24 {
25 return sbm->cur_num;
26 }
27 /*----------------------------------------------------------------------------*/
28 sb_manager_t
SBManagerCreate(size_t chunk_size,uint8_t disable_rings,uint32_t concurrency)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 *
SBInit(sb_manager_t sbm,uint32_t init_seq)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
SBFree(sb_manager_t sbm,struct tcp_send_buffer * buf)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
SBPut(sb_manager_t sbm,struct tcp_send_buffer * buf,const void * data,size_t len)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
SBRemove(sb_manager_t sbm,struct tcp_send_buffer * buf,size_t len)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