]> git.pond.sub.org Git - empserver/blob - src/lib/gen/ioqueue.c
Remove declaration that should have been removed in rev. 1.9. Doc
[empserver] / src / lib / gen / ioqueue.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  ioqueue.c: Read and write i/o queues
29  * 
30  *  Known contributors to this file:
31  *     
32  */
33
34 /*
35  * Read and write onto io queues.  Note that
36  * the io queues don't actually do any writing;
37  * that is left for a higher level.
38  */
39
40 #include <config.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #if !defined(_WIN32)
46 #include <sys/uio.h>
47 #endif
48 #include "misc.h"
49 #include "queue.h"
50 #include "ioqueue.h"
51
52 static int ioqtocbuf(struct ioqueue *ioq, char *buf, int cc, int stopc);
53 #if !defined(_WIN32)
54 static int ioqtoiov(struct ioqueue *ioq, struct iovec *iov, int max);
55 #endif
56 static int ioqtobuf(struct ioqueue *ioq, char *buf, int cc);
57 static int appendcc(struct ioqueue *ioq, char *buf, int cc);
58 static int removecc(struct ioqueue *ioq, int cc);
59
60 struct ioqueue *
61 ioq_create(int size)
62 {
63     struct ioqueue *ioq;
64
65     ioq = malloc(sizeof(struct ioqueue));
66     emp_initque(&ioq->list.queue);
67     ioq->list.nbytes = 0;
68     ioq->list.offset = 0;
69     ioq->list.size = 0;
70     ioq->list.data = 0;
71     ioq->bufsize = size;
72     ioq->cc = 0;
73     return ioq;
74 }
75
76 void
77 ioq_destroy(struct ioqueue *ioq)
78 {
79     ioq_drain(ioq);
80     free(ioq);
81 }
82
83 void
84 ioq_drain(struct ioqueue *ioq)
85 {
86     struct emp_qelem *qp;
87     struct io *io;
88
89     while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
90         io = (struct io *)qp;
91         emp_remque(&io->queue);
92         free(io->data);
93         free(io);
94     }
95
96     ioq->cc = 0;
97 }
98
99 /*
100  * copy batch of pointers into the passed
101  * iovec, but don't actually dequeue the data.
102  * return # of iovec initialized.
103  */
104 #if !defined(_WIN32)
105 int
106 ioq_makeiov(struct ioqueue *ioq, struct iovec *iov, int cc)
107 {
108     if (ioq->cc <= 0)
109         return 0;
110     return ioqtoiov(ioq, iov, cc);
111 }
112 #endif
113
114 /*
115  * Copy the specified number of characters into the buffer
116  * provided, without actually dequeueing the data.  Return
117  * number of bytes actually found.
118  */
119 int
120 ioq_peek(struct ioqueue *ioq, char *buf, int cc)
121 {
122     return ioqtobuf(ioq, buf, cc);
123 }
124
125 int
126 ioq_dequeue(struct ioqueue *ioq, int cc)
127 {
128     return removecc(ioq, cc);
129 }
130
131 void
132 ioq_append(struct ioqueue *ioq, char *buf, int cc)
133 {
134     appendcc(ioq, buf, cc);
135 }
136
137 int
138 ioq_qsize(struct ioqueue *ioq)
139 {
140     return ioq->cc;
141 }
142
143 /*
144  * read a line of text up to (but not including)
145  * the newline.  return -1 and read nothing if
146  * no input is available
147  */
148 int
149 ioq_gets(struct ioqueue *ioq, char *buf, int cc)
150 {
151     int nbytes;
152     int actual;
153
154     nbytes = ioqtocbuf(ioq, buf, cc - 1, '\n');
155     if (nbytes >= 0) {
156         actual = nbytes;
157         if (actual > cc - 1)
158             actual = cc - 1;
159         /* telnet terminates lines with "\r\n", get rid of \r */
160         if (actual > 0 && buf[actual-1] == '\r')
161             actual--;
162         buf[actual] = '\0';
163         /* remove the newline too */
164         removecc(ioq, nbytes + 1);
165     }
166     return nbytes;
167 }
168
169 int
170 ioq_puts(struct ioqueue *ioq, char *buf)
171 {
172     return appendcc(ioq, buf, strlen(buf));
173 }
174
175 /*
176  * copy cc bytes from ioq to buf.
177  * this routine doesn't free memory; this is
178  * left for a higher level.
179  */
180 static int
181 ioqtobuf(struct ioqueue *ioq, char *buf, int cc)
182 {
183     struct io *io;
184     struct emp_qelem *qp;
185     struct emp_qelem *head;
186     int nbytes, nleft;
187     char *offset;
188
189     nleft = cc;
190     offset = buf;
191     head = &ioq->list.queue;
192     for (qp = head->q_forw; qp != head && nleft > 0; qp = qp->q_forw) {
193         io = (struct io *)qp;
194         if ((nbytes = io->nbytes - io->offset) < 0) {
195             /* XXX log something here */
196             continue;
197         }
198         if (nbytes > 0) {
199             if (nleft < nbytes)
200                 nbytes = nleft;
201             memcpy(offset, io->data + io->offset, nbytes);
202             offset += nbytes;
203             nleft -= nbytes;
204         }
205     }
206     return offset - buf;
207 }
208
209 /*
210  * copy at most cc bytes from ioq to buf,
211  * terminating on the stop character.
212  */
213 static int
214 ioqtocbuf(struct ioqueue *ioq, char *buf, int cc, int stopc)
215 {
216     int nbytes;
217     char *p;
218     int n;
219     struct io *io;
220     struct emp_qelem *qp;
221     struct emp_qelem *head;
222     int total;
223     int found;
224
225     head = &ioq->list.queue;
226     found = 0;
227     total = 0;
228     for (qp = head->q_forw; qp != head; qp = qp->q_forw) {
229         io = (struct io *)qp;
230         if ((nbytes = io->nbytes - io->offset) <= 0)
231             continue;
232         p = io->data + io->offset;
233         for (n = 0; n < nbytes && p[n] != stopc; n++) ;
234         total += n;
235         if (n < nbytes) {
236             found++;
237             break;
238         }
239     }
240     if (found == 0)
241         return -1;
242     ioqtobuf(ioq, buf, cc < total ? cc : total);
243     return total;
244 }
245
246 /*
247  * initialize an iovec to point at max bytes worth
248  * of data from the ioqueue.
249  */
250 #if !defined(_WIN32)
251 static int
252 ioqtoiov(struct ioqueue *ioq, struct iovec *iov, int max)
253 {
254     struct io *io;
255     int cc, niov, len;
256     struct emp_qelem *qp;
257
258     cc = max;
259     niov = 0;
260     qp = ioq->list.queue.q_forw;
261     while (qp != &ioq->list.queue && cc > 0) {
262         io = (struct io *)qp;
263         len = io->nbytes - io->offset;
264         if (len > cc)
265             len = cc;
266         iov->iov_base = io->data + io->offset;
267         iov->iov_len = len;
268         cc -= len;
269         niov++;
270         iov++;
271         qp = qp->q_forw;
272         if (niov >= 16)
273             break;
274     }
275     return niov;
276 }
277 #endif
278
279 /*
280  * append a buffer to the end of the ioq.
281  */
282 static int
283 appendcc(struct ioqueue *ioq, char *buf, int cc)
284 {
285     struct io *io;
286     int len;
287     char *ptr;
288     int avail;
289
290     /* determine if any space is left */
291     io = (struct io *)ioq->list.queue.q_back;
292     avail = io->size - io->nbytes;
293     if (avail > 0) {
294         /* append to existing buffer */
295         len = cc > avail ? avail : cc;
296         memcpy(io->data + io->nbytes, buf, len);
297         io->nbytes += len;
298         ioq->cc += len;
299         if (avail < cc)
300             appendcc(ioq, buf + len, cc - len);
301     } else {
302         /* create a new buffer, minimum bufsize bytes */
303         len = cc > ioq->bufsize ? cc : ioq->bufsize;
304         ptr = malloc(len);
305         memcpy(ptr, buf, cc);
306         io = malloc(sizeof(struct io));
307         io->nbytes = cc;
308         io->size = len;
309         io->offset = 0;
310         io->data = ptr;
311         emp_insque(&io->queue, ioq->list.queue.q_back);
312         ioq->cc += cc;
313     }
314     return cc;
315 }
316
317 /*
318  * remove cc bytes from ioqueue ioq
319  * free memory, dequeue io elements
320  * which are no longer used.
321  */
322 static int
323 removecc(struct ioqueue *ioq, int cc)
324 {
325     struct io *io;
326     struct emp_qelem *qp;
327     int nbytes, there, remain;
328
329     nbytes = 0;
330     remain = cc;
331     while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
332         io = (struct io *)qp;
333         there = io->nbytes - io->offset;
334         if (there < 0) {
335             /* error */
336             emp_remque(&io->queue);
337             free(io);
338             continue;
339         }
340         if (remain >= there) {
341             /* not enough or exact; free entry */
342             nbytes += there;
343             remain -= there;
344             emp_remque(&io->queue);
345             free(io->data);
346             free(io);
347         } else {
348             /* too much; increment offset */
349             io->offset += remain;
350             nbytes += remain;
351             remain = 0;
352         }
353         if (remain <= 0)
354             break;
355     }
356     ioq->cc -= nbytes;
357     return nbytes;
358 }
359
360 #if defined(_WIN32)
361 /*
362  * Make an (output) buffer up to the
363  * maximum size of the buffer.
364  *
365  * We don't free the bytes...
366  */
367 int
368 ioq_makebuf(struct ioqueue *ioq, char *pBuf, int nBufLen)
369 {
370     struct io *io;
371     struct emp_qelem *qp;
372     struct emp_qelem *head;
373     int nbytes;
374     int nleft;
375     int ncopied;
376     char *offset;
377
378     ncopied = 0;
379     nleft = nBufLen;
380     offset = pBuf;
381     head = &ioq->list.queue;
382
383     for (qp = head->q_forw; (qp != head) && (nleft > 0); qp = qp->q_forw) {
384         io = (struct io *)qp;
385         nbytes = io->nbytes - io->offset;
386         if (nbytes < 0) {
387             /* Paranoid check for bad buffer. */
388             continue;
389         }
390
391         /* too many bytes, wait till next time. */
392         if (nbytes > nleft)
393             break;
394
395         memcpy(offset, io->data + io->offset, nbytes);
396         offset += nbytes;
397         nleft -= nbytes;
398         ncopied += nbytes;
399     }
400     return ncopied;
401 }
402 #endif /* _WIN32 */