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