Changeset 988 for vendor/current/lib/async_req
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- Location:
- vendor/current/lib/async_req
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/lib/async_req/async_sock.c
r860 r988 28 28 #include <tevent.h> 29 29 #include "lib/async_req/async_sock.h" 30 #include "lib/util/iov_buf.h" 30 31 31 32 /* Note: lib/util/ is currently GPL */ 32 33 #include "lib/util/tevent_unix.h" 33 #include "lib/util/util.h" 34 35 #ifndef TALLOC_FREE 36 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0) 37 #endif 38 39 struct sendto_state { 40 int fd; 41 const void *buf; 42 size_t len; 43 int flags; 44 const struct sockaddr_storage *addr; 45 socklen_t addr_len; 46 ssize_t sent; 47 }; 48 49 static void sendto_handler(struct tevent_context *ev, 50 struct tevent_fd *fde, 51 uint16_t flags, void *private_data); 52 53 struct tevent_req *sendto_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, 54 int fd, const void *buf, size_t len, int flags, 55 const struct sockaddr_storage *addr) 56 { 57 struct tevent_req *result; 58 struct sendto_state *state; 59 struct tevent_fd *fde; 60 61 result = tevent_req_create(mem_ctx, &state, struct sendto_state); 62 if (result == NULL) { 63 return result; 64 } 65 state->fd = fd; 66 state->buf = buf; 67 state->len = len; 68 state->flags = flags; 69 state->addr = addr; 70 71 switch (addr->ss_family) { 72 case AF_INET: 73 state->addr_len = sizeof(struct sockaddr_in); 74 break; 75 #if defined(HAVE_IPV6) 76 case AF_INET6: 77 state->addr_len = sizeof(struct sockaddr_in6); 78 break; 79 #endif 80 case AF_UNIX: 81 state->addr_len = sizeof(struct sockaddr_un); 82 break; 83 default: 84 state->addr_len = sizeof(struct sockaddr_storage); 85 break; 86 } 87 88 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, sendto_handler, 89 result); 90 if (fde == NULL) { 91 TALLOC_FREE(result); 92 return NULL; 93 } 94 return result; 95 } 96 97 static void sendto_handler(struct tevent_context *ev, 98 struct tevent_fd *fde, 99 uint16_t flags, void *private_data) 100 { 101 struct tevent_req *req = talloc_get_type_abort( 102 private_data, struct tevent_req); 103 struct sendto_state *state = 104 tevent_req_data(req, struct sendto_state); 105 106 state->sent = sendto(state->fd, state->buf, state->len, state->flags, 107 (struct sockaddr *)state->addr, state->addr_len); 108 if ((state->sent == -1) && (errno == EINTR)) { 109 /* retry */ 110 return; 111 } 112 if (state->sent == -1) { 113 tevent_req_error(req, errno); 114 return; 115 } 116 tevent_req_done(req); 117 } 118 119 ssize_t sendto_recv(struct tevent_req *req, int *perrno) 120 { 121 struct sendto_state *state = 122 tevent_req_data(req, struct sendto_state); 123 124 if (tevent_req_is_unix_error(req, perrno)) { 125 return -1; 126 } 127 return state->sent; 128 } 129 130 struct recvfrom_state { 131 int fd; 132 void *buf; 133 size_t len; 134 int flags; 135 struct sockaddr_storage *addr; 136 socklen_t *addr_len; 137 ssize_t received; 138 }; 139 140 static void recvfrom_handler(struct tevent_context *ev, 141 struct tevent_fd *fde, 142 uint16_t flags, void *private_data); 143 144 struct tevent_req *recvfrom_send(TALLOC_CTX *mem_ctx, 145 struct tevent_context *ev, 146 int fd, void *buf, size_t len, int flags, 147 struct sockaddr_storage *addr, 148 socklen_t *addr_len) 149 { 150 struct tevent_req *result; 151 struct recvfrom_state *state; 152 struct tevent_fd *fde; 153 154 result = tevent_req_create(mem_ctx, &state, struct recvfrom_state); 155 if (result == NULL) { 156 return result; 157 } 158 state->fd = fd; 159 state->buf = buf; 160 state->len = len; 161 state->flags = flags; 162 state->addr = addr; 163 state->addr_len = addr_len; 164 165 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, recvfrom_handler, 166 result); 167 if (fde == NULL) { 168 TALLOC_FREE(result); 169 return NULL; 170 } 171 return result; 172 } 173 174 static void recvfrom_handler(struct tevent_context *ev, 175 struct tevent_fd *fde, 176 uint16_t flags, void *private_data) 177 { 178 struct tevent_req *req = talloc_get_type_abort( 179 private_data, struct tevent_req); 180 struct recvfrom_state *state = 181 tevent_req_data(req, struct recvfrom_state); 182 183 state->received = recvfrom(state->fd, state->buf, state->len, 184 state->flags, (struct sockaddr *)state->addr, 185 state->addr_len); 186 if ((state->received == -1) && (errno == EINTR)) { 187 /* retry */ 188 return; 189 } 190 if (state->received == 0) { 191 tevent_req_error(req, EPIPE); 192 return; 193 } 194 if (state->received == -1) { 195 tevent_req_error(req, errno); 196 return; 197 } 198 tevent_req_done(req); 199 } 200 201 ssize_t recvfrom_recv(struct tevent_req *req, int *perrno) 202 { 203 struct recvfrom_state *state = 204 tevent_req_data(req, struct recvfrom_state); 205 206 if (tevent_req_is_unix_error(req, perrno)) { 207 return -1; 208 } 209 return state->received; 210 } 34 #include "lib/util/samba_util.h" 211 35 212 36 struct async_connect_state { 213 37 int fd; 38 struct tevent_fd *fde; 214 39 int result; 215 int sys_errno;216 40 long old_sockflags; 217 41 socklen_t address_len; 218 42 struct sockaddr_storage address; 43 44 void (*before_connect)(void *private_data); 45 void (*after_connect)(void *private_data); 46 void *private_data; 219 47 }; 220 48 49 static void async_connect_cleanup(struct tevent_req *req, 50 enum tevent_req_state req_state); 221 51 static void async_connect_connected(struct tevent_context *ev, 222 52 struct tevent_fd *fde, uint16_t flags, … … 236 66 */ 237 67 238 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx, 239 struct tevent_context *ev, 240 int fd, const struct sockaddr *address, 241 socklen_t address_len) 242 { 243 struct tevent_req *result; 68 struct tevent_req *async_connect_send( 69 TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd, 70 const struct sockaddr *address, socklen_t address_len, 71 void (*before_connect)(void *private_data), 72 void (*after_connect)(void *private_data), 73 void *private_data) 74 { 75 struct tevent_req *req; 244 76 struct async_connect_state *state; 245 struct tevent_fd *fde; 246 247 result = tevent_req_create( 248 mem_ctx, &state, struct async_connect_state); 249 if (result == NULL) { 77 int ret; 78 79 req = tevent_req_create(mem_ctx, &state, struct async_connect_state); 80 if (req == NULL) { 250 81 return NULL; 251 82 } … … 257 88 258 89 state->fd = fd; 259 state->sys_errno = 0; 90 state->before_connect = before_connect; 91 state->after_connect = after_connect; 92 state->private_data = private_data; 260 93 261 94 state->old_sockflags = fcntl(fd, F_GETFL, 0); 262 95 if (state->old_sockflags == -1) { 263 goto post_errno; 264 } 96 tevent_req_error(req, errno); 97 return tevent_req_post(req, ev); 98 } 99 100 tevent_req_set_cleanup_fn(req, async_connect_cleanup); 265 101 266 102 state->address_len = address_len; 267 103 if (address_len > sizeof(state->address)) { 268 errno = EINVAL;269 goto post_errno;104 tevent_req_error(req, EINVAL); 105 return tevent_req_post(req, ev); 270 106 } 271 107 memcpy(&state->address, address, address_len); 272 108 273 set_blocking(fd, false); 109 ret = set_blocking(fd, false); 110 if (ret == -1) { 111 tevent_req_error(req, errno); 112 return tevent_req_post(req, ev); 113 } 114 115 if (state->before_connect != NULL) { 116 state->before_connect(state->private_data); 117 } 274 118 275 119 state->result = connect(fd, address, address_len); 120 121 if (state->after_connect != NULL) { 122 state->after_connect(state->private_data); 123 } 124 276 125 if (state->result == 0) { 277 tevent_req_done(result); 278 goto done; 279 } 280 281 /** 282 * A number of error messages show that something good is progressing 283 * and that we have to wait for readability. 284 * 285 * If none of them are present, bail out. 126 tevent_req_done(req); 127 return tevent_req_post(req, ev); 128 } 129 130 /* 131 * The only errno indicating that the connect is still in 132 * flight is EINPROGRESS, everything else is an error 286 133 */ 287 134 288 if (!(errno == EINPROGRESS || errno == EALREADY || 289 #ifdef EISCONN 290 errno == EISCONN || 291 #endif 292 errno == EAGAIN || errno == EINTR)) { 293 state->sys_errno = errno; 294 goto post_errno; 295 } 296 297 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE, 298 async_connect_connected, result); 299 if (fde == NULL) { 300 state->sys_errno = ENOMEM; 301 goto post_errno; 302 } 303 return result; 304 305 post_errno: 306 tevent_req_error(result, state->sys_errno); 307 done: 308 fcntl(fd, F_SETFL, state->old_sockflags); 309 return tevent_req_post(result, ev); 135 if (errno != EINPROGRESS) { 136 tevent_req_error(req, errno); 137 return tevent_req_post(req, ev); 138 } 139 140 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, 141 async_connect_connected, req); 142 if (state->fde == NULL) { 143 tevent_req_error(req, ENOMEM); 144 return tevent_req_post(req, ev); 145 } 146 return req; 147 } 148 149 static void async_connect_cleanup(struct tevent_req *req, 150 enum tevent_req_state req_state) 151 { 152 struct async_connect_state *state = 153 tevent_req_data(req, struct async_connect_state); 154 155 TALLOC_FREE(state->fde); 156 if (state->fd != -1) { 157 int ret; 158 159 ret = fcntl(state->fd, F_SETFL, state->old_sockflags); 160 if (ret == -1) { 161 abort(); 162 } 163 164 state->fd = -1; 165 } 310 166 } 311 167 … … 327 183 tevent_req_data(req, struct async_connect_state); 328 184 int ret; 329 330 ret = connect(state->fd, (struct sockaddr *)(void *)&state->address, 331 state->address_len); 332 if (ret == 0) { 333 state->sys_errno = 0; 334 TALLOC_FREE(fde); 335 tevent_req_done(req); 336 return; 337 } 338 if (errno == EINPROGRESS) { 339 /* Try again later, leave the fde around */ 340 return; 341 } 342 state->sys_errno = errno; 343 TALLOC_FREE(fde); 344 tevent_req_error(req, errno); 185 int socket_error = 0; 186 socklen_t slen = sizeof(socket_error); 187 188 ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR, 189 &socket_error, &slen); 190 191 if (ret != 0) { 192 /* 193 * According to Stevens this is the Solaris behaviour 194 * in case the connection encountered an error: 195 * getsockopt() fails, error is in errno 196 */ 197 tevent_req_error(req, errno); 198 return; 199 } 200 201 if (socket_error != 0) { 202 /* 203 * Berkeley derived implementations (including) Linux 204 * return the pending error via socket_error. 205 */ 206 tevent_req_error(req, socket_error); 207 return; 208 } 209 210 tevent_req_done(req); 345 211 return; 346 212 } … … 348 214 int async_connect_recv(struct tevent_req *req, int *perrno) 349 215 { 350 struct async_connect_state *state = 351 tevent_req_data(req, struct async_connect_state); 352 int err; 353 354 fcntl(state->fd, F_SETFL, state->old_sockflags); 355 356 if (tevent_req_is_unix_error(req, &err)) { 216 int err = tevent_req_simple_recv_unix(req); 217 218 if (err != 0) { 357 219 *perrno = err; 358 220 return -1; 359 221 } 360 222 361 if (state->sys_errno == 0) { 362 return 0; 363 } 364 365 *perrno = state->sys_errno; 366 return -1; 223 return 0; 367 224 } 368 225 … … 370 227 struct tevent_context *ev; 371 228 int fd; 229 struct tevent_fd *fde; 372 230 struct iovec *iov; 373 231 int count; … … 377 235 }; 378 236 237 static void writev_cleanup(struct tevent_req *req, 238 enum tevent_req_state req_state); 379 239 static void writev_trigger(struct tevent_req *req, void *private_data); 380 240 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde, … … 399 259 state->iov = (struct iovec *)talloc_memdup( 400 260 state, iov, sizeof(struct iovec) * count); 401 if ( state->iov == NULL) {402 goto fail;261 if (tevent_req_nomem(state->iov, req)) { 262 return tevent_req_post(req, ev); 403 263 } 404 264 state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ; 405 265 state->err_on_readability = err_on_readability; 406 266 267 tevent_req_set_cleanup_fn(req, writev_cleanup); 268 407 269 if (queue == NULL) { 408 struct tevent_fd *fde; 409 fde = tevent_add_fd(state->ev, state, state->fd, 270 state->fde = tevent_add_fd(state->ev, state, state->fd, 410 271 state->flags, writev_handler, req); 411 if (tevent_req_nomem( fde, req)) {272 if (tevent_req_nomem(state->fde, req)) { 412 273 return tevent_req_post(req, ev); 413 274 } … … 416 277 417 278 if (!tevent_queue_add(queue, ev, req, writev_trigger, NULL)) { 418 goto fail; 279 tevent_req_oom(req); 280 return tevent_req_post(req, ev); 419 281 } 420 282 return req; 421 fail: 422 TALLOC_FREE(req); 423 return NULL; 283 } 284 285 static void writev_cleanup(struct tevent_req *req, 286 enum tevent_req_state req_state) 287 { 288 struct writev_state *state = tevent_req_data(req, struct writev_state); 289 290 TALLOC_FREE(state->fde); 424 291 } 425 292 … … 427 294 { 428 295 struct writev_state *state = tevent_req_data(req, struct writev_state); 429 struct tevent_fd *fde; 430 431 fde = tevent_add_fd(state->ev, state, state->fd, state->flags, 296 297 state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags, 432 298 writev_handler, req); 433 if ( fde == NULL) {434 tevent_req_error(req, ENOMEM);299 if (tevent_req_nomem(state->fde, req)) { 300 return; 435 301 } 436 302 } … … 443 309 struct writev_state *state = 444 310 tevent_req_data(req, struct writev_state); 445 size_t to_write, written; 446 int i; 447 448 to_write = 0; 311 size_t written; 312 bool ok; 449 313 450 314 if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) { … … 480 344 } 481 345 482 for (i=0; i<state->count; i++) {483 to_write += state->iov[i].iov_len;484 }485 486 346 written = writev(state->fd, state->iov, state->count); 487 347 if ((written == -1) && (errno == EINTR)) { … … 499 359 state->total_size += written; 500 360 501 if (written == to_write) { 361 ok = iov_advance(&state->iov, &state->count, written); 362 if (!ok) { 363 tevent_req_error(req, EIO); 364 return; 365 } 366 367 if (state->count == 0) { 502 368 tevent_req_done(req); 503 369 return; 504 }505 506 /*507 * We've written less than we were asked to, drop stuff from508 * state->iov.509 */510 511 while (written > 0) {512 if (written < state->iov[0].iov_len) {513 state->iov[0].iov_base =514 (char *)state->iov[0].iov_base + written;515 state->iov[0].iov_len -= written;516 break;517 }518 written -= state->iov[0].iov_len;519 state->iov += 1;520 state->count -= 1;521 370 } 522 371 } … … 526 375 struct writev_state *state = 527 376 tevent_req_data(req, struct writev_state); 377 ssize_t ret; 528 378 529 379 if (tevent_req_is_unix_error(req, perrno)) { 380 tevent_req_received(req); 530 381 return -1; 531 382 } 532 return state->total_size; 383 ret = state->total_size; 384 tevent_req_received(req); 385 return ret; 533 386 } 534 387 535 388 struct read_packet_state { 536 389 int fd; 390 struct tevent_fd *fde; 537 391 uint8_t *buf; 538 392 size_t nread; … … 541 395 }; 542 396 397 static void read_packet_cleanup(struct tevent_req *req, 398 enum tevent_req_state req_state); 543 399 static void read_packet_handler(struct tevent_context *ev, 544 400 struct tevent_fd *fde, … … 553 409 void *private_data) 554 410 { 555 struct tevent_req *re sult;411 struct tevent_req *req; 556 412 struct read_packet_state *state; 557 struct tevent_fd *fde; 558 559 result = tevent_req_create(mem_ctx, &state, struct read_packet_state); 560 if (result == NULL) { 413 414 req = tevent_req_create(mem_ctx, &state, struct read_packet_state); 415 if (req == NULL) { 561 416 return NULL; 562 417 } … … 566 421 state->private_data = private_data; 567 422 423 tevent_req_set_cleanup_fn(req, read_packet_cleanup); 424 568 425 state->buf = talloc_array(state, uint8_t, initial); 569 if (state->buf == NULL) { 570 goto fail; 571 } 572 573 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler, 574 result); 575 if (fde == NULL) { 576 goto fail; 577 } 578 return result; 579 fail: 580 TALLOC_FREE(result); 581 return NULL; 426 if (tevent_req_nomem(state->buf, req)) { 427 return tevent_req_post(req, ev); 428 } 429 430 state->fde = tevent_add_fd(ev, state, fd, 431 TEVENT_FD_READ, read_packet_handler, 432 req); 433 if (tevent_req_nomem(state->fde, req)) { 434 return tevent_req_post(req, ev); 435 } 436 return req; 437 } 438 439 static void read_packet_cleanup(struct tevent_req *req, 440 enum tevent_req_state req_state) 441 { 442 struct read_packet_state *state = 443 tevent_req_data(req, struct read_packet_state); 444 445 TALLOC_FREE(state->fde); 582 446 } 583 447 … … 596 460 nread = recv(state->fd, state->buf+state->nread, total-state->nread, 597 461 0); 462 if ((nread == -1) && (errno == ENOTSOCK)) { 463 nread = read(state->fd, state->buf+state->nread, 464 total-state->nread); 465 } 598 466 if ((nread == -1) && (errno == EINTR)) { 599 467 /* retry */ … … 655 523 656 524 if (tevent_req_is_unix_error(req, perrno)) { 525 tevent_req_received(req); 657 526 return -1; 658 527 } 659 528 *pbuf = talloc_move(mem_ctx, &state->buf); 529 tevent_req_received(req); 660 530 return talloc_get_size(*pbuf); 661 531 } 532 533 struct wait_for_read_state { 534 struct tevent_fd *fde; 535 int fd; 536 bool check_errors; 537 }; 538 539 static void wait_for_read_cleanup(struct tevent_req *req, 540 enum tevent_req_state req_state); 541 static void wait_for_read_done(struct tevent_context *ev, 542 struct tevent_fd *fde, 543 uint16_t flags, 544 void *private_data); 545 546 struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx, 547 struct tevent_context *ev, int fd, 548 bool check_errors) 549 { 550 struct tevent_req *req; 551 struct wait_for_read_state *state; 552 553 req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state); 554 if (req == NULL) { 555 return NULL; 556 } 557 558 tevent_req_set_cleanup_fn(req, wait_for_read_cleanup); 559 560 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, 561 wait_for_read_done, req); 562 if (tevent_req_nomem(state->fde, req)) { 563 return tevent_req_post(req, ev); 564 } 565 566 state->fd = fd; 567 state->check_errors = check_errors; 568 return req; 569 } 570 571 static void wait_for_read_cleanup(struct tevent_req *req, 572 enum tevent_req_state req_state) 573 { 574 struct wait_for_read_state *state = 575 tevent_req_data(req, struct wait_for_read_state); 576 577 TALLOC_FREE(state->fde); 578 } 579 580 static void wait_for_read_done(struct tevent_context *ev, 581 struct tevent_fd *fde, 582 uint16_t flags, 583 void *private_data) 584 { 585 struct tevent_req *req = talloc_get_type_abort( 586 private_data, struct tevent_req); 587 struct wait_for_read_state *state = 588 tevent_req_data(req, struct wait_for_read_state); 589 ssize_t nread; 590 char c; 591 592 if ((flags & TEVENT_FD_READ) == 0) { 593 return; 594 } 595 596 if (!state->check_errors) { 597 tevent_req_done(req); 598 return; 599 } 600 601 nread = recv(state->fd, &c, 1, MSG_PEEK); 602 603 if (nread == 0) { 604 tevent_req_error(req, EPIPE); 605 return; 606 } 607 608 if ((nread == -1) && (errno == EINTR)) { 609 /* come back later */ 610 return; 611 } 612 613 if ((nread == -1) && (errno == ENOTSOCK)) { 614 /* Ignore this specific error on pipes */ 615 tevent_req_done(req); 616 return; 617 } 618 619 if (nread == -1) { 620 tevent_req_error(req, errno); 621 return; 622 } 623 624 tevent_req_done(req); 625 } 626 627 bool wait_for_read_recv(struct tevent_req *req, int *perr) 628 { 629 int err = tevent_req_simple_recv_unix(req); 630 631 if (err != 0) { 632 *perr = err; 633 return false; 634 } 635 636 return true; 637 } -
vendor/current/lib/async_req/async_sock.h
r740 r988 27 27 #include <talloc.h> 28 28 #include <tevent.h> 29 #include "system/network.h" 29 30 30 struct tevent_req *sendto_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, 31 int fd, const void *buf, size_t len, int flags, 32 const struct sockaddr_storage *addr); 33 ssize_t sendto_recv(struct tevent_req *req, int *perrno); 34 35 struct tevent_req *recvfrom_send(TALLOC_CTX *mem_ctx, 36 struct tevent_context *ev, 37 int fd, void *buf, size_t len, int flags, 38 struct sockaddr_storage *addr, 39 socklen_t *addr_len); 40 ssize_t recvfrom_recv(struct tevent_req *req, int *perrno); 41 42 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx, 43 struct tevent_context *ev, 44 int fd, const struct sockaddr *address, 45 socklen_t address_len); 31 struct tevent_req *async_connect_send( 32 TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd, 33 const struct sockaddr *address, socklen_t address_len, 34 void (*before_connect)(void *private_data), 35 void (*after_connect)(void *private_data), 36 void *private_data); 46 37 int async_connect_recv(struct tevent_req *req, int *perrno); 47 38 … … 62 53 uint8_t **pbuf, int *perrno); 63 54 55 struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx, 56 struct tevent_context *ev, int fd, 57 bool check_errors); 58 bool wait_for_read_recv(struct tevent_req *req, int *perr); 59 64 60 #endif -
vendor/current/lib/async_req/wscript_build
r740 r988 4 4 bld.SAMBA_SUBSYSTEM('LIBASYNC_REQ', 5 5 source='async_sock.c', 6 public_deps='talloc tevent ',7 deps=' UTIL_TEVENT'6 public_deps='talloc tevent iov_buf', 7 deps='tevent-util socket-blocking' 8 8 ) 9 9 10 bld.SAMBA_BINARY('async_connect_send_test', 11 source='async_connect_send_test.c', 12 deps='LIBASYNC_REQ', 13 install=False 14 )
Note:
See TracChangeset
for help on using the changeset viewer.