catalinux / Conn (public) (License: LGPLv2) (since 2016-03-01) (hash sha1)
Net library for easy building ipv4/ipv6 network daemons/clients
List of commits:
Subject Hash Author Date (UTC)
Added support for multiple polling engines and added epoll engine. ecf8b9c40ddae857b9d7dd72dee6596c1689db3e Catalin(ux) M. BOIE 2009-02-23 10:02:39
Duilder updates. db4999d6737f84d17c3b9aa5863483c91d6ed1a7 Catalin(ux) M. BOIE 2008-12-08 14:17:02
Bump up the version to 1.0.11. c623ba1f66e79d758d88407b6224c3574d9fd730 Catalin(ux) M. BOIE 2008-07-16 06:38:33
Added Conn_for_every_line. e7b9ae7009aa9a5cafa1f0f4e3916729f69dbb6b Catalin(ux) M. BOIE 2008-07-15 14:38:29
Bump version to 1.0.10. 4919629756fe6236e2ff75e646e612ed534353e8 Catalin(ux) M. BOIE 2008-07-04 09:23:00
Updated duilder. a20257fddc85103b43978c64d9cd4a5d4c1451ea Catalin(ux) M. BOIE 2008-07-04 09:14:18
Added SRPM_POST_RUN duilder config variable. f7c007d745d147f285ad8bc0a9bdfea3a7d832c0 Catalin(ux) M. BOIE 2008-07-04 09:13:47
Changed my e-mail address and URL. 9353a5fd0cad934232e41b23ee10872f33df2da1 Catalin(ux) M. BOIE 2008-07-04 09:13:10
Updated .gitignore. c40b1c4bf37a2b43804e39444571110eb79be466 Catalin(ux) M. BOIE 2008-07-04 09:07:56
Added .gitignore for examples directory. fc20d411e784066c30e3abe3d77989168fca1ee9 Catalin(ux) M. BOIE 2008-07-04 09:07:33
Added Conn_get_line. 5916ac4c9544d242a21ac50178efae893dff4806 Catalin(ux) M. BOIE 2008-07-04 08:59:27
Prepared to use duilder (my custom builder). 058d181795e64c0d1a82d587e7b1d858b7af87b2 Catalin(ux) M. BOIE 2008-03-21 13:37:19
Populated .gitignore file. e549ac0271ac654f039d5a04a0708d25030b0ed6 Catalin(ux) M. BOIE 2008-03-21 13:12:49
Replaced umbrella with embedromix. 6b6671cce7f0a2c98ac27705ad638c4e1bc52213 Catalin(ux) M. BOIE 2007-10-03 21:56:40
Incremented revision. e79bace79bb15f59133841a144ef1ff04e516cd5 Catalin(ux) M. BOIE 2007-10-03 21:55:25
Changed changelog. 00c9dba4e97d924299fd992ff8f4e20fce5c770e Catalin(ux) M. BOIE 2007-10-03 20:43:21
First import. 5ad0e7b8aa527aaebab52c53b45c36257fce5d0a Catalin(ux) M. BOIE 2007-10-03 20:20:26
Commit ecf8b9c40ddae857b9d7dd72dee6596c1689db3e - Added support for multiple polling engines and added epoll engine.
Signed-off-by: Catalin(ux) M. BOIE <catab@embedromix.ro>
Author: Catalin(ux) M. BOIE
Author date (UTC): 2009-02-23 10:02
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2009-03-05 15:31
Parent(s): db4999d6737f84d17c3b9aa5863483c91d6ed1a7
Signing key:
Tree: 98e4b6555729521ccc32ff8659081aa9900a9ac0
File Lines added Lines deleted
.gitignore 2 1
Conn.c 551 1297
Conn.h 4 210
Conn_config.h.in 2 0
Conn_engine_core.c 865 0
Conn_engine_core.h 76 35
Conn_engine_epoll.c 182 0
Conn_engine_epoll.h 23 0
Conn_engine_poll.c 152 0
Conn_engine_poll.h 22 0
Makefile.in 12 3
TODO 3 0
duilder 30 19
duilder.conf 1 0
examples/Makefile 9 8
examples/c.c 19 28
examples/c.run 3 0
examples/line1.c 0 12
examples/raw.c 2 15
examples/raw2.c 0 12
examples/s.c 21 33
examples/s.run 12 1
examples/timeout.c 0 12
examples/udp_s.c 0 12
File .gitignore changed (mode: 100644) (index dff4e6d..762bb46)
1 1 Changelog Changelog
2 Makefile
2 ./Makefile
3 3 Conn.spec Conn.spec
4 Conn_config.h
4 5 *.o *.o
5 6 *.a *.a
6 7 *.so *.so
File Conn.c changed (mode: 100644) (index 4f15ea5..c36c300)
7 7 */ */
8 8
9 9 #include "Conn.h" #include "Conn.h"
10 #include "Conn_engine_poll.h"
11 #include "Conn_engine_epoll.h"
10 12
11 13
12 /* Visible variables */
13 void (*Conn_accept_cb)(struct Conn *C) = NULL;
14 void (*Conn_recv_cb)(struct Conn *C) = NULL;
15 void (*Conn_send_cb)(struct Conn *C) = NULL;
16 void (*Conn_data_cb)(struct Conn *C) = NULL;
17 void (*Conn_close_cb)(struct Conn *C) = NULL;
18 void (*Conn_trigger_cb)(struct Conn *C) = NULL;
19 void (*Conn_error_cb)(struct Conn *C) = NULL;
20 void (*Conn_connected_cb)(struct Conn *C) = NULL;
21
22 char *(*Conn_status_slot_html_cb)(struct Conn *C);
23 char *(*Conn_status_cb)(void);
24
25
26 unsigned int Conn_max_reached = 0;
27 unsigned int Conn_default_ibuf = 128;
28 unsigned int Conn_default_obuf = 128;
29 unsigned int Conn_max_ibuf = 4096000;
30 unsigned int Conn_max_obuf = 4096000;
31
32 /* Max bytes enqueued on one send/recv call */
33 unsigned int Conn_max_send = 32 * 1024;
34 unsigned int Conn_max_recv = 32 * 1024;
35
36 unsigned int Conn_no = 0;
37 unsigned int Conn_max = 0;
38 unsigned long Conn_total = 0;
39 unsigned int Conn_start = 0;
40 unsigned int Conn_pending = 0;
41 struct timeval Conn_now;
42 unsigned short Conn_level = 0; /* debug level */
43
44 14 /* Internal variables */ /* Internal variables */
45 static char Conn_error[512];
46 static struct pollfd *Conn_pfds = NULL;
47 static struct Conn *Conns = NULL;
48 static unsigned int Conn_inited = 0;
49 static unsigned int Conn_accept_is_allowed;
50 static unsigned int Conn_allocated = 0;
51 static unsigned long long Conn_id = 1;
15 /* Engine */
16 static unsigned int Conn_engine;
17 static unsigned int Conn_engine_poll_found;
18 static unsigned int Conn_engine_epoll_found;
19
20 /* Engine functions */
21 static int (*Conn_engine_init)(void);
22 static int (*Conn_engine_shutdown)(void);
23 static int (*Conn_engine_grow)(unsigned int);
24 static int (*Conn_engine_add_obj)(struct Conn *);
25 static int (*Conn_engine_del_obj)(struct Conn *);
26 static int (*Conn_engine_chg_obj)(struct Conn *);
27 static int (*Conn_engine_poll)(int, void (*cb)(struct Conn *C, const int revents));
28 static void (*Conn_engine_move_slot)(const unsigned int dst,
29 const unsigned int src);
52 30
53 static FILE *Conn_Log = NULL;
54 static int debug_band = 11;
55 31
56 32 /* Functions */ /* Functions */
57 33
58 34 /* /*
59 * Difference between two timeval strutures, in milliseconds
35 * Set prefered engine
60 36 */ */
61 long long Conn_time_diff(const struct timeval *t1, const struct timeval *t2)
37 int Conn_engine_set(const unsigned int engine)
62 38 { {
63 return (t1->tv_sec - t2->tv_sec) * 1000
64 + (t1->tv_usec - t2->tv_usec) / 1000;
65 }
39 if (engine == Conn_engine)
40 return 0;
66 41
67 char *Conn_strerror(void)
68 {
69 return Conn_error;
42 if (engine == CONN_ENGINE_POLL) {
43 if (Conn_engine_poll_found == 0) {
44 snprintf(Conn_error, sizeof(Conn_error),
45 "Cannot use engine POLL. Probably not supported.");
46 return -1;
47 }
48
49 #ifdef POLL_FOUND
50 /* Set variables */
51 CONN_POLLIN = POLLIN;
52 CONN_POLLOUT = POLLOUT;
53 CONN_POLLPRI = POLLPRI;
54 CONN_POLLERR = POLLERR;
55 CONN_POLLHUP = POLLHUP;
56 CONN_POLLNVAL = POLLNVAL;
57 CONN_POLLRDNORM = POLLRDNORM;
58 CONN_POLLRDBAND = POLLRDBAND;
59 /* Set functions */
60 Conn_engine_init = Conn_poll_init;
61 Conn_engine_shutdown = Conn_poll_shutdown;
62 Conn_engine_grow = Conn_poll_grow;
63 Conn_engine_add_obj = Conn_poll_add_obj;
64 Conn_engine_del_obj = Conn_poll_del_obj;
65 Conn_engine_chg_obj = Conn_poll_chg_obj;
66 Conn_engine_poll = Conn_poll_poll;
67 Conn_engine_move_slot = Conn_poll_move_slot;
68 #endif
69 } else if (engine == CONN_ENGINE_EPOLL) {
70 if (Conn_engine_epoll_found == 0) {
71 snprintf(Conn_error, sizeof(Conn_error),
72 "Cannot use engine EPOLL. Probably not supported.");
73 return -1;
74 }
75
76 #ifdef EPOLL_FOUND
77 /* Set variables */
78 CONN_POLLIN = EPOLLIN;
79 CONN_POLLOUT = EPOLLOUT;
80 CONN_POLLPRI = EPOLLPRI;
81 CONN_POLLERR = EPOLLERR;
82 CONN_POLLHUP = EPOLLHUP;
83 CONN_POLLNVAL = 0; /* not defined for epoll */
84 CONN_POLLRDNORM = 0; /* not defined for epoll */
85 CONN_POLLRDBAND = 0; /* not defined for epoll */
86 /* Set functions */
87 Conn_engine_init = Conn_epoll_init;
88 Conn_engine_shutdown = Conn_epoll_shutdown;
89 Conn_engine_grow = Conn_epoll_grow;
90 Conn_engine_add_obj = Conn_epoll_add_obj;
91 Conn_engine_del_obj = Conn_epoll_del_obj;
92 Conn_engine_chg_obj = Conn_epoll_chg_obj;
93 Conn_engine_poll = Conn_epoll_poll;
94 Conn_engine_move_slot = Conn_epoll_move_slot;
95 #endif
96 } else {
97 snprintf(Conn_error, sizeof(Conn_error),
98 "Cannot use engine %u because is not supported.", engine);
99 return -1;
100 }
101
102 return 0;
70 103 } }
71 104
72 /* set noblocking */
73 static int Conn_setnonblock(int fd)
105 int Conn_init(unsigned int max)
74 106 { {
75 int ret;
76 long flags;
107 unsigned int ret;
108 unsigned int engine;
77 109
78 flags = fcntl(fd, F_GETFL, 0);
79 if (flags == -1)
80 return -1;
110 if (Conn_inited == 1)
111 return 0;
112
113 Conn_max = max;
81 114
82 flags |= O_NONBLOCK;
115 Conn_no = 0;
116 Conn_total = 0;
117 Conn_max_reached = 0;
118 gettimeofday(&Conn_now, NULL);
119 Conn_start = Conn_now.tv_sec;
120 Conn_accept_is_allowed = 1;
121 Conn_accept_is_allowed_last = 1;
122 Conn_allocated = 0;
123
124 snprintf(Conn_error, sizeof(Conn_error), "%s", "");
83 125
84 ret = fcntl(fd, F_SETFL, flags);
126 #ifdef POLL_FOUND
127 engine = CONN_ENGINE_POLL;
128 Conn_engine_poll_found = 1;
129 #endif
85 130
86 return ret;
87 }
131 #ifdef EPOLL_FOUND
132 engine = CONN_ENGINE_EPOLL;
133 Conn_engine_epoll_found = 1;
134 #endif
88 135
89 static void Log(unsigned short level, char *format, ...)
90 {
91 va_list ap;
92 FILE *out;
136 ret = Conn_engine_set(engine);
137 if (ret != 0)
138 return -1;
93 139
94 if (level > Conn_level)
95 return;
140 ret = Conn_engine_init();
141 if (ret != 0)
142 return -1;
96 143
97 if (Conn_Log == NULL)
98 out = stderr;
99 else
100 out = Conn_Log;
101 fprintf(out, "%ld.%06ld ",
102 Conn_now.tv_sec, Conn_now.tv_usec);
144 Conn_inited = 1;
103 145
104 va_start(ap, format);
105 vfprintf(out, format, ap);
106 va_end(ap);
146 return 0;
107 147 } }
108 148
109 char *Conn_dump(char *buf_src, int len_src)
149 int Conn_enqueue(struct Conn *C, void *buf, size_t count)
110 150 { {
111 int i, j;
112 char tmp[3];
113 char *buf_dst;
114 unsigned char c;
115
116 if (len_src < 0)
117 return strdup("[Error: len < 0]");
118
119 Log(30, "\tConn_dump(%p, len=%d)\n",
120 buf_src, len_src);
121
122 buf_dst = malloc(len_src * 4 + 1);
123 if (buf_dst == NULL)
124 return strdup("Memory allocation error1!");
125
126 j = 0;
127 for (i = 0; i < len_src; i++) {
128 c = buf_src[i];
129 if ((c < 32) || (c > 127)) {
130 buf_dst[j++] = '[';
131 snprintf(tmp, sizeof(tmp), "%02x", c);
132 buf_dst[j++] = tmp[0];
133 buf_dst[j++] = tmp[1];
134 buf_dst[j++] = ']';
135 } else {
136 buf_dst[j++] = c;
137 }
138 }
151 unsigned int slot, r;
152 char *dump;
139 153
140 buf_dst[j] = '\0';
154 if (C == NULL) {
155 Log(0, "ERROR: Somebody try to enqueue something to a NULL conn.\n");
156 return -1;
157 }
141 158
142 /*
143 Log(0, "%s ([%s], %d, [%s], %d\n",
144 __FUNCTION__, buf_src, len_src, buf_dst, len_dst);
145 */
159 if (Conn_level >= 10) {
160 dump = Conn_dump(buf, count);
161 Log(0, "\tTry to enqueue %d bytes to id %llu [%s]...\n",
162 count, C->id, dump);
163 free(dump);
164 }
146 165
147 return buf_dst;
148 }
166 /* we cannot use pointers directly because they can change under us in 'expand' */
167 slot = C->slot;
149 168
150 char *Conn_dumphex(char *buf_src, int len_src)
151 {
152 int i, j;
153 char tmp[3];
154 char *buf_dst;
155 unsigned char c;
156
157 if (len_src < 0)
158 return strdup("[Error: len < 0]");
159
160 Log(30, "\tConn_dumphex(%p, len=%d)\n",
161 buf_src, len_src);
162
163 buf_dst = malloc(len_src * 2 + 1);
164 if (buf_dst == NULL)
165 return strdup("Memory allocation error1!");
166
167 j = 0;
168 for (i = 0; i < len_src; i++) {
169 c = buf_src[i];
170 snprintf(tmp, sizeof(tmp), "%02x", c);
171 buf_dst[j++] = tmp[0];
172 buf_dst[j++] = tmp[1];
169 if (Conns[slot].obuf_size - Conns[slot].obuf_tail < count) {
170 r = Conn_try_expand_buf(&Conns[slot], 0, count);
171 if (r != 0)
172 return -1;
173 173 } }
174 174
175 buf_dst[j] = '\0';
175 memcpy(Conns[slot].obuf + Conns[slot].obuf_tail, buf, count);
176 Conns[slot].obuf_tail += count;
176 177
177 return buf_dst;
178 }
178 Conns[slot].events |= CONN_POLLOUT;
179 Conn_engine_chg_obj(&Conns[slot]);
179 180
180 void Conn_debug(FILE *f, unsigned short debug)
181 {
182 Conn_Log = f;
183 Conn_level = debug;
181 return 0;
184 182 } }
185 183
186 /* Grow Conn structures */
187 static unsigned int Conn_grow(void)
184 static void Conn_free_intern(struct Conn *C)
188 185 { {
189 unsigned int alloc;
190 struct pollfd *p, *set;
191 struct Conn *q, *set2;
186 unsigned int slot;
192 187
193 Log(10, "%s() Try to grow from %d to %d.\n",
194 __FUNCTION__,
195 Conn_allocated, Conn_allocated + 128);
188 slot = C->slot;
196 189
197 alloc = Conn_allocated + 128;
190 Log(7, "Cleaning-up slot in %s state id %llu [%s]...\n",
191 Conn_state(C), C->id, Conn_errno(C));
198 192
199 p = (struct pollfd *) realloc(Conn_pfds, alloc * sizeof(struct pollfd));
200 if (p == NULL)
201 return 0;
193 snprintf(Conn_error, sizeof(Conn_error),
194 "%s", Conn_errno(C));
202 195
203 q = (struct Conn *) realloc(Conns, alloc * sizeof(struct Conn));
204 if (q == NULL) {
205 free(p);
206 return 0;
196 if (C->error_state != CONN_ERROR_USERREQ) {
197 if (Conns[slot].cb_error)
198 Conns[slot].cb_error(C);
199 else if (Conn_error_cb)
200 Conn_error_cb(C);
207 201 } }
208 202
209 set = p + Conn_allocated;
210 memset(set, 0, 128 * sizeof(struct pollfd));
211 Conn_pfds = p;
203 if (Conns[slot].state == CONN_STATE_OPEN) {
204 if (Conns[slot].cb_close)
205 Conns[slot].cb_close(C);
206 else if (Conn_close_cb)
207 Conn_close_cb(&Conns[slot]);
208 }
212 209
213 set2 = q + Conn_allocated;
214 memset(set2, 0, 128 * sizeof(struct Conn));
215 Conns = q;
210 if (Conns[slot].fd > -1) {
211 close(Conns[slot].fd);
212 Conns[slot].fd = -1;
213 }
216 214
217 Conn_allocated = alloc;
215 Conn_engine_del_obj(&Conns[slot]);
218 216
219 return 1;
220 }
217 /* Reset tsend, else we enter in a timeout error loop */
218 Conns[slot].tsend.tv_sec = 0;
219 Conns[slot].tsend.tv_usec = 0;
221 220
222 int Conn_init(unsigned int max)
223 {
224 unsigned int ret;
221 /* Reset the connection attempt time */
222 Conns[slot].conn_syn.tv_sec = 0;
223 Conns[slot].conn_syn.tv_usec = 0;
225 224
226 if (Conn_inited == 1)
227 return 0;
225 if (Conns[slot].flags & CONN_FLAGS_AUTO_RECONNECT) {
226 Conns[slot].tryat = Conn_now.tv_sec + Conns[slot].delay;
227 Conns[slot].error_state = 0;
228 Conns[slot].state = CONN_STATE_CONNECT_0;
228 229
229 Conn_max = max;
230 Conns[slot].ibuf_head = 0;
231 Conns[slot].ibuf_tail = 0;
230 232
231 Conn_no = 0;
232 Conn_total = 0;
233 Conn_max_reached = 0;
234 gettimeofday(&Conn_now, NULL);
235 Conn_start = Conn_now.tv_sec;
236 Conn_accept_is_allowed = 1;
237 Conn_allocated = 0;
233 Conns[slot].obuf_head = 0;
234 Conns[slot].obuf_tail = 0;
238 235
239 snprintf(Conn_error, sizeof(Conn_error), "%s", "");
236 Conn_pending++;
237 } else {
238 Conns[slot].type = Conn_type_UNK;
239 Conns[slot].state = CONN_STATE_FREE;
240 240
241 ret = Conn_grow();
242 if (ret == 0) {
243 snprintf(Conn_error, sizeof(Conn_error),
244 "Cannot grow anymore. Probably memory shortage.");
245 return -1;
246 }
241 /*TODO: add to free list*/
247 242
248 Conn_inited = 1;
243 if (slot < Conn_no - 1) {
244 /* free old mem */
245 if (Conns[slot].ibuf)
246 free(Conns[slot].ibuf);
247 if (Conns[slot].obuf)
248 free(Conns[slot].obuf);
249 249
250 return 0;
250 Conn_engine_move_slot(slot, Conn_no - 1);
251 Conns[slot] = Conns[Conn_no - 1];
252 Conns[slot].slot = slot;
253
254 /* fixes */
255 Conns[Conn_no - 1].ibuf = NULL;
256 Conns[Conn_no - 1].ibuf_size = 0;
257 Conns[Conn_no - 1].obuf = NULL;
258 Conns[Conn_no - 1].obuf_size = 0;
259 }
260
261 if (Conn_no == Conn_max)
262 Conn_accept_is_allowed = 1;
263
264 Conn_no--;
265 }
251 266 } }
252 267
253 static void Conn_accept_allow(unsigned short val)
268 /*
269 * Grow Conn structures (cells)
270 */
271 static int Conn_grow(void)
254 272 { {
255 unsigned int i;
273 int ret;
274 unsigned int alloc;
275 struct Conn *p, *set;
256 276
257 if (Conn_accept_is_allowed == val)
258 return;
277 Log(10, "%s() Try to grow cells from %d to %d.\n",
278 __FUNCTION__,
279 Conn_allocated, Conn_allocated + 128);
259 280
260 Log(10, "%s: Turn accept allow to %d (%s)\n",
261 __FUNCTION__, val, val == 0 ? "off" : "on");
281 alloc = Conn_allocated + 128;
262 282
263 for (i = 0; i < Conn_no; i++) {
264 if (Conns[i].type != Conn_type_MASTER)
265 continue;
283 ret = Conn_engine_grow(alloc);
284 if (ret != 0)
285 return -1;
266 286
267 if (val == 0)
268 Conn_pfds[i].events &= ~POLLIN;
269 else
270 Conn_pfds[i].events |= POLLIN;
271 }
287 p = (struct Conn *) realloc(Conns, alloc * sizeof(struct Conn));
288 if (p == NULL)
289 return -1;
290
291 set = p + Conn_allocated;
292 memset(set, 0, 128 * sizeof(struct Conn));
293 Conns = p;
294
295 Conn_allocated = alloc;
272 296
273 Conn_accept_is_allowed = val;
297 return 0;
274 298 } }
275 299
276 /* Alloc a Conn structure */
300 /*
301 * Allocs a Conn structure
302 */
277 303 static struct Conn *Conn_alloc(void) static struct Conn *Conn_alloc(void)
278 304 { {
279 305 unsigned int slot, growok; unsigned int slot, growok;
 
... ... static struct Conn *Conn_alloc(void)
291 317
292 318 if (Conn_allocated == Conn_no) { if (Conn_allocated == Conn_no) {
293 319 growok = Conn_grow(); growok = Conn_grow();
294 if (growok == 0) {
320 if (growok != 0) {
295 321 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
296 322 "Cannot grow anymore. Probably memory shortage."); "Cannot grow anymore. Probably memory shortage.");
297 323 return NULL; return NULL;
 
... ... static struct Conn *Conn_alloc(void)
345 371 Conns[slot].band_tokens = 0; Conns[slot].band_tokens = 0;
346 372 Conns[slot].band_lasttime = Conn_now; Conns[slot].band_lasttime = Conn_now;
347 373
348 Conn_pfds[slot].fd = -1;
349 Conn_pfds[slot].events = 0;
350 Conn_pfds[slot].revents = 0;
374 Conns[slot].fd = -1;
375 Conns[slot].events = 0;
376 Conns[slot].revents = 0;
351 377 Conns[slot].state = CONN_STATE_EMPTY; Conns[slot].state = CONN_STATE_EMPTY;
352 378
353 379 Conns[slot].flags = 0; Conns[slot].flags = 0;
 
... ... static struct Conn *Conn_alloc(void)
358 384 slot, Conn_no); slot, Conn_no);
359 385
360 386 if (Conn_no == Conn_max) if (Conn_no == Conn_max)
361 Conn_accept_allow(0);
387 Conn_accept_is_allowed = 0;
362 388
363 389 return &Conns[slot]; return &Conns[slot];
364 390 } }
365 391
366 /*
367 * If put buffer is empty, just mark for closing.
368 * If we have data, set the flag to do the closing after send.
369 */
370 void Conn_close(struct Conn *C)
392 struct Conn *Conn_socket(int domain, int type, int port)
371 393 { {
372 if (C->obuf_head == C->obuf_tail)
373 C->error_state = CONN_ERROR_USERREQ;
374 else
375 C->flags |= CONN_FLAGS_CLOSE_AFTER_SEND;
376 }
394 struct Conn *C;
395 int i, ret;
396 struct sockaddr *psa = NULL;
397 struct sockaddr_in sa;
398 struct sockaddr_in6 sa6;
399 int sock_len = 0;
400 char *addr = "?";
401 int do_bind = 1, do_listen = 1;
402 int protocol = 0;
403 int first_state;
377 404
378 /*
379 * Returns string representation of errno code
380 */
381 static char *Conn_errno(struct Conn *C)
382 {
383 static char buf[256];
384 char *is;
385
386 switch (C->error_state) {
387 case CONN_ERROR_USERREQ: is = "user"; break;
388 case CONN_ERROR_POLL: is = "poll"; break;
389 case CONN_ERROR_RECV: is = "recv"; break;
390 case CONN_ERROR_SEND: is = "send"; break;
391 case CONN_ERROR_SOCKET: is = "socket"; break;
392 case CONN_ERROR_HANGUP: is = "hangup"; break;
393 case CONN_ERROR_GETADDRINFO: is = "lookup error"; break;
394 case CONN_ERROR_EXPIRED: is = "expired"; break;
395 case CONN_ERROR_ACCEPT: is = "accept"; break;
396 case CONN_ERROR_MEM: is = "allocation failed"; break;
397 case CONN_ERROR_CONNECT: is = "connect"; break;
398 case CONN_ERROR_READ_TIMEOUT: is = "read timeout"; break;
399 case CONN_ERROR_CONN_TIMEOUT: is = "conn timeout"; break;
400
401 default: is = "?";
402 }
405 switch (domain) {
406 case PF_INET:
407 memset(&sa, 0, sizeof(sa));
408 sa.sin_family = AF_INET;
409 sa.sin_addr.s_addr = htonl(INADDR_ANY);
410 sa.sin_port = htons(port);
411 psa = (struct sockaddr *) &sa;
412 sock_len = sizeof(sa);
413 addr = "0.0.0.0";
414 if (type == SOCK_STREAM) {
415 first_state = CONN_STATE_LISTEN;
416 } else if (type == SOCK_DGRAM) {
417 do_listen = 0;
418 first_state = CONN_STATE_OPEN;
419 }
420 break;
403 421
404 snprintf(buf, sizeof(buf), "%s (%s)",
405 is, strerror(C->xerrno));
422 case PF_INET6:
423 memset(&sa6, 0, sizeof(sa6));
424 sa6.sin6_family = AF_INET6;
425 ret = inet_pton(AF_INET6, "::", &sa6.sin6_addr);
426 if (ret < 0) {
427 snprintf(Conn_error, sizeof(Conn_error),
428 "inet_pton(::) failed");
429 return NULL;
430 }
431 sa6.sin6_port = htons(port);
432 psa = (struct sockaddr *) &sa6;
433 sock_len = sizeof(sa6);
434 addr = "::";
435 if (type == SOCK_STREAM) {
436 first_state = CONN_STATE_LISTEN;
437 } else if (type == SOCK_DGRAM) {
438 do_listen = 0;
439 first_state = CONN_STATE_OPEN;
440 }
441 break;
406 442
407 return buf;
408 }
443 case PF_PACKET:
444 do_bind = 0;
445 protocol = htons(port);
446 first_state = CONN_STATE_OPEN;
447 break;
409 448
410 static char *Conn_state(struct Conn *C)
411 {
412 switch (C->state) {
413 case CONN_STATE_FREE: return "FREE";
414 case CONN_STATE_EMPTY: return "EMPTY";
415 case CONN_STATE_OPEN: return "OPEN";
416 case CONN_STATE_LISTEN: return "LISTEN";
417 case CONN_STATE_CONNECT_0: return "CONN0";
418 case CONN_STATE_CONNECT_a: return "CONNa";
419 case CONN_STATE_CONNECT_b: return "CONNb";
420
421 default: return "BUG?";
422 }
423 }
424
425 static void Conn_free_intern(struct Conn *C)
426 {
427 unsigned int slot;
428
429 slot = C->slot;
430
431 Log(7, "Cleaning-up slot in %s state id %llu [%s]...\n",
432 Conn_state(C), C->id, Conn_errno(C));
433
434 snprintf(Conn_error, sizeof(Conn_error),
435 "%s", Conn_errno(C));
436
437 if (C->error_state != CONN_ERROR_USERREQ) {
438 if (Conns[slot].cb_error)
439 Conns[slot].cb_error(C);
440 else if (Conn_error_cb)
441 Conn_error_cb(C);
442 }
443
444 if (Conns[slot].state == CONN_STATE_OPEN) {
445 if (Conns[slot].cb_close)
446 Conns[slot].cb_close(C);
447 else if (Conn_close_cb)
448 Conn_close_cb(&Conns[slot]);
449 }
450
451 if (Conn_pfds[slot].fd > -1) {
452 close(Conn_pfds[slot].fd);
453 Conn_pfds[slot].fd = -1;
454 }
455
456 /* Reset tsend, else we enter in a timeout error loop */
457 Conns[slot].tsend.tv_sec = 0;
458 Conns[slot].tsend.tv_usec = 0;
459
460 Conn_pfds[slot].events = 0;
461 Conn_pfds[slot].revents = 0;
462
463 /* Reset the connection attempt time */
464 Conns[slot].conn_syn.tv_sec = 0;
465 Conns[slot].conn_syn.tv_usec = 0;
466
467 if (Conns[slot].flags & CONN_FLAGS_AUTO_RECONNECT) {
468 Conns[slot].tryat = Conn_now.tv_sec + Conns[slot].delay;
469 Conns[slot].error_state = 0;
470 Conns[slot].state = CONN_STATE_CONNECT_0;
471
472 Conns[slot].ibuf_head = 0;
473 Conns[slot].ibuf_tail = 0;
474
475 Conns[slot].obuf_head = 0;
476 Conns[slot].obuf_tail = 0;
477
478 Conn_pending++;
479 } else {
480 Conns[slot].type = Conn_type_UNK;
481 Conns[slot].state = CONN_STATE_FREE;
482
483 if (slot < Conn_no - 1) {
484 Log(10, "Move last pfd/Conn entry %d -> %d...\n",
485 Conn_no - 1, slot);
486
487 /* free old mem */
488 if (Conns[slot].ibuf)
489 free(Conns[slot].ibuf);
490 if (Conns[slot].obuf)
491 free(Conns[slot].obuf);
492
493 Conn_pfds[slot] = Conn_pfds[Conn_no - 1];
494 Conns[slot] = Conns[Conn_no - 1];
495 Conns[slot].slot = slot;
496
497 /* fix */
498 Conns[Conn_no - 1].ibuf = NULL;
499 Conns[Conn_no - 1].ibuf_size = 0;
500 Conns[Conn_no - 1].obuf = NULL;
501 Conns[Conn_no - 1].obuf_size = 0;
502 }
503
504 Conn_no--;
505
506 Conn_accept_allow(1);
507 }
508 }
509
510 /*
511 * Expand the requested buffer
512 * what = 0 for out buffer, what = 1 for input buffer
513 * returns 0 if OK, -1 on error
514 */
515 int Conn_try_expand_buf(struct Conn *C, int what, int needed)
516 {
517 char *p;
518 unsigned int hm;
519 unsigned int slot, old_size, amount, head, tail;
520
521 slot = C->slot;
522
523 if (what == 0) {
524 head = C->obuf_head;
525 tail = C->obuf_tail;
526 } else {
527 head = C->ibuf_head;
528 tail = C->ibuf_tail;
529 }
530
531 Log(10, "\tTry to expand buffer on slot %u for [%s] needed=%d head=%u tail=%u.\n",
532 slot, what == 0 ? "o" : "i", needed,
533 head, tail);
534
535 amount = needed;
536
537 if (what == 0) {
538 if (amount < Conn_default_obuf)
539 amount = Conn_default_obuf;
540 old_size = Conns[slot].obuf_size;
541 hm = Conns[slot].obuf_size + amount;
542 if (hm > Conn_max_obuf)
543 hm = Conn_max_obuf;
544 p = realloc(Conns[slot].obuf, hm);
545 if (p == NULL) {
546 Log(3, "Cannot realloc obuf!\n");
547 return -1;
548 }
549 Conns[slot].obuf = p;
550 Conns[slot].obuf_size = hm;
551 Log(10, "\tSucces. Old/new size = %u/%u.\n",
552 old_size, Conns[slot].obuf_size);
553 } else {
554 if (amount < Conn_default_ibuf)
555 amount = Conn_default_ibuf;
556 old_size = Conns[slot].ibuf_size;
557 hm = Conns[slot].ibuf_size + amount;
558 if (hm > Conn_max_ibuf)
559 hm = Conn_max_ibuf;
560 p = realloc(Conns[slot].ibuf, hm);
561 if (p == NULL) {
562 Log(3, "Cannot realloc ibuf!\n");
563 return -1;
564 }
565 Conns[slot].ibuf = p;
566 Conns[slot].ibuf_size = hm;
567 Log(10, "\tSucces. Old/new size = %u/%u.\n",
568 old_size, Conns[slot].ibuf_size);
569 }
570
571 return 0;
572 }
573
574 int Conn_enqueue(struct Conn *C, void *buf, size_t count)
575 {
576 unsigned int slot, r;
577 char *dump;
578
579 if (C == NULL) {
580 Log(0, "ERROR: Somebody try to enqueue something to a NULL conn.\n");
581 return -1;
582 }
583
584 if (Conn_level >= 10) {
585 dump = Conn_dump(buf, count);
586 Log(0, "\tTry to enqueue %d bytes to id %llu [%s]...\n",
587 count, C->id, dump);
588 free(dump);
589 }
590
591 /* we cannot use pointers directly because they can change under us */
592 slot = C->slot;
593
594 if (Conns[slot].obuf_size - Conns[slot].obuf_tail < count) {
595 r = Conn_try_expand_buf(&Conns[slot], 0, count);
596 if (r != 0)
597 return -1;
598 }
599
600 memcpy(Conns[slot].obuf + Conns[slot].obuf_tail, buf, count);
601 Conns[slot].obuf_tail += count;
602
603 Conn_pfds[slot].events |= POLLOUT;
604
605 return 0;
606 }
607
608 struct Conn *Conn_socket(int domain, int type, int port)
609 {
610 struct Conn *C;
611 int i, ret;
612 struct sockaddr *psa = NULL;
613 struct sockaddr_in sa;
614 struct sockaddr_in6 sa6;
615 int sock_len = 0;
616 char *addr = "?";
617 unsigned int slot;
618 int do_bind = 1, do_listen = 1;
619 int protocol = 0;
620 int first_state;
621
622 switch (domain) {
623 case PF_INET:
624 memset(&sa, 0, sizeof(sa));
625 sa.sin_family = AF_INET;
626 sa.sin_addr.s_addr = htonl(INADDR_ANY);
627 sa.sin_port = htons(port);
628 psa = (struct sockaddr *) &sa;
629 sock_len = sizeof(sa);
630 addr = "0.0.0.0";
631 if (type == SOCK_STREAM) {
632 first_state = CONN_STATE_LISTEN;
633 } else if (type == SOCK_DGRAM) {
634 do_listen = 0;
635 first_state = CONN_STATE_OPEN;
636 }
637 break;
638
639 case PF_INET6:
640 memset(&sa6, 0, sizeof(sa6));
641 sa6.sin6_family = AF_INET6;
642 ret = inet_pton(AF_INET6, "::", &sa6.sin6_addr);
643 if (ret < 0) {
644 snprintf(Conn_error, sizeof(Conn_error),
645 "inet_pton(::) failed");
646 return NULL;
647 }
648 sa6.sin6_port = htons(port);
649 psa = (struct sockaddr *) &sa6;
650 sock_len = sizeof(sa6);
651 addr = "::";
652 if (type == SOCK_STREAM) {
653 first_state = CONN_STATE_LISTEN;
654 } else if (type == SOCK_DGRAM) {
655 do_listen = 0;
656 first_state = CONN_STATE_OPEN;
657 }
658 break;
659
660 case PF_PACKET:
661 do_bind = 0;
662 protocol = htons(port);
663 first_state = CONN_STATE_OPEN;
664 break;
665
666 default:
667 snprintf(Conn_error, sizeof(Conn_error),
668 "Invalid domain [%d]!", domain);
669 return NULL;
449 default:
450 snprintf(Conn_error, sizeof(Conn_error),
451 "Invalid domain [%d]!", domain);
452 return NULL;
670 453 } }
671 454
672 455 C = Conn_alloc(); C = Conn_alloc();
673 456 if (!C) if (!C)
674 457 return NULL; return NULL;
675 458
676 slot = C->slot;
677
678 Conn_pfds[slot].fd = socket(domain, type, protocol);
679 if (Conn_pfds[slot].fd == -1) {
459 C->fd = socket(domain, type, protocol);
460 if (C->fd == -1) {
680 461 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
681 462 "Cannot create socket (%d, %d, %d) [%s]", "Cannot create socket (%d, %d, %d) [%s]",
682 463 domain, type, protocol, strerror(errno)); domain, type, protocol, strerror(errno));
683 Conns[slot].xerrno = errno;
464 C->xerrno = errno;
684 465 goto out; goto out;
685 466 } }
686 Conn_pfds[slot].events = POLLIN;
687 467
688 Conn_setnonblock(Conn_pfds[slot].fd);
468 Conn_setnonblock(C->fd);
689 469
690 470 if (domain == PF_INET6) { if (domain == PF_INET6) {
691 471 #ifndef IPV6_V6ONLY #ifndef IPV6_V6ONLY
692 472 #define IPV6_V6ONLY 26 #define IPV6_V6ONLY 26
693 473 #endif #endif
694 474 i = 1; i = 1;
695 setsockopt(Conn_pfds[slot].fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i));
475 setsockopt(C->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i, sizeof(i));
696 476 } }
697 477
698 478 /* Default, client */ /* Default, client */
 
