]> git.pond.sub.org Git - empserver/blob - src/client/ioqueue.c
Import of Empire 4.2.12
[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 <sys/types.h>
36 #ifndef _WIN32
37 #include <sys/uio.h>
38 #include <unistd.h>
39 #endif
40 #include "misc.h"
41 #include "queue.h"
42 #include "ioqueue.h"
43
44 #ifdef _WIN32
45 typedef struct     iovec  {
46         char   *iov_base;
47         int     iov_len;
48 } iovec_t;
49 #endif
50
51
52 static int ioqtobuf();
53 static int ioqtoiov();
54 static void enqueuecc();
55 static int dequeuecc();
56
57 void insque();
58 void remque();
59 void initque();
60 struct qelem *makeqt();
61 void free();
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
197 int
198 ioqtobuf(ioq, buf, cc)
199         register struct ioqueue *ioq;
200         s_char  *buf;
201         int     cc;
202 {
203         register struct io *io;
204         struct  qelem *qp;
205         s_char  *offset;
206         int     nbytes;
207         int     nleft;
208
209         nleft = cc;
210         offset = buf;
211         for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
212                 io = (struct io *) qp;
213                 if ((nbytes = io->nbytes - io->offset) < 0) {
214                         fprintf(stderr, "ioqtobuf: offset %d nbytes %d\n",
215                                 io->offset, io->nbytes);
216                         continue;
217                 }
218                 if (nbytes > 0) {
219                         if (nleft < nbytes)
220                                 nbytes = nleft;
221                         bcopy(io->data + io->offset, offset, nbytes);
222                         offset += nbytes;
223                         nleft -= nbytes;
224                 }
225         }
226         return offset - buf;
227 }
228
229 /*
230  * translate "around" max bytes to an iovec
231  * array.  The limit max is only advisory,
232  * and more may get buffered.  It is an attempt to limit
233  * really silly sends -- like sending 40k on a socket
234  * with one writev for example.  This makes the processing
235  * of a full ioqueue still be quick.
236  */
237 static
238 int
239 ioqtoiov(ioq, iov, max)
240         register struct ioqueue *ioq;
241         register struct iovec *iov;
242         register int max;
243 {
244         register struct io *io;
245         register int cc;
246         register int niov;
247         struct  qelem *qp;
248
249         cc = 0;
250         niov = 0;
251         qp = ioq->queue.q_forw;
252         for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
253                 io = (struct io *) qp;
254                 if (niov >= MAXIOV || cc >= max)
255                         break;
256                 iov->iov_base = io->data + io->offset;
257                 iov->iov_len = io->nbytes - io->offset;
258                 cc += io->nbytes - io->offset;
259                 niov++;
260                 iov++;
261         }
262         return niov;
263 }
264
265 /*
266  * append a buffer to the end of the ioq.
267  */
268 static void
269 enqueuecc(ioq, buf, cc)
270         struct  ioqueue *ioq;
271         s_char  *buf;
272         int     cc;
273 {
274         struct  io *io;
275
276         io = (struct io *) malloc(sizeof(*io));
277         io->nbytes = cc;
278         io->offset = 0;
279         io->data = buf;
280         insque(&io->queue, ioq->queue.q_back);
281         ioq->cc += cc;
282 }
283
284 /*
285  * remove cc bytes from ioqueue ioq
286  * free memory, dequeue io elements
287  * which are no longer used.
288  */
289 static
290 int
291 dequeuecc(ioq, cc)
292         register struct ioqueue *ioq;
293         register int cc;
294 {
295         register struct io *io;
296         register struct qelem *qp;
297         register int nbytes;
298         register int there;
299
300         nbytes = 0;
301         while ((qp = ioq->queue.q_forw) != &ioq->queue) {
302                 io = (struct io *) qp;
303                 there = io->nbytes - io->offset;
304                 if (there < 0) {
305                         fprintf(stderr, "dequeuecc: nbytes %d, offset %d\n",
306                                 io->nbytes, io->offset);
307                         continue;
308                 }
309                 if (cc > there) {
310                         cc -= there;
311                         nbytes += there;
312                         (void) remque(&io->queue);
313                         free(io->data);
314                 } else {
315                         io->offset += cc;
316                         nbytes += cc;
317                         break;
318                 }
319         }
320         ioq->cc -= nbytes;
321         return nbytes;
322 }