]> git.pond.sub.org Git - empserver/blob - src/lib/gen/ioqueue.c
COPYING duplicates information from README. Remove. Move GPL from
[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>             /* malloc free */
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, s_char *buf, int cc,
53                      register int stopc);
54 #if !defined(_WIN32)
55 static int ioqtoiov(struct ioqueue *ioq, struct iovec *iov,
56                     register int max);
57 #endif
58 static int ioqtobuf(struct ioqueue *ioq, s_char *buf, int cc);
59 static int appendcc(struct ioqueue *ioq, s_char *buf, int cc);
60 static int removecc(struct ioqueue *ioq, register int cc);
61
62 #if defined(_WIN32)
63 static void loc_StripDels(char *pBuf);
64 #endif
65
66 struct ioqueue *
67 ioq_create(int size)
68 {
69     struct ioqueue *ioq;
70
71     ioq = malloc(sizeof(struct ioqueue));
72     emp_initque(&ioq->list.queue);
73     ioq->list.nbytes = 0;
74     ioq->list.offset = 0;
75     ioq->list.size = 0;
76     ioq->list.data = 0;
77     ioq->bufsize = size;
78     ioq->cc = 0;
79     return ioq;
80 }
81
82 void
83 ioq_destroy(struct ioqueue *ioq)
84 {
85     ioq_drain(ioq);
86     free(ioq);
87 }
88
89 void
90 ioq_drain(struct ioqueue *ioq)
91 {
92     struct emp_qelem *qp;
93     struct io *io;
94
95     while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
96         io = (struct io *)qp;
97         emp_remque(&io->queue);
98         free(io->data);
99         free(io);
100     }
101
102     ioq->cc = 0;
103 }
104
105 /*
106  * copy batch of pointers into the passed
107  * iovec, but don't actually dequeue the data.
108  * return # of iovec initialized.
109  */
110 #if !defined(_WIN32)
111 int
112 ioq_makeiov(struct ioqueue *ioq, struct iovec *iov, int cc)
113 {
114     if (ioq->cc <= 0)
115         return 0;
116     return ioqtoiov(ioq, iov, cc);
117 }
118 #endif
119
120 /*
121  * Copy the specified number of characters into the buffer
122  * provided, without actually dequeueing the data.  Return
123  * number of bytes actually found.
124  */
125 int
126 ioq_peek(struct ioqueue *ioq, s_char *buf, int cc)
127 {
128     return ioqtobuf(ioq, buf, cc);
129 }
130
131 int
132 ioq_dequeue(struct ioqueue *ioq, int cc)
133 {
134     return removecc(ioq, cc);
135 }
136
137 void
138 ioq_append(struct ioqueue *ioq, s_char *buf, int cc)
139 {
140     appendcc(ioq, buf, cc);
141 }
142
143 int
144 ioq_qsize(struct ioqueue *ioq)
145 {
146     return ioq->cc;
147 }
148
149 /*
150  * read a line of text up to (but not including)
151  * the newline.  return -1 and read nothing if
152  * no input is available
153  */
154 int
155 ioq_gets(struct ioqueue *ioq, s_char *buf, int cc)
156 {
157     int nbytes;
158     int actual;
159
160     nbytes = ioqtocbuf(ioq, buf, cc - 1, '\n');
161     if (nbytes >= 0) {
162         actual = nbytes;
163         if (actual > cc - 1)
164             actual = cc - 1;
165         /* telnet terminates lines with "\r\n", get rid of \r */
166         if (actual > 0 && buf[actual-1] == '\r')
167             actual--;
168         buf[actual] = '\0';
169         /* remove the newline too */
170         removecc(ioq, nbytes + 1);
171     }
172     return nbytes;
173 }
174
175 int
176 ioq_puts(struct ioqueue *ioq, s_char *buf)
177 {
178     return appendcc(ioq, buf, strlen(buf));
179 }
180
181 /*
182  * all the rest are local to this module
183  */
184
185
186 /*
187  * copy cc bytes from ioq to buf.
188  * this routine doesn't free memory; this is
189  * left for a higher level.
190  */
191 static int
192 ioqtobuf(struct ioqueue *ioq, s_char *buf, int cc)
193 {
194     struct io *io;
195     struct emp_qelem *qp;
196     struct emp_qelem *head;
197     register int nbytes;
198     register int nleft;
199     register s_char *offset;
200
201     nleft = cc;
202     offset = buf;
203     head = &ioq->list.queue;
204     for (qp = head->q_forw; qp != head && nleft > 0; qp = qp->q_forw) {
205         io = (struct io *)qp;
206         if ((nbytes = io->nbytes - io->offset) < 0) {
207             /* XXX log something here */
208             continue;
209         }
210         if (nbytes > 0) {
211             if (nleft < nbytes)
212                 nbytes = nleft;
213             memcpy(offset, io->data + io->offset, nbytes);
214             offset += nbytes;
215             nleft -= nbytes;
216         }
217     }
218     return offset - buf;
219 }
220
221 /*
222  * copy at most cc bytes from ioq to buf,
223  * terminating on the stop character.
224  */
225 static int
226 ioqtocbuf(struct ioqueue *ioq, s_char *buf, int cc, register int stopc)
227 {
228     register int nbytes;
229     register s_char *p;
230     register int n;
231     struct io *io;
232     struct emp_qelem *qp;
233     struct emp_qelem *head;
234     int total;
235     int found;
236
237     head = &ioq->list.queue;
238     found = 0;
239     total = 0;
240     for (qp = head->q_forw; qp != head; qp = qp->q_forw) {
241         io = (struct io *)qp;
242         if ((nbytes = io->nbytes - io->offset) <= 0)
243             continue;
244         p = io->data + io->offset;
245         for (n = 0; n < nbytes && p[n] != stopc; n++) ;
246         total += n;
247         if (n < nbytes) {
248             found++;
249             break;
250         }
251     }
252     if (found == 0)
253         return -1;
254     ioqtobuf(ioq, buf, cc < total ? cc : total);
255     return total;
256 }
257
258 /*
259  * initialize an iovec to point at max bytes worth
260  * of data from the ioqueue.
261  */
262 #if !defined(_WIN32)
263 static int
264 ioqtoiov(struct ioqueue *ioq, struct iovec *iov, register int max)
265 {
266     struct io *io;
267     register int cc;
268     register int niov;
269     register int len;
270     struct emp_qelem *qp;
271
272     cc = max;
273     niov = 0;
274     qp = ioq->list.queue.q_forw;
275     while (qp != &ioq->list.queue && cc > 0) {
276         io = (struct io *)qp;
277         len = io->nbytes - io->offset;
278         if (len > cc)
279             len = cc;
280         iov->iov_base = io->data + io->offset;
281         iov->iov_len = len;
282         cc -= len;
283         niov++;
284         iov++;
285         qp = qp->q_forw;
286         if (niov >= 16)
287             break;
288     }
289     return niov;
290 }
291 #endif
292
293 /*
294  * append a buffer to the end of the ioq.
295  */
296 static int
297 appendcc(struct ioqueue *ioq, s_char *buf, int cc)
298 {
299     struct io *io;
300     int len;
301     s_char *ptr;
302     int avail;
303
304     /* determine if any space is left */
305     io = (struct io *)ioq->list.queue.q_back;
306     avail = io->size - io->nbytes;
307     if (avail > 0) {
308         /* append to existing buffer */
309         len = cc > avail ? avail : cc;
310         memcpy(io->data + io->nbytes, buf, len);
311         io->nbytes += len;
312         ioq->cc += len;
313         if (avail < cc)
314             appendcc(ioq, buf + len, cc - len);
315     } else {
316         /* create a new buffer, minimum bufsize bytes */
317         len = cc > ioq->bufsize ? cc : ioq->bufsize;
318         ptr = malloc(len);
319         memcpy(ptr, buf, cc);
320         io = malloc(sizeof(struct io));
321         io->nbytes = cc;
322         io->size = len;
323         io->offset = 0;
324         io->data = ptr;
325         emp_insque(&io->queue, ioq->list.queue.q_back);
326         ioq->cc += cc;
327     }
328     return cc;
329 }
330
331 /*
332  * remove cc bytes from ioqueue ioq
333  * free memory, dequeue io elements
334  * which are no longer used.
335  */
336 static int
337 removecc(struct ioqueue *ioq, register int cc)
338 {
339     struct io *io;
340     struct emp_qelem *qp;
341     register int nbytes;
342     register int there;
343     register int remain;
344
345     nbytes = 0;
346     remain = cc;
347     while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
348         io = (struct io *)qp;
349         there = io->nbytes - io->offset;
350         if (there < 0) {
351             /* error */
352             emp_remque(&io->queue);
353             free(io);
354             continue;
355         }
356         if (remain >= there) {
357             /* not enough or exact; free entry */
358             nbytes += there;
359             remain -= there;
360             emp_remque(&io->queue);
361             free(io->data);
362             free(io);
363         } else {
364             /* too much; increment offset */
365             io->offset += remain;
366             nbytes += remain;
367             remain = 0;
368         }
369         if (remain <= 0)
370             break;
371     }
372     ioq->cc -= nbytes;
373     return nbytes;
374 }
375
376 #if defined(_WIN32)
377 /*
378  * Make an (output) buffer up to the
379  * maximum size of the buffer.
380  *
381  * We don't free the bytes...
382  */
383 int
384 ioq_makebuf(struct ioqueue *ioq, char *pBuf, int nBufLen)
385 {
386     struct io *io;
387     struct emp_qelem *qp;
388     struct emp_qelem *head;
389     int nbytes;
390     int nleft;
391     int ncopied;
392     s_char *offset;
393
394     ncopied = 0;
395     nleft = nBufLen;
396     offset = pBuf;
397     head = &ioq->list.queue;
398
399     for (qp = head->q_forw; (qp != head) && (nleft > 0); qp = qp->q_forw) {
400         io = (struct io *)qp;
401         nbytes = io->nbytes - io->offset;
402         if (nbytes < 0) {
403             /* Paranoid check for bad buffer. */
404             continue;
405         }
406
407         /* too many bytes, wait till next time. */
408         if (nbytes > nleft)
409             break;
410
411         memcpy(offset, io->data + io->offset, nbytes);
412         offset += nbytes;
413         nleft -= nbytes;
414         ncopied += nbytes;
415     }
416     return ncopied;
417 }
418 #endif /* _WIN32 */