... ... struct Conn *Conn_socket(int domain, int type, int port)
700 480
701 481 if (do_bind == 1) { if (do_bind == 1) {
702 482 i = 1; i = 1;
703 setsockopt(Conn_pfds[slot].fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
483 setsockopt(C->fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
704 484
705 ret = bind(Conn_pfds[slot].fd, psa, sock_len);
485 ret = bind(C->fd, psa, sock_len);
706 486 if (ret < 0) { if (ret < 0) {
707 487 snprintf(Conn_error, sizeof(Conn_error), snprintf(Conn_error, sizeof(Conn_error),
708 488 "Cannot bind [%s]", strerror(errno)); "Cannot bind [%s]", strerror(errno));
709 Conns[slot].xerrno = errno;
489 C->xerrno = errno;
710 490 goto out; goto out;
711 491 } }
712 492
713 493 if (do_listen == 1) { if (do_listen == 1) {
714 listen(Conn_pfds[slot].fd, 128);
494 listen(C->fd, 128);
715 495 C->type = Conn_type_MASTER; C->type = Conn_type_MASTER;
716 496 } }
717 497 } }
 
... ... struct Conn *Conn_socket(int domain, int type, int port)
726 506
727 507 C->id = Conn_id++; C->id = Conn_id++;
728 508
729 snprintf(Conns[slot].addr, sizeof(Conns[slot].addr), "%s", addr);
730 Conns[slot].port = port;
509 snprintf(C->addr, sizeof(C->addr), "%s", addr);
510 C->port = port;
731 511
732 Conns[slot].sock_domain = domain;
733 Conns[slot].sock_type = type;
512 C->sock_domain = domain;
513 C->sock_type = type;
734 514
735 return &Conns[slot];
515 C->events = CONN_POLLIN;
516 C->revents = 0;
517
518 ret = Conn_engine_add_obj(C);
519 if (ret != 0) {
520 C->xerrno = 0;
521 goto out;
522 }
523
524 return C;
736 525
737 526 out: out:
738 Conns[slot].error_state = CONN_ERROR_SOCKET;
739 Conn_free_intern(&Conns[slot]);
527 C->error_state = CONN_ERROR_SOCKET;
528 Conn_free_intern(C);
740 529
741 530 return NULL; return NULL;
742 531 } }
743 532
744 void Conn_new(struct Conn *C)
533 struct Conn *Conn_connect(int domain, int type, char *addr, int port)
745 534 { {
535 struct Conn *X;
536 unsigned int Xslot;
537
538 Log(8, "%s(%s, %d)\n",
539 __FUNCTION__, addr, port);
540
541 X = Conn_alloc();
542 if (!X)
543 return NULL;
544
545 Xslot = X->slot;
546
547 Conns[Xslot].type = Conn_type_CLIENT;
548 Conns[Xslot].error_state = 0;
549 Conns[Xslot].state = CONN_STATE_CONNECT_a;
550 snprintf(Conns[Xslot].addr, sizeof(Conns[Xslot].addr), "%s", addr);
551 Conns[Xslot].port = port;
552 Conns[Xslot].sock_domain = domain;
553 Conns[Xslot].sock_type = type;
554 Conns[Xslot].id = Conn_id++;
555 Conns[Xslot].start = Conn_now.tv_sec;
556
557 Conn_pending++;
558
559 return &Conns[Xslot];
746 560 } }
747 561
748 void Conn_accept(struct Conn *C)
562 static void Conn_accept(struct Conn *C)
749 563 { {
750 564 int fd; int fd;
751 565 struct sockaddr *pca; struct sockaddr *pca;
 
... ... void Conn_accept(struct Conn *C)
755 569 struct Conn *X; struct Conn *X;
756 570 unsigned int slot, Xslot; unsigned int slot, Xslot;
757 571
572 Log(10, "Accepting a connection via %s/%d, type %s, domain %s.\n",
573 C->addr, C->port, Conn_type(C), Conn_domain(C));
574
758 575 slot = C->slot; slot = C->slot;
759 576 switch(Conns[slot].sock_domain) { switch(Conns[slot].sock_domain) {
760 577 case PF_INET: case PF_INET:
 
... ... void Conn_accept(struct Conn *C)
779 596 return; return;
780 597 } }
781 598
782 fd = accept(Conn_pfds[slot].fd, pca, &cax_len);
599 fd = accept(Conns[slot].fd, pca, &cax_len);
783 600 if (fd == -1) { if (fd == -1) {
784 601 if (errno == EAGAIN) if (errno == EAGAIN)
785 602 return; return;
 
... ... void Conn_accept(struct Conn *C)
825 642 Conns[Xslot].error_state = 0; Conns[Xslot].error_state = 0;
826 643 Conns[Xslot].state = CONN_STATE_OPEN; Conns[Xslot].state = CONN_STATE_OPEN;
827 644 Conns[Xslot].via = Conns[slot].port; Conns[Xslot].via = Conns[slot].port;
828 Conn_pfds[Xslot].fd = fd;
829 Conn_pfds[Xslot].events = POLLIN;
645 Conns[Xslot].fd = fd;
830 646 Conns[Xslot].sock_domain = Conns[slot].sock_domain; Conns[Xslot].sock_domain = Conns[slot].sock_domain;
831 647 Conns[Xslot].sock_type = Conns[slot].sock_type; Conns[Xslot].sock_type = Conns[slot].sock_type;
832 648 Conns[Xslot].start = Conn_now.tv_sec; Conns[Xslot].start = Conn_now.tv_sec;
833 649 Conns[Xslot].id = Conn_id++; Conns[Xslot].id = Conn_id++;
650 Conns[Xslot].events = CONN_POLLIN;
651 Conns[Xslot].revents = 0;
652
653 Conn_setnonblock(Conns[Xslot].fd);
834 654
835 Conn_setnonblock(Conn_pfds[Xslot].fd);
655 Conn_engine_add_obj(&Conns[Xslot]);
836 656
837 657 if (Conns[slot].cb_accept) if (Conns[slot].cb_accept)
838 658 Conns[slot].cb_accept(&Conns[slot]); Conns[slot].cb_accept(&Conns[slot]);
 
... ... void Conn_accept(struct Conn *C)
842 662 Conn_total++; Conn_total++;
843 663 } }
844 664
845 static void Conn_poll_status(short ev, char *ret)
846 {
847 strcpy(ret, "________");
848
849 if (ev & POLLIN) ret[0] = 'I';
850 if (ev & POLLPRI) ret[1] = 'P';
851 if (ev & POLLOUT) ret[2] = 'O';
852 if (ev & POLLERR) ret[3] = 'E';
853 if (ev & POLLHUP) ret[4] = 'H';
854 if (ev & POLLNVAL) ret[5] = 'V';
855 if (ev & POLLRDNORM) ret[6] = 'r';
856 if (ev & POLLRDBAND) ret[7] = 'R';
857 }
858
859 static char *Conn_domain(struct Conn *C)
665 static void Conn_accept_allow(void)
860 666 { {
861 switch (C->sock_domain) {
862 case PF_INET: return "IPv4";
863 case PF_INET6: return "IPv6";
864 case PF_PACKET: return "PACKET";
667 unsigned int i;
865 668
866 default: return "?";
867 }
868 }
669 if (Conn_accept_is_allowed == Conn_accept_is_allowed_last)
670 return;
869 671
870 static char *Conn_type(struct Conn *C)
871 {
872 switch (C->sock_type) {
873 case SOCK_STREAM: return "stream";
874 case SOCK_DGRAM: return "dgram";
875 case SOCK_RAW: return "raw";
672 Log(10, "%s: Turning accept allow from %d to %d...\n",
673 __FUNCTION__, Conn_accept_is_allowed_last,
674 Conn_accept_is_allowed);
876 675
877 default: return "?";
878 }
879 }
676 for (i = 0; i < Conn_no; i++) {
677 if (Conns[i].type != Conn_type_MASTER)
678 continue;
880 679
881 static char *Conn_socktype(struct Conn *C)
882 {
883 switch (C->type) {
884 case Conn_type_MASTER: return "master";
885 case Conn_type_CLIENT: return "client";
886 case Conn_type_UNK: return "unk";
680 if (Conn_accept_is_allowed == 0)
681 Conns[i].events &= ~CONN_POLLIN;
682 else
683 Conns[i].events |= CONN_POLLIN;
887 684
888 default:
889 return "?";
685 Conn_engine_chg_obj(&Conns[i]);
890 686 } }
687
688 Conn_accept_is_allowed_last = Conn_accept_is_allowed;
891 689 } }
892 690
893 691 /* /*
894 * Returns a nice speed
692 * Add tokens to connection
895 693 */ */
896 void Conn_speed(char *dst, unsigned int dst_len, unsigned int speed)
694 static void Conn_band_update(struct Conn *C)
897 695 { {
898 float sp;
696 unsigned int slot;
697 long diff;
899 698
900 sp = speed;
699 /* no need */
700 if (C->band_width == 0)
701 return;
901 702
902 if (speed < 1000)
903 snprintf(dst, dst_len, "%.2fBps", sp);
904 else if (speed < 1000 * 1000)
905 snprintf(dst, dst_len, "%.2fKBps", sp / 1000);
906 else
907 snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000);
908 }
909
910 char *Conn_status_slot(struct Conn *C)
911 {
912 static char tmp[1024];
913 char polle[16], pollr[16];
914 char speedi[32], speedo[32];
915 unsigned int dT, si, so;
916
917 Conn_poll_status(Conn_pfds[C->slot].events, polle);
918 Conn_poll_status(Conn_pfds[C->slot].revents, pollr);
919
920 dT = Conn_now.tv_sec - C->start;
921 if (dT == 0)
922 dT = 1;
923 si = C->bi / dT;
924 so = C->bo / dT;
925
926 Conn_speed(speedi, sizeof(speedi), si);
927 Conn_speed(speedo, sizeof(speedo), so);
928
929 snprintf(tmp, sizeof(tmp), "%4d fd%4d"
930 " %4s %6s %5s %6s"
931 " %39s/%-5d\n"
932 " Via%-5d [%s][%s] IO=%llu/%llu"
933 " BS=%u/%u S=%s/%s"
934 " T=%ld bw=%u f=%u tk=%u id=%llu\n",
935 C->slot, Conn_pfds[C->slot].fd,
936 Conn_domain(C), Conn_type(C), Conn_socktype(C), Conn_state(C),
937 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
938 C->ibuf_size, C->obuf_size, speedi, speedo,
939 Conn_now.tv_sec - C->start,
940 C->band_width, C->band_factor, C->band_tokens,
941 C->id);
942
943 return tmp;
944 }
945
946 char *Conn_status_slot_html(struct Conn *C)
947 {
948 static char tmp[1024];
949 char polle[16], pollr[16], *ext = "";
950 char speedi[32], speedo[32];
951 unsigned int dT, si, so;
952
953 Conn_poll_status(Conn_pfds[C->slot].events, polle);
954 Conn_poll_status(Conn_pfds[C->slot].revents, pollr);
955
956 dT = Conn_now.tv_sec - C->start;
957 if (dT == 0)
958 dT = 1;
959 si = C->bi / dT;
960 so = C->bo / dT;
961
962 Conn_speed(speedi, sizeof(speedi), si);
963 Conn_speed(speedo, sizeof(speedo), so);
964
965 if (Conn_status_slot_html_cb)
966 ext = Conn_status_slot_html_cb(C);
967
968 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td><td>%d</td>"
969 "<td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
970 "<td>%s/%d</td>"
971 "<td>%d</td><td>%s</td><td>%s</td><td>%llu / %llu</td>"
972 "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>"
973 "<td>%u</td><td>%u</td><td>%u</td>"
974 "%s\n",
975 C->id, C->slot, Conn_pfds[C->slot].fd,
976 Conn_domain(C), Conn_type(C), Conn_socktype(C), Conn_state(C),
977 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
978 C->ibuf_size, C->obuf_size,
979 speedi, speedo, Conn_now.tv_sec - C->start,
980 C->band_width, C->band_factor, C->band_tokens,
981 ext);
982
983 return tmp;
984 }
985
986 /* flags: bit 1 = 1 - html */
987 char *Conn_status(unsigned int flags)
988 {
989 unsigned int len = 0, i, max;
990 struct Conn *C;
991 char tmp[512], tmp_len;
992 char polle[16], pollr[16];
993 char *buf, *slot, *ext = "";
994 char speedi[32], speedo[32];
995 unsigned long long bi, bo, dT;
996
997 max = (Conn_no + 1) * 512 - 1;
998 buf = malloc(max + 1);
999 if (!buf)
1000 return strdup("No enough memory!");
1001
1002 strcpy(buf, "");
1003
1004 gettimeofday(&Conn_now, NULL);
1005 /* TODO: "len += " is incorrect */
1006 tmp_len = snprintf(tmp, sizeof(tmp), "Conn_pending=%d Conn_no/Conn_max=%d/%d Conn_total=%lu Conn_uptime=%lus Conn_allocated=%d\n",
1007 Conn_pending, Conn_no, Conn_max, Conn_total, Conn_now.tv_sec - Conn_start, Conn_allocated);
1008 if (len + tmp_len < max) {
1009 strcat(buf, tmp);
1010 len += tmp_len;
1011 }
1012
1013 if (flags & 1)
1014 if (Conn_status_cb)
1015 ext = Conn_status_cb();
1016
1017 if (flags & 1) {
1018 strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n");
1019 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
1020 strcat(buf, "<td>ID</td>");
1021 strcat(buf, "<td>Slot</td>");
1022 strcat(buf, "<td>FD</td>");
1023 strcat(buf, "<td>Dom</td>");
1024 strcat(buf, "<td>Type</td>");
1025 strcat(buf, "<td>SType</td>");
1026 strcat(buf, "<td>State</td>");
1027 strcat(buf, "<td>Addr/port</td>");
1028 strcat(buf, "<td>Via</td>");
1029 strcat(buf, "<td>Polle</td>");
1030 strcat(buf, "<td>Pollr</td>");
1031 strcat(buf, "<td>BI/BO</td>");
1032 strcat(buf, "<td>BUF I/O</td>");
1033 strcat(buf, "<td>Speed I/O</td>");
1034 strcat(buf, "<td>Elap (s)</td>");
1035 strcat(buf, "<td>Band</td>");
1036 strcat(buf, "<td>F</td>");
1037 strcat(buf, "<td>Tks</td>");
1038 strcat(buf, ext);
1039 strcat(buf, "</tr>\n");
1040 } else {
1041 strcat(buf, ext);
1042 }
1043
1044 bi = 0; bo = 0; dT = 0;
1045 for (i = 0; i < Conn_no; i++) {
1046 C = &Conns[i];
1047 if (C->state == CONN_STATE_FREE)
1048 continue;
1049
1050 if (C->type == Conn_type_CLIENT) {
1051 bi += C->bi;
1052 bo += C->bo;
1053 dT += Conn_now.tv_sec - C->start;
1054 }
1055
1056 if (flags & 1)
1057 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
1058
1059 Conn_poll_status(Conn_pfds[C->slot].events, polle);
1060 Conn_poll_status(Conn_pfds[C->slot].revents, pollr);
1061
1062 if ((flags & 1) == 0)
1063 slot = Conn_status_slot(C);
1064 else
1065 slot = Conn_status_slot_html(C);
1066 len += snprintf(tmp, sizeof(tmp), "%s", slot);
1067 if (len < max)
1068 strcat(buf, tmp);
1069
1070 if (flags & 1)
1071 strcat(buf, "</tr>\n");
1072 }
1073
1074 if (flags & 1)
1075 strcat(buf, "</table>\n");
1076
1077 if (dT == 0)
1078 dT = 1;
1079
1080 Conn_speed(speedi, sizeof(speedi), bi / dT);
1081 Conn_speed(speedo, sizeof(speedo), bo / dT);
1082
1083 tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s / %s."
1084 " Total bytes I/O: %llu / %llu\n",
1085 speedi, speedo, bi, bo);
1086 if (len + tmp_len < max) {
1087 strcat(buf, tmp);
1088 len += tmp_len;
1089 }
1090
1091 return buf;
1092 }
1093
1094 /*
1095 * Returns the number of bytes in 'in' buffer
1096 */
1097 unsigned int Conn_qlen(struct Conn *C)
1098 {
1099 return C->ibuf_tail - C->ibuf_head;
1100 }
1101
1102 /*
1103 * Eat @bytes from head of input buffer
1104 */
1105 void Conn_eat(struct Conn *C, unsigned int bytes)
1106 {
1107 unsigned int slot;
1108
1109 slot = C->slot;
1110
1111 /* advance head */
1112 Conns[slot].ibuf_head += bytes;
1113 if (Conns[slot].ibuf_head >= Conns[slot].ibuf_tail) {
1114 Conns[slot].ibuf_head = 0;
1115 Conns[slot].ibuf_tail = 0;
1116 }
1117
1118 Log(10, "Conn_eat(C, %u) head=%u tail=%u qlen=%u\n",
1119 bytes, C->ibuf_head, C->ibuf_tail,
1120 Conn_qlen(C));
1121 }
1122
1123 /*
1124 * Eat all input buffer
1125 */
1126 void Conn_eatall(struct Conn *C)
1127 {
1128 Conn_eat(C, Conn_qlen(C));
1129 }
1130
1131 /*
1132 * Add tokens to connection
1133 */
1134 void Conn_band_update(struct Conn *C)
1135 {
1136 unsigned int slot;
1137 long diff;
1138
1139 /* no need */
1140 if (C->band_width == 0)
1141 return;
1142
1143 diff = (Conn_now.tv_sec - C->band_lasttime.tv_sec) * 1000000;
1144 diff += Conn_now.tv_usec - C->band_lasttime.tv_usec;
1145 diff /= 100000;
703 diff = (Conn_now.tv_sec - C->band_lasttime.tv_sec) * 1000000;
704 diff += Conn_now.tv_usec - C->band_lasttime.tv_usec;
705 diff /= 100000;
1146 706
1147 707 /* already added in this hundred of milisecond? */ /* already added in this hundred of milisecond? */
1148 708 if (diff == 0) if (diff == 0)
 
... ... void Conn_band_update(struct Conn *C)
1158 718 C->band_tokens = C->band_factor * C->band_width; C->band_tokens = C->band_factor * C->band_width;
1159 719
1160 720 slot = C->slot; slot = C->slot;
1161 Conn_pfds[slot].events |= POLLOUT;
721 Conns[slot].events |= CONN_POLLOUT;
722 Conn_engine_chg_obj(&Conns[slot]);
1162 723
1163 724 Log(debug_band, "\t\tBAND: Added tokens -> %u.\n", Log(debug_band, "\t\tBAND: Added tokens -> %u.\n",
1164 725 C->band_tokens); C->band_tokens);
 
... ... int Conn_band(struct Conn *C, unsigned int width, unsigned int factor)
1185 746 return 0; return 0;
1186 747 } }
1187 748
749 static void Conn_trytoconnect(void)
750 {
751 struct addrinfo hints;
752 struct addrinfo *res;
753 int i, ret;
754 char port[8];
755
756 Log(8, "%s() Conn_no=%d Conn_pending=%d\n",
757 __FUNCTION__, Conn_no, Conn_pending);
758
759 for (i = Conn_no - 1; i >= 0; i--) {
760 if (Conns[i].type != Conn_type_CLIENT)
761 continue;
762
763 if ((Conns[i].state == CONN_STATE_CONNECT_0)
764 && (Conns[i].tryat <= Conn_now.tv_sec)) {
765 Conns[i].state = CONN_STATE_CONNECT_a;
766 }
767
768 if (Conns[i].state != CONN_STATE_CONNECT_a)
769 continue;
770
771 Log(9, "\tTry to connect to %s/%d...\n",
772 Conns[i].addr, Conns[i].port);
773
774 memset(&hints, 0, sizeof(hints));
775 if (Conns[i].sock_domain == 0)
776 hints.ai_family = PF_UNSPEC;
777 else
778 hints.ai_family = Conns[i].sock_domain;
779 hints.ai_socktype = Conns[i].sock_type;
780 /*hints.ai_flags = AI_NUMERICHOST;*/
781 hints.ai_flags = AI_ADDRCONFIG;
782 snprintf(port, sizeof(port), "%d", Conns[i].port);
783 res = NULL;
784 ret = getaddrinfo(Conns[i].addr, port, &hints, &res);
785 if (ret != 0) {
786 snprintf(Conn_error, sizeof(Conn_error),
787 "Cannot call getaddrinfo [%s]", gai_strerror(ret));
788 Log(9, "\t%s\n", Conn_error);
789 Conns[i].error_state = CONN_ERROR_GETADDRINFO;
790 Conn_free_intern(&Conns[i]);
791 if (res)
792 freeaddrinfo(res);
793 continue;
794 }
795
796 if (Conns[i].fd == -1) {
797 Conns[i].fd = socket(res->ai_family, res->ai_socktype, 0);
798 if (Conns[i].fd == -1) {
799 snprintf(Conn_error, sizeof(Conn_error),
800 "Cannot create socket [%s]", strerror(errno));
801 Log(9, "\t%s\n", Conn_error);
802 Conns[i].error_state = CONN_ERROR_SOCKET;
803 Conn_free_intern(&Conns[i]);
804 freeaddrinfo(res);
805 continue;
806 }
807 Log(10, " Allocated socket %d\n",
808 Conns[i].fd);
809
810 Conn_setnonblock(Conns[i].fd);
811
812 Conns[i].events |= (CONN_POLLIN | CONN_POLLOUT);
813 Conn_engine_add_obj(&Conns[i]);
814 }
815
816 Log(9, "\tconnecting...\n");
817 /* Set syn time */
818 Conns[i].conn_syn = Conn_now;
819 ret = connect(Conns[i].fd, res->ai_addr, res->ai_addrlen);
820 if ((ret != 0) && (errno != EINPROGRESS)) {
821 snprintf(Conn_error, sizeof(Conn_error),
822 "Cannot connect [%d] [%s]", errno, strerror(errno));
823 Log(9, "\t%s\n", Conn_error);
824 Conns[i].error_state = CONN_ERROR_CONNECT;
825 Conn_free_intern(&Conns[i]);
826 freeaddrinfo(res);
827 continue;
828 }
829
830 Conns[i].state = CONN_STATE_CONNECT_b;
831 Conn_pending--;
832 Conn_total++;
833
834 freeaddrinfo(res);
835 }
836
837 Log(10, "%s() FINISH\n",
838 __FUNCTION__);
839 }
840
1188 841 static void Conn_send_cb_i(struct Conn *C) static void Conn_send_cb_i(struct Conn *C)
1189 842 { {
1190 843 ssize_t n; ssize_t n;
 
... ... static void Conn_send_cb_i(struct Conn *C)
1217 870 max = Conns[slot].band_tokens; max = Conns[slot].band_tokens;
1218 871 if (max == 0) { if (max == 0) {
1219 872 Log(debug_band, "\tBAND: Suspend 100ms the C (no tokens)!\n"); Log(debug_band, "\tBAND: Suspend 100ms the C (no tokens)!\n");
1220 Conn_pfds[slot].events &= ~POLLOUT;
873 Conns[slot].events &= ~CONN_POLLOUT;
874 Conn_engine_chg_obj(&Conns[slot]);
1221 875 return; return;
1222 876 } }
1223 877 } }
1224 878
1225 879 again: again:
1226 Log(10, "\tsend(fd%d, buf=%p (head=%u), max=%d (count=%d), 0)...\n",
1227 Conn_pfds[slot].fd, buf, Conns[slot].obuf_head, max, count);
1228 n = send(Conn_pfds[slot].fd, buf, max, 0);
880 Log(10, "\tsend(fd%d, buf (head=%u, tail=%u), max=%d (count=%d), 0)...\n",
881 Conns[slot].fd, Conns[slot].obuf_head,
882 Conns[slot].obuf_tail, max, count);
883 n = send(Conns[slot].fd, buf, max, 0);
1229 884 xerrno = errno; xerrno = errno;
1230 885 if ((n == -1) && (errno == EINTR)) if ((n == -1) && (errno == EINTR))
1231 886 goto again; goto again;
 
