Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // Written in NSPR style to also be suitable for adding to the NSS demo suite | 4 // Written in NSPR style to also be suitable for adding to the NSS demo suite |
| 5 | 5 |
| 6 /* memio is a simple NSPR I/O layer that lets you decouple NSS from | 6 /* memio is a simple NSPR I/O layer that lets you decouple NSS from |
| 7 * the real network. It's rather like openssl's memory bio, | 7 * the real network. It's rather like openssl's memory bio, |
| 8 * and is useful when your app absolutely, positively doesn't | 8 * and is useful when your app absolutely, positively doesn't |
| 9 * want to let NSS do its own networking. | 9 * want to let NSS do its own networking. |
| 10 */ | 10 */ |
| 11 | 11 |
| 12 #include <stdlib.h> | 12 #include <stdlib.h> |
| 13 #include <string.h> | 13 #include <string.h> |
| 14 | 14 |
| 15 #include <prerror.h> | 15 #include <prerror.h> |
| 16 #include <prinit.h> | 16 #include <prinit.h> |
| 17 #include <prlog.h> | 17 #include <prlog.h> |
| 18 | 18 |
| 19 #include "nss_memio.h" | 19 #include "nss_memio.h" |
| 20 | 20 |
| 21 /*--------------- private memio types -----------------------*/ | 21 /*--------------- private memio types -----------------------*/ |
| 22 | 22 |
| 23 /*---------------------------------------------------------------------- | 23 /*---------------------------------------------------------------------- |
| 24 Simple private circular buffer class. Size cannot be changed once allocated. | 24 Simple private circular buffer class. Size cannot be changed once allocated. |
| 25 ----------------------------------------------------------------------*/ | 25 ----------------------------------------------------------------------*/ |
| 26 | 26 |
| 27 struct memio_buffer { | 27 struct memio_buffer { |
| 28 int head; /* where to take next byte out of buf */ | 28 int head; /* where to take next byte out of buf */ |
| 29 int tail; /* where to put next byte into buf */ | 29 int tail; /* where to put next byte into buf */ |
| 30 int bufsize; /* number of bytes allocated to buf */ | 30 int bufsize; /* number of bytes allocated to buf */ |
| 31 /* TODO(port): error handling is pessimistic right now. | 31 /* TODO(port): error handling is pessimistic right now. |
|
mef
2014/10/10 20:38:17
not sure that this comment should align with those
| |
| 32 * Once an error is set, the socket is considered broken | 32 * Once an error is set, the socket is considered broken |
| 33 * (PR_WOULD_BLOCK_ERROR not included). | 33 * (PR_WOULD_BLOCK_ERROR not included). |
| 34 */ | 34 */ |
| 35 PRErrorCode last_err; | 35 PRErrorCode last_err; |
| 36 char *buf; | 36 char* buf; |
| 37 }; | 37 }; |
| 38 | 38 |
| 39 | |
| 40 /* The 'secret' field of a PRFileDesc created by memio_CreateIOLayer points | 39 /* The 'secret' field of a PRFileDesc created by memio_CreateIOLayer points |
| 41 * to one of these. | 40 * to one of these. |
| 42 * In the public header, we use struct memio_Private as a typesafe alias | 41 * In the public header, we use struct memio_Private as a typesafe alias |
| 43 * for this. This causes a few ugly typecasts in the private file, but | 42 * for this. This causes a few ugly typecasts in the private file, but |
| 44 * seems safer. | 43 * seems safer. |
| 45 */ | 44 */ |
| 46 struct PRFilePrivate { | 45 struct PRFilePrivate { |
| 47 /* read requests are satisfied from this buffer */ | 46 /* read requests are satisfied from this buffer */ |
| 48 struct memio_buffer readbuf; | 47 struct memio_buffer readbuf; |
| 49 | 48 |
| 50 /* write requests are satisfied from this buffer */ | 49 /* write requests are satisfied from this buffer */ |
| 51 struct memio_buffer writebuf; | 50 struct memio_buffer writebuf; |
| 52 | 51 |
| 53 /* SSL needs to know socket peer's name */ | 52 /* SSL needs to know socket peer's name */ |
| 54 PRNetAddr peername; | 53 PRNetAddr peername; |
| 55 | 54 |
| 56 /* if set, empty I/O returns EOF instead of EWOULDBLOCK */ | 55 /* if set, empty I/O returns EOF instead of EWOULDBLOCK */ |
| 57 int eof; | 56 int eof; |
| 58 | 57 |
| 59 /* if set, the number of bytes requested from readbuf that were not | 58 /* if set, the number of bytes requested from readbuf that were not |
| 60 * fulfilled (due to readbuf being empty) */ | 59 * fulfilled (due to readbuf being empty) */ |
| 61 int read_requested; | 60 int read_requested; |
| 62 }; | 61 }; |
| 63 | 62 |
| 64 /*--------------- private memio_buffer functions ---------------------*/ | 63 /*--------------- private memio_buffer functions ---------------------*/ |
| 65 | 64 |
| 66 /* Forward declarations. */ | 65 /* Forward declarations. */ |
| 67 | 66 |
| 68 /* Allocate a memio_buffer of given size. */ | 67 /* Allocate a memio_buffer of given size. */ |
| 69 static void memio_buffer_new(struct memio_buffer *mb, int size); | 68 static void memio_buffer_new(struct memio_buffer* mb, int size); |
| 70 | 69 |
| 71 /* Deallocate a memio_buffer allocated by memio_buffer_new. */ | 70 /* Deallocate a memio_buffer allocated by memio_buffer_new. */ |
| 72 static void memio_buffer_destroy(struct memio_buffer *mb); | 71 static void memio_buffer_destroy(struct memio_buffer* mb); |
| 73 | 72 |
| 74 /* How many bytes can be read out of the buffer without wrapping */ | 73 /* How many bytes can be read out of the buffer without wrapping */ |
| 75 static int memio_buffer_used_contiguous(const struct memio_buffer *mb); | 74 static int memio_buffer_used_contiguous(const struct memio_buffer* mb); |
| 76 | 75 |
| 77 /* How many bytes exist after the wrap? */ | 76 /* How many bytes exist after the wrap? */ |
| 78 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb); | 77 static int memio_buffer_wrapped_bytes(const struct memio_buffer* mb); |
| 79 | 78 |
| 80 /* How many bytes can be written into the buffer without wrapping */ | 79 /* How many bytes can be written into the buffer without wrapping */ |
| 81 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb); | 80 static int memio_buffer_unused_contiguous(const struct memio_buffer* mb); |
| 82 | 81 |
| 83 /* Write n bytes into the buffer. Returns number of bytes written. */ | 82 /* Write n bytes into the buffer. Returns number of bytes written. */ |
| 84 static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n); | 83 static int memio_buffer_put(struct memio_buffer* mb, const char* buf, int n); |
| 85 | 84 |
| 86 /* Read n bytes from the buffer. Returns number of bytes read. */ | 85 /* Read n bytes from the buffer. Returns number of bytes read. */ |
| 87 static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n); | 86 static int memio_buffer_get(struct memio_buffer* mb, char* buf, int n); |
| 88 | 87 |
| 89 /* Allocate a memio_buffer of given size. */ | 88 /* Allocate a memio_buffer of given size. */ |
| 90 static void memio_buffer_new(struct memio_buffer *mb, int size) | 89 static void memio_buffer_new(struct memio_buffer* mb, int size) { |
| 91 { | 90 mb->head = 0; |
| 92 mb->head = 0; | 91 mb->tail = 0; |
| 93 mb->tail = 0; | 92 mb->bufsize = size; |
| 94 mb->bufsize = size; | 93 mb->buf = malloc(size); |
| 95 mb->buf = malloc(size); | |
| 96 } | 94 } |
| 97 | 95 |
| 98 /* Deallocate a memio_buffer allocated by memio_buffer_new. */ | 96 /* Deallocate a memio_buffer allocated by memio_buffer_new. */ |
| 99 static void memio_buffer_destroy(struct memio_buffer *mb) | 97 static void memio_buffer_destroy(struct memio_buffer* mb) { |
| 100 { | 98 free(mb->buf); |
| 101 free(mb->buf); | 99 mb->buf = NULL; |
| 102 mb->buf = NULL; | 100 mb->bufsize = 0; |
| 103 mb->bufsize = 0; | 101 mb->head = 0; |
| 104 mb->head = 0; | 102 mb->tail = 0; |
| 105 mb->tail = 0; | |
| 106 } | 103 } |
| 107 | 104 |
| 108 /* How many bytes can be read out of the buffer without wrapping */ | 105 /* How many bytes can be read out of the buffer without wrapping */ |
| 109 static int memio_buffer_used_contiguous(const struct memio_buffer *mb) | 106 static int memio_buffer_used_contiguous(const struct memio_buffer* mb) { |
| 110 { | 107 return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head); |
| 111 return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head); | |
| 112 } | 108 } |
| 113 | 109 |
| 114 /* How many bytes exist after the wrap? */ | 110 /* How many bytes exist after the wrap? */ |
| 115 static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb) | 111 static int memio_buffer_wrapped_bytes(const struct memio_buffer* mb) { |
| 116 { | 112 return (mb->tail >= mb->head) ? 0 : mb->tail; |
| 117 return (mb->tail >= mb->head) ? 0 : mb->tail; | |
| 118 } | 113 } |
| 119 | 114 |
| 120 /* How many bytes can be written into the buffer without wrapping */ | 115 /* How many bytes can be written into the buffer without wrapping */ |
| 121 static int memio_buffer_unused_contiguous(const struct memio_buffer *mb) | 116 static int memio_buffer_unused_contiguous(const struct memio_buffer* mb) { |
| 122 { | 117 if (mb->head > mb->tail) |
| 123 if (mb->head > mb->tail) return mb->head - mb->tail - 1; | 118 return mb->head - mb->tail - 1; |
| 124 return mb->bufsize - mb->tail - (mb->head == 0); | 119 return mb->bufsize - mb->tail - (mb->head == 0); |
| 125 } | 120 } |
| 126 | 121 |
| 127 /* Write n bytes into the buffer. Returns number of bytes written. */ | 122 /* Write n bytes into the buffer. Returns number of bytes written. */ |
| 128 static int memio_buffer_put(struct memio_buffer *mb, const char *buf, int n) | 123 static int memio_buffer_put(struct memio_buffer* mb, const char* buf, int n) { |
| 129 { | 124 int len; |
| 130 int len; | 125 int transferred = 0; |
| 131 int transferred = 0; | 126 |
| 132 | 127 /* Handle part before wrap */ |
|
mef
2014/10/10 20:38:17
I think NSS has/had formatting different from Chro
| |
| 133 /* Handle part before wrap */ | 128 len = PR_MIN(n, memio_buffer_unused_contiguous(mb)); |
| 129 if (len > 0) { | |
| 130 /* Buffer not full */ | |
| 131 memcpy(&mb->buf[mb->tail], buf, len); | |
| 132 mb->tail += len; | |
| 133 if (mb->tail == mb->bufsize) | |
| 134 mb->tail = 0; | |
| 135 n -= len; | |
| 136 buf += len; | |
| 137 transferred += len; | |
| 138 | |
| 139 /* Handle part after wrap */ | |
| 134 len = PR_MIN(n, memio_buffer_unused_contiguous(mb)); | 140 len = PR_MIN(n, memio_buffer_unused_contiguous(mb)); |
| 135 if (len > 0) { | 141 if (len > 0) { |
| 136 /* Buffer not full */ | 142 /* Output buffer still not full, input buffer still not empty */ |
| 137 memcpy(&mb->buf[mb->tail], buf, len); | 143 memcpy(&mb->buf[mb->tail], buf, len); |
| 138 mb->tail += len; | 144 mb->tail += len; |
| 139 if (mb->tail == mb->bufsize) | 145 if (mb->tail == mb->bufsize) |
| 140 mb->tail = 0; | 146 mb->tail = 0; |
| 141 n -= len; | 147 transferred += len; |
| 142 buf += len; | |
| 143 transferred += len; | |
| 144 | |
| 145 /* Handle part after wrap */ | |
| 146 len = PR_MIN(n, memio_buffer_unused_contiguous(mb)); | |
| 147 if (len > 0) { | |
| 148 /* Output buffer still not full, input buffer still not empty */ | |
| 149 memcpy(&mb->buf[mb->tail], buf, len); | |
| 150 mb->tail += len; | |
| 151 if (mb->tail == mb->bufsize) | |
| 152 mb->tail = 0; | |
| 153 transferred += len; | |
| 154 } | |
| 155 } | 148 } |
| 156 | 149 } |
| 157 return transferred; | 150 |
| 158 } | 151 return transferred; |
| 159 | 152 } |
| 160 | 153 |
| 161 /* Read n bytes from the buffer. Returns number of bytes read. */ | 154 /* Read n bytes from the buffer. Returns number of bytes read. */ |
| 162 static int memio_buffer_get(struct memio_buffer *mb, char *buf, int n) | 155 static int memio_buffer_get(struct memio_buffer* mb, char* buf, int n) { |
| 163 { | 156 int len; |
| 164 int len; | 157 int transferred = 0; |
| 165 int transferred = 0; | 158 |
| 166 | 159 /* Handle part before wrap */ |
| 167 /* Handle part before wrap */ | 160 len = PR_MIN(n, memio_buffer_used_contiguous(mb)); |
| 161 if (len) { | |
| 162 memcpy(buf, &mb->buf[mb->head], len); | |
| 163 mb->head += len; | |
| 164 if (mb->head == mb->bufsize) | |
| 165 mb->head = 0; | |
| 166 n -= len; | |
| 167 buf += len; | |
| 168 transferred += len; | |
| 169 | |
| 170 /* Handle part after wrap */ | |
| 168 len = PR_MIN(n, memio_buffer_used_contiguous(mb)); | 171 len = PR_MIN(n, memio_buffer_used_contiguous(mb)); |
| 169 if (len) { | 172 if (len) { |
| 170 memcpy(buf, &mb->buf[mb->head], len); | 173 memcpy(buf, &mb->buf[mb->head], len); |
| 171 mb->head += len; | 174 mb->head += len; |
| 172 if (mb->head == mb->bufsize) | 175 if (mb->head == mb->bufsize) |
| 173 mb->head = 0; | 176 mb->head = 0; |
| 174 n -= len; | 177 transferred += len; |
| 175 buf += len; | |
| 176 transferred += len; | |
| 177 | |
| 178 /* Handle part after wrap */ | |
| 179 len = PR_MIN(n, memio_buffer_used_contiguous(mb)); | |
| 180 if (len) { | |
| 181 memcpy(buf, &mb->buf[mb->head], len); | |
| 182 mb->head += len; | |
| 183 if (mb->head == mb->bufsize) | |
| 184 mb->head = 0; | |
| 185 transferred += len; | |
| 186 } | |
| 187 } | 178 } |
| 188 | 179 } |
| 189 return transferred; | 180 |
| 181 return transferred; | |
| 190 } | 182 } |
| 191 | 183 |
| 192 /*--------------- private memio functions -----------------------*/ | 184 /*--------------- private memio functions -----------------------*/ |
| 193 | 185 |
| 194 static PRStatus PR_CALLBACK memio_Close(PRFileDesc *fd) | 186 static PRStatus PR_CALLBACK memio_Close(PRFileDesc* fd) { |
| 195 { | 187 struct PRFilePrivate* secret = fd->secret; |
| 196 struct PRFilePrivate *secret = fd->secret; | 188 memio_buffer_destroy(&secret->readbuf); |
| 197 memio_buffer_destroy(&secret->readbuf); | 189 memio_buffer_destroy(&secret->writebuf); |
| 198 memio_buffer_destroy(&secret->writebuf); | 190 free(secret); |
| 199 free(secret); | 191 fd->dtor(fd); |
| 200 fd->dtor(fd); | 192 return PR_SUCCESS; |
| 201 return PR_SUCCESS; | 193 } |
| 202 } | 194 |
| 203 | 195 static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc* fd, PRIntn how) { |
| 204 static PRStatus PR_CALLBACK memio_Shutdown(PRFileDesc *fd, PRIntn how) | 196 /* TODO: pass shutdown status to app somehow */ |
| 205 { | 197 return PR_SUCCESS; |
| 206 /* TODO: pass shutdown status to app somehow */ | |
| 207 return PR_SUCCESS; | |
| 208 } | 198 } |
| 209 | 199 |
| 210 /* If there was a network error in the past taking bytes | 200 /* If there was a network error in the past taking bytes |
| 211 * out of the buffer, return it to the next call that | 201 * out of the buffer, return it to the next call that |
| 212 * tries to read from an empty buffer. | 202 * tries to read from an empty buffer. |
| 213 */ | 203 */ |
| 214 static int PR_CALLBACK memio_Recv(PRFileDesc *fd, void *buf, PRInt32 len, | 204 static int PR_CALLBACK memio_Recv(PRFileDesc* fd, |
| 215 PRIntn flags, PRIntervalTime timeout) | 205 void* buf, |
| 216 { | 206 PRInt32 len, |
| 217 struct PRFilePrivate *secret; | 207 PRIntn flags, |
| 218 struct memio_buffer *mb; | 208 PRIntervalTime timeout) { |
| 219 int rv; | 209 struct PRFilePrivate* secret; |
| 220 | 210 struct memio_buffer* mb; |
| 221 if (flags) { | 211 int rv; |
| 222 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | 212 |
| 223 return -1; | 213 if (flags) { |
| 224 } | 214 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); |
| 225 | 215 return -1; |
| 226 secret = fd->secret; | 216 } |
| 227 mb = &secret->readbuf; | 217 |
| 228 PR_ASSERT(mb->bufsize); | 218 secret = fd->secret; |
| 229 rv = memio_buffer_get(mb, buf, len); | 219 mb = &secret->readbuf; |
| 230 if (rv == 0 && !secret->eof) { | 220 PR_ASSERT(mb->bufsize); |
| 231 secret->read_requested = len; | 221 rv = memio_buffer_get(mb, buf, len); |
| 232 /* If there is no more data in the buffer, report any pending errors | 222 if (rv == 0 && !secret->eof) { |
| 233 * that were previously observed. Note that both the readbuf and the | 223 secret->read_requested = len; |
| 234 * writebuf are checked for errors, since the application may have | 224 /* If there is no more data in the buffer, report any pending errors |
| 235 * encountered a socket error while writing that would otherwise not | 225 * that were previously observed. Note that both the readbuf and the |
| 236 * be reported until the application attempted to write again - which | 226 * writebuf are checked for errors, since the application may have |
| 237 * it may never do. | 227 * encountered a socket error while writing that would otherwise not |
| 238 */ | 228 * be reported until the application attempted to write again - which |
| 239 if (mb->last_err) | 229 * it may never do. |
| 240 PR_SetError(mb->last_err, 0); | |
| 241 else if (secret->writebuf.last_err) | |
| 242 PR_SetError(secret->writebuf.last_err, 0); | |
| 243 else | |
| 244 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); | |
| 245 return -1; | |
| 246 } | |
| 247 | |
| 248 secret->read_requested = 0; | |
| 249 return rv; | |
| 250 } | |
| 251 | |
| 252 static int PR_CALLBACK memio_Read(PRFileDesc *fd, void *buf, PRInt32 len) | |
| 253 { | |
| 254 /* pull bytes from buffer */ | |
| 255 return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT); | |
| 256 } | |
| 257 | |
| 258 static int PR_CALLBACK memio_Send(PRFileDesc *fd, const void *buf, PRInt32 len, | |
| 259 PRIntn flags, PRIntervalTime timeout) | |
| 260 { | |
| 261 struct PRFilePrivate *secret; | |
| 262 struct memio_buffer *mb; | |
| 263 int rv; | |
| 264 | |
| 265 secret = fd->secret; | |
| 266 mb = &secret->writebuf; | |
| 267 PR_ASSERT(mb->bufsize); | |
| 268 | |
| 269 /* Note that the read error state is not reported, because it cannot be | |
| 270 * reported until all buffered data has been read. If there is an error | |
| 271 * with the next layer, attempting to call Send again will report the | |
| 272 * error appropriately. | |
| 273 */ | 230 */ |
| 274 if (mb->last_err) { | 231 if (mb->last_err) |
| 275 PR_SetError(mb->last_err, 0); | 232 PR_SetError(mb->last_err, 0); |
| 276 return -1; | 233 else if (secret->writebuf.last_err) |
| 277 } | 234 PR_SetError(secret->writebuf.last_err, 0); |
| 278 rv = memio_buffer_put(mb, buf, len); | 235 else |
| 279 if (rv == 0) { | 236 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); |
| 280 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); | 237 return -1; |
| 281 return -1; | 238 } |
| 282 } | 239 |
| 283 return rv; | 240 secret->read_requested = 0; |
| 284 } | 241 return rv; |
| 285 | 242 } |
| 286 static int PR_CALLBACK memio_Write(PRFileDesc *fd, const void *buf, PRInt32 len) | 243 |
| 287 { | 244 static int PR_CALLBACK memio_Read(PRFileDesc* fd, void* buf, PRInt32 len) { |
| 288 /* append bytes to buffer */ | 245 /* pull bytes from buffer */ |
| 289 return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT); | 246 return memio_Recv(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT); |
| 290 } | 247 } |
| 291 | 248 |
| 292 static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) | 249 static int PR_CALLBACK memio_Send(PRFileDesc* fd, |
| 293 { | 250 const void* buf, |
| 294 /* TODO: fail if memio_SetPeerName has not been called */ | 251 PRInt32 len, |
| 295 struct PRFilePrivate *secret = fd->secret; | 252 PRIntn flags, |
| 296 *addr = secret->peername; | 253 PRIntervalTime timeout) { |
| 254 struct PRFilePrivate* secret; | |
| 255 struct memio_buffer* mb; | |
| 256 int rv; | |
| 257 | |
| 258 secret = fd->secret; | |
| 259 mb = &secret->writebuf; | |
| 260 PR_ASSERT(mb->bufsize); | |
| 261 | |
| 262 /* Note that the read error state is not reported, because it cannot be | |
| 263 * reported until all buffered data has been read. If there is an error | |
| 264 * with the next layer, attempting to call Send again will report the | |
| 265 * error appropriately. | |
| 266 */ | |
| 267 if (mb->last_err) { | |
| 268 PR_SetError(mb->last_err, 0); | |
| 269 return -1; | |
| 270 } | |
| 271 rv = memio_buffer_put(mb, buf, len); | |
| 272 if (rv == 0) { | |
| 273 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); | |
| 274 return -1; | |
| 275 } | |
| 276 return rv; | |
| 277 } | |
| 278 | |
| 279 static int PR_CALLBACK | |
| 280 memio_Write(PRFileDesc* fd, const void* buf, PRInt32 len) { | |
| 281 /* append bytes to buffer */ | |
| 282 return memio_Send(fd, buf, len, 0, PR_INTERVAL_NO_TIMEOUT); | |
| 283 } | |
| 284 | |
| 285 static PRStatus PR_CALLBACK memio_GetPeerName(PRFileDesc* fd, PRNetAddr* addr) { | |
| 286 /* TODO: fail if memio_SetPeerName has not been called */ | |
| 287 struct PRFilePrivate* secret = fd->secret; | |
| 288 *addr = secret->peername; | |
| 289 return PR_SUCCESS; | |
| 290 } | |
| 291 | |
| 292 static PRStatus memio_GetSocketOption(PRFileDesc* fd, | |
| 293 PRSocketOptionData* data) { | |
| 294 /* | |
| 295 * Even in the original version for real tcp sockets, | |
| 296 * PR_SockOpt_Nonblocking is a special case that does not | |
| 297 * translate to a getsockopt() call | |
| 298 */ | |
| 299 if (PR_SockOpt_Nonblocking == data->option) { | |
| 300 data->value.non_blocking = PR_TRUE; | |
| 297 return PR_SUCCESS; | 301 return PR_SUCCESS; |
| 298 } | 302 } |
| 299 | 303 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); |
| 300 static PRStatus memio_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) | 304 return PR_FAILURE; |
| 301 { | |
| 302 /* | |
| 303 * Even in the original version for real tcp sockets, | |
| 304 * PR_SockOpt_Nonblocking is a special case that does not | |
| 305 * translate to a getsockopt() call | |
| 306 */ | |
| 307 if (PR_SockOpt_Nonblocking == data->option) { | |
| 308 data->value.non_blocking = PR_TRUE; | |
| 309 return PR_SUCCESS; | |
| 310 } | |
| 311 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); | |
| 312 return PR_FAILURE; | |
| 313 } | 305 } |
| 314 | 306 |
| 315 /*--------------- private memio data -----------------------*/ | 307 /*--------------- private memio data -----------------------*/ |
| 316 | 308 |
| 317 /* | 309 /* |
| 318 * Implement just the bare minimum number of methods needed to make ssl happy. | 310 * Implement just the bare minimum number of methods needed to make ssl happy. |
| 319 * | 311 * |
| 320 * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls | 312 * Oddly, PR_Recv calls ssl_Recv calls ssl_SocketIsBlocking calls |
| 321 * PR_GetSocketOption, so we have to provide an implementation of | 313 * PR_GetSocketOption, so we have to provide an implementation of |
| 322 * PR_GetSocketOption that just says "I'm nonblocking". | 314 * PR_GetSocketOption that just says "I'm nonblocking". |
| 323 */ | 315 */ |
| 324 | 316 |
| 325 static struct PRIOMethods memio_layer_methods = { | 317 static struct PRIOMethods memio_layer_methods = { |
| 326 PR_DESC_LAYERED, | 318 PR_DESC_LAYERED, |
| 327 memio_Close, | 319 memio_Close, |
| 328 memio_Read, | 320 memio_Read, |
| 329 memio_Write, | 321 memio_Write, |
| 330 NULL, | 322 NULL, |
| 331 NULL, | 323 NULL, |
| 332 NULL, | 324 NULL, |
| 333 NULL, | 325 NULL, |
| 334 NULL, | 326 NULL, |
| 335 NULL, | 327 NULL, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 356 NULL, | 348 NULL, |
| 357 NULL, | 349 NULL, |
| 358 NULL, | 350 NULL, |
| 359 NULL, | 351 NULL, |
| 360 NULL, | 352 NULL, |
| 361 NULL, | 353 NULL, |
| 362 }; | 354 }; |
| 363 | 355 |
| 364 static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER; | 356 static PRDescIdentity memio_identity = PR_INVALID_IO_LAYER; |
| 365 | 357 |
| 366 static PRStatus memio_InitializeLayerName(void) | 358 static PRStatus memio_InitializeLayerName(void) { |
| 367 { | 359 memio_identity = PR_GetUniqueIdentity("memio"); |
| 368 memio_identity = PR_GetUniqueIdentity("memio"); | 360 return PR_SUCCESS; |
| 369 return PR_SUCCESS; | |
| 370 } | 361 } |
| 371 | 362 |
| 372 /*--------------- public memio functions -----------------------*/ | 363 /*--------------- public memio functions -----------------------*/ |
| 373 | 364 |
| 374 PRFileDesc *memio_CreateIOLayer(int readbufsize, int writebufsize) | 365 PRFileDesc* memio_CreateIOLayer(int readbufsize, int writebufsize) { |
| 375 { | 366 PRFileDesc* fd; |
| 376 PRFileDesc *fd; | 367 struct PRFilePrivate* secret; |
| 377 struct PRFilePrivate *secret; | 368 static PRCallOnceType once; |
| 378 static PRCallOnceType once; | |
| 379 | 369 |
| 380 PR_CallOnce(&once, memio_InitializeLayerName); | 370 PR_CallOnce(&once, memio_InitializeLayerName); |
| 381 | 371 |
| 382 fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods); | 372 fd = PR_CreateIOLayerStub(memio_identity, &memio_layer_methods); |
| 383 secret = malloc(sizeof(struct PRFilePrivate)); | 373 secret = malloc(sizeof(struct PRFilePrivate)); |
| 384 memset(secret, 0, sizeof(*secret)); | 374 memset(secret, 0, sizeof(*secret)); |
| 385 | 375 |
| 386 memio_buffer_new(&secret->readbuf, readbufsize); | 376 memio_buffer_new(&secret->readbuf, readbufsize); |
| 387 memio_buffer_new(&secret->writebuf, writebufsize); | 377 memio_buffer_new(&secret->writebuf, writebufsize); |
| 388 fd->secret = secret; | 378 fd->secret = secret; |
| 389 return fd; | 379 return fd; |
| 390 } | 380 } |
| 391 | 381 |
| 392 void memio_SetPeerName(PRFileDesc *fd, const PRNetAddr *peername) | 382 void memio_SetPeerName(PRFileDesc* fd, const PRNetAddr* peername) { |
| 393 { | 383 PRFileDesc* memiofd = PR_GetIdentitiesLayer(fd, memio_identity); |
| 394 PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity); | 384 struct PRFilePrivate* secret = memiofd->secret; |
| 395 struct PRFilePrivate *secret = memiofd->secret; | 385 secret->peername = *peername; |
| 396 secret->peername = *peername; | |
| 397 } | 386 } |
| 398 | 387 |
| 399 memio_Private *memio_GetSecret(PRFileDesc *fd) | 388 memio_Private* memio_GetSecret(PRFileDesc* fd) { |
| 400 { | 389 PRFileDesc* memiofd = PR_GetIdentitiesLayer(fd, memio_identity); |
| 401 PRFileDesc *memiofd = PR_GetIdentitiesLayer(fd, memio_identity); | 390 struct PRFilePrivate* secret = memiofd->secret; |
| 402 struct PRFilePrivate *secret = memiofd->secret; | 391 return (memio_Private*)secret; |
| 403 return (memio_Private *)secret; | |
| 404 } | 392 } |
| 405 | 393 |
| 406 int memio_GetReadRequest(memio_Private *secret) | 394 int memio_GetReadRequest(memio_Private* secret) { |
| 407 { | 395 return ((PRFilePrivate*)secret)->read_requested; |
| 408 return ((PRFilePrivate *)secret)->read_requested; | |
| 409 } | 396 } |
| 410 | 397 |
| 411 int memio_GetReadParams(memio_Private *secret, char **buf) | 398 int memio_GetReadParams(memio_Private* secret, char** buf) { |
| 412 { | 399 struct memio_buffer* mb = &((PRFilePrivate*)secret)->readbuf; |
| 413 struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf; | 400 PR_ASSERT(mb->bufsize); |
| 414 PR_ASSERT(mb->bufsize); | |
| 415 | 401 |
| 416 *buf = &mb->buf[mb->tail]; | 402 *buf = &mb->buf[mb->tail]; |
| 417 return memio_buffer_unused_contiguous(mb); | 403 return memio_buffer_unused_contiguous(mb); |
| 418 } | 404 } |
| 419 | 405 |
| 420 int memio_GetReadableBufferSize(memio_Private *secret) | 406 int memio_GetReadableBufferSize(memio_Private* secret) { |
| 421 { | 407 struct memio_buffer* mb = &((PRFilePrivate*)secret)->readbuf; |
| 422 struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf; | 408 PR_ASSERT(mb->bufsize); |
| 423 PR_ASSERT(mb->bufsize); | |
| 424 | 409 |
| 425 return memio_buffer_used_contiguous(mb); | 410 return memio_buffer_used_contiguous(mb); |
| 426 } | 411 } |
| 427 | 412 |
| 428 void memio_PutReadResult(memio_Private *secret, int bytes_read) | 413 void memio_PutReadResult(memio_Private* secret, int bytes_read) { |
| 429 { | 414 struct memio_buffer* mb = &((PRFilePrivate*)secret)->readbuf; |
| 430 struct memio_buffer* mb = &((PRFilePrivate *)secret)->readbuf; | 415 PR_ASSERT(mb->bufsize); |
| 431 PR_ASSERT(mb->bufsize); | |
| 432 | 416 |
| 433 if (bytes_read > 0) { | 417 if (bytes_read > 0) { |
| 434 mb->tail += bytes_read; | 418 mb->tail += bytes_read; |
| 435 if (mb->tail == mb->bufsize) | 419 if (mb->tail == mb->bufsize) |
| 436 mb->tail = 0; | 420 mb->tail = 0; |
| 437 } else if (bytes_read == 0) { | 421 } else if (bytes_read == 0) { |
| 438 /* Record EOF condition and report to caller when buffer runs dry */ | 422 /* Record EOF condition and report to caller when buffer runs dry */ |
| 439 ((PRFilePrivate *)secret)->eof = PR_TRUE; | 423 ((PRFilePrivate*)secret)->eof = PR_TRUE; |
| 440 } else /* if (bytes_read < 0) */ { | 424 } else /* if (bytes_read < 0) */ { |
| 441 mb->last_err = bytes_read; | 425 mb->last_err = bytes_read; |
| 442 } | 426 } |
| 443 } | 427 } |
| 444 | 428 |
| 445 int memio_GetWriteParams(memio_Private *secret, | 429 int memio_GetWriteParams(memio_Private* secret, |
| 446 const char **buf1, unsigned int *len1, | 430 const char** buf1, |
| 447 const char **buf2, unsigned int *len2) | 431 unsigned int* len1, |
| 448 { | 432 const char** buf2, |
| 449 struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf; | 433 unsigned int* len2) { |
| 450 PR_ASSERT(mb->bufsize); | 434 struct memio_buffer* mb = &((PRFilePrivate*)secret)->writebuf; |
| 435 PR_ASSERT(mb->bufsize); | |
| 451 | 436 |
| 452 if (mb->last_err) | 437 if (mb->last_err) |
| 453 return mb->last_err; | 438 return mb->last_err; |
| 454 | 439 |
| 455 *buf1 = &mb->buf[mb->head]; | 440 *buf1 = &mb->buf[mb->head]; |
| 456 *len1 = memio_buffer_used_contiguous(mb); | 441 *len1 = memio_buffer_used_contiguous(mb); |
| 457 *buf2 = mb->buf; | 442 *buf2 = mb->buf; |
| 458 *len2 = memio_buffer_wrapped_bytes(mb); | 443 *len2 = memio_buffer_wrapped_bytes(mb); |
| 459 return 0; | 444 return 0; |
| 460 } | 445 } |
| 461 | 446 |
| 462 void memio_PutWriteResult(memio_Private *secret, int bytes_written) | 447 void memio_PutWriteResult(memio_Private* secret, int bytes_written) { |
| 463 { | 448 struct memio_buffer* mb = &((PRFilePrivate*)secret)->writebuf; |
| 464 struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf; | 449 PR_ASSERT(mb->bufsize); |
| 465 PR_ASSERT(mb->bufsize); | |
| 466 | 450 |
| 467 if (bytes_written > 0) { | 451 if (bytes_written > 0) { |
| 468 mb->head += bytes_written; | 452 mb->head += bytes_written; |
| 469 if (mb->head >= mb->bufsize) | 453 if (mb->head >= mb->bufsize) |
| 470 mb->head -= mb->bufsize; | 454 mb->head -= mb->bufsize; |
| 471 } else if (bytes_written < 0) { | 455 } else if (bytes_written < 0) { |
| 472 mb->last_err = bytes_written; | 456 mb->last_err = bytes_written; |
| 473 } | 457 } |
| 474 } | 458 } |
| 475 | 459 |
| 476 /*--------------- private memio_buffer self-test -----------------*/ | 460 /*--------------- private memio_buffer self-test -----------------*/ |
| 477 | 461 |
| 478 /* Even a trivial unit test is very helpful when doing circular buffers. */ | 462 /* Even a trivial unit test is very helpful when doing circular buffers. */ |
| 479 /*#define TRIVIAL_SELF_TEST*/ | 463 /*#define TRIVIAL_SELF_TEST*/ |
| 480 #ifdef TRIVIAL_SELF_TEST | 464 #ifdef TRIVIAL_SELF_TEST |
| 481 #include <stdio.h> | 465 #include <stdio.h> |
| 482 | 466 |
| 483 #define TEST_BUFLEN 7 | 467 #define TEST_BUFLEN 7 |
| 484 | 468 |
| 485 #define CHECKEQ(a, b) { \ | 469 #define CHECKEQ(a, b) \ |
| 486 if ((a) != (b)) { \ | 470 { \ |
| 487 printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \ | 471 if ((a) != (b)) { \ |
| 488 exit(1); \ | 472 printf("%d != %d, Test failed line %d\n", a, b, __LINE__); \ |
| 489 } \ | 473 exit(1); \ |
| 490 } | 474 } \ |
| 475 } | |
| 491 | 476 |
| 492 int main() | 477 int main() { |
| 493 { | 478 struct memio_buffer mb; |
| 494 struct memio_buffer mb; | 479 char buf[100]; |
| 495 char buf[100]; | 480 int i; |
| 496 int i; | |
| 497 | 481 |
| 498 memio_buffer_new(&mb, TEST_BUFLEN); | 482 memio_buffer_new(&mb, TEST_BUFLEN); |
| 499 | 483 |
| 500 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1); | 484 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN - 1); |
| 501 CHECKEQ(memio_buffer_used_contiguous(&mb), 0); | 485 CHECKEQ(memio_buffer_used_contiguous(&mb), 0); |
| 502 | 486 |
| 503 CHECKEQ(memio_buffer_put(&mb, "howdy", 5), 5); | 487 CHECKEQ(memio_buffer_put(&mb, "howdy", 5), 5); |
| 504 | 488 |
| 505 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5); | 489 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN - 1 - 5); |
| 506 CHECKEQ(memio_buffer_used_contiguous(&mb), 5); | 490 CHECKEQ(memio_buffer_used_contiguous(&mb), 5); |
| 507 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); | 491 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); |
| 508 | 492 |
| 509 CHECKEQ(memio_buffer_put(&mb, "!", 1), 1); | 493 CHECKEQ(memio_buffer_put(&mb, "!", 1), 1); |
| 510 | 494 |
| 511 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); | 495 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); |
| 512 CHECKEQ(memio_buffer_used_contiguous(&mb), 6); | 496 CHECKEQ(memio_buffer_used_contiguous(&mb), 6); |
| 513 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); | 497 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); |
| 514 | 498 |
| 515 CHECKEQ(memio_buffer_get(&mb, buf, 6), 6); | 499 CHECKEQ(memio_buffer_get(&mb, buf, 6), 6); |
| 516 CHECKEQ(memcmp(buf, "howdy!", 6), 0); | 500 CHECKEQ(memcmp(buf, "howdy!", 6), 0); |
| 517 | 501 |
| 518 CHECKEQ(memio_buffer_unused_contiguous(&mb), 1); | 502 CHECKEQ(memio_buffer_unused_contiguous(&mb), 1); |
| 519 CHECKEQ(memio_buffer_used_contiguous(&mb), 0); | 503 CHECKEQ(memio_buffer_used_contiguous(&mb), 0); |
| 520 | 504 |
| 521 CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5); | 505 CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5); |
| 522 | 506 |
| 523 CHECKEQ(memio_buffer_used_contiguous(&mb), 1); | 507 CHECKEQ(memio_buffer_used_contiguous(&mb), 1); |
| 524 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4); | 508 CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4); |
| 525 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5); | 509 CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN - 1 - 5); |
| 526 | 510 |
| 527 CHECKEQ(memio_buffer_put(&mb, "5", 1), 1); | 511 CHECKEQ(memio_buffer_put(&mb, "5", 1), 1); |
| 528 | 512 |
| 529 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); | 513 CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); |
| 530 CHECKEQ(memio_buffer_used_contiguous(&mb), 1); | 514 CHECKEQ(memio_buffer_used_contiguous(&mb), 1); |
| 531 | 515 |
| 532 /* TODO: add more cases */ | 516 /* TODO: add more cases */ |
| 533 | 517 |
| 534 printf("Test passed\n"); | 518 printf("Test passed\n"); |
| 535 exit(0); | 519 exit(0); |
| 536 } | 520 } |
| 537 | 521 |
| 538 #endif | 522 #endif |
| OLD | NEW |