Remove a few #ifdef EWOULDBLOCk
[samba.git] / source3 / lib / unix_msg / unix_msg.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Copyright (C) Volker Lendecke 2013
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "replace.h"
20 #include "unix_msg.h"
21 #include "system/select.h"
22 #include "system/time.h"
23 #include "system/network.h"
24 #include "dlinklist.h"
25 #include "pthreadpool/pthreadpool.h"
26 #include <fcntl.h>
27
28 /*
29  * This file implements two abstractions: The "unix_dgram" functions implement
30  * queueing for unix domain datagram sockets. You can send to a destination
31  * socket, and if that has no free space available, it will fall back to an
32  * anonymous socket that will poll for writability. "unix_dgram" expects the
33  * data size not to exceed the system limit.
34  *
35  * The "unix_msg" functions implement the fragmentation of large messages on
36  * top of "unix_dgram". This is what is exposed to the user of this API.
37  */
38
39 struct unix_dgram_msg {
40         struct unix_dgram_msg *prev, *next;
41
42         int sock;
43         ssize_t sent;
44         int sys_errno;
45         size_t buflen;
46         uint8_t buf[];
47 };
48
49 struct unix_dgram_send_queue {
50         struct unix_dgram_send_queue *prev, *next;
51         struct unix_dgram_ctx *ctx;
52         int sock;
53         struct unix_dgram_msg *msgs;
54         char path[];
55 };
56
57 struct unix_dgram_ctx {
58         int sock;
59         pid_t created_pid;
60         const struct poll_funcs *ev_funcs;
61         size_t max_msg;
62
63         void (*recv_callback)(struct unix_dgram_ctx *ctx,
64                               uint8_t *msg, size_t msg_len,
65                               void *private_data);
66         void *private_data;
67
68         struct poll_watch *sock_read_watch;
69         struct unix_dgram_send_queue *send_queues;
70
71         struct pthreadpool *send_pool;
72         struct poll_watch *pool_read_watch;
73
74         uint8_t *recv_buf;
75         char path[];
76 };
77
78 static ssize_t iov_buflen(const struct iovec *iov, int iovlen);
79 static void unix_dgram_recv_handler(struct poll_watch *w, int fd, short events,
80                                     void *private_data);
81
82 /* Set socket non blocking. */
83 static int prepare_socket_nonblock(int sock)
84 {
85         int flags;
86 #ifdef O_NONBLOCK
87 #define FLAG_TO_SET O_NONBLOCK
88 #else
89 #ifdef SYSV
90 #define FLAG_TO_SET O_NDELAY
91 #else /* BSD */
92 #define FLAG_TO_SET FNDELAY
93 #endif
94 #endif
95
96         flags = fcntl(sock, F_GETFL);
97         if (flags == -1) {
98                 return errno;
99         }
100         flags |= FLAG_TO_SET;
101         if (fcntl(sock, F_SETFL, flags) == -1) {
102                 return errno;
103         }
104
105 #undef FLAG_TO_SET
106         return 0;
107 }
108
109 /* Set socket close on exec. */
110 static int prepare_socket_cloexec(int sock)
111 {
112 #ifdef FD_CLOEXEC
113         int flags;
114
115         flags = fcntl(sock, F_GETFD, 0);
116         if (flags == -1) {
117                 return errno;
118         }
119         flags |= FD_CLOEXEC;
120         if (fcntl(sock, F_SETFD, flags) == -1) {
121                 return errno;
122         }
123 #endif
124         return 0;
125 }
126
127 /* Set socket non blocking and close on exec. */
128 static int prepare_socket(int sock)
129 {
130         int ret = prepare_socket_nonblock(sock);
131
132         if (ret) {
133                 return ret;
134         }
135         return prepare_socket_cloexec(sock);
136 }
137
138 static int unix_dgram_init(const struct sockaddr_un *addr, size_t max_msg,
139                            const struct poll_funcs *ev_funcs,
140                            void (*recv_callback)(struct unix_dgram_ctx *ctx,
141                                                  uint8_t *msg, size_t msg_len,
142                                                  void *private_data),
143                            void *private_data,
144                            struct unix_dgram_ctx **result)
145 {
146         struct unix_dgram_ctx *ctx;
147         size_t pathlen;
148         int ret;
149
150         if (addr != NULL) {
151                 pathlen = strlen(addr->sun_path)+1;
152         } else {
153                 pathlen = 1;
154         }
155
156         ctx = malloc(offsetof(struct unix_dgram_ctx, path) + pathlen);
157         if (ctx == NULL) {
158                 return ENOMEM;
159         }
160         if (addr != NULL) {
161                 memcpy(ctx->path, addr->sun_path, pathlen);
162         } else {
163                 ctx->path[0] = '\0';
164         }
165
166         *ctx = (struct unix_dgram_ctx) {
167                 .max_msg = max_msg,
168                 .ev_funcs = ev_funcs,
169                 .recv_callback = recv_callback,
170                 .private_data = private_data,
171                 .created_pid = (pid_t)-1
172         };
173
174         ctx->recv_buf = malloc(max_msg);
175         if (ctx->recv_buf == NULL) {
176                 free(ctx);
177                 return ENOMEM;
178         }
179
180         ctx->sock = socket(AF_UNIX, SOCK_DGRAM, 0);
181         if (ctx->sock == -1) {
182                 ret = errno;
183                 goto fail_free;
184         }
185
186         /* Set non-blocking and close-on-exec. */
187         ret = prepare_socket(ctx->sock);
188         if (ret != 0) {
189                 goto fail_close;
190         }
191
192         if (addr != NULL) {
193                 ret = bind(ctx->sock,
194                            (const struct sockaddr *)(const void *)addr,
195                            sizeof(*addr));
196                 if (ret == -1) {
197                         ret = errno;
198                         goto fail_close;
199                 }
200
201                 ctx->created_pid = getpid();
202
203                 ctx->sock_read_watch = ctx->ev_funcs->watch_new(
204                         ctx->ev_funcs, ctx->sock, POLLIN,
205                         unix_dgram_recv_handler, ctx);
206
207                 if (ctx->sock_read_watch == NULL) {
208                         ret = ENOMEM;
209                         goto fail_close;
210                 }
211         }
212
213         *result = ctx;
214         return 0;
215
216 fail_close:
217         close(ctx->sock);
218 fail_free:
219         free(ctx->recv_buf);
220         free(ctx);
221         return ret;
222 }
223
224 static void unix_dgram_recv_handler(struct poll_watch *w, int fd, short events,
225                                     void *private_data)
226 {
227         struct unix_dgram_ctx *ctx = (struct unix_dgram_ctx *)private_data;
228         ssize_t received;
229         struct msghdr msg;
230         struct iovec iov;
231
232         iov = (struct iovec) {
233                 .iov_base = (void *)ctx->recv_buf,
234                 .iov_len = ctx->max_msg,
235         };
236
237         msg = (struct msghdr) {
238                 .msg_iov = &iov,
239                 .msg_iovlen = 1,
240 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
241                 .msg_control = NULL,
242                 .msg_controllen = 0,
243 #endif
244         };
245
246         received = recvmsg(fd, &msg, 0);
247         if (received == -1) {
248                 if ((errno == EAGAIN) ||
249                     (errno == EWOULDBLOCK) ||
250                     (errno == EINTR) || (errno == ENOMEM)) {
251                         /* Not really an error - just try again. */
252                         return;
253                 }
254                 /* Problem with the socket. Set it unreadable. */
255                 ctx->ev_funcs->watch_update(w, 0);
256                 return;
257         }
258         if (received > ctx->max_msg) {
259                 /* More than we expected, not for us */
260                 return;
261         }
262         ctx->recv_callback(ctx, ctx->recv_buf, received, ctx->private_data);
263 }
264
265 static void unix_dgram_job_finished(struct poll_watch *w, int fd, short events,
266                                     void *private_data);
267
268 static int unix_dgram_init_pthreadpool(struct unix_dgram_ctx *ctx)
269 {
270         int ret, signalfd;
271
272         if (ctx->send_pool != NULL) {
273                 return 0;
274         }
275
276         ret = pthreadpool_init(0, &ctx->send_pool);
277         if (ret != 0) {
278                 return ret;
279         }
280
281         signalfd = pthreadpool_signal_fd(ctx->send_pool);
282
283         ctx->pool_read_watch = ctx->ev_funcs->watch_new(
284                 ctx->ev_funcs, signalfd, POLLIN,
285                 unix_dgram_job_finished, ctx);
286         if (ctx->pool_read_watch == NULL) {
287                 pthreadpool_destroy(ctx->send_pool);
288                 ctx->send_pool = NULL;
289                 return ENOMEM;
290         }
291
292         return 0;
293 }
294
295 static int unix_dgram_send_queue_init(
296         struct unix_dgram_ctx *ctx, const struct sockaddr_un *dst,
297         struct unix_dgram_send_queue **result)
298 {
299         struct unix_dgram_send_queue *q;
300         size_t pathlen;
301         int ret, err;
302
303         pathlen = strlen(dst->sun_path)+1;
304
305         q = malloc(offsetof(struct unix_dgram_send_queue, path) + pathlen);
306         if (q == NULL) {
307                 return ENOMEM;
308         }
309         q->ctx = ctx;
310         q->msgs = NULL;
311         memcpy(q->path, dst->sun_path, pathlen);
312
313         q->sock = socket(AF_UNIX, SOCK_DGRAM, 0);
314         if (q->sock == -1) {
315                 err = errno;
316                 goto fail_free;
317         }
318
319         err = prepare_socket_cloexec(q->sock);
320         if (err != 0) {
321                 goto fail_close;
322         }
323
324         do {
325                 ret = connect(q->sock,
326                               (const struct sockaddr *)(const void *)dst,
327                               sizeof(*dst));
328         } while ((ret == -1) && (errno == EINTR));
329
330         if (ret == -1) {
331                 err = errno;
332                 goto fail_close;
333         }
334
335         err = unix_dgram_init_pthreadpool(ctx);
336         if (err != 0) {
337                 goto fail_close;
338         }
339
340         DLIST_ADD(ctx->send_queues, q);
341
342         *result = q;
343         return 0;
344
345 fail_close:
346         close(q->sock);
347 fail_free:
348         free(q);
349         return err;
350 }
351
352 static void unix_dgram_send_queue_free(struct unix_dgram_send_queue *q)
353 {
354         struct unix_dgram_ctx *ctx = q->ctx;
355
356         while (q->msgs != NULL) {
357                 struct unix_dgram_msg *msg;
358                 msg = q->msgs;
359                 DLIST_REMOVE(q->msgs, msg);
360                 free(msg);
361         }
362         close(q->sock);
363         DLIST_REMOVE(ctx->send_queues, q);
364         free(q);
365 }
366
367 static struct unix_dgram_send_queue *find_send_queue(
368         struct unix_dgram_ctx *ctx, const char *dst_sock)
369 {
370         struct unix_dgram_send_queue *s;
371
372         for (s = ctx->send_queues; s != NULL; s = s->next) {
373                 if (strcmp(s->path, dst_sock) == 0) {
374                         return s;
375                 }
376         }
377         return NULL;
378 }
379
380 static int queue_msg(struct unix_dgram_send_queue *q,
381                      const struct iovec *iov, int iovlen)
382 {
383         struct unix_dgram_msg *msg;
384         ssize_t buflen;
385         size_t msglen;
386         int i;
387
388         buflen = iov_buflen(iov, iovlen);
389         if (buflen == -1) {
390                 return EINVAL;
391         }
392
393         msglen = offsetof(struct unix_dgram_msg, buf) + buflen;
394         if ((msglen < buflen) ||
395             (msglen < offsetof(struct unix_dgram_msg, buf))) {
396                 /* overflow */
397                 return EINVAL;
398         }
399
400         msg = malloc(msglen);
401         if (msg == NULL) {
402                 return ENOMEM;
403         }
404         msg->buflen = buflen;
405         msg->sock = q->sock;
406
407         buflen = 0;
408         for (i=0; i<iovlen; i++) {
409                 memcpy(&msg->buf[buflen], iov[i].iov_base, iov[i].iov_len);
410                 buflen += iov[i].iov_len;
411         }
412
413         DLIST_ADD_END(q->msgs, msg, struct unix_dgram_msg);
414         return 0;
415 }
416
417 static void unix_dgram_send_job(void *private_data)
418 {
419         struct unix_dgram_msg *msg = private_data;
420
421         do {
422                 msg->sent = send(msg->sock, msg->buf, msg->buflen, 0);
423         } while ((msg->sent == -1) && (errno == EINTR));
424 }
425
426 static void unix_dgram_job_finished(struct poll_watch *w, int fd, short events,
427                                     void *private_data)
428 {
429         struct unix_dgram_ctx *ctx = private_data;
430         struct unix_dgram_send_queue *q;
431         struct unix_dgram_msg *msg;
432         int ret, job;
433
434         ret = pthreadpool_finished_jobs(ctx->send_pool, &job, 1);
435         if (ret != 1) {
436                 return;
437         }
438
439         for (q = ctx->send_queues; q != NULL; q = q->next) {
440                 if (job == q->sock) {
441                         break;
442                 }
443         }
444
445         if (q == NULL) {
446                 /* Huh? Should not happen */
447                 return;
448         }
449
450         msg = q->msgs;
451         DLIST_REMOVE(q->msgs, msg);
452         free(msg);
453
454         if (q->msgs != NULL) {
455                 ret = pthreadpool_add_job(ctx->send_pool, q->sock,
456                                           unix_dgram_send_job, q->msgs);
457                 if (ret == 0) {
458                         return;
459                 }
460         }
461
462         unix_dgram_send_queue_free(q);
463 }
464
465 static int unix_dgram_send(struct unix_dgram_ctx *ctx,
466                            const struct sockaddr_un *dst,
467                            const struct iovec *iov, int iovlen)
468 {
469         struct unix_dgram_send_queue *q;
470         struct msghdr msg;
471         int ret;
472
473         /*
474          * To preserve message ordering, we have to queue a message when
475          * others are waiting in line already.
476          */
477         q = find_send_queue(ctx, dst->sun_path);
478         if (q != NULL) {
479                 return queue_msg(q, iov, iovlen);
480         }
481
482         /*
483          * Try a cheap nonblocking send
484          */
485
486         msg = (struct msghdr) {
487                 .msg_name = discard_const_p(struct sockaddr_un, dst),
488                 .msg_namelen = sizeof(*dst),
489                 .msg_iov = discard_const_p(struct iovec, iov),
490                 .msg_iovlen = iovlen
491         };
492
493         ret = sendmsg(ctx->sock, &msg, 0);
494         if (ret >= 0) {
495                 return 0;
496         }
497         if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)) {
498                 return errno;
499         }
500
501         ret = unix_dgram_send_queue_init(ctx, dst, &q);
502         if (ret != 0) {
503                 return ret;
504         }
505         ret = queue_msg(q, iov, iovlen);
506         if (ret != 0) {
507                 unix_dgram_send_queue_free(q);
508                 return ret;
509         }
510         ret = pthreadpool_add_job(ctx->send_pool, q->sock,
511                                   unix_dgram_send_job, q->msgs);
512         if (ret != 0) {
513                 unix_dgram_send_queue_free(q);
514                 return ret;
515         }
516         return 0;
517 }
518
519 static int unix_dgram_sock(struct unix_dgram_ctx *ctx)
520 {
521         return ctx->sock;
522 }
523
524 static int unix_dgram_free(struct unix_dgram_ctx *ctx)
525 {
526         if (ctx->send_queues != NULL) {
527                 return EBUSY;
528         }
529
530         if (ctx->send_pool != NULL) {
531                 int ret = pthreadpool_destroy(ctx->send_pool);
532                 if (ret != 0) {
533                         return ret;
534                 }
535                 ctx->ev_funcs->watch_free(ctx->pool_read_watch);
536         }
537
538         ctx->ev_funcs->watch_free(ctx->sock_read_watch);
539
540         if (getpid() == ctx->created_pid) {
541                 /* If we created it, unlink. Otherwise someone else might
542                  * still have it open */
543                 unlink(ctx->path);
544         }
545
546         close(ctx->sock);
547         free(ctx->recv_buf);
548         free(ctx);
549         return 0;
550 }
551
552 /*
553  * Every message starts with a uint64_t cookie.
554  *
555  * A value of 0 indicates a single-fragment message which is complete in
556  * itself. The data immediately follows the cookie.
557  *
558  * Every multi-fragment message has a cookie != 0 and starts with a cookie
559  * followed by a struct unix_msg_header and then the data. The pid and sock
560  * fields are used to assure uniqueness on the receiver side.
561  */
562
563 struct unix_msg_hdr {
564         size_t msglen;
565         pid_t pid;
566         int sock;
567 };
568
569 struct unix_msg {
570         struct unix_msg *prev, *next;
571         size_t msglen;
572         size_t received;
573         pid_t sender_pid;
574         int sender_sock;
575         uint64_t cookie;
576         uint8_t buf[1];
577 };
578
579 struct unix_msg_ctx {
580         struct unix_dgram_ctx *dgram;
581         size_t fragment_len;
582         uint64_t cookie;
583
584         void (*recv_callback)(struct unix_msg_ctx *ctx,
585                               uint8_t *msg, size_t msg_len,
586                               void *private_data);
587         void *private_data;
588
589         struct unix_msg *msgs;
590 };
591
592 static void unix_msg_recv(struct unix_dgram_ctx *ctx,
593                           uint8_t *msg, size_t msg_len,
594                           void *private_data);
595
596 int unix_msg_init(const struct sockaddr_un *addr,
597                   const struct poll_funcs *ev_funcs,
598                   size_t fragment_len, uint64_t cookie,
599                   void (*recv_callback)(struct unix_msg_ctx *ctx,
600                                         uint8_t *msg, size_t msg_len,
601                                         void *private_data),
602                   void *private_data,
603                   struct unix_msg_ctx **result)
604 {
605         struct unix_msg_ctx *ctx;
606         int ret;
607
608         ctx = malloc(sizeof(*ctx));
609         if (ctx == NULL) {
610                 return ENOMEM;
611         }
612
613         *ctx = (struct unix_msg_ctx) {
614                 .fragment_len = fragment_len,
615                 .cookie = cookie,
616                 .recv_callback = recv_callback,
617                 .private_data = private_data
618         };
619
620         ret = unix_dgram_init(addr, fragment_len, ev_funcs,
621                               unix_msg_recv, ctx, &ctx->dgram);
622         if (ret != 0) {
623                 free(ctx);
624                 return ret;
625         }
626
627         *result = ctx;
628         return 0;
629 }
630
631 int unix_msg_send(struct unix_msg_ctx *ctx, const struct sockaddr_un *dst,
632                   const struct iovec *iov, int iovlen)
633 {
634         ssize_t msglen;
635         size_t sent;
636         int ret = 0;
637         struct iovec iov_copy[iovlen+2];
638         struct unix_msg_hdr hdr;
639         struct iovec src_iov;
640
641         if (iovlen < 0) {
642                 return EINVAL;
643         }
644
645         msglen = iov_buflen(iov, iovlen);
646         if (msglen == -1) {
647                 return EINVAL;
648         }
649
650         if (msglen <= (ctx->fragment_len - sizeof(uint64_t))) {
651                 uint64_t cookie = 0;
652
653                 iov_copy[0].iov_base = &cookie;
654                 iov_copy[0].iov_len = sizeof(cookie);
655                 if (iovlen > 0) {
656                         memcpy(&iov_copy[1], iov,
657                                sizeof(struct iovec) * iovlen);
658                 }
659
660                 return unix_dgram_send(ctx->dgram, dst, iov_copy, iovlen+1);
661         }
662
663         hdr = (struct unix_msg_hdr) {
664                 .msglen = msglen,
665                 .pid = getpid(),
666                 .sock = unix_dgram_sock(ctx->dgram)
667         };
668
669         iov_copy[0].iov_base = &ctx->cookie;
670         iov_copy[0].iov_len = sizeof(ctx->cookie);
671         iov_copy[1].iov_base = &hdr;
672         iov_copy[1].iov_len = sizeof(hdr);
673
674         sent = 0;
675         src_iov = iov[0];
676
677         /*
678          * The following write loop sends the user message in pieces. We have
679          * filled the first two iovecs above with "cookie" and "hdr". In the
680          * following loops we pull message chunks from the user iov array and
681          * fill iov_copy piece by piece, possibly truncating chunks from the
682          * caller's iov array. Ugly, but hopefully efficient.
683          */
684
685         while (sent < msglen) {
686                 size_t fragment_len;
687                 size_t iov_index = 2;
688
689                 fragment_len = sizeof(ctx->cookie) + sizeof(hdr);
690
691                 while (fragment_len < ctx->fragment_len) {
692                         size_t space, chunk;
693
694                         space = ctx->fragment_len - fragment_len;
695                         chunk = MIN(space, src_iov.iov_len);
696
697                         iov_copy[iov_index].iov_base = src_iov.iov_base;
698                         iov_copy[iov_index].iov_len = chunk;
699                         iov_index += 1;
700
701                         src_iov.iov_base = (char *)src_iov.iov_base + chunk;
702                         src_iov.iov_len -= chunk;
703                         fragment_len += chunk;
704
705                         if (src_iov.iov_len == 0) {
706                                 iov += 1;
707                                 iovlen -= 1;
708                                 if (iovlen == 0) {
709                                         break;
710                                 }
711                                 src_iov = iov[0];
712                         }
713                 }
714                 sent += (fragment_len - sizeof(ctx->cookie) - sizeof(hdr));
715
716                 ret = unix_dgram_send(ctx->dgram, dst, iov_copy, iov_index);
717                 if (ret != 0) {
718                         break;
719                 }
720         }
721
722         ctx->cookie += 1;
723         if (ctx->cookie == 0) {
724                 ctx->cookie += 1;
725         }
726
727         return ret;
728 }
729
730 static void unix_msg_recv(struct unix_dgram_ctx *dgram_ctx,
731                           uint8_t *buf, size_t buflen,
732                           void *private_data)
733 {
734         struct unix_msg_ctx *ctx = (struct unix_msg_ctx *)private_data;
735         struct unix_msg_hdr hdr;
736         struct unix_msg *msg;
737         size_t space;
738         uint64_t cookie;
739
740         if (buflen < sizeof(cookie)) {
741                 return;
742         }
743         memcpy(&cookie, buf, sizeof(cookie));
744
745         buf += sizeof(cookie);
746         buflen -= sizeof(cookie);
747
748         if (cookie == 0) {
749                 ctx->recv_callback(ctx, buf, buflen, ctx->private_data);
750                 return;
751         }
752
753         if (buflen < sizeof(hdr)) {
754                 return;
755         }
756         memcpy(&hdr, buf, sizeof(hdr));
757
758         buf += sizeof(hdr);
759         buflen -= sizeof(hdr);
760
761         for (msg = ctx->msgs; msg != NULL; msg = msg->next) {
762                 if ((msg->sender_pid == hdr.pid) &&
763                     (msg->sender_sock == hdr.sock)) {
764                         break;
765                 }
766         }
767
768         if ((msg != NULL) && (msg->cookie != cookie)) {
769                 DLIST_REMOVE(ctx->msgs, msg);
770                 free(msg);
771                 msg = NULL;
772         }
773
774         if (msg == NULL) {
775                 msg = malloc(offsetof(struct unix_msg, buf) + hdr.msglen);
776                 if (msg == NULL) {
777                         return;
778                 }
779                 *msg = (struct unix_msg) {
780                         .msglen = hdr.msglen,
781                         .sender_pid = hdr.pid,
782                         .sender_sock = hdr.sock,
783                         .cookie = cookie
784                 };
785                 DLIST_ADD(ctx->msgs, msg);
786         }
787
788         space = msg->msglen - msg->received;
789         if (buflen > space) {
790                 return;
791         }
792
793         memcpy(msg->buf + msg->received, buf, buflen);
794         msg->received += buflen;
795
796         if (msg->received < msg->msglen) {
797                 return;
798         }
799
800         DLIST_REMOVE(ctx->msgs, msg);
801         ctx->recv_callback(ctx, msg->buf, msg->msglen, ctx->private_data);
802         free(msg);
803 }
804
805 int unix_msg_free(struct unix_msg_ctx *ctx)
806 {
807         int ret;
808
809         ret = unix_dgram_free(ctx->dgram);
810         if (ret != 0) {
811                 return ret;
812         }
813
814         while (ctx->msgs != NULL) {
815                 struct unix_msg *msg = ctx->msgs;
816                 DLIST_REMOVE(ctx->msgs, msg);
817                 free(msg);
818         }
819
820         free(ctx);
821         return 0;
822 }
823
824 static ssize_t iov_buflen(const struct iovec *iov, int iovlen)
825 {
826         size_t buflen = 0;
827         int i;
828
829         for (i=0; i<iovlen; i++) {
830                 size_t thislen = iov[i].iov_len;
831                 size_t tmp = buflen + thislen;
832
833                 if ((tmp < buflen) || (tmp < thislen)) {
834                         /* overflow */
835                         return -1;
836                 }
837                 buflen = tmp;
838         }
839         return buflen;
840 }