... ... static void Conn_send_cb_i(struct Conn *C)
1234 889 return; return;
1235 890
1236 891 Log(10, "%s: Slot %u: FD%d Sent %d bytes [head=%d tail=%d]\n", Log(10, "%s: Slot %u: FD%d Sent %d bytes [head=%d tail=%d]\n",
1237 __FUNCTION__, slot, Conn_pfds[slot].fd,
892 __FUNCTION__, slot, Conns[slot].fd,
1238 893 n, Conns[slot].obuf_head, Conns[slot].obuf_tail); n, Conns[slot].obuf_head, Conns[slot].obuf_tail);
1239 894 if (Conn_level >= 10) { if (Conn_level >= 10) {
1240 895 dump = Conn_dump(buf, n); dump = Conn_dump(buf, n);
 
... ... static void Conn_recv_cb_i(struct Conn *C)
1293 948 max = Conn_max_recv; max = Conn_max_recv;
1294 949
1295 950 while (1) { while (1) {
1296 n = recv(Conn_pfds[slot].fd, Conns[slot].ibuf + Conns[slot].ibuf_tail, max, 0);
951 n = recv(Conns[slot].fd, Conns[slot].ibuf + Conns[slot].ibuf_tail, max, 0);
1297 952 if ((n == -1) && (errno == EINTR)) if ((n == -1) && (errno == EINTR))
1298 953 continue; continue;
1299 954
 
... ... static void Conn_recv_cb_i(struct Conn *C)
1303 958 } }
1304 959
1305 960 Log(10, "%s: Slot %u: FD%d Received %d bytes.\n", Log(10, "%s: Slot %u: FD%d Received %d bytes.\n",
1306 __FUNCTION__, slot, Conn_pfds[slot].fd, n);
961 __FUNCTION__, slot, Conns[slot].fd, n);
1307 962
1308 963 if (n > 0) { if (n > 0) {
1309 964 if (Conn_level >= 10) { if (Conn_level >= 10) {
 
... ... static void Conn_recv_cb_i(struct Conn *C)
1333 988 } }
1334 989
1335 990 /* /*
1336 * Set some internal parameters
991 * Callback that is called for every connection
992 * TODO: Hm. For epoll seems that we do not scan all entries and this affects expiration!
1337 993 */ */
1338 void Conn_set(struct Conn *C, int var, unsigned int val)
994 static void Conn_poll_cb(struct Conn *C, const int revents)
1339 995 { {
1340 unsigned int slot;
1341 int fd;
996 Log(12, "%s: revents=%x.\n", __FUNCTION__, revents);
997 C->revents = revents;
1342 998
1343 slot = C->slot;
1344 fd = Conn_pfds[slot].fd;
999 if (Conn_level >= 12)
1000 Log(12, "\t%s\n", Conn_status_slot(C));
1345 1001
1346 switch (var) {
1347 case CONN_PARA_AUTO_RECONNECT:
1348 C->flags |= (val == 0) ? 0 : CONN_FLAGS_AUTO_RECONNECT;
1349 break;
1350 case CONN_PARA_RECONNECT_DELAY:
1351 C->delay = val;
1352 break;
1353 case CONN_PARA_IDLE_TIME:
1354 C->idle = val;
1355 break;
1356 case CONN_PARA_READ_TIMEOUT:
1357 C->read_timeout = val;
1358 break;
1359 case CONN_PARA_CONN_TIMEOUT:
1360 C->conn_timeout = val;
1361 break;
1362 case CONN_PARA_TRIGGER:
1363 C->trigger = val;
1364 break;
1365 case CONN_PARA_IBUF:
1366 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
1367 break;
1368 case CONN_PARA_OBUF:
1369 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
1370 break;
1002 if (C->revents & CONN_POLLHUP) {
1003 C->error_state = CONN_ERROR_HANGUP;
1004 /* TODO: Add it to the close list to speed it up */
1371 1005 } }
1372 }
1373
1374 struct Conn *Conn_connect(int domain, int type, char *addr, int port)
1375 {
1376 struct Conn *X;
1377 unsigned int Xslot;
1378
1379 Log(8, "%s(%s, %d)\n",
1380 __FUNCTION__, addr, port);
1381
1382 X = Conn_alloc();
1383 if (!X)
1384 return NULL;
1385
1386 Xslot = X->slot;
1387
1388 Conns[Xslot].type = Conn_type_CLIENT;
1389 Conns[Xslot].error_state = 0;
1390 Conns[Xslot].state = CONN_STATE_CONNECT_a;
1391 snprintf(Conns[Xslot].addr, sizeof(Conns[Xslot].addr), "%s", addr);
1392 Conns[Xslot].port = port;
1393 Conns[Xslot].sock_domain = domain;
1394 Conns[Xslot].sock_type = type;
1395 Conns[Xslot].id = Conn_id++;
1396 Conns[Xslot].start = Conn_now.tv_sec;
1397
1398 Conn_pending++;
1399
1400 return &Conns[Xslot];
1401 }
1402
1403 static void Conn_trytoconnect(void)
1404 {
1405 struct addrinfo hints;
1406 struct addrinfo *res;
1407 int i, ret;
1408 char port[8];
1409
1410 Log(8, "%s() Conn_no=%d Conn_pending=%d\n",
1411 __FUNCTION__, Conn_no, Conn_pending);
1412 1006
1413 for (i = Conn_no - 1; i >= 0; i--) {
1414 if (Conns[i].type != Conn_type_CLIENT)
1415 continue;
1007 if (C->revents & CONN_POLLERR) {
1008 C->error_state = CONN_ERROR_POLL;
1009 C->xerrno = 0; /* TODO: unknown error? */
1010 /* TODO: CONN_ERROR_POLL is correct here? */
1011 }
1416 1012
1417 if ((Conns[i].state == CONN_STATE_CONNECT_0)
1418 && (Conns[i].tryat <= Conn_now.tv_sec)) {
1419 Conns[i].state = CONN_STATE_CONNECT_a;
1013 /* First, test we have a new connection */
1014 if ((C->revents & CONN_POLLOUT)
1015 && (Conn_ignore(C) == 0)) {
1016 /* We just established a connection */
1017 if (C->state == CONN_STATE_CONNECT_b) {
1018 if (C->cb_connected != NULL)
1019 C->cb_connected(C);
1020 else if (Conn_connected_cb)
1021 Conn_connected_cb(C);
1022 C->state = CONN_STATE_OPEN;
1420 1023 } }
1024 }
1421 1025
1422 if (Conns[i].state != CONN_STATE_CONNECT_a)
1423 continue;
1424
1425 Log(9, "\tTry to connect to %s/%d...\n",
1426 Conns[i].addr, Conns[i].port);
1427
1428 memset(&hints, 0, sizeof(hints));
1429 if (Conns[i].sock_domain == 0)
1430 hints.ai_family = PF_UNSPEC;
1431 else
1432 hints.ai_family = Conns[i].sock_domain;
1433 hints.ai_socktype = Conns[i].sock_type;
1434 /*hints.ai_flags = AI_NUMERICHOST;*/
1435 hints.ai_flags = 0;
1436 snprintf(port, sizeof(port), "%d", Conns[i].port);
1437 res = NULL;
1438 ret = getaddrinfo(Conns[i].addr, port, &hints, &res);
1439 if (ret != 0) {
1440 snprintf(Conn_error, sizeof(Conn_error),
1441 "Cannot call getaddrinfo [%s]", gai_strerror(ret));
1442 Log(9, "\t%s\n", Conn_error);
1443 Conns[i].error_state = CONN_ERROR_GETADDRINFO;
1444 Conn_free_intern(&Conns[i]);
1445 if (res)
1446 freeaddrinfo(res);
1447 continue;
1026 /* Second, test for error or input */
1027 if ((C->revents & CONN_POLLIN)
1028 && (Conn_ignore(C) == 0)) {
1029 if (C->type == Conn_type_MASTER) {
1030 Conn_accept(C);
1031 } else {
1032 if (C->cb_recv)
1033 C->cb_recv(C);
1034 else if (Conn_recv_cb != NULL)
1035 Conn_recv_cb(C);
1036 else
1037 Conn_recv_cb_i(C);
1448 1038 } }
1039 }
1449 1040
1450 if (Conn_pfds[i].fd == -1) {
1451 Conn_pfds[i].fd = socket(res->ai_family, res->ai_socktype, 0);
1452 if (Conn_pfds[i].fd == -1) {
1453 snprintf(Conn_error, sizeof(Conn_error),
1454 "Cannot create socket [%s]", strerror(errno));
1455 Log(9, "\t%s\n", Conn_error);
1456 Conns[i].error_state = CONN_ERROR_SOCKET;
1457 Conn_free_intern(&Conns[i]);
1458 freeaddrinfo(res);
1459 continue;
1041 if ((C->revents & CONN_POLLOUT)
1042 && (Conn_ignore(C) == 0)) {
1043 /* We can send data */
1044 if (C->state == CONN_STATE_OPEN) {
1045 if (C->cb_send)
1046 C->cb_send(C);
1047 else if (Conn_send_cb != NULL)
1048 Conn_send_cb(C);
1049 else
1050 Conn_send_cb_i(C);
1051
1052 if (C->obuf_head == C->obuf_tail) {
1053 C->events &= ~EPOLLOUT;
1054 Conn_epoll_chg_obj(C);
1055 if (C->flags & CONN_FLAGS_CLOSE_AFTER_SEND)
1056 C->error_state = CONN_ERROR_USERREQ;
1460 1057 } }
1461 Log(10, " Allocated socket %d\n",
1462 Conn_pfds[i].fd);
1463 Conn_pfds[i].events |= POLLIN | POLLOUT;
1464
1465 Conn_setnonblock(Conn_pfds[i].fd);
1466 }
1467
1468 Log(9, "\tconnecting...\n");
1469 /* Set syn time */
1470 Conns[i].conn_syn = Conn_now;
1471 ret = connect(Conn_pfds[i].fd, res->ai_addr, res->ai_addrlen);
1472 if ((ret != 0) && (errno != EINPROGRESS)) {
1473 snprintf(Conn_error, sizeof(Conn_error),
1474 "Cannot connect [%d] [%s]", errno, strerror(errno));
1475 Log(9, "\t%s\n", Conn_error);
1476 Conns[i].error_state = CONN_ERROR_CONNECT;
1477 Conn_free_intern(&Conns[i]);
1478 freeaddrinfo(res);
1479 continue;
1480 1058 } }
1481
1482 Conns[i].state = CONN_STATE_CONNECT_b;
1483 Conn_pending--;
1484 Conn_total++;
1485
1486 freeaddrinfo(res);
1487 1059 } }
1488 1060
1489 Log(10, "%s() FINISH\n",
1490 __FUNCTION__);
1491 }
1492
1493 /*
1494 * Returns 1 if we can ignore this connection */
1495 static int Conn_ignore(struct Conn *C)
1496 {
1497 if (C->error_state > 0)
1498 return 1;
1499
1500 return 0;
1501 }
1502
1503 /*
1504 * Close a connection if it exceeded maximum idle time or got a timeout
1505 */
1506 static void Conn_expire(struct Conn *C)
1507 {
1508 long long diff_ms;
1509
1510 if ((C->trigger > 0)
1511 && (C->last_trigger + C->trigger < Conn_now.tv_sec)) {
1512 C->last_trigger = Conn_now.tv_sec;
1513 if (C->cb_trigger)
1514 C->cb_trigger(C);
1515 else if (Conn_trigger_cb)
1516 Conn_trigger_cb(C);
1517 }
1061 /* test if it expired/timout */
1062 Conn_expire(C);
1518 1063
1519 if ((C->idle > 0) && (C->trecv.tv_sec + C->idle < Conn_now.tv_sec)) {
1520 C->error_state = CONN_ERROR_EXPIRED;
1521 } else if ((C->read_timeout > 0) && (C->tsend.tv_sec > 0)
1522 && (C->tsend.tv_sec > C->trecv.tv_sec)) {
1523 diff_ms = Conn_time_diff(&Conn_now, &C->tsend);
1524 if (diff_ms > C->read_timeout) {
1525 C->error_state = CONN_ERROR_READ_TIMEOUT;
1526 }
1527 } else if ((C->conn_timeout > 0) && (C->state == CONN_STATE_CONNECT_b)) {
1528 diff_ms = Conn_time_diff(&Conn_now, &C->conn_syn);
1529 if (diff_ms > C->conn_timeout) {
1530 /* connection attempt expired */
1531 C->error_state = CONN_ERROR_CONN_TIMEOUT;
1532 }
1064 if (C->error_state > 0) {
1065 /* TODO: put it on a list and before exit scan the list */
1066 Conn_free_intern(C);
1067 } else {
1068 /* add tokens */
1069 Conn_band_update(C);
1533 1070 } }
1534 1071 } }
1535 1072
 
... ... static void Conn_expire(struct Conn *C)
1539 1076 */ */
1540 1077 int Conn_poll(int timeout) int Conn_poll(int timeout)
1541 1078 { {
1542 int i;
1543 short rev;
1544 char *stats;
1079 int ret;
1545 1080 int timeout2; int timeout2;
1546 int events;
1547 1081
1548 1082 Log(11, "Conn_poll(timeout=%d Conn_no=%d)\n", Log(11, "Conn_poll(timeout=%d Conn_no=%d)\n",
1549 1083 timeout, Conn_no); timeout, Conn_no);
 
... ... int Conn_poll(int timeout)
1560 1094 if (Conn_pending > 0) if (Conn_pending > 0)
1561 1095 Conn_trytoconnect(); Conn_trytoconnect();
1562 1096
1563 again:
1564 events = poll(&Conn_pfds[0], Conn_no, timeout2);
1565 if ((events == -1) && (errno == EINTR))
1566 goto again;
1567
1568 if (events < 0) {
1569 snprintf(Conn_error, sizeof(Conn_error),
1570 "poll(%p, %d): %s",
1571 (void *)Conn_pfds, Conn_no, strerror(errno));
1097 ret = Conn_engine_poll(timeout2, Conn_poll_cb);
1098 if (ret < 0)
1572 1099 return -1; return -1;
1573 }
1574 1100
1575 gettimeofday(&Conn_now, NULL);
1576
1577 if (Conn_level >= 11) {
1578 stats = Conn_status(0);
1579 Log(0, "%s\n", stats);
1580 free(stats);
1581 }
1582
1583 /* We do revers scan because of moving Conn objects */
1584 Log(11, "Process %d events...\n",
1585 events);
1586 for (i = Conn_no - 1; i >= 0; i--) {
1587 if (events > 0) {
1588 rev = Conn_pfds[i].revents;
1589
1590 if (rev == 0)
1591 continue;
1592
1593 events--;
1594
1595 if (rev & POLLHUP) {
1596 Conns[i].error_state = CONN_ERROR_HANGUP;
1597 }
1598
1599 if (rev & POLLERR) {
1600 Conns[i].error_state = CONN_ERROR_POLL;
1601 Conns[i].xerrno = 0;
1602 }
1603
1604 if (rev & POLLNVAL) {
1605 Log(0, "BUG NVAL!\n");
1606 exit(1);
1607 }
1608
1609 /* First, test we have a new connection */
1610 if ((rev & POLLOUT) && (Conn_ignore(&Conns[i]) == 0)) {
1611 /* We just established a connection */
1612 if (Conns[i].state == CONN_STATE_CONNECT_b) {
1613 if (Conns[i].cb_connected)
1614 Conns[i].cb_connected(&Conns[i]);
1615 else if (Conn_connected_cb)
1616 Conn_connected_cb(&Conns[i]);
1617 Conns[i].state = CONN_STATE_OPEN;
1618 }
1619 }
1620
1621 /* Second, test for error or input */
1622 if ((rev & POLLIN) && (Conn_ignore(&Conns[i]) == 0)) {
1623 if (Conns[i].type == Conn_type_MASTER) {
1624 Conn_accept(&Conns[i]);
1625 } else {
1626 if (Conns[i].cb_recv)
1627 Conns[i].cb_recv(&Conns[i]);
1628 else if (Conn_recv_cb != NULL)
1629 Conn_recv_cb(&Conns[i]);
1630 else
1631 Conn_recv_cb_i(&Conns[i]);
1632 }
1633 }
1634
1635 if ((rev & POLLOUT) && (Conn_ignore(&Conns[i]) == 0)) {
1636 /* We can send data */
1637 if (Conns[i].state == CONN_STATE_OPEN) {
1638 if (Conns[i].cb_send)
1639 Conns[i].cb_send(&Conns[i]);
1640 else if (Conn_send_cb != NULL)
1641 Conn_send_cb(&Conns[i]);
1642 else
1643 Conn_send_cb_i(&Conns[i]);
1644
1645 if (Conns[i].obuf_head == Conns[i].obuf_tail) {
1646 Conn_pfds[i].events &= ~POLLOUT;
1647 if (Conns[i].flags & CONN_FLAGS_CLOSE_AFTER_SEND)
1648 Conns[i].error_state = CONN_ERROR_USERREQ;
1649 }
1650 }
1651 }
1652 }
1653
1654 /* test if it expired/timout */
1655 Conn_expire(&Conns[i]);
1656
1657 if (Conns[i].error_state > 0) {
1658 Conn_free_intern(&Conns[i]);
1659 } else {
1660 /* add tokens */
1661 Conn_band_update(&Conns[i]);
1662 }
1663 }
1101 /* block accept if full queue */
1102 Conn_accept_allow();
1664 1103
1665 1104 if (timeout == -1) if (timeout == -1)
1666 1105 goto loop; goto loop;
1667 else
1668 return 1;
1669
1670 return 1;
1671 }
1672
1673 /*
1674 * Set NODELAY on socket
1675 */
1676 int Conn_nodelay(struct Conn *C)
1677 {
1678 int i, fd;
1679
1680 fd = Conn_pfds[C->slot] . fd;
1681 i = 1;
1682 return setsockopt(fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
1683 }
1684
1685 void Conn_rollback(struct Conn *C, unsigned int bytes)
1686 {
1687 if (C->obuf_tail - C->obuf_head <= bytes)
1688 C->obuf_tail -= bytes;
1689 }
1690
1691 /*
1692 * Search for str in active buffer from a given offset
1693 * Returns pointer to string if match or NUll if doesn't.
1694 */
1695 char *Conn_ostrstr(struct Conn *C, unsigned int off, char *str)
1696 {
1697 unsigned int len, str_len, i;
1698 char *buf, *ret = NULL;
1699
1700 len = C->ibuf_tail - C->ibuf_head - off;
1701 buf = C->ibuf + C->ibuf_head + off;
1702 str_len = strlen(str);
1703
1704 if (len < str_len)
1705 return NULL;
1706
1707 i = 0;
1708 while (i <= len - str_len) {
1709 if (strncmp(buf + i, str, str_len) == 0) {
1710 ret = buf + i;
1711 break;
1712 }
1713
1714 i++;
1715 }
1716 1106
1717 1107 return ret; return ret;
1718 1108 } }
1719
1720 /*
1721 * Search for str in active buffer
1722 * Returns pointer to string if match or NUll if doesn't.
1723 */
1724 char *Conn_strstr(struct Conn *C, char *str)
1725 {
1726 return Conn_ostrstr(C, 0, str);
1727 }
1728
1729 /*
1730 * Returns a pointer to current in buffer
1731 */
1732 char *Conn_ibuf(struct Conn *C)
1733 {
1734 return C->ibuf + C->ibuf_head;
1735 }
1736
1737 /*
1738 * Returns a pointer to current out buffer
1739 */
1740 char *Conn_obuf(struct Conn *C)
1741 {
1742 return C->obuf + C->obuf_head;
1743 }
1744
1745 /*
1746 * Returns the id of a connection
1747 */
1748 unsigned long long Conn_getid(struct Conn *C)
1749 {
1750 return C->id;
1751 }
1752
1753 /*
1754 * Returns a Conn* searching for id
1755 */
1756 struct Conn *Conn_get(unsigned long long id)
1757 {
1758 struct Conn *R = NULL;
1759 int i;
1760
1761 for (i = Conn_no - 1; i >= 0; i--) {
1762 if (Conns[i].id == id) {
1763 R = &Conns[i];
1764 break;
1765 }
1766 }
1767
1768 return R;
1769 }
1770
1771
1772 /*
1773 * Returns the fd associated with C
1774 */
1775 int Conn_get_fd(struct Conn *C)
1776 {
1777 if (C == NULL)
1778 return -1;
1779
1780 return Conn_pfds[C->slot].fd;
1781 }
1782
1783 /*
1784 * Returns the timeval of the last packet
1785 */
1786 void Conn_last_time(struct Conn *C, struct timeval *tv)
1787 {
1788 *tv = C->trecv;
1789 }
1790
1791 /*
1792 * Set a callback
1793 */
1794 int Conn_set_cb(struct Conn *C, unsigned int type, void (*f)(struct Conn *))
1795 {
1796 switch (type) {
1797 case CONN_CB_ACCEPT: C->cb_accept = f; break;
1798 case CONN_CB_RECV: C->cb_recv = f; break;
1799 case CONN_CB_SEND: C->cb_send = f; break;
1800 case CONN_CB_DATA: C->cb_data = f; break;
1801 case CONN_CB_CLOSE: C->cb_close = f; break;
1802 case CONN_CB_TRIGGER: C->cb_trigger = f; break;
1803 case CONN_CB_ERROR: C->cb_error = f; break;
1804 case CONN_CB_CONNECTED: C->cb_connected = f; break;
1805
1806 default:
1807 return -1;
1808 }
1809
1810 return 0;
1811 }
1812
1813 /*
1814 * Returns a '\0' terminated line, modifying received buffer
1815 */
1816 char *Conn_get_line(struct Conn *C)
1817 {
1818 char *cr;
1819
1820 cr = Conn_strstr(C, "\n");
1821 if (!cr)
1822 return NULL;
1823
1824 *cr = '\0';
1825
1826 return Conn_ibuf(C);
1827 }
1828
1829 /*
1830 * Helper help building text line daemons
1831 */
1832 void Conn_for_every_line(struct Conn *C, int (*cb)(struct Conn *C, char *line))
1833 {
1834 int ret = 0;
1835 char *line;
1836 unsigned int line_size;
1837
1838 if (cb == NULL)
1839 return;
1840
1841 while (1) {
1842 line = Conn_get_line(C);
1843 if (line == NULL)
1844 break;
1845
1846 line_size = strlen(line) + 1;
1847
1848 ret = cb(C, line);
1849 if (ret != 0)
1850 break;
1851
1852 Conn_eat(C, line_size);
1853 }
1854 }
File Conn.h changed (mode: 100644) (index 7241948..6a4f651)
1 1 #ifndef _Conn_h #ifndef _Conn_h
2 2 #define _Conn_h 1 #define _Conn_h 1
3 3
4 #define _GNU_SOURCE
4 #include <Conn_engine_core.h>
5 5
6 #include <stdarg.h>
7 #include <resolv.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <netinet/in.h>
11 #include <netdb.h>
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <sys/stat.h>
15 #include <sys/socket.h>
16 #include <unistd.h>
17 #include <time.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <sys/poll.h>
24 #include <arpa/inet.h>
25 #include <netinet/tcp.h>
26
27
28
29 /* type */
30 #define Conn_type_MASTER 1
31 #define Conn_type_CLIENT 2
32 #define Conn_type_UNK 3
33
34
35 /* state */
36 #define CONN_STATE_START 0
37 #define CONN_STATE_FREE CONN_STATE_START + 1
38 #define CONN_STATE_EMPTY CONN_STATE_START + 2
39 #define CONN_STATE_OPEN CONN_STATE_START + 3
40 #define CONN_STATE_LISTEN CONN_STATE_START + 4
41 #define CONN_STATE_CONNECT_0 CONN_STATE_START + 5
42 #define CONN_STATE_CONNECT_a CONN_STATE_START + 6
43 #define CONN_STATE_CONNECT_b CONN_STATE_START + 7
44
45
46 /* error kind */
47 #define CONN_ERROR_START 0
48 #define CONN_ERROR_USERREQ CONN_ERROR_START + 1 /* user requested the close */
49 #define CONN_ERROR_POLL CONN_ERROR_START + 2
50 #define CONN_ERROR_RECV CONN_ERROR_START + 3
51 #define CONN_ERROR_SEND CONN_ERROR_START + 4
52 #define CONN_ERROR_SOCKET CONN_ERROR_START + 5
53 #define CONN_ERROR_HANGUP CONN_ERROR_START + 6
54 #define CONN_ERROR_GETADDRINFO CONN_ERROR_START + 7
55 #define CONN_ERROR_EXPIRED CONN_ERROR_START + 8
56 #define CONN_ERROR_ACCEPT CONN_ERROR_START + 9
57 #define CONN_ERROR_MEM CONN_ERROR_START + 10
58 #define CONN_ERROR_CONNECT CONN_ERROR_START + 11
59 #define CONN_ERROR_READ_TIMEOUT CONN_ERROR_START + 12
60 #define CONN_ERROR_CONN_TIMEOUT CONN_ERROR_START + 13
61
62
63 /* FLAGS */
64 #define CONN_FLAGS_AUTO_RECONNECT 0x01 << 0
65 #define CONN_FLAGS_CLOSE_AFTER_SEND 0x01 << 1
66
67
68 /* Parameters */
69 #define CONN_PARA_START 0
70 #define CONN_PARA_AUTO_RECONNECT CONN_PARA_START + 1
71 #define CONN_PARA_RECONNECT_DELAY CONN_PARA_START + 2
72 #define CONN_PARA_IDLE_TIME CONN_PARA_START + 3
73 #define CONN_PARA_READ_TIMEOUT CONN_PARA_START + 4
74 #define CONN_PARA_CONN_TIMEOUT CONN_PARA_START + 5
75 #define CONN_PARA_TRIGGER CONN_PARA_START + 6
76 #define CONN_PARA_IBUF CONN_PARA_START + 7
77 #define CONN_PARA_OBUF CONN_PARA_START + 8
78
79 /* Callbacks */
80 #define CONN_CB_START 0
81 #define CONN_CB_ACCEPT CONN_CB_START + 1
82 #define CONN_CB_RECV CONN_CB_START + 2
83 #define CONN_CB_SEND CONN_CB_START + 3
84 #define CONN_CB_DATA CONN_CB_START + 4
85 #define CONN_CB_CLOSE CONN_CB_START + 5
86 #define CONN_CB_TRIGGER CONN_CB_START + 6
87 #define CONN_CB_ERROR CONN_CB_START + 7
88 #define CONN_CB_CONNECTED CONN_CB_START + 8
89
90
91 struct Conn
92 {
93 unsigned char type;
94
95 unsigned char state;
96 unsigned char error_state;
97
98 unsigned int slot;
99
100 char *ibuf;
101 unsigned int ibuf_size, ibuf_head, ibuf_tail;
102
103 char *obuf;
104 unsigned int obuf_size, obuf_head, obuf_tail;
105
106 struct timeval trecv, tsend; /* last time we saw an receive/send */
107 unsigned int idle; /* idle time allowed */
108 unsigned int read_timeout; /* Max timeout for receiving an answer (milliseconds) */
109
110 struct timeval conn_syn; /* Time when a connection was initiated */
111 unsigned int conn_timeout; /* Timeout for connection (milliseconds) */
112
113 time_t last_trigger; /* last trigger was at */
114 unsigned int trigger; /* Frequency of wakeup a connection */
115
116 int sock_domain;
117 int sock_type;
118
119 char addr[64];
120 int port, via; /* "via" is the port via a client was accepted */
121
122 unsigned long long bi, bo;
123
124 void *private; /* private use by user */
125
126 /* reconnect stuff */
127 unsigned int retries;
128 unsigned int delay; /* delay between reconnects */
129 time_t tryat; /* when we go to CONNECT_a state */
130
131 int xerrno;
132
133 time_t start;
134
135 unsigned int flags;
136
137 /* bandwidth stuff */
138 struct timeval band_lasttime; /* last time tokens were added */
139 unsigned int band_tokens; /* 1 token -> 1000 bytes */
140 unsigned int band_factor; /* tokens cannot go past f * w */
141 unsigned int band_width; /* in 1000b increments */
142
143 unsigned long long id; /* the id of a connection */
144
145 /* Specific callbacks */
146 void (*cb_accept)(struct Conn *C);
147 void (*cb_recv)(struct Conn *C);
148 void (*cb_send)(struct Conn *C);
149 void (*cb_data)(struct Conn *C);
150 void (*cb_close)(struct Conn *C);
151 void (*cb_trigger)(struct Conn *C);
152 void (*cb_error)(struct Conn *C);
153 void (*cb_connected)(struct Conn *C);
154 };
155
156
157
158 /* Variables */
159 extern void (*Conn_accept_cb)(struct Conn *C);
160 extern void (*Conn_recv_cb)(struct Conn *C);
161 extern void (*Conn_send_cb)(struct Conn *C);
162 extern void (*Conn_data_cb)(struct Conn *C);
163 extern void (*Conn_close_cb)(struct Conn *C);
164 extern void (*Conn_trigger_cb)(struct Conn *C);
165 extern void (*Conn_error_cb)(struct Conn *C);
166 extern void (*Conn_connected_cb)(struct Conn *C);
167
168 extern char *(*Conn_status_slot_html_cb)(struct Conn *C);
169 extern char *(*Conn_status_cb)(void);
170
171 extern unsigned int Conn_max_reached;
172 extern unsigned int Conn_default_ibuf;
173 extern unsigned int Conn_default_obuf;
174 extern unsigned int Conn_max_ibuf;
175 extern unsigned int Conn_max_obuf;
176 extern unsigned int Conn_no;
177 extern unsigned int Conn_max;
178 extern unsigned long Conn_total;
179 extern unsigned int Conn_start;
180 extern unsigned int Conn_pending;
181 extern struct timeval Conn_now;
182
183 extern unsigned int Conn_max_send;
184 extern unsigned int Conn_max_recv;
185
186 extern unsigned short Conn_level;
187
188
189 /* Functions */
190 extern char *Conn_strerror(void);
191 6 extern int Conn_init(unsigned int max); extern int Conn_init(unsigned int max);
192 extern void Conn_close(struct Conn *C);
193 7 extern ssize_t Conn_send(struct Conn *C, void *buf, size_t count); extern ssize_t Conn_send(struct Conn *C, void *buf, size_t count);
194 8 extern ssize_t Conn_recv(struct Conn *C, void *buf, size_t count); extern ssize_t Conn_recv(struct Conn *C, void *buf, size_t count);
195 9 extern struct Conn *Conn_socket(int domain, int type, int port); extern struct Conn *Conn_socket(int domain, int type, int port);
196 extern char *Conn_status(unsigned int flags);
197 10 extern int Conn_poll(int timeout); extern int Conn_poll(int timeout);
198 11 extern int Conn_enqueue(struct Conn *C, void *buf, size_t count); extern int Conn_enqueue(struct Conn *C, void *buf, size_t count);
12 /*
199 13 extern void Conn_debug(FILE *f, unsigned short debug); extern void Conn_debug(FILE *f, unsigned short debug);
14 */
200 15 extern struct Conn *Conn_connect(int domain, int type, char *addr, int port); extern struct Conn *Conn_connect(int domain, int type, char *addr, int port);
201 extern char *Conn_dump(char *buf_src, int len_src);
202 extern char *Conn_dumphex(char *buf_src, int len_src);
203 extern int Conn_nodelay(struct Conn *C);
204 extern void Conn_rollback(struct Conn *C, unsigned int bytes);
205 extern char *Conn_strstr(struct Conn *C, char *str);
206 extern unsigned int Conn_qlen(struct Conn *C);
207 extern void Conn_eat(struct Conn *C, unsigned int bytes);
208 extern void Conn_eatall(struct Conn *C);
209 extern char *Conn_ibuf(struct Conn *C);
210 extern char *Conn_obuf(struct Conn *C);
211 extern int Conn_try_expand_buf(struct Conn *C, int what, int needed);
212 16 extern int Conn_band(struct Conn *C, unsigned int width, unsigned int factor); extern int Conn_band(struct Conn *C, unsigned int width, unsigned int factor);
213 extern void Conn_set(struct Conn *C, int var, unsigned int val);
214 extern char *Conn_ostrstr(struct Conn *C, unsigned int off, char *str);
215 extern unsigned long long Conn_getid(struct Conn *C);
216 extern struct Conn *Conn_get(unsigned long long id);
217 extern int Conn_get_fd(struct Conn *C);
218 extern void Conn_last_time(struct Conn *C, struct timeval *tv);
219 extern int Conn_set_cb(struct Conn *C, unsigned int type,
220 void (*f)(struct Conn *));
221 extern char *Conn_get_line(struct Conn *C);
222 extern void Conn_for_every_line(struct Conn *C,
223 int (*cb)(struct Conn *C, char *line));
17
224 18
225 19 #endif #endif
File Conn_config.h.in added (mode: 100644) (index 0000000..68138d7)
1 #define POLL_FOUND @POLL_FOUND@
2 #define EPOLL_FOUND @EPOLL_FOUND@
File Conn_engine_core.c added (mode: 100644) (index 0000000..791e972)
1 /*
2 * Author: Catalin(ux) M BOIE <catab at embedromix.ro>
3 * Date: 2004-2008
4 * Description: Some functions to help writing network servers and clients,
5 * both ipv4 and ipv6.
6 * Licence: LGPL
7 */
8
9 #include "Conn_engine_core.h"
10
11
12 /* Visible variables */
13 void (*Conn_accept_cb)(struct Conn *C) = NULL;
14 void (*Conn_recv_cb)(struct Conn *C) = NULL;
15 void (*Conn_send_cb)(struct Conn *C) = NULL;
16 void (*Conn_data_cb)(struct Conn *C) = NULL;
17 void (*Conn_close_cb)(struct Conn *C) = NULL;
18 void (*Conn_trigger_cb)(struct Conn *C) = NULL;
19 void (*Conn_error_cb)(struct Conn *C) = NULL;
20 void (*Conn_connected_cb)(struct Conn *C) = NULL;
21
22 char *(*Conn_status_slot_html_cb)(const struct Conn *C);
23 char *(*Conn_status_cb)(void);
24
25
26 unsigned int Conn_max_reached = 0;
27 unsigned int Conn_default_ibuf = 128;
28 unsigned int Conn_default_obuf = 128;
29 unsigned int Conn_max_ibuf = 4096000;
30 unsigned int Conn_max_obuf = 4096000;
31
32 /* Max bytes enqueued on one send/recv call */
33 unsigned int Conn_max_send = 32 * 1024;
34 unsigned int Conn_max_recv = 32 * 1024;
35
36 unsigned int Conn_no = 0;
37 unsigned int Conn_max = 0;
38 unsigned long Conn_total = 0;
39 unsigned int Conn_start = 0;
40 unsigned int Conn_pending = 0;
41 struct timeval Conn_now;
42 unsigned short Conn_level = 0; /* debug level */
43 unsigned int Conn_accept_is_allowed;
44 unsigned int Conn_accept_is_allowed_last;
45
46 struct Conn *Conns = NULL;
47 unsigned int Conn_inited = 0;
48 unsigned int Conn_allocated = 0;
49 unsigned long long Conn_id = 1;
50
51 char Conn_error[512];
52
53 FILE *Conn_Log = NULL;
54 int debug_band = 11;
55
56 /* Flags */
57 unsigned int CONN_POLLIN;
58 unsigned int CONN_POLLOUT;
59 unsigned int CONN_POLLPRI;
60 unsigned int CONN_POLLERR;
61 unsigned int CONN_POLLHUP;
62 unsigned int CONN_POLLNVAL;
63 unsigned int CONN_POLLRDNORM;
64 unsigned int CONN_POLLRDBAND;
65
66
67 /* Functions */
68
69 char *Conn_strerror(void)
70 {
71 return Conn_error;
72 }
73
74 /*
75 * Difference between two timeval strutures, in milliseconds
76 */
77 long long Conn_time_diff(const struct timeval *t1, const struct timeval *t2)
78 {
79 return (t1->tv_sec - t2->tv_sec) * 1000
80 + (t1->tv_usec - t2->tv_usec) / 1000;
81 }
82
83 /*
84 * Returns string representation of errno code
85 */
86 char *Conn_errno(const struct Conn *C)
87 {
88 static char buf[256];
89 char *is;
90
91 switch (C->error_state) {
92 case CONN_ERROR_USERREQ: is = "user"; break;
93 case CONN_ERROR_POLL: is = "poll"; break;
94 case CONN_ERROR_RECV: is = "recv"; break;
95 case CONN_ERROR_SEND: is = "send"; break;
96 case CONN_ERROR_SOCKET: is = "socket"; break;
97 case CONN_ERROR_HANGUP: is = "hangup"; break;
98 case CONN_ERROR_GETADDRINFO: is = "lookup error"; break;
99 case CONN_ERROR_EXPIRED: is = "expired"; break;
100 case CONN_ERROR_ACCEPT: is = "accept"; break;
101 case CONN_ERROR_MEM: is = "allocation failed"; break;
102 case CONN_ERROR_CONNECT: is = "connect"; break;
103 case CONN_ERROR_READ_TIMEOUT: is = "read timeout"; break;
104 case CONN_ERROR_CONN_TIMEOUT: is = "conn timeout"; break;
105
106 default: is = "?";
107 }
108
109 snprintf(buf, sizeof(buf), "%s (%s)",
110 is, (C->xerrno > 0) ? strerror(C->xerrno) : "-");
111
112 return buf;
113 }
114
115 /* set noblocking */
116 int Conn_setnonblock(const int fd)
117 {
118 int ret;
119 long flags;
120
121 flags = fcntl(fd, F_GETFL, 0);
122 if (flags == -1)
123 return -1;
124
125 flags |= O_NONBLOCK;
126
127 ret = fcntl(fd, F_SETFL, flags);
128
129 return ret;
130 }
131
132 void Log(const unsigned short level, char *format, ...)
133 {
134 va_list ap;
135 FILE *out;
136
137 if (level > Conn_level)
138 return;
139
140 if (Conn_Log == NULL)
141 out = stderr;
142 else
143 out = Conn_Log;
144 fprintf(out, "%ld.%06ld ",
145 Conn_now.tv_sec, Conn_now.tv_usec);
146
147 va_start(ap, format);
148 vfprintf(out, format, ap);
149 va_end(ap);
150 }
151
152 char *Conn_dump(const char *buf_src, const int len_src)
153 {
154 int i, j;
155 char tmp[3];
156 char *buf_dst;
157 unsigned char c;
158
159 if (len_src < 0)
160 return strdup("[Error: len < 0]");
161
162 Log(30, "\tConn_dump(%p, len=%d)\n",
163 buf_src, len_src);
164
165 buf_dst = malloc(len_src * 4 + 1);
166 if (buf_dst == NULL)
167 return strdup("Memory allocation error1!");
168
169 j = 0;
170 for (i = 0; i < len_src; i++) {
171 c = buf_src[i];
172 if ((c < 32) || (c > 127)) {
173 buf_dst[j++] = '[';
174 snprintf(tmp, sizeof(tmp), "%02x", c);
175 buf_dst[j++] = tmp[0];
176 buf_dst[j++] = tmp[1];
177 buf_dst[j++] = ']';
178 } else {
179 buf_dst[j++] = c;
180 }
181 }
182
183 buf_dst[j] = '\0';
184
185 /*
186 Log(0, "%s ([%s], %d, [%s], %d\n",
187 __FUNCTION__, buf_src, len_src, buf_dst, len_dst);
188 */
189
190 return buf_dst;
191 }
192
193 char *Conn_dumphex(const char *buf_src, const int len_src)
194 {
195 int i, j;
196 char tmp[3];
197 char *buf_dst;
198 unsigned char c;
199
200 if (len_src < 0)
201 return strdup("[Error: len < 0]");
202
203 Log(30, "\tConn_dumphex(%p, len=%d)\n",
204 buf_src, len_src);
205
206 buf_dst = malloc(len_src * 2 + 1);
207 if (buf_dst == NULL)
208 return strdup("Memory allocation error1!");
209
210 j = 0;
211 for (i = 0; i < len_src; i++) {
212 c = buf_src[i];
213 snprintf(tmp, sizeof(tmp), "%02x", c);
214 buf_dst[j++] = tmp[0];
215 buf_dst[j++] = tmp[1];
216 }
217
218 buf_dst[j] = '\0';
219
220 return buf_dst;
221 }
222
223 void Conn_debug(FILE *f, const unsigned short debug)
224 {
225 Conn_Log = f;
226 Conn_level = debug;
227 }
228
229 char *Conn_state(const struct Conn *C)
230 {
231 switch (C->state) {
232 case CONN_STATE_FREE: return "FREE";
233 case CONN_STATE_EMPTY: return "EMPTY";
234 case CONN_STATE_OPEN: return "OPEN";
235 case CONN_STATE_LISTEN: return "LISTEN";
236 case CONN_STATE_CONNECT_0: return "CONN0";
237 case CONN_STATE_CONNECT_a: return "CONNa";
238 case CONN_STATE_CONNECT_b: return "CONNb";
239
240 default: return "BUG?";
241 }
242 }
243
244 /*
245 * Expand the requested buffer
246 * what = 0 for out buffer, what = 1 for input buffer
247 * returns 0 if OK, -1 on error
248 */
249 int Conn_try_expand_buf(struct Conn *C, const int what, const int needed)
250 {
251 char *p;
252 unsigned int hm;
253 unsigned int slot, old_size, amount, head, tail;
254
255 slot = C->slot;
256
257 if (what == 0) {
258 head = C->obuf_head;
259 tail = C->obuf_tail;
260 } else {
261 head = C->ibuf_head;
262 tail = C->ibuf_tail;
263 }
264
265 Log(10, "\tTry to expand buffer on slot %u for [%s] needed=%d head=%u tail=%u.\n",
266 slot, what == 0 ? "o" : "i", needed,
267 head, tail);
268
269 amount = needed;
270
271 if (what == 0) {
272 if (amount < Conn_default_obuf)
273 amount = Conn_default_obuf;
274 old_size = Conns[slot].obuf_size;
275 hm = Conns[slot].obuf_size + amount;
276 if (hm > Conn_max_obuf)
277 hm = Conn_max_obuf;
278 p = realloc(Conns[slot].obuf, hm);
279 if (p == NULL) {
280 Log(3, "Cannot realloc obuf!\n");
281 return -1;
282 }
283 Conns[slot].obuf = p;
284 Conns[slot].obuf_size = hm;
285 Log(10, "\tSucces. Old/new size = %u/%u.\n",
286 old_size, Conns[slot].obuf_size);
287 } else {
288 if (amount < Conn_default_ibuf)
289 amount = Conn_default_ibuf;
290 old_size = Conns[slot].ibuf_size;
291 hm = Conns[slot].ibuf_size + amount;
292 if (hm > Conn_max_ibuf)
293 hm = Conn_max_ibuf;
294 p = realloc(Conns[slot].ibuf, hm);
295 if (p == NULL) {
296 Log(3, "Cannot realloc ibuf!\n");
297 return -1;
298 }
299 Conns[slot].ibuf = p;
300 Conns[slot].ibuf_size = hm;
301 Log(10, "\tSucces. Old/new size = %u/%u.\n",
302 old_size, Conns[slot].ibuf_size);
303 }
304
305 return 0;
306 }
307
308 static void Conn_poll_status(const short ev, char *ret)
309 {
310 strcpy(ret, "________");
311
312 if (ev & CONN_POLLIN) ret[0] = 'I';
313 if (ev & CONN_POLLPRI) ret[1] = 'P';
314 if (ev & CONN_POLLOUT) ret[2] = 'O';
315 if (ev & CONN_POLLERR) ret[3] = 'E';
316 if (ev & CONN_POLLHUP) ret[4] = 'H';
317 if (ev & CONN_POLLNVAL) ret[5] = 'V';
318 if (ev & CONN_POLLRDNORM) ret[6] = 'r';
319 if (ev & CONN_POLLRDBAND) ret[7] = 'R';
320 }
321
322 char *Conn_domain(const struct Conn *C)
323 {
324 switch (C->sock_domain) {
325 case PF_INET: return "IPv4";
326 case PF_INET6: return "IPv6";
327 case PF_PACKET: return "PACKET";
328
329 default: return "?";
330 }
331 }
332
333 char *Conn_type(const struct Conn *C)
334 {
335 switch (C->sock_type) {
336 case SOCK_STREAM: return "stream";
337 case SOCK_DGRAM: return "dgram";
338 case SOCK_RAW: return "raw";
339
340 default: return "?";
341 }
342 }
343
344 static char *Conn_socktype(const struct Conn *C)
345 {
346 switch (C->type) {
347 case Conn_type_MASTER: return "master";
348 case Conn_type_CLIENT: return "client";
349 case Conn_type_UNK: return "unk";
350
351 default:
352 return "?";
353 }
354 }
355
356 /*
357 * Returns a nice speed
358 */
359 void Conn_speed(char *dst, const unsigned int dst_len, const unsigned int speed)
360 {
361 float sp;
362
363 sp = speed;
364
365 if (speed < 1000)
366 snprintf(dst, dst_len, "%.2fBps", sp);
367 else if (speed < 1000 * 1000)
368 snprintf(dst, dst_len, "%.2fKBps", sp / 1000);
369 else
370 snprintf(dst, dst_len, "%.2fMBps", sp / 1000 / 1000);
371 }
372
373 char *Conn_status_slot(const struct Conn *C)
374 {
375 static char tmp[1024];
376 char polle[16], pollr[16];
377 char speedi[32], speedo[32];
378 unsigned int dT, si, so;
379
380 Conn_poll_status(C->events, polle);
381 Conn_poll_status(C->revents, pollr);
382
383 dT = Conn_now.tv_sec - C->start;
384 if (dT == 0)
385 dT = 1;
386 si = C->bi / dT;
387 so = C->bo / dT;
388
389 Conn_speed(speedi, sizeof(speedi), si);
390 Conn_speed(speedo, sizeof(speedo), so);
391
392 snprintf(tmp, sizeof(tmp), "%4d fd%4d"
393 " %4s %6s %5s %6s"
394 " %39s/%-5d\n"
395 " Via%-5d [%s][%s] IO=%llu/%llu"
396 " BS=%u/%u S=%s/%s"
397 " T=%ld bw=%u f=%u tk=%u id=%llu\n",
398 C->slot, C->fd,
399 Conn_domain(C), Conn_type(C), Conn_socktype(C), Conn_state(C),
400 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
401 C->ibuf_size, C->obuf_size, speedi, speedo,
402 Conn_now.tv_sec - C->start,
403 C->band_width, C->band_factor, C->band_tokens,
404 C->id);
405
406 return tmp;
407 }
408
409 char *Conn_status_slot_html(const struct Conn *C)
410 {
411 static char tmp[1024];
412 char polle[16], pollr[16], *ext = "";
413 char speedi[32], speedo[32];
414 unsigned int dT, si, so;
415
416 Conn_poll_status(Conns[C->slot].events, polle);
417 Conn_poll_status(Conns[C->slot].revents, pollr);
418
419 dT = Conn_now.tv_sec - C->start;
420 if (dT == 0)
421 dT = 1;
422 si = C->bi / dT;
423 so = C->bo / dT;
424
425 Conn_speed(speedi, sizeof(speedi), si);
426 Conn_speed(speedo, sizeof(speedo), so);
427
428 if (Conn_status_slot_html_cb)
429 ext = Conn_status_slot_html_cb(C);
430
431 snprintf(tmp, sizeof(tmp), "<td>%llu</td><td>%d</td><td>%d</td>"
432 "<td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
433 "<td>%s/%d</td>"
434 "<td>%d</td><td>%s</td><td>%s</td><td>%llu / %llu</td>"
435 "<td>%u / %u</td><td>%s / %s</td><td>%ld</td>"
436 "<td>%u</td><td>%u</td><td>%u</td>"
437 "%s\n",
438 C->id, C->slot, C->fd,
439 Conn_domain(C), Conn_type(C), Conn_socktype(C), Conn_state(C),
440 C->addr, C->port, C->via, polle, pollr, C->bi, C->bo,
441 C->ibuf_size, C->obuf_size,
442 speedi, speedo, Conn_now.tv_sec - C->start,
443 C->band_width, C->band_factor, C->band_tokens,
444 ext);
445
446 return tmp;
447 }
448
449 /* flags: bit 1 = 1 - html */
450 char *Conn_status(const unsigned int flags)
451 {
452 unsigned int len = 0, i, max;
453 struct Conn *C;
454 char tmp[512], tmp_len;
455 char polle[16], pollr[16];
456 char *buf, *slot, *ext = "";
457 char speedi[32], speedo[32];
458 unsigned long long bi, bo, dT;
459
460 max = (Conn_no + 1) * 512 - 1;
461 buf = malloc(max + 1);
462 if (!buf)
463 return strdup("No enough memory!");
464
465 strcpy(buf, "");
466
467 gettimeofday(&Conn_now, NULL);
468 /* TODO: "len += " is incorrect */
469 tmp_len = snprintf(tmp, sizeof(tmp), "Conn_pending=%d Conn_no/Conn_max=%d/%d Conn_total=%lu Conn_uptime=%lus Conn_allocated=%d\n",
470 Conn_pending, Conn_no, Conn_max, Conn_total, Conn_now.tv_sec - Conn_start, Conn_allocated);
471 if (len + tmp_len < max) {
472 strcat(buf, tmp);
473 len += tmp_len;
474 }
475
476 if (flags & 1)
477 if (Conn_status_cb)
478 ext = Conn_status_cb();
479
480 if (flags & 1) {
481 strcat(buf, "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#aaaaaa\">\n");
482 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
483 strcat(buf, "<td>ID</td>");
484 strcat(buf, "<td>Slot</td>");
485 strcat(buf, "<td>FD</td>");
486 strcat(buf, "<td>Dom</td>");
487 strcat(buf, "<td>Type</td>");
488 strcat(buf, "<td>SType</td>");
489 strcat(buf, "<td>State</td>");
490 strcat(buf, "<td>Addr/port</td>");
491 strcat(buf, "<td>Via</td>");
492 strcat(buf, "<td>Polle</td>");
493 strcat(buf, "<td>Pollr</td>");
494 strcat(buf, "<td>BI/BO</td>");
495 strcat(buf, "<td>BUF I/O</td>");
496 strcat(buf, "<td>Speed I/O</td>");
497 strcat(buf, "<td>Elap (s)</td>");
498 strcat(buf, "<td>Band</td>");
499 strcat(buf, "<td>F</td>");
500 strcat(buf, "<td>Tks</td>");
501 strcat(buf, ext);
502 strcat(buf, "</tr>\n");
503 } else {
504 strcat(buf, ext);
505 }
506
507 bi = 0; bo = 0; dT = 0;
508 for (i = 0; i < Conn_no; i++) {
509 C = &Conns[i];
510 if (C->state == CONN_STATE_FREE)
511 continue;
512
513 if (C->type == Conn_type_CLIENT) {
514 bi += C->bi;
515 bo += C->bo;
516 dT += Conn_now.tv_sec - C->start;
517 }
518
519 if (flags & 1)
520 strcat(buf, "<tr bgcolor=\"ffffff\">\n");
521
522 Conn_poll_status(Conns[C->slot].events, polle);
523 Conn_poll_status(Conns[C->slot].revents, pollr);
524
525 if ((flags & 1) == 0)
526 slot = Conn_status_slot(C);
527 else
528 slot = Conn_status_slot_html(C);
529 len += snprintf(tmp, sizeof(tmp), "%s", slot);
530 if (len < max)
531 strcat(buf, tmp);
532
533 if (flags & 1)
534 strcat(buf, "</tr>\n");
535 }
536
537 if (flags & 1)
538 strcat(buf, "</table>\n");
539
540 if (dT == 0)
541 dT = 1;
542
543 Conn_speed(speedi, sizeof(speedi), bi / dT);
544 Conn_speed(speedo, sizeof(speedo), bo / dT);
545
546 tmp_len = snprintf(tmp, sizeof(tmp), "Total speed I/O: %s / %s."
547 " Total bytes I/O: %llu / %llu\n",
548 speedi, speedo, bi, bo);
549 if (len + tmp_len < max) {
550 strcat(buf, tmp);
551 len += tmp_len;
552 }
553
554 return buf;
555 }
556
557 /*
558 * Returns the number of bytes in 'in' buffer
559 */
560 unsigned int Conn_qlen(const struct Conn *C)
561 {
562 return C->ibuf_tail - C->ibuf_head;
563 }
564
565 /*
566 * Returns 1 if we can ignore this connection
567 */
568 int Conn_ignore(struct Conn *C)
569 {
570 if (C->error_state > 0)
571 return 1;
572
573 return 0;
574 }
575
576 /*
577 * Close a connection if it exceeded maximum idle time or got a timeout
578 */
579 void Conn_expire(struct Conn *C)
580 {
581 long long diff_ms;
582
583 if ((C->trigger > 0)
584 && (C->last_trigger + C->trigger < Conn_now.tv_sec)) {
585 C->last_trigger = Conn_now.tv_sec;
586 if (C->cb_trigger)
587 C->cb_trigger(C);
588 else if (Conn_trigger_cb)
589 Conn_trigger_cb(C);
590 }
591
592 if ((C->idle > 0) && (C->trecv.tv_sec + C->idle < Conn_now.tv_sec)) {
593 C->error_state = CONN_ERROR_EXPIRED;
594 } else if ((C->read_timeout > 0) && (C->tsend.tv_sec > 0)
595 && (C->tsend.tv_sec > C->trecv.tv_sec)) {
596 diff_ms = Conn_time_diff(&Conn_now, &C->tsend);
597 if (diff_ms > C->read_timeout) {
598 C->error_state = CONN_ERROR_READ_TIMEOUT;
599 }
600 } else if ((C->conn_timeout > 0) && (C->state == CONN_STATE_CONNECT_b)) {
601 diff_ms = Conn_time_diff(&Conn_now, &C->conn_syn);
602 if (diff_ms > C->conn_timeout) {
603 /* connection attempt expired */
604 C->error_state = CONN_ERROR_CONN_TIMEOUT;
605 }
606 }
607 }
608
609 /*
610 * Set NODELAY on socket
611 */
612 int Conn_nodelay(const struct Conn *C)
613 {
614 int i = 1;
615
616 return setsockopt(C->fd, SOL_TCP, TCP_NODELAY, &i, sizeof(i));
617 }
618
619 void Conn_rollback(struct Conn *C, const unsigned int bytes)
620 {
621 if (C->obuf_tail - C->obuf_head <= bytes)
622 C->obuf_tail -= bytes;
623 }
624
625 /*
626 * Returns a pointer to current in buffer
627 */
628 char *Conn_ibuf(const struct Conn *C)
629 {
630 return C->ibuf + C->ibuf_head;
631 }
632
633 /*
634 * Returns a pointer to current out buffer
635 */
636 char *Conn_obuf(const struct Conn *C)
637 {
638 return C->obuf + C->obuf_head;
639 }
640
641 /*
642 * Returns the id of a connection
643 */
644 unsigned long long Conn_getid(const struct Conn *C)
645 {
646 return C->id;
647 }
648
649 /*
650 * Returns a Conn* searching by id
651 */
652 struct Conn *Conn_get(const unsigned long long id)
653 {
654 struct Conn *R = NULL;
655 int i;
656
657 for (i = Conn_no - 1; i >= 0; i--) {
658 if (Conns[i].id == id) {
659 R = &Conns[i];
660 break;
661 }
662 }
663
664 return R;
665 }
666
667 /*
668 * Returns the fd associated with C
669 */
670 int Conn_get_fd(const struct Conn *C)
671 {
672 if (C == NULL)
673 return -1;
674
675 return C->fd;
676 }
677
678 /*
679 * Returns the timeval of the last packet
680 */
681 void Conn_last_time(const struct Conn *C, struct timeval *tv)
682 {
683 *tv = C->trecv;
684 }
685
686 /*
687 * Search for str in active buffer from a given offset
688 * Returns pointer to string if match or NUll if doesn't.
689 */
690 char *Conn_ostrstr(struct Conn *C, const unsigned int off, const char *str)
691 {
692 unsigned int len, str_len, i;
693 char *buf, *ret = NULL;
694
695 len = C->ibuf_tail - C->ibuf_head - off;
696 buf = C->ibuf + C->ibuf_head + off;
697 str_len = strlen(str);
698
699 if (len < str_len)
700 return NULL;
701
702 i = 0;
703 while (i <= len - str_len) {
704 if (strncmp(buf + i, str, str_len) == 0) {
705 ret = buf + i;
706 break;
707 }
708
709 i++;
710 }
711
712 return ret;
713 }
714
715 /*
716 * Search for str in active buffer
717 * Returns pointer to string if match or NUll if doesn't.
718 */
719 char *Conn_strstr(struct Conn *C, const char *str)
720 {
721 return Conn_ostrstr(C, 0, str);
722 }
723
724 /*
725 * Set a callback
726 */
727 int Conn_set_cb(struct Conn *C, const unsigned int type, void (*f)(struct Conn *))
728 {
729 switch (type) {
730 case CONN_CB_ACCEPT: C->cb_accept = f; break;
731 case CONN_CB_RECV: C->cb_recv = f; break;
732 case CONN_CB_SEND: C->cb_send = f; break;
733 case CONN_CB_DATA: C->cb_data = f; break;
734 case CONN_CB_CLOSE: C->cb_close = f; break;
735 case CONN_CB_TRIGGER: C->cb_trigger = f; break;
736 case CONN_CB_ERROR: C->cb_error = f; break;
737 case CONN_CB_CONNECTED: C->cb_connected = f; break;
738
739 default:
740 return -1;
741 }
742
743 return 0;
744 }
745
746 /*
747 * Returns a '\0' terminated line, modifying received buffer
748 */
749 char *Conn_get_line(struct Conn *C)
750 {
751 char *cr;
752
753 cr = Conn_strstr(C, "\n");
754 if (!cr)
755 return NULL;
756
757 *cr = '\0';
758
759 return Conn_ibuf(C);
760 }
761
762 /*
763 * Helper help building text line daemons
764 */
765 void Conn_for_every_line(struct Conn *C, int (*cb)(struct Conn *C, char *line))
766 {
767 int ret = 0;
768 char *line;
769 unsigned int line_size;
770
771 if (cb == NULL)
772 return;
773
774 while (1) {
775 line = Conn_get_line(C);
776 if (line == NULL)
777 break;
778
779 line_size = strlen(line) + 1;
780
781 ret = cb(C, line);
782 if (ret != 0)
783 break;
784
785 Conn_eat(C, line_size);
786 }
787 }
788
789 /*
790 * Eat @bytes from head of input buffer
791 */
792 void Conn_eat(struct Conn *C, const unsigned int bytes)
793 {
794 unsigned int slot;
795
796 slot = C->slot;
797
798 /* advance head */
799 Conns[slot].ibuf_head += bytes;
800 if (Conns[slot].ibuf_head >= Conns[slot].ibuf_tail) {
801 Conns[slot].ibuf_head = 0;
802 Conns[slot].ibuf_tail = 0;
803 }
804
805 Log(10, "Conn_eat(C, %u) head=%u tail=%u qlen=%u\n",
806 bytes, C->ibuf_head, C->ibuf_tail,
807 Conn_qlen(C));
808 }
809
810 /*
811 * Eat all input buffer
812 */
813 void Conn_eatall(struct Conn *C)
814 {
815 Conn_eat(C, Conn_qlen(C));
816 }
817
818 /*
819 * If put buffer is empty, just mark for closing.
820 * If we have data, set the flag to do the closing after send.
821 */
822 void Conn_close(struct Conn *C)
823 {
824 if (C->obuf_head == C->obuf_tail)
825 C->error_state = CONN_ERROR_USERREQ;
826 else
827 C->flags |= CONN_FLAGS_CLOSE_AFTER_SEND;
828 }
829
830 /*
831 * Set some internal parameters
832 */
833 void Conn_set(struct Conn *C, const unsigned int var, const int val)
834 {
835 int fd;
836
837 fd = Conn_get_fd(C);
838
839 switch (var) {
840 case CONN_PARA_AUTO_RECONNECT:
841 C->flags |= (val == 0) ? 0 : CONN_FLAGS_AUTO_RECONNECT;
842 break;
843 case CONN_PARA_RECONNECT_DELAY:
844 C->delay = val;
845 break;
846 case CONN_PARA_IDLE_TIME:
847 C->idle = val;
848 break;
849 case CONN_PARA_READ_TIMEOUT:
850 C->read_timeout = val;
851 break;
852 case CONN_PARA_CONN_TIMEOUT:
853 C->conn_timeout = val;
854 break;
855 case CONN_PARA_TRIGGER:
856 C->trigger = val;
857 break;
858 case CONN_PARA_IBUF:
859 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));
860 break;
861 case CONN_PARA_OBUF:
862 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
863 break;
864 }
865 }
File Conn_engine_core.h copied from file Conn.h (similarity 69%) (mode: 100644) (index 7241948..93ae938)
1 #ifndef _Conn_h
2 #define _Conn_h 1
1 #ifndef CONN_ENGINE_CORE_H
2 #define CONN_ENGINE_CORE_H
3
4 #include <Conn_config.h>
3 5
4 6 #define _GNU_SOURCE #define _GNU_SOURCE
5 7
 
20 22 #include <unistd.h> #include <unistd.h>
21 23 #include <string.h> #include <string.h>
22 24 #include <fcntl.h> #include <fcntl.h>
23 #include <sys/poll.h>
24 25 #include <arpa/inet.h> #include <arpa/inet.h>
25 26 #include <netinet/tcp.h> #include <netinet/tcp.h>
26 27
27 28
28
29 29 /* type */ /* type */
30 30 #define Conn_type_MASTER 1 #define Conn_type_MASTER 1
31 31 #define Conn_type_CLIENT 2 #define Conn_type_CLIENT 2
 
87 87 #define CONN_CB_ERROR CONN_CB_START + 7 #define CONN_CB_ERROR CONN_CB_START + 7
88 88 #define CONN_CB_CONNECTED CONN_CB_START + 8 #define CONN_CB_CONNECTED CONN_CB_START + 8
89 89
90 /* Engine type */
91 #define CONN_ENGINE_POLL 1
92 #define CONN_ENGINE_EPOLL 2
93
94 extern unsigned int CONN_POLLIN;
95 extern unsigned int CONN_POLLOUT;
96 extern unsigned int CONN_POLLPRI;
97 extern unsigned int CONN_POLLERR;
98 extern unsigned int CONN_POLLHUP;
99 extern unsigned int CONN_POLLNVAL;
100 extern unsigned int CONN_POLLRDNORM;
101 extern unsigned int CONN_POLLRDBAND;
90 102
91 103 struct Conn struct Conn
92 104 { {
105 int fd;
106 unsigned int events, revents; /* I/O events */
107
93 108 unsigned char type; unsigned char type;
94 109
95 110 unsigned char state; unsigned char state;
 
... ... struct Conn
104 119 unsigned int obuf_size, obuf_head, obuf_tail; unsigned int obuf_size, obuf_head, obuf_tail;
105 120
106 121 struct timeval trecv, tsend; /* last time we saw an receive/send */ struct timeval trecv, tsend; /* last time we saw an receive/send */
107 unsigned int idle; /* idle time allowed */
122 time_t idle; /* idle time allowed */
108 123 unsigned int read_timeout; /* Max timeout for receiving an answer (milliseconds) */ unsigned int read_timeout; /* Max timeout for receiving an answer (milliseconds) */
109 124
110 125 struct timeval conn_syn; /* Time when a connection was initiated */ struct timeval conn_syn; /* Time when a connection was initiated */
111 126 unsigned int conn_timeout; /* Timeout for connection (milliseconds) */ unsigned int conn_timeout; /* Timeout for connection (milliseconds) */
112 127
113 128 time_t last_trigger; /* last trigger was at */ time_t last_trigger; /* last trigger was at */
114 unsigned int trigger; /* Frequency of wakeup a connection */
129 time_t trigger; /* Frequency of wakeup a connection */
115 130
116 131 int sock_domain; int sock_domain;
117 132 int sock_type; int sock_type;
 
... ... extern void (*Conn_trigger_cb)(struct Conn *C);
165 180 extern void (*Conn_error_cb)(struct Conn *C); extern void (*Conn_error_cb)(struct Conn *C);
166 181 extern void (*Conn_connected_cb)(struct Conn *C); extern void (*Conn_connected_cb)(struct Conn *C);
167 182
168 extern char *(*Conn_status_slot_html_cb)(struct Conn *C);
183 extern char *(*Conn_status_slot_html_cb)(const struct Conn *C);
169 184 extern char *(*Conn_status_cb)(void); extern char *(*Conn_status_cb)(void);
170 185
171 186 extern unsigned int Conn_max_reached; extern unsigned int Conn_max_reached;
 
... ... extern unsigned int Conn_max_send;
184 199 extern unsigned int Conn_max_recv; extern unsigned int Conn_max_recv;
185 200
186 201 extern unsigned short Conn_level; extern unsigned short Conn_level;
202 extern unsigned int Conn_accept_is_allowed;
203 extern unsigned int Conn_accept_is_allowed_last;
204
205 extern struct Conn *Conns;
206 extern unsigned int Conn_inited;
207 extern unsigned int Conn_allocated;
208 extern unsigned long long Conn_id;
209
210 extern char Conn_error[512];
211
212 extern FILE *Conn_Log;
213 extern int debug_band;
187 214
188 215
189 216 /* Functions */ /* Functions */
190 217 extern char *Conn_strerror(void); extern char *Conn_strerror(void);
191 extern int Conn_init(unsigned int max);
218 extern void Log(const unsigned short level, char *format, ...);
219 extern char *Conn_errno(const struct Conn *C);
220 extern char *Conn_status_slot(const struct Conn *C);
221 extern char *Conn_status(const unsigned int flags);
222 extern int Conn_try_expand_buf(struct Conn *C, const int what,
223 const int needed);
224 extern char *Conn_state(const struct Conn *C);
225
226 extern long long Conn_time_diff(const struct timeval *t1,
227 const struct timeval *t2);
228 extern void Conn_last_time(const struct Conn *C, struct timeval *tv);
229
230 extern int Conn_setnonblock(const int fd);
231
232 extern char *Conn_dump(const char *buf_src, const int len_src);
233 extern char *Conn_dumphex(const char *buf_src, const int len_src);
234 extern void Conn_debug(FILE *f, const unsigned short debug);
235
192 236 extern void Conn_close(struct Conn *C); extern void Conn_close(struct Conn *C);
193 extern ssize_t Conn_send(struct Conn *C, void *buf, size_t count);
194 extern ssize_t Conn_recv(struct Conn *C, void *buf, size_t count);
195 extern struct Conn *Conn_socket(int domain, int type, int port);
196 extern char *Conn_status(unsigned int flags);
197 extern int Conn_poll(int timeout);
198 extern int Conn_enqueue(struct Conn *C, void *buf, size_t count);
199 extern void Conn_debug(FILE *f, unsigned short debug);
200 extern struct Conn *Conn_connect(int domain, int type, char *addr, int port);
201 extern char *Conn_dump(char *buf_src, int len_src);
202 extern char *Conn_dumphex(char *buf_src, int len_src);
203 extern int Conn_nodelay(struct Conn *C);
204 extern void Conn_rollback(struct Conn *C, unsigned int bytes);
205 extern char *Conn_strstr(struct Conn *C, char *str);
206 extern unsigned int Conn_qlen(struct Conn *C);
207 extern void Conn_eat(struct Conn *C, unsigned int bytes);
208 extern void Conn_eatall(struct Conn *C);
209 extern char *Conn_ibuf(struct Conn *C);
210 extern char *Conn_obuf(struct Conn *C);
211 extern int Conn_try_expand_buf(struct Conn *C, int what, int needed);
212 extern int Conn_band(struct Conn *C, unsigned int width, unsigned int factor);
213 extern void Conn_set(struct Conn *C, int var, unsigned int val);
214 extern char *Conn_ostrstr(struct Conn *C, unsigned int off, char *str);
215 extern unsigned long long Conn_getid(struct Conn *C);
216 extern struct Conn *Conn_get(unsigned long long id);
217 extern int Conn_get_fd(struct Conn *C);
218 extern void Conn_last_time(struct Conn *C, struct timeval *tv);
219 extern int Conn_set_cb(struct Conn *C, unsigned int type,
237
238 extern int Conn_ignore(struct Conn *C);
239
240 extern void Conn_expire(struct Conn *C);
241
242 extern int Conn_set_cb(struct Conn *C, const unsigned int type,
220 243 void (*f)(struct Conn *)); void (*f)(struct Conn *));
221 244 extern char *Conn_get_line(struct Conn *C); extern char *Conn_get_line(struct Conn *C);
222 245 extern void Conn_for_every_line(struct Conn *C, extern void Conn_for_every_line(struct Conn *C,
223 246 int (*cb)(struct Conn *C, char *line)); int (*cb)(struct Conn *C, char *line));
224 247
248 extern void Conn_eat(struct Conn *C, const unsigned int bytes);
249 extern void Conn_eatall(struct Conn *C);
250
251 extern unsigned int Conn_qlen(const struct Conn *C);
252
253 extern void Conn_set(struct Conn *C, const unsigned int var,
254 const int val);
255
256 extern int Conn_get_fd(const struct Conn *C);
257
258 extern unsigned long long Conn_getid(const struct Conn *C);
259
260 extern char *Conn_ibuf(const struct Conn *C);
261 extern char *Conn_obuf(const struct Conn *C);
262
263 extern char *Conn_domain(const struct Conn *C);
264 extern char *Conn_type(const struct Conn *C);
265
225 266 #endif #endif
File Conn_engine_epoll.c added (mode: 100644) (index 0000000..0bf0866)
1 #include <Conn_config.h>
2
3 #ifdef EPOLL_FOUND
4
5 #include <Conn_engine_epoll.h>
6
7 /*
8 * Variables
9 */
10 static unsigned long Conn_epoll_allocated_slots = 0;
11 static int Conn_epoll_fd;
12 static struct epoll_event *Conn_epoll_events = NULL;
13
14 /*
15 * Functions
16 */
17
18 /*
19 * Init the engine
20 */
21 int Conn_epoll_init(void)
22 {
23 Conn_epoll_fd = epoll_create(256);
24 if (Conn_epoll_fd == -1) {
25 snprintf(Conn_error, sizeof(Conn_error),
26 "Cannot open epoll socket (%s).", strerror(errno));
27 return -1;
28 }
29
30 return 0;
31 }
32
33 int Conn_epoll_shutdown(void)
34 {
35 close(Conn_epoll_fd);
36
37 return 0;
38 }
39
40 /*
41 * Grow the number of slots needed for epoll
42 */
43 int Conn_epoll_grow(unsigned int alloc)
44 {
45 struct epoll_event *p, *set;
46 unsigned int diff;
47
48 Log(10, "%s: Try to grow pollfds from %d to %d.\n",
49 __FUNCTION__,
50 Conn_epoll_allocated_slots, alloc);
51
52 if (alloc <= Conn_epoll_allocated_slots)
53 return 0;
54
55 diff = alloc - Conn_epoll_allocated_slots;
56
57 p = (struct epoll_event *) realloc(Conn_epoll_events, alloc
58 * sizeof(struct epoll_event));
59 if (p == NULL) {
60 snprintf(Conn_error, sizeof(Conn_error),
61 "Cannot alloc memory for epoll_events.");
62 return -1;
63 }
64
65 set = p + Conn_epoll_allocated_slots;
66 memset(set, 0, diff * sizeof(struct epoll_event));
67 Conn_epoll_events = p;
68
69 return 0;
70 }
71
72 /*
73 * Add a target to the list
74 */
75 int Conn_epoll_add_obj(struct Conn *C)
76 {
77 int ret;
78 struct epoll_event ev;
79
80 memset(&ev, 0, sizeof(ev));
81 ev.data.ptr = C;
82 ev.events = C->events;
83 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_ADD, C->fd, &ev);
84 if (ret == -1) {
85 snprintf(Conn_error, sizeof(Conn_error),
86 "Cannot add obj to list (%s).", strerror(errno));
87 return -1;
88 }
89
90 return 0;
91 }
92
93 /*
94 * Remove a target from list
95 */
96 int Conn_epoll_del_obj(struct Conn *C)
97 {
98 int ret;
99
100 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_DEL, C->fd, NULL);
101 if (ret == -1) {
102 snprintf(Conn_error, sizeof(Conn_error),
103 "Cannot delete obj to list (%s).", strerror(errno));
104 return -1;
105 }
106
107 return 0;
108 }
109
110 /*
111 * Change event mask
112 */
113 int Conn_epoll_chg_obj(struct Conn *C)
114 {
115 struct epoll_event ev;
116 int ret;
117
118 memset(&ev, 0, sizeof(ev));
119 ev.events = C->events;
120 ev.data.ptr = C;
121 ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_MOD, C->fd, &ev);
122 if (ret != 0) {
123 snprintf(Conn_error, sizeof(Conn_error),
124 "Cannot modify events for obj (%s).", strerror(errno));
125 return -1;
126 }
127
128 return 0;
129 }
130
131 /*
132 * Calls a callback for fds with activity
133 * Returns: -1 on error, 0 nothing to do, n (>0) if some work was done
134 * timeout is in 1/1000 seconds increments.
135 */
136 int Conn_epoll_poll(const int timeout2, void (*cb)(struct Conn *C,
137 const int revents))
138 {
139 int i, events;
140
141 again:
142 events = epoll_wait(Conn_epoll_fd, Conn_epoll_events, Conn_no, timeout2);
143 if ((events == -1) && (errno == EINTR))
144 goto again;
145
146 if (events < 0) {
147 snprintf(Conn_error, sizeof(Conn_error),
148 "%s: Conn_no=%d [%s]",
149 __FUNCTION__, Conn_no, strerror(errno));
150 return -1;
151 }
152
153 if (events == 0)
154 return 0;
155
156 gettimeofday(&Conn_now, NULL);
157
158 Log(11, "Processing %d event(s)...\n", events);
159 i = events - 1;
160 do {
161 cb((struct Conn *) Conn_epoll_events[i].data.ptr,
162 Conn_epoll_events[i].events);
163
164 i--;
165 } while (i >= 0);
166
167 return events;
168 }
169
170 /*
171 * Move a slot over an other.
172 */
173 void Conn_epoll_move_slot(const unsigned int dst, const unsigned int src)
174 {
175 unsigned int tmp;
176
177 /* Nothing to do - shut up the compiler */
178 tmp = dst;
179 tmp = src;
180 }
181
182 #endif
File Conn_engine_epoll.h added (mode: 100644) (index 0000000..b648aaf)
1 #ifndef CONN_ENGINE_EPOLL_H
2 #define CONN_ENGINE_EPOLL_H
3
4 #ifdef EPOLL_FOUND
5
6 #include <sys/epoll.h>
7
8 #include <Conn_engine_core.h>
9
10 extern int Conn_epoll_init(void);
11 extern int Conn_epoll_shutdown(void);
12 extern int Conn_epoll_grow(unsigned int alloc);
13 extern int Conn_epoll_add_obj(struct Conn *C);
14 extern int Conn_epoll_del_obj(struct Conn *C);
15 extern int Conn_epoll_chg_obj(struct Conn *C);
16 extern int Conn_epoll_poll(const int timeout2, void (*cb)(struct Conn *C,
17 const int revents));
18 extern void Conn_epoll_move_slot(const unsigned int dst,
19 const unsigned int src);
20
21 #endif
22
23 #endif
File Conn_engine_poll.c added (mode: 100644) (index 0000000..264b9b6)
1 #include <Conn_config.h>
2
3 #ifdef POLL_FOUND
4
5 #include <Conn_engine_poll.h>
6
7 /*
8 * Variables
9 */
10 static unsigned long Conn_poll_allocated_slots = 0;
11 static struct pollfd *Conn_poll_pfds = NULL;
12
13 /*
14 * Functions
15 */
16
17 /*
18 * Init the engine
19 */
20 int Conn_poll_init(void)
21 {
22 return 0;
23 }
24
25 int Conn_poll_shutdown(void)
26 {
27 free(Conn_poll_pfds);
28
29 return 0;
30 }
31
32 /*
33 * Grow the number of slots needed for poll
34 */
35 int Conn_poll_grow(unsigned int alloc)
36 {
37 struct pollfd *p, *set;
38 unsigned int diff, mem;
39
40 Log(10, "%s: Trying to grow pollfds from %d to %d.\n",
41 __FUNCTION__,
42 Conn_poll_allocated_slots, alloc);
43
44 if (alloc <= Conn_poll_allocated_slots)
45 return 0;
46
47 diff = alloc - Conn_poll_allocated_slots;
48
49 mem = alloc * sizeof(struct pollfd);
50 p = (struct pollfd *) realloc(Conn_poll_pfds, mem);
51 if (p == NULL) {
52 snprintf(Conn_error, sizeof(Conn_error),
53 "Cannot alloc %u bytes for pollfds.", mem);
54 return -1;
55 }
56
57 set = p + Conn_poll_allocated_slots;
58 memset(set, 0, diff * sizeof(struct pollfd));
59 Conn_poll_pfds = p;
60
61 return 0;
62 }
63
64 /*
65 * Add a target to the list
66 */
67 int Conn_poll_add_obj(struct Conn *C)
68 {
69 Conn_poll_pfds[C->slot].fd = C->fd;
70 Conn_poll_pfds[C->slot].events = C->events;
71
72 return 0;
73 }
74
75 /*
76 * Remove a target from the list
77 */
78 int Conn_poll_del_obj(struct Conn *C)
79 {
80 Conn_poll_pfds[C->slot].fd = -1;
81 Conn_poll_pfds[C->slot].events = 0;
82
83 return 0;
84 }
85
86 /*
87 * Change event mask
88 */
89 int Conn_poll_chg_obj(struct Conn *C)
90 {
91 Conn_poll_pfds[C->slot].events = C->events;
92
93 return 0;
94 }
95
96
97 /*
98 * Calls a callback for fds with activity
99 * Returns: -1 on error, 0 nothing to do, n (>0) if some work was done
100 * timeout is in 1/1000 seconds increments.
101 */
102 int Conn_poll_poll(const int timeout2, void (*cb)(struct Conn *C,
103 const int revents))
104 {
105 int i, events;
106
107 again:
108 events = poll(&Conn_poll_pfds[0], Conn_no, timeout2);
109 if ((events == -1) && (errno == EINTR))
110 goto again;
111
112 if (events < 0) {
113 snprintf(Conn_error, sizeof(Conn_error),
114 "%s: Conn_no=%d [%s]",
115 __FUNCTION__, Conn_no,
116 strerror(errno));
117 return -1;
118 }
119
120 if (events == 0)
121 return 0;
122
123 gettimeofday(&Conn_now, NULL);
124
125 /* We do revers scan because of moving Conn objects */
126 Log(11, "Processing %d event(s)...\n",
127 events);
128 i = Conn_no - 1;
129 do {
130 if (Conn_poll_pfds[i].revents & POLLNVAL) {
131 Log(0, "BUG NVAL!\n");
132 exit(1);
133 }
134
135 cb(&Conns[i], Conn_poll_pfds[i].revents);
136
137 i--;
138 } while (i >= 0);
139
140 return events;
141
142 }
143
144 /*
145 * Move a slot over an other.
146 */
147 void Conn_poll_move_slot(const unsigned int dst, const unsigned int src)
148 {
149 Conn_poll_pfds[dst] = Conn_poll_pfds[src];
150 }
151
152 #endif
File Conn_engine_poll.h added (mode: 100644) (index 0000000..f897f7d)
1 #ifndef CONN_ENGINE_POLL_H
2 #define CONN_ENGINE_POLL_H
3
4 #ifdef POLL_FOUND
5
6 #include <sys/poll.h>
7
8 #include <Conn_engine_core.h>
9
10 extern int Conn_poll_init(void);
11 extern int Conn_poll_shutdown(void);
12 extern int Conn_poll_grow(unsigned int alloc);
13 extern int Conn_poll_add_obj(struct Conn *C);
14 extern int Conn_poll_del_obj(struct Conn *C);
15 extern int Conn_poll_chg_obj(struct Conn *C);
16 extern int Conn_poll_poll(const int timeout2, void (*cb)(struct Conn *C,
17 const int revents));
18 extern void Conn_poll_move_slot(const unsigned int dst,
19 const unsigned int src);
20 #endif
21
22 #endif
File Makefile.in changed (mode: 100644) (index 73073f4..be2b8cb)
1 1 export CC := gcc export CC := gcc
2 2 export INCS += -I. export INCS += -I.
3 export LIBS += -L/usr/local/lib
3 export LIBS +=
4 4 export CFLAGS += -ggdb3 -Wall -Wextra -pedantic -Wno-long-long -pipe -fpic -O0 export CFLAGS += -ggdb3 -Wall -Wextra -pedantic -Wno-long-long -pipe -fpic -O0
5 export OBJS += Conn.o
5 export OBJS += Conn_engine_core.o Conn_engine_poll.o Conn_engine_epoll.o Conn.o
6 6
7 7 .PHONY: all .PHONY: all
8 8 all: libConn.so.@VER@ libConn.a examples all: libConn.so.@VER@ libConn.a examples
9 9
10 10
11 Conn_engine_core.o: Conn_engine_core.c Conn_engine_core.h Conn_config.h
12 $(CC) $(CFLAGS) $(INCS) -c Conn_engine_core.c -o $@
13
14 Conn_engine_poll.o: Conn_engine_poll.c Conn_config.h Conn_engine_core.h
15 $(CC) $(CFLAGS) $(INCS) -c Conn_engine_poll.c -o $@
16
17 Conn_engine_epoll.o: Conn_engine_epoll.c Conn_config.h Conn_engine_core.h
18 $(CC) $(CFLAGS) $(INCS) -c Conn_engine_epoll.c -o $@
19
11 20 %.o: %.c %.o: %.c
12 21 gcc $(CFLAGS) $(INCS) $< -c gcc $(CFLAGS) $(INCS) $< -c
13 22
14 23 libConn.so.@VER@: $(OBJS) libConn.so.@VER@: $(OBJS)
15 $(CC) $(CFLAGS) -shared -Wl,-soname,libConn.so \
24 $(CC) $(CFLAGS) $(INCS) -shared -Wl,-soname,libConn.so \
16 25 -o $@ $(OBJS) -lc $(LIBS) -o $@ $(OBJS) -lc $(LIBS)
17 26 ln -sf $@ libConn.so ln -sf $@ libConn.so
18 27
File TODO changed (mode: 100644) (index b9f9dab..8e95002)
... ... Pentru a reduce numarul de conexiuni in TIME-WAIT:
41 41 [ ] Change socket buffer accordingly with user settings to minimize [ ] Change socket buffer accordingly with user settings to minimize
42 42 needed memory. needed memory.
43 43
44 [ ] Dump how many memory is in use vor various parts of the internal data.
45 [ ] Switch to enum for easy debugging.
46 [ ] Do not mix slot and id and fd in examples.
File duilder changed (mode: 100755) (index b04240a..c725a3c)
... ... function duilder_docs()
9 9 EXPORT_PATH="${3}" EXPORT_PATH="${3}"
10 10
11 11 echo "Copying docs to [${EXPORT_PATH}]..." echo "Copying docs to [${EXPORT_PATH}]..."
12 for f in README License LICENSE Changelog TODO FAQ INSTALL; do
12 for f in README License LICENCE Changelog TODO FAQ INSTALL; do
13 13 if [ -r "${f}" ]; then if [ -r "${f}" ]; then
14 14 cp -vp "${f}" "${EXPORT_PATH}/" cp -vp "${f}" "${EXPORT_PATH}/"
15 15 fi fi
 
... ... function duilder_git()
51 51 echo "Generate GIT tree for HTTP transport..." echo "Generate GIT tree for HTTP transport..."
52 52 if [ ! -d "${GIT_DEST}/${PRJ}.git" ]; then if [ ! -d "${GIT_DEST}/${PRJ}.git" ]; then
53 53 git-clone --bare . "${GIT_DEST}/${PRJ}.git" git-clone --bare . "${GIT_DEST}/${PRJ}.git"
54
55 # Activate post-update hook
56 54 chmod a+x "${GIT_DEST}/${PRJ}.git/hooks/post-update" chmod a+x "${GIT_DEST}/${PRJ}.git/hooks/post-update"
57
58 # add project name and description
59 55 echo "${PRJ}" > "${GIT_DEST}/${PRJ}.git/description" echo "${PRJ}" > "${GIT_DEST}/${PRJ}.git/description"
60
61 56 # allow export by git daemon? # allow export by git daemon?
62 57 #touch "${GIT_DEST}/${PRJ}.git/git-daemon-export-ok #touch "${GIT_DEST}/${PRJ}.git/git-daemon-export-ok
63 58 else else
 
... ... function duilder_tar()
193 188
194 189 #################################################################### ####################################################################
195 190
196 # Multiplexer
191 ###### Multiplexer
197 192 if [ "${1}" = "docs" ]; then if [ "${1}" = "docs" ]; then
198 193 shift shift
199 194 duilder_docs "$@" duilder_docs "$@"
 
... ... done
289 284 DB_SUPPORT=0 DB_SUPPORT=0
290 285
291 286 echo -n "Searching for PostgreSQL..." echo -n "Searching for PostgreSQL..."
287 PG_FOUND=0
288 PG_VERSION=""
292 289 set +e set +e
293 290 PG_VERSION="`pg_config --version 2>/dev/null`" PG_VERSION="`pg_config --version 2>/dev/null`"
294 291 set -e set -e
295 292 if [ -z "${PG_VERSION}" ]; then if [ -z "${PG_VERSION}" ]; then
296 293 echo " not found." echo " not found."
297 PG_FOUND=0
298 294 else else
299 295 echo " found version ${PG_VERSION}." echo " found version ${PG_VERSION}."
300 296 PG_FOUND=1 PG_FOUND=1
301 297 PG_INC="${DB_INC} -I`pg_config --includedir`" PG_INC="${DB_INC} -I`pg_config --includedir`"
302 298 PG_LIB="${DB_INC} -L`pg_config --libdir` -lpq" PG_LIB="${DB_INC} -L`pg_config --libdir` -lpq"
303
304 echo "s#@PG_VERSION@#${PG_VERSION}#g" >> tmp.sed
305 echo "s#@PG_INC@#${PG_INC}#g" >> tmp.sed
306 echo "s#@PG_LIB@#${PG_LIB}#g" >> tmp.sed
307
308 299 DB_SUPPORT=1 DB_SUPPORT=1
309 echo "s#@DB_SUPPORT@#${DB_SUPPORT}#g" >> tmp.sed
310 300 fi fi
311 echo "s#@PG_FOUND@#${PG_FOUND}#g" >> tmp.sed
312 301
302 echo -n "Searching for poll..."
303 set +e
304 echo -e "#include <sys/poll.h> \n int main(void) { struct pollfd x; memset(&x, 0, sizeof(struct pollfd)); return poll(&x, 1, 0); }" | gcc -x c -pipe - -o /dev/null 2>/dev/null
305 set -e
306 E="${?}"
307 if [ "${E}" != "0" ]; then
308 echo " not found."
309 echo "s#@POLL_FOUND@#0#g" >> tmp.sed
310 else
311 echo " found."
312 echo "s#@POLL_FOUND@#1#g" >> tmp.sed
313 fi
313 314
314 315 echo -n "Searching for epoll..." echo -n "Searching for epoll..."
315 316 set +e set +e
316 317 echo -e "#include <sys/epoll.h> \n int main(void) { return epoll_create(64); }" | gcc -x c -pipe - -o /dev/null 2>/dev/null echo -e "#include <sys/epoll.h> \n int main(void) { return epoll_create(64); }" | gcc -x c -pipe - -o /dev/null 2>/dev/null
317 E="${?}"
318 318 set -e set -e
319 E="${?}"
319 320 if [ "${E}" != "0" ]; then if [ "${E}" != "0" ]; then
320 321 echo " not found." echo " not found."
321 322 echo "s#@EPOLL_FOUND@#0#g" >> tmp.sed echo "s#@EPOLL_FOUND@#0#g" >> tmp.sed
 
... ... fi
328 329 echo "s#@PRJ@#${PRJ}#g" >> tmp.sed echo "s#@PRJ@#${PRJ}#g" >> tmp.sed
329 330 echo "s#@VER@#${VER}#g" >> tmp.sed echo "s#@VER@#${VER}#g" >> tmp.sed
330 331 echo "s#@REV@#${REV}#g" >> tmp.sed echo "s#@REV@#${REV}#g" >> tmp.sed
331 echo "s#@DESCRIPTION@#${DESCRIPTION}#g" >> tmp.sed
332
333 332 echo "s#@ETC@#${ETC}#g" >> tmp.sed echo "s#@ETC@#${ETC}#g" >> tmp.sed
334 333 echo "s#@BIN@#${BIN}#g" >> tmp.sed echo "s#@BIN@#${BIN}#g" >> tmp.sed
335 334 echo "s#@USR_BIN@#${USR_BIN}#g" >> tmp.sed echo "s#@USR_BIN@#${USR_BIN}#g" >> tmp.sed
 
... ... echo "s#@USR_INCLUDE@#${USR_INCLUDE}#g" >> tmp.sed
340 339 echo "s#@USR_INC@#${USR_INCLUDE}#g" >> tmp.sed echo "s#@USR_INC@#${USR_INCLUDE}#g" >> tmp.sed
341 340 echo "s#@USR_LIB@#${USR_LIB}#g" >> tmp.sed echo "s#@USR_LIB@#${USR_LIB}#g" >> tmp.sed
342 341 echo "s#@USR_SHARE_DOC@#${USR_SHARE_DOC}#g" >> tmp.sed echo "s#@USR_SHARE_DOC@#${USR_SHARE_DOC}#g" >> tmp.sed
342 # PG stuff
343 echo "s#@PG_VERSION@#${PG_VERSION}#g" >> tmp.sed
344 echo "s#@PG_FOUND@#${PG_FOUND}#g" >> tmp.sed
345 echo "s#@PG_INC@#${PG_INC}#g" >> tmp.sed
346 echo "s#@PG_LIB@#${PG_LIB}#g" >> tmp.sed
347 # DB stuff
348 echo "s#@DB_SUPPORT@#${DB_SUPPORT}#g" >> tmp.sed
343 349 # Export stuff # Export stuff
344 350 echo "s#@EXPORT_PATH@#${EXPORT_PATH}#g" >> tmp.sed echo "s#@EXPORT_PATH@#${EXPORT_PATH}#g" >> tmp.sed
345 351
 
... ... if [ -r "${PRJ}.spec.in" ]; then
401 407 fi fi
402 408
403 409 if [ -r config.h.in ]; then if [ -r config.h.in ]; then
404 echo "Generate config.h file..."
410 echo "Generating config.h file..."
405 411 sed -f tmp.sed config.h.in > config.h sed -f tmp.sed config.h.in > config.h
406 412 fi fi
407 413
414 if [ -r "${CONFIG_H}.in" ]; then
415 echo "Generating ${CONFIG_H} file..."
416 sed -f tmp.sed "${CONFIG_H}.in" > "${CONFIG_H}"
417 fi
418
408 419 rm -f tmp.sed rm -f tmp.sed
409 420
410 421 if [ "`basename ${0}`" = "duilderx" ]; then if [ "`basename ${0}`" = "duilderx" ]; then
File duilder.conf changed (mode: 100644) (index 22c92fc..6581230)
... ... SRPM_POST_RUN="/usr/local/bin/submit_package"
11 11 BUILD_TGZ="1" BUILD_TGZ="1"
12 12 BUILD_DEB="1" BUILD_DEB="1"
13 13
14 CONFIG_H="Conn_config.h"
File examples/Makefile changed (mode: 100644) (index 1503a0b..1c5e9b6)
... ... TARGETS := s c raw udp_s timeout trigger line1
2 2
3 3 all: $(TARGETS) all: $(TARGETS)
4 4
5 INCS += -I. -I..
5 INCS += -I..
6 6 LIBS += -L.. -lConn LIBS += -L.. -lConn
7 7 OBJS := OBJS :=
8 DEPS := ../libConn.so.$(VER) $(OBJS)
8 9
9 s: s.c $(OBJS)
10 s: s.c $(DEPS)
10 11 gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS) gcc $(CFLAGS) $(INCS) s.c -o s $(LIBS)
11 12
12 c: c.c $(OBJS)
13 c: c.c $(DEPS)
13 14 gcc $(CFLAGS) $(INCS) c.c -o c $(LIBS) gcc $(CFLAGS) $(INCS) c.c -o c $(LIBS)
14 15
15 raw: raw.c $(OBJS)
16 raw: raw.c $(DEPS)
16 17 gcc $(CFLAGS) $(INCS) raw.c -o raw $(LIBS) gcc $(CFLAGS) $(INCS) raw.c -o raw $(LIBS)
17 18
18 udp_s: udp_s.c $(OBJS)
19 udp_s: udp_s.c $(DEPS)
19 20 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
20 21
21 timeout: timeout.c $(OBJS)
22 timeout: timeout.c $(DEPS)
22 23 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
23 24
24 line1: line1.c $(OBJS)
25 line1: line1.c $(DEPS)
25 26 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
26 27
27 %: %.c $(OBJS)
28 %: %.c $(DEPS)
28 29 gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS) gcc $(CFLAGS) $(INCS) $@.c -o $@ $(LIBS)
29 30
30 31
File examples/c.c changed (mode: 100644) (index 008f6c0..f7a867a)
20 20 #include <Conn.h> #include <Conn.h>
21 21
22 22 /* Global variables */ /* Global variables */
23 static unsigned short debug = 1;
23 static unsigned short debug = 12;
24 24
25 25 static FILE *Logf = NULL; static FILE *Logf = NULL;
26 26 static char *log_file = "c.log"; static char *log_file = "c.log";
 
... ... struct priv
33 33 }; };
34 34
35 35
36 static void Log(unsigned short level, char *format, ...)
37 {
38 va_list ap;
39
40 if (level > debug)
41 return;
42
43 va_start(ap, format);
44 vfprintf(Logf, format, ap);
45 va_end(ap);
46 }
47
48 36 static void c_connected(struct Conn *C) static void c_connected(struct Conn *C)
49 37 { {
50 38 struct priv *p; struct priv *p;
 
... ... static void c_data(struct Conn *C)
73 61 { {
74 62 struct priv *p; struct priv *p;
75 63 char *dump; char *dump;
76
77 if (debug >= 8) {
78 dump = Conn_dump(C->ibuf + C->ibuf_head, C->ibuf_tail - C->ibuf_head);
79 Log(8, "data: recv: %s\n", dump);
80 free(dump);
81 }
64 char *line;
82 65
83 66 p = (struct priv *) C->private; p = (struct priv *) C->private;
84 67
85 p->dummy = 1;
68 while ((line = Conn_get_line(C))) {
69 if (debug >= 8) {
70 dump = Conn_dump(line, strlen(line));
71 Log(8, "data: recv: %s\n", dump);
72 free(dump);
73 }
86 74
87 answers++;
75 p->dummy++;
88 76
89 Conn_close(C);
77 answers++;
90 78
91 Conn_eatall(C);
79 Conn_eat(C, strlen(line));
80 }
81
82 Conn_close(C);
92 83 } }
93 84
94 85 static void c_error(struct Conn *C) static void c_error(struct Conn *C)
95 86 { {
96 Log(0, "%s Slot=%d C=%p [%s]\n",
97 __FUNCTION__, C ? C->slot : -1, (void *) C, Conn_strerror());
87 Log(0, "%s id=%llu [%s]\n",
88 __FUNCTION__, Conn_getid(C), Conn_strerror());
98 89 } }
99 90
100 91 int main(void) int main(void)
101 92 { {
102 93 char *stat; char *stat;
103 int i, ret;
94 int ret;
104 95 struct timeval start, end; struct timeval start, end;
105 96 unsigned int elap; unsigned int elap;
106 unsigned int ipv4conns = 10000, ipv6conns = 0;
97 unsigned int i, ipv4conns = 1, ipv6conns = 0;
107 98 struct Conn *C4, *C6; struct Conn *C4, *C6;
108 99
109 100
 
... ... int main(void)
139 130
140 131 /* ipv4 */ /* ipv4 */
141 132 for (i = 0; i < ipv4conns; i++) { for (i = 0; i < ipv4conns; i++) {
142 C4 = Conn_connect(PF_INET, SOCK_STREAM, "82.79.23.14", port);
133 C4 = Conn_connect(PF_INET, SOCK_STREAM, "127.0.0.1", port);
143 134 if (C4 == NULL) { if (C4 == NULL) {
144 135 Log(0, "Error calling Conn_connect [%s]!\n", Log(0, "Error calling Conn_connect [%s]!\n",
145 136 Conn_strerror()); Conn_strerror());
File examples/c.run changed (mode: 100755) (index 03ef1bc..7e3ca4a)
1 1 #!/bin/bash #!/bin/bash
2 2
3 export LD_LIBRARY_PATH=..:${LD_LIBRARY_PATH}
4
3 5 ulimit -n60000 ulimit -n60000
6 >c.log
4 7 ./c ./c
File examples/line1.c changed (mode: 100644) (index a9b23f7..9326277)
... ... static int port = 9000;
28 28 static short ipv4 = 1, ipv6 = 1; static short ipv4 = 1, ipv6 = 1;
29 29 static int maxconn = 0; static int maxconn = 0;
30 30
31 static void Log(unsigned short level, char *format, ...)
32 {
33 va_list ap;
34
35 if (level > debug)
36 return;
37
38 va_start(ap, format);
39 vfprintf(Logf, format, ap);
40 va_end(ap);
41 }
42
43 31 static void s_accept(struct Conn *C) static void s_accept(struct Conn *C)
44 32 { {
45 33 Log(4, "%s (A connection was accepted from [%s] on slot %d. Set POLLIN and enq greeting...\n", Log(4, "%s (A connection was accepted from [%s] on slot %d. Set POLLIN and enq greeting...\n",
File examples/raw.c changed (mode: 100644) (index e9ac471..c4464ae)
... ... static int port = 9000;
29 29 static int maxconn = 0; static int maxconn = 0;
30 30
31 31
32 static void Log(unsigned short level, char *format, ...)
33 {
34 va_list ap;
35
36 if (level > debug)
37 return;
38
39 va_start(ap, format);
40 vfprintf(Logf, format, ap);
41 va_end(ap);
42 }
43
44 32 static void s_close(struct Conn *C) static void s_close(struct Conn *C)
45 33 { {
46 34 Log(5, "%s (A connection will be closed [%s] on slot %d)\n", Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
 
... ... static void s_data(struct Conn *C)
69 57
70 58 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
71 59 { {
72 Log(1, "%s slot=%d C=%p [%s]\n",
73 __FUNCTION__, C == NULL ? -1 : C->slot, (void *) C,
74 Conn_strerror());
60 Log(1, "%s id=%llu [%s]\n",
61 __FUNCTION__, Conn_getid(C), Conn_strerror());
75 62 } }
76 63
77 64 int main(void) int main(void)
File examples/raw2.c changed (mode: 100644) (index e8d73ae..4145267)
... ... static int port = 9000;
29 29 static int maxconn = 0; static int maxconn = 0;
30 30
31 31
32 static void Log(unsigned short level, char *format, ...)
33 {
34 va_list ap;
35
36 if (level > debug)
37 return;
38
39 va_start(ap, format);
40 vfprintf(Logf, format, ap);
41 va_end(ap);
42 }
43
44 32 static void s_close(struct Conn *C) static void s_close(struct Conn *C)
45 33 { {
46 34 Log(5, "%s (A connection will be closed [%s] on slot %d)\n", Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
File examples/s.c changed (mode: 100644) (index 13143a0..d269331)
20 20 #include <Conn.h> #include <Conn.h>
21 21
22 22 /* Global variables */ /* Global variables */
23 static unsigned short debug = 1;
23 static unsigned short debug = 12;
24 24
25 25 static FILE *Logf = NULL; static FILE *Logf = NULL;
26 26 static char *log_file = "s.log"; static char *log_file = "s.log";
 
... ... static int port = 9000;
28 28 static short ipv4 = 1, ipv6 = 1; static short ipv4 = 1, ipv6 = 1;
29 29 static int maxconn = 0; static int maxconn = 0;
30 30
31 static void Log(unsigned short level, char *format, ...)
32 {
33 va_list ap;
34
35 if (level > debug)
36 return;
37
38 va_start(ap, format);
39 vfprintf(Logf, format, ap);
40 va_end(ap);
41 }
42
43 31 static void s_accept(struct Conn *C) static void s_accept(struct Conn *C)
44 32 { {
45 33 char *s; char *s;
46 34
47 Log(4, "%s (A connection was accepted from [%s] on slot %d. Set POLLIN and enq greeting...\n",
48 __FUNCTION__, C->addr, C->slot);
35 Log(4, "%s (A connection was accepted from [%s/%d]. Enqueue greeting...\n",
36 __FUNCTION__, C->addr, C->port);
49 37
50 38 s = "Hello!\r\n"; s = "Hello!\r\n";
51 39 Conn_enqueue(C, s, strlen(s)); Conn_enqueue(C, s, strlen(s));
52 Conn_close(C);
53 40 } }
54 41
55 42 static void s_close(struct Conn *C) static void s_close(struct Conn *C)
56 43 { {
57 Log(5, "%s (A connection will be closed [%s] on slot %d)\n",
58 __FUNCTION__, C->addr, C->slot);
44 Log(5, "%s (A connection will be closed [%s/%d] id=%lld)\n",
45 __FUNCTION__, C->addr, C->port, Conn_getid(C));
59 46 } }
60 47
61 48 static void s_data(struct Conn *C) static void s_data(struct Conn *C)
62 49 { {
63 int len;
64 char *buf;
50 char *line;
65 51 char *dump; char *dump;
66 52
67 len = C->ibuf_tail - C->ibuf_head;
68 buf = C->ibuf + C->ibuf_head;
53 line = Conn_get_line(C);
54 if (!line)
55 return;
69 56
70 57 if (debug >= 8) { if (debug >= 8) {
71 dump = Conn_dump(buf, len);
58 dump = Conn_dump(line, strlen(line));
72 59 Log(8, "%s: recv head=%d tail=%d bytes on slot %d: [%s]\n", Log(8, "%s: recv head=%d tail=%d bytes on slot %d: [%s]\n",
73 60 __FUNCTION__, C->ibuf_head, C->ibuf_tail, __FUNCTION__, C->ibuf_head, C->ibuf_tail,
74 61 C->slot, dump); C->slot, dump);
75 62 free(dump); free(dump);
76 63 } }
77 64
78 Log(8, " Send back: %s", buf);
79 Conn_enqueue(C, buf, len);
65 if (strcasecmp(line, "quit") == 0)
66 exit(0);
67
68 Log(8, " Send back: %s", line);
69 Conn_enqueue(C, line, strlen(line));
80 70
81 Conn_eatall(C);
71 Conn_eat(C, strlen(line) + 1);
82 72 } }
83 73
84 74 static void s_error(struct Conn *C) static void s_error(struct Conn *C)
85 75 { {
86 Log(1, "%s slot=%d C=%p\n",
87 __FUNCTION__, C == NULL ? -1 : C->slot, (void *) C);
76 Log(1, "%s id=%llu (%s)\n",
77 __FUNCTION__, Conn_getid(C), Conn_strerror());
88 78 } }
89 79
90 80 int main(void) int main(void)
 
... ... int main(void)
151 141 return 1; return 1;
152 142 } }
153 143
154 loops++;
155 if (ret == 0)
156 break;
157
144 /* Allow 30 seconds and exit */
158 145 /* /*
159 if (loops > 1000000)
146 loops++;
147 if (loops > 30)
160 148 break; break;
161 149 */ */
162 150 } }
File examples/s.run changed (mode: 100755) (index 3b88a01..2109611)
1 1 #!/bin/bash #!/bin/bash
2 2
3 ulimit -n60000
3 export LD_LIBRARY_PATH=..:${LD_LIBRARY_PATH}
4
5 ulimit -n200000
6 #strace -f -s1024 -o s.out \
7 >s.log
8 valgrind --tool=memcheck \
9 -v \
10 --num-callers=16 \
11 --leak-check=full \
12 --db-command="gdb -nw %f %p" \
13 --db-attach=yes \
14 --show-reachable=yes \
4 15 ./s ./s
File examples/timeout.c changed (mode: 100644) (index 7b9b734..8245c3a)
... ... static FILE *Logf = NULL;
26 26 static char *log_file = "timeout.log"; static char *log_file = "timeout.log";
27 27
28 28
29 static void Log(unsigned short level, char *format, ...)
30 {
31 va_list ap;
32
33 if (level > debug)
34 return;
35
36 va_start(ap, format);
37 vfprintf(Logf, format, ap);
38 va_end(ap);
39 }
40
41 29 static void c_connected(struct Conn *C) static void c_connected(struct Conn *C)
42 30 { {
43 31 Log(4, "%s(A connection was estabilished on slot %d)\n", Log(4, "%s(A connection was estabilished on slot %d)\n",
File examples/udp_s.c changed (mode: 100644) (index b7f10db..1516c3f)
... ... static struct sockaddr_in from;
31 31 static socklen_t from_len; static socklen_t from_len;
32 32
33 33
34 static void Log(unsigned short level, char *format, ...)
35 {
36 va_list ap;
37
38 if (level > debug)
39 return;
40
41 va_start(ap, format);
42 vfprintf(Logf, format, ap);
43 va_end(ap);
44 }
45
46 34 static void s_send(struct Conn *C) static void s_send(struct Conn *C)
47 35 { {
48 36 int fd; int fd;
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/Conn

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/Conn

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/Conn

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main