1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22 #include "uv.h"
23 #include "uv-common.h"
24
25 #include <assert.h>
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <stddef.h> /* NULL */
29 #include <stdio.h>
30 #include <stdlib.h> /* malloc */
31 #include <string.h> /* memset */
32
33 #if defined(_WIN32)
34 # include <malloc.h> /* malloc */
35 #else
36 # include <net/if.h> /* if_nametoindex */
37 # include <sys/un.h> /* AF_UNIX, sockaddr_un */
38 #endif
39
40
41 typedef struct {
42 uv_malloc_func local_malloc;
43 uv_realloc_func local_realloc;
44 uv_calloc_func local_calloc;
45 uv_free_func local_free;
46 } uv__allocator_t;
47
48 static uv__allocator_t uv__allocator = {
49 malloc,
50 realloc,
51 calloc,
52 free,
53 };
54
uv__strdup(const char * s)55 char* uv__strdup(const char* s) {
56 size_t len = strlen(s) + 1;
57 char* m = uv__malloc(len);
58 if (m == NULL)
59 return NULL;
60 return memcpy(m, s, len);
61 }
62
uv__strndup(const char * s,size_t n)63 char* uv__strndup(const char* s, size_t n) {
64 char* m;
65 size_t len = strlen(s);
66 if (n < len)
67 len = n;
68 m = uv__malloc(len + 1);
69 if (m == NULL)
70 return NULL;
71 m[len] = '\0';
72 return memcpy(m, s, len);
73 }
74
uv__malloc(size_t size)75 void* uv__malloc(size_t size) {
76 if (size > 0)
77 return uv__allocator.local_malloc(size);
78 return NULL;
79 }
80
uv__free(void * ptr)81 void uv__free(void* ptr) {
82 int saved_errno;
83
84 /* Libuv expects that free() does not clobber errno. The system allocator
85 * honors that assumption but custom allocators may not be so careful.
86 */
87 saved_errno = errno;
88 uv__allocator.local_free(ptr);
89 errno = saved_errno;
90 }
91
uv__calloc(size_t count,size_t size)92 void* uv__calloc(size_t count, size_t size) {
93 return uv__allocator.local_calloc(count, size);
94 }
95
uv__realloc(void * ptr,size_t size)96 void* uv__realloc(void* ptr, size_t size) {
97 if (size > 0)
98 return uv__allocator.local_realloc(ptr, size);
99 uv__free(ptr);
100 return NULL;
101 }
102
uv_replace_allocator(uv_malloc_func malloc_func,uv_realloc_func realloc_func,uv_calloc_func calloc_func,uv_free_func free_func)103 int uv_replace_allocator(uv_malloc_func malloc_func,
104 uv_realloc_func realloc_func,
105 uv_calloc_func calloc_func,
106 uv_free_func free_func) {
107 if (malloc_func == NULL || realloc_func == NULL ||
108 calloc_func == NULL || free_func == NULL) {
109 return UV_EINVAL;
110 }
111
112 uv__allocator.local_malloc = malloc_func;
113 uv__allocator.local_realloc = realloc_func;
114 uv__allocator.local_calloc = calloc_func;
115 uv__allocator.local_free = free_func;
116
117 return 0;
118 }
119
120 #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
121
uv_handle_size(uv_handle_type type)122 size_t uv_handle_size(uv_handle_type type) {
123 switch (type) {
124 UV_HANDLE_TYPE_MAP(XX)
125 default:
126 return -1;
127 }
128 }
129
uv_req_size(uv_req_type type)130 size_t uv_req_size(uv_req_type type) {
131 switch(type) {
132 UV_REQ_TYPE_MAP(XX)
133 default:
134 return -1;
135 }
136 }
137
138 #undef XX
139
140
uv_loop_size(void)141 size_t uv_loop_size(void) {
142 return sizeof(uv_loop_t);
143 }
144
145
uv_buf_init(char * base,unsigned int len)146 uv_buf_t uv_buf_init(char* base, unsigned int len) {
147 uv_buf_t buf;
148 buf.base = base;
149 buf.len = len;
150 return buf;
151 }
152
153
uv__unknown_err_code(int err)154 static const char* uv__unknown_err_code(int err) {
155 char buf[32];
156 char* copy;
157
158 snprintf(buf, sizeof(buf), "Unknown system error %d", err);
159 copy = uv__strdup(buf);
160
161 return copy != NULL ? copy : "Unknown system error";
162 }
163
164 #define UV_ERR_NAME_GEN_R(name, _) \
165 case UV_## name: \
166 uv__strscpy(buf, #name, buflen); break;
uv_err_name_r(int err,char * buf,size_t buflen)167 char* uv_err_name_r(int err, char* buf, size_t buflen) {
168 switch (err) {
169 UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
170 default: snprintf(buf, buflen, "Unknown system error %d", err);
171 }
172 return buf;
173 }
174 #undef UV_ERR_NAME_GEN_R
175
176
177 #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
uv_err_name(int err)178 const char* uv_err_name(int err) {
179 switch (err) {
180 UV_ERRNO_MAP(UV_ERR_NAME_GEN)
181 }
182 return uv__unknown_err_code(err);
183 }
184 #undef UV_ERR_NAME_GEN
185
186
187 #define UV_STRERROR_GEN_R(name, msg) \
188 case UV_ ## name: \
189 snprintf(buf, buflen, "%s", msg); break;
uv_strerror_r(int err,char * buf,size_t buflen)190 char* uv_strerror_r(int err, char* buf, size_t buflen) {
191 switch (err) {
192 UV_ERRNO_MAP(UV_STRERROR_GEN_R)
193 default: snprintf(buf, buflen, "Unknown system error %d", err);
194 }
195 return buf;
196 }
197 #undef UV_STRERROR_GEN_R
198
199
200 #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
uv_strerror(int err)201 const char* uv_strerror(int err) {
202 switch (err) {
203 UV_ERRNO_MAP(UV_STRERROR_GEN)
204 }
205 return uv__unknown_err_code(err);
206 }
207 #undef UV_STRERROR_GEN
208
209
uv_ip4_addr(const char * ip,int port,struct sockaddr_in * addr)210 int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
211 memset(addr, 0, sizeof(*addr));
212 addr->sin_family = AF_INET;
213 addr->sin_port = htons(port);
214 #ifdef SIN6_LEN
215 addr->sin_len = sizeof(*addr);
216 #endif
217 return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
218 }
219
220
uv_ip6_addr(const char * ip,int port,struct sockaddr_in6 * addr)221 int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
222 char address_part[40];
223 size_t address_part_size;
224 const char* zone_index;
225
226 memset(addr, 0, sizeof(*addr));
227 addr->sin6_family = AF_INET6;
228 addr->sin6_port = htons(port);
229 #ifdef SIN6_LEN
230 addr->sin6_len = sizeof(*addr);
231 #endif
232
233 zone_index = strchr(ip, '%');
234 if (zone_index != NULL) {
235 address_part_size = zone_index - ip;
236 if (address_part_size >= sizeof(address_part))
237 address_part_size = sizeof(address_part) - 1;
238
239 memcpy(address_part, ip, address_part_size);
240 address_part[address_part_size] = '\0';
241 ip = address_part;
242
243 zone_index++; /* skip '%' */
244 /* NOTE: unknown interface (id=0) is silently ignored */
245 #ifdef _WIN32
246 addr->sin6_scope_id = atoi(zone_index);
247 #else
248 addr->sin6_scope_id = if_nametoindex(zone_index);
249 #endif
250 }
251
252 return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
253 }
254
255
uv_ip4_name(const struct sockaddr_in * src,char * dst,size_t size)256 int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
257 return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
258 }
259
260
uv_ip6_name(const struct sockaddr_in6 * src,char * dst,size_t size)261 int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
262 return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
263 }
264
265
uv_tcp_bind(uv_tcp_t * handle,const struct sockaddr * addr,unsigned int flags)266 int uv_tcp_bind(uv_tcp_t* handle,
267 const struct sockaddr* addr,
268 unsigned int flags) {
269 unsigned int addrlen;
270
271 if (handle->type != UV_TCP)
272 return UV_EINVAL;
273
274 if (addr->sa_family == AF_INET)
275 addrlen = sizeof(struct sockaddr_in);
276 else if (addr->sa_family == AF_INET6)
277 addrlen = sizeof(struct sockaddr_in6);
278 else
279 return UV_EINVAL;
280
281 return uv__tcp_bind(handle, addr, addrlen, flags);
282 }
283
284
uv_udp_bind(uv_udp_t * handle,const struct sockaddr * addr,unsigned int flags)285 int uv_udp_bind(uv_udp_t* handle,
286 const struct sockaddr* addr,
287 unsigned int flags) {
288 unsigned int addrlen;
289
290 if (handle->type != UV_UDP)
291 return UV_EINVAL;
292
293 if (addr->sa_family == AF_INET)
294 addrlen = sizeof(struct sockaddr_in);
295 else if (addr->sa_family == AF_INET6)
296 addrlen = sizeof(struct sockaddr_in6);
297 else
298 return UV_EINVAL;
299
300 return uv__udp_bind(handle, addr, addrlen, flags);
301 }
302
303
uv_tcp_connect(uv_connect_t * req,uv_tcp_t * handle,const struct sockaddr * addr,uv_connect_cb cb)304 int uv_tcp_connect(uv_connect_t* req,
305 uv_tcp_t* handle,
306 const struct sockaddr* addr,
307 uv_connect_cb cb) {
308 unsigned int addrlen;
309
310 if (handle->type != UV_TCP)
311 return UV_EINVAL;
312
313 if (addr->sa_family == AF_INET)
314 addrlen = sizeof(struct sockaddr_in);
315 else if (addr->sa_family == AF_INET6)
316 addrlen = sizeof(struct sockaddr_in6);
317 else
318 return UV_EINVAL;
319
320 return uv__tcp_connect(req, handle, addr, addrlen, cb);
321 }
322
323
uv_udp_connect(uv_udp_t * handle,const struct sockaddr * addr)324 int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {
325 unsigned int addrlen;
326
327 if (handle->type != UV_UDP)
328 return UV_EINVAL;
329
330 /* Disconnect the handle */
331 if (addr == NULL) {
332 if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))
333 return UV_ENOTCONN;
334
335 return uv__udp_disconnect(handle);
336 }
337
338 if (addr->sa_family == AF_INET)
339 addrlen = sizeof(struct sockaddr_in);
340 else if (addr->sa_family == AF_INET6)
341 addrlen = sizeof(struct sockaddr_in6);
342 else
343 return UV_EINVAL;
344
345 if (handle->flags & UV_HANDLE_UDP_CONNECTED)
346 return UV_EISCONN;
347
348 return uv__udp_connect(handle, addr, addrlen);
349 }
350
351
uv__udp_is_connected(uv_udp_t * handle)352 int uv__udp_is_connected(uv_udp_t* handle) {
353 struct sockaddr_storage addr;
354 int addrlen;
355 if (handle->type != UV_UDP)
356 return 0;
357
358 addrlen = sizeof(addr);
359 if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)
360 return 0;
361
362 return addrlen > 0;
363 }
364
365
uv__udp_check_before_send(uv_udp_t * handle,const struct sockaddr * addr)366 int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {
367 unsigned int addrlen;
368
369 if (handle->type != UV_UDP)
370 return UV_EINVAL;
371
372 if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))
373 return UV_EISCONN;
374
375 if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))
376 return UV_EDESTADDRREQ;
377
378 if (addr != NULL) {
379 if (addr->sa_family == AF_INET)
380 addrlen = sizeof(struct sockaddr_in);
381 else if (addr->sa_family == AF_INET6)
382 addrlen = sizeof(struct sockaddr_in6);
383 #if defined(AF_UNIX) && !defined(_WIN32)
384 else if (addr->sa_family == AF_UNIX)
385 addrlen = sizeof(struct sockaddr_un);
386 #endif
387 else
388 return UV_EINVAL;
389 } else {
390 addrlen = 0;
391 }
392
393 return addrlen;
394 }
395
396
uv_udp_send(uv_udp_send_t * req,uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,uv_udp_send_cb send_cb)397 int uv_udp_send(uv_udp_send_t* req,
398 uv_udp_t* handle,
399 const uv_buf_t bufs[],
400 unsigned int nbufs,
401 const struct sockaddr* addr,
402 uv_udp_send_cb send_cb) {
403 int addrlen;
404
405 addrlen = uv__udp_check_before_send(handle, addr);
406 if (addrlen < 0)
407 return addrlen;
408
409 return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
410 }
411
412
uv_udp_try_send(uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr)413 int uv_udp_try_send(uv_udp_t* handle,
414 const uv_buf_t bufs[],
415 unsigned int nbufs,
416 const struct sockaddr* addr) {
417 int addrlen;
418
419 addrlen = uv__udp_check_before_send(handle, addr);
420 if (addrlen < 0)
421 return addrlen;
422
423 return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
424 }
425
426
uv_udp_recv_start(uv_udp_t * handle,uv_alloc_cb alloc_cb,uv_udp_recv_cb recv_cb)427 int uv_udp_recv_start(uv_udp_t* handle,
428 uv_alloc_cb alloc_cb,
429 uv_udp_recv_cb recv_cb) {
430 if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
431 return UV_EINVAL;
432 else
433 return uv__udp_recv_start(handle, alloc_cb, recv_cb);
434 }
435
436
uv_udp_recv_stop(uv_udp_t * handle)437 int uv_udp_recv_stop(uv_udp_t* handle) {
438 if (handle->type != UV_UDP)
439 return UV_EINVAL;
440 else
441 return uv__udp_recv_stop(handle);
442 }
443
444
uv_walk(uv_loop_t * loop,uv_walk_cb walk_cb,void * arg)445 void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
446 QUEUE queue;
447 QUEUE* q;
448 uv_handle_t* h;
449
450 QUEUE_MOVE(&loop->handle_queue, &queue);
451 while (!QUEUE_EMPTY(&queue)) {
452 q = QUEUE_HEAD(&queue);
453 h = QUEUE_DATA(q, uv_handle_t, handle_queue);
454
455 QUEUE_REMOVE(q);
456 QUEUE_INSERT_TAIL(&loop->handle_queue, q);
457
458 if (h->flags & UV_HANDLE_INTERNAL) continue;
459 walk_cb(h, arg);
460 }
461 }
462
463
uv__print_handles(uv_loop_t * loop,int only_active,FILE * stream)464 static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
465 const char* type;
466 QUEUE* q;
467 uv_handle_t* h;
468
469 if (loop == NULL)
470 loop = uv_default_loop();
471
472 QUEUE_FOREACH(q, &loop->handle_queue) {
473 h = QUEUE_DATA(q, uv_handle_t, handle_queue);
474
475 if (only_active && !uv__is_active(h))
476 continue;
477
478 switch (h->type) {
479 #define X(uc, lc) case UV_##uc: type = #lc; break;
480 UV_HANDLE_TYPE_MAP(X)
481 #undef X
482 default: type = "<unknown>";
483 }
484
485 fprintf(stream,
486 "[%c%c%c] %-8s %p\n",
487 "R-"[!(h->flags & UV_HANDLE_REF)],
488 "A-"[!(h->flags & UV_HANDLE_ACTIVE)],
489 "I-"[!(h->flags & UV_HANDLE_INTERNAL)],
490 type,
491 (void*)h);
492 }
493 }
494
495
uv_print_all_handles(uv_loop_t * loop,FILE * stream)496 void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
497 uv__print_handles(loop, 0, stream);
498 }
499
500
uv_print_active_handles(uv_loop_t * loop,FILE * stream)501 void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
502 uv__print_handles(loop, 1, stream);
503 }
504
505
uv_ref(uv_handle_t * handle)506 void uv_ref(uv_handle_t* handle) {
507 uv__handle_ref(handle);
508 }
509
510
uv_unref(uv_handle_t * handle)511 void uv_unref(uv_handle_t* handle) {
512 uv__handle_unref(handle);
513 }
514
515
uv_has_ref(const uv_handle_t * handle)516 int uv_has_ref(const uv_handle_t* handle) {
517 return uv__has_ref(handle);
518 }
519
520
uv_stop(uv_loop_t * loop)521 void uv_stop(uv_loop_t* loop) {
522 loop->stop_flag = 1;
523 }
524
525
uv_now(const uv_loop_t * loop)526 uint64_t uv_now(const uv_loop_t* loop) {
527 return loop->time;
528 }
529
530
531
uv__count_bufs(const uv_buf_t bufs[],unsigned int nbufs)532 size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
533 unsigned int i;
534 size_t bytes;
535
536 bytes = 0;
537 for (i = 0; i < nbufs; i++)
538 bytes += (size_t) bufs[i].len;
539
540 return bytes;
541 }
542
uv_recv_buffer_size(uv_handle_t * handle,int * value)543 int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
544 return uv__socket_sockopt(handle, SO_RCVBUF, value);
545 }
546
uv_send_buffer_size(uv_handle_t * handle,int * value)547 int uv_send_buffer_size(uv_handle_t* handle, int *value) {
548 return uv__socket_sockopt(handle, SO_SNDBUF, value);
549 }
550
uv_fs_event_getpath(uv_fs_event_t * handle,char * buffer,size_t * size)551 int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
552 size_t required_len;
553
554 if (!uv__is_active(handle)) {
555 *size = 0;
556 return UV_EINVAL;
557 }
558
559 required_len = strlen(handle->path);
560 if (required_len >= *size) {
561 *size = required_len + 1;
562 return UV_ENOBUFS;
563 }
564
565 memcpy(buffer, handle->path, required_len);
566 *size = required_len;
567 buffer[required_len] = '\0';
568
569 return 0;
570 }
571
572 /* The windows implementation does not have the same structure layout as
573 * the unix implementation (nbufs is not directly inside req but is
574 * contained in a nested union/struct) so this function locates it.
575 */
uv__get_nbufs(uv_fs_t * req)576 static unsigned int* uv__get_nbufs(uv_fs_t* req) {
577 #ifdef _WIN32
578 return &req->fs.info.nbufs;
579 #else
580 return &req->nbufs;
581 #endif
582 }
583
584 /* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
585 * systems. So, the memory should be released using free(). On Windows,
586 * uv__malloc() is used, so use uv__free() to free memory.
587 */
588 #ifdef _WIN32
589 # define uv__fs_scandir_free uv__free
590 #else
591 # define uv__fs_scandir_free free
592 #endif
593
uv__fs_scandir_cleanup(uv_fs_t * req)594 void uv__fs_scandir_cleanup(uv_fs_t* req) {
595 uv__dirent_t** dents;
596
597 unsigned int* nbufs = uv__get_nbufs(req);
598
599 dents = req->ptr;
600 if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
601 (*nbufs)--;
602 for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
603 uv__fs_scandir_free(dents[*nbufs]);
604
605 uv__fs_scandir_free(req->ptr);
606 req->ptr = NULL;
607 }
608
609
uv_fs_scandir_next(uv_fs_t * req,uv_dirent_t * ent)610 int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
611 uv__dirent_t** dents;
612 uv__dirent_t* dent;
613 unsigned int* nbufs;
614
615 /* Check to see if req passed */
616 if (req->result < 0)
617 return req->result;
618
619 /* Ptr will be null if req was canceled or no files found */
620 if (!req->ptr)
621 return UV_EOF;
622
623 nbufs = uv__get_nbufs(req);
624 assert(nbufs);
625
626 dents = req->ptr;
627
628 /* Free previous entity */
629 if (*nbufs > 0)
630 uv__fs_scandir_free(dents[*nbufs - 1]);
631
632 /* End was already reached */
633 if (*nbufs == (unsigned int) req->result) {
634 uv__fs_scandir_free(dents);
635 req->ptr = NULL;
636 return UV_EOF;
637 }
638
639 dent = dents[(*nbufs)++];
640
641 ent->name = dent->d_name;
642 ent->type = uv__fs_get_dirent_type(dent);
643
644 return 0;
645 }
646
uv__fs_get_dirent_type(uv__dirent_t * dent)647 uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {
648 uv_dirent_type_t type;
649
650 #ifdef HAVE_DIRENT_TYPES
651 switch (dent->d_type) {
652 case UV__DT_DIR:
653 type = UV_DIRENT_DIR;
654 break;
655 case UV__DT_FILE:
656 type = UV_DIRENT_FILE;
657 break;
658 case UV__DT_LINK:
659 type = UV_DIRENT_LINK;
660 break;
661 case UV__DT_FIFO:
662 type = UV_DIRENT_FIFO;
663 break;
664 case UV__DT_SOCKET:
665 type = UV_DIRENT_SOCKET;
666 break;
667 case UV__DT_CHAR:
668 type = UV_DIRENT_CHAR;
669 break;
670 case UV__DT_BLOCK:
671 type = UV_DIRENT_BLOCK;
672 break;
673 default:
674 type = UV_DIRENT_UNKNOWN;
675 }
676 #else
677 type = UV_DIRENT_UNKNOWN;
678 #endif
679
680 return type;
681 }
682
uv__fs_readdir_cleanup(uv_fs_t * req)683 void uv__fs_readdir_cleanup(uv_fs_t* req) {
684 uv_dir_t* dir;
685 uv_dirent_t* dirents;
686 int i;
687
688 if (req->ptr == NULL)
689 return;
690
691 dir = req->ptr;
692 dirents = dir->dirents;
693 req->ptr = NULL;
694
695 if (dirents == NULL)
696 return;
697
698 for (i = 0; i < req->result; ++i) {
699 uv__free((char*) dirents[i].name);
700 dirents[i].name = NULL;
701 }
702 }
703
704
uv_loop_configure(uv_loop_t * loop,uv_loop_option option,...)705 int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
706 va_list ap;
707 int err;
708
709 va_start(ap, option);
710 /* Any platform-agnostic options should be handled here. */
711 err = uv__loop_configure(loop, option, ap);
712 va_end(ap);
713
714 return err;
715 }
716
717
718 static uv_loop_t default_loop_struct;
719 static uv_loop_t* default_loop_ptr;
720
721
uv_default_loop(void)722 uv_loop_t* uv_default_loop(void) {
723 if (default_loop_ptr != NULL)
724 return default_loop_ptr;
725
726 if (uv_loop_init(&default_loop_struct))
727 return NULL;
728
729 default_loop_ptr = &default_loop_struct;
730 return default_loop_ptr;
731 }
732
733
uv_loop_new(void)734 uv_loop_t* uv_loop_new(void) {
735 uv_loop_t* loop;
736
737 loop = uv__malloc(sizeof(*loop));
738 if (loop == NULL)
739 return NULL;
740
741 if (uv_loop_init(loop)) {
742 uv__free(loop);
743 return NULL;
744 }
745
746 return loop;
747 }
748
749
uv_loop_close(uv_loop_t * loop)750 int uv_loop_close(uv_loop_t* loop) {
751 QUEUE* q;
752 uv_handle_t* h;
753 #ifndef NDEBUG
754 void* saved_data;
755 #endif
756
757 if (uv__has_active_reqs(loop))
758 return UV_EBUSY;
759
760 QUEUE_FOREACH(q, &loop->handle_queue) {
761 h = QUEUE_DATA(q, uv_handle_t, handle_queue);
762 if (!(h->flags & UV_HANDLE_INTERNAL))
763 return UV_EBUSY;
764 }
765
766 uv__loop_close(loop);
767
768 #ifndef NDEBUG
769 saved_data = loop->data;
770 memset(loop, -1, sizeof(*loop));
771 loop->data = saved_data;
772 #endif
773 if (loop == default_loop_ptr)
774 default_loop_ptr = NULL;
775
776 return 0;
777 }
778
779
uv_loop_delete(uv_loop_t * loop)780 void uv_loop_delete(uv_loop_t* loop) {
781 uv_loop_t* default_loop;
782 int err;
783
784 default_loop = default_loop_ptr;
785
786 err = uv_loop_close(loop);
787 (void) err; /* Squelch compiler warnings. */
788 assert(err == 0);
789 if (loop != default_loop)
790 uv__free(loop);
791 }
792
793
uv_os_free_environ(uv_env_item_t * envitems,int count)794 void uv_os_free_environ(uv_env_item_t* envitems, int count) {
795 int i;
796
797 for (i = 0; i < count; i++) {
798 uv__free(envitems[i].name);
799 }
800
801 uv__free(envitems);
802 }
803
804
uv_free_cpu_info(uv_cpu_info_t * cpu_infos,int count)805 void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
806 int i;
807
808 for (i = 0; i < count; i++)
809 uv__free(cpu_infos[i].model);
810
811 uv__free(cpu_infos);
812 }
813