Skip to content
Newer
Older
100644 163 lines (132 sloc) 3.77 KB
6f4e067 Initial checkin of the shared IO Atom code. It was written for gateke…
Scott Bronson authored Mar 9, 2007
1 // atom.c
2 // Scott Bronson
3 // 22 Feb 2006
4
5
6 // Some utility functions that are common to all IO Atom pollers.
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include "atom.h"
12
13
14 /** Reads from the given io_atom.
15 *
16 * @param io The io_atom to read from.
17 * @param buf the buffer to fill with data
18 * @param cnt the number of bytes to read
19 * @param readlen returns the number of bytes you need to process.
20 * If readlen is nonzero, then error is guaranteed to be 0.
21 *
22 * @returns 0 on success, or the error code in errno if there was
23 * an error. If there was an error but errno doesn't say what it was
24 * then -1 is returned. A return value of EPIPE means you hit EOF
25 * (file) or the remote peer closed its connection (pipe, socket).
26 * If the remote reset its connection, we return EPIPE as well
27 * (because, like close, this indicates that the remote has disappeared).
28 */
29
30 int io_read(io_atom *io, char *buf, size_t cnt, size_t *readlen)
31 {
32 ssize_t len;
33
34 *readlen = 0;
35 do {
36 len = read(io->fd, buf, cnt);
37 } while (errno == EINTR); // stupid posix
38
39 if(len > 0) {
40 // success!
41 *readlen = len;
42 return 0;
43 }
44
45 if(len == 0) {
46 // the remote has closed the connection.
47 return EPIPE;
48 }
49
50 // an error ocurred during the read
51 if(errno == EAGAIN || errno == EWOULDBLOCK) {
52 // turns out there was nothing to read after all? weird.
53 // there was no error, but nothing to process either.
54 return 0;
55 }
56
57 // Not sure this is a good idea... ECONNRESET means that the
58 // peer has closed the connection (probably by suddenly losing
59 // power rather than simply closing the socket) so we'll treat
60 // it the same as the remote shutting down.
61 if(errno == ECONNRESET) {
62 return EPIPE;
63 }
64
65 return errno ? errno : -1;
66 }
67
68
69 /**
70 * Writes to the given atom.
71 *
72 * You should always be able to write all data.
73 *
74 * @returns 0 on success, the error code if there was a failure.
75 *
76 * A return value of -EPIPE means that the remote peer closed its
77 * connection. HOWEVER, your app will already have received a
78 * SIGPIPE, so you'll have to block this signal if you want to
79 * handle the -EPIPE return code.
80 *
81 * We treat handle the remote resetting the connection the same as
82 * it closing the connection. So, when errno is ECONNRESET, this
83 * routine will return EPIPE to tell you that the remote is gone.
84 * You don't need to worry about this: EPIPE means no more remote.
85 */
86
87 int io_write(io_atom *io, char *buf, size_t cnt, size_t *wrlen)
88 {
89 ssize_t len;
90
91 *wrlen = 0;
92 do {
93 len = write(io->fd, buf, cnt);
94 } while(errno == EINTR);
95
96 if(len > 0) {
97 *wrlen = len;
98 return 0;
99 }
100
101 if(len < 0) {
102 if(errno == ECONNRESET) {
103 return EPIPE;
104 }
105 return errno ? errno : -1;
106 }
107
108 // nothing was written but there was no error??
109 return 0;
110 }
111
112
113 /** Removes the atom from polling and closes its file descriptor.
114 */
115
116 void io_close(io_atom *io)
117 {
118 io_del(io);
119 close(io->fd);
120 io->fd = -1;
121 }
122
123
124 /**
125 * Converts a string into an integer.
126 *
127 * It is unfortunate that this routine has to be included
128 * in the core library but I don't know where else to put
129 * it...
130 *
131 * Unlinke the standard C routines,
132 * this routine returns an error if the conversion fails.
133 * C generally just gives you a garbage number.
134 *
135 * Also, unlinke the standard routine, the string must be
136 * null terminated and contain only the number.
137 *
138 * @returns 1 if the conversion was successful, 0 if not.
139 */
140
141 int io_safe_atoi(const char *str, int *num)
142 {
143 char *remainder;
144
145 if(*str == '\0') {
146 // blank string (strtol would parse this as "0").
147 return 0;
148 }
149
150 errno = 0;
151 *num = strtol(str, &remainder, 10);
152 if(errno) {
153 return 0;
154 }
155
156 if(*remainder != '\0') {
157 return 0;
158 }
159
160 return 1;
161 }
162
Something went wrong with that request. Please try again.