]> git.pond.sub.org Git - empserver/blob - src/client/ioqueue.c
ec04c41cb42c18f0911b174c48a335e7e2a6031b
[empserver] / src / client / ioqueue.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  ioqueue.c: Manage an i/o queue
29  * 
30  *  Known contributors to this file:
31  *     Steve McClure, 1998
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #ifndef _WIN32
38 #include <sys/uio.h>
39 #include <unistd.h>
40 #endif
41 #include "misc.h"
42 #include "queue.h"
43 #include "ioqueue.h"
44
45 #ifdef _WIN32
46 typedef struct iovec {
47     char *iov_base;
48     int iov_len;
49 } iovec_t;
50 #endif
51
52
53 static int ioqtobuf();
54 static int ioqtoiov();
55 static void enqueuecc();
56 static int dequeuecc();
57
58 void insque();
59 void remque();
60 void initque();
61 struct qelem *makeqt();
62
63 void
64 ioq_init(ioq, bsize)
65 struct ioqueue *ioq;
66 int bsize;
67 {
68     extern s_char num_teles[];
69
70     initque(&ioq->queue);
71     ioq->cc = 0;
72     ioq->bsize = bsize;
73     *num_teles = '\0';
74 }
75
76 /*
77  * copy batch of pointers into the passed
78  * iovec, but don't actually dequeue the data.
79  * return # of iovec initialized.
80  */
81 int
82 ioq_peekiov(ioq, iov, max)
83 struct ioqueue *ioq;
84 struct iovec *iov;
85 int max;
86 {
87     if (ioq->cc <= 0)
88         return 0;
89     return ioqtoiov(ioq, iov, max);
90 }
91
92 /*
93  * Copy the specified number of characters into the buffer
94  * provided, without actually dequeueing the data.  Return
95  * number of bytes actually found.
96  */
97 int
98 ioq_peek(ioq, buf, cc)
99 struct ioqueue *ioq;
100 s_char *buf;
101 int cc;
102 {
103     return ioqtobuf(ioq, buf, cc);
104 }
105
106 int
107 ioq_dequeue(ioq, cc)
108 struct ioqueue *ioq;
109 int cc;
110 {
111     if (dequeuecc(ioq, cc) != cc)
112         return 0;
113     return cc;
114 }
115
116 int
117 ioq_read(ioq, buf, cc)
118 struct ioqueue *ioq;
119 s_char *buf;
120 int cc;
121 {
122     int n;
123
124     n = ioqtobuf(ioq, buf, cc);
125     if (n > 0)
126         dequeuecc(ioq, n);
127     return n;
128 }
129
130 void
131 ioq_write(ioq, buf, cc)
132 struct ioqueue *ioq;
133 s_char *buf;
134 int cc;
135 {
136     enqueuecc(ioq, buf, cc);
137 }
138
139 int
140 ioq_qsize(ioq)
141 struct ioqueue *ioq;
142 {
143     return ioq->cc;
144 }
145
146 void
147 ioq_drain(ioq)
148 struct ioqueue *ioq;
149 {
150     struct io *io;
151     struct qelem *qp;
152
153     while ((qp = ioq->queue.q_forw) != &ioq->queue) {
154         io = (struct io *)qp;
155         free(io->data);
156         (void)remque(&io->queue);
157         (void)free(io);
158     }
159     ioq->cc = 0;
160 }
161
162 s_char *
163 ioq_gets(ioq, buf, cc)
164 struct ioqueue *ioq;
165 s_char *buf;
166 int cc;
167 {
168     register s_char *p;
169     register s_char *end;
170     int nbytes;
171
172     nbytes = ioqtobuf(ioq, buf, cc);
173     if (nbytes < cc)
174         cc = nbytes;
175     end = &buf[cc];
176     for (p = buf; p < end && *p; p++) {
177         if (*p == '\n') {
178             *p = '\0';
179             dequeuecc(ioq, (p - buf) + 1);
180             return buf;
181         }
182     }
183     return 0;
184 }
185
186 /*
187  * all the rest are local to this module
188  */
189
190
191 /*
192  * copy cc bytes from ioq to buf.
193  * this routine doesn't free memory; this is
194  * left for a higher level.
195  */
196 static int
197 ioqtobuf(ioq, buf, cc)
198 register struct ioqueue *ioq;
199 s_char *buf;
200 int cc;
201 {
202     register struct io *io;
203     struct qelem *qp;
204     s_char *offset;
205     int nbytes;
206     int nleft;
207
208     nleft = cc;
209     offset = buf;
210     for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
211         io = (struct io *)qp;
212         if ((nbytes = io->nbytes - io->offset) < 0) {
213             fprintf(stderr, "ioqtobuf: offset %d nbytes %d\n",
214                     io->offset, io->nbytes);
215             continue;
216         }
217         if (nbytes > 0) {
218             if (nleft < nbytes)
219                 nbytes = nleft;
220             memcpy(offset, io->data + io->offset, nbytes);
221             offset += nbytes;
222             nleft -= nbytes;
223         }
224     }
225     return offset - buf;
226 }
227
228 /*
229  * translate "around" max bytes to an iovec
230  * array.  The limit max is only advisory,
231  * and more may get buffered.  It is an attempt to limit
232  * really silly sends -- like sending 40k on a socket
233  * with one writev for example.  This makes the processing
234  * of a full ioqueue still be quick.
235  */
236 static int
237 ioqtoiov(ioq, iov, max)
238 register struct ioqueue *ioq;
239 register struct iovec *iov;
240 register int max;
241 {
242     register struct io *io;
243     register int cc;
244     register int niov;
245     struct qelem *qp;
246
247     cc = 0;
248     niov = 0;
249     qp = ioq->queue.q_forw;
250     for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
251         io = (struct io *)qp;
252         if (niov >= MAXIOV || cc >= max)
253             break;
254         iov->iov_base = io->data + io->offset;
255         iov->iov_len = io->nbytes - io->offset;
256         cc += io->nbytes - io->offset;
257         niov++;
258         iov++;
259     }
260     return niov;
261 }
262
263 /*
264  * append a buffer to the end of the ioq.
265  */
266 static void
267 enqueuecc(ioq, buf, cc)
268 struct ioqueue *ioq;
269 s_char *buf;
270 int cc;
271 {
272     struct io *io;
273
274     io = (struct io *)malloc(sizeof(*io));
275     io->nbytes = cc;
276     io->offset = 0;
277     io->data = buf;
278     insque(&io->queue, ioq->queue.q_back);
279     ioq->cc += cc;
280 }
281
282 /*
283  * remove cc bytes from ioqueue ioq
284  * free memory, dequeue io elements
285  * which are no longer used.
286  */
287 static int
288 dequeuecc(ioq, cc)
289 register struct ioqueue *ioq;
290 register int cc;
291 {
292     register struct io *io;
293     register struct qelem *qp;
294     register int nbytes;
295     register int there;
296
297     nbytes = 0;
298     while ((qp = ioq->queue.q_forw) != &ioq->queue) {
299         io = (struct io *)qp;
300         there = io->nbytes - io->offset;
301         if (there < 0) {
302             fprintf(stderr, "dequeuecc: nbytes %d, offset %d\n",
303                     io->nbytes, io->offset);
304             continue;
305         }
306         if (cc > there) {
307             cc -= there;
308             nbytes += there;
309             (void)remque(&io->queue);
310             free(io->data);
311         } else {
312             io->offset += cc;
313             nbytes += cc;
314             break;
315         }
316     }
317     ioq->cc -= nbytes;
318     return nbytes;
319 }