It seems that IRIX doesn't have IOV_MAX
[ira/wip.git] / lib / tsocket / tsocket.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6      ** NOTE! The following LGPL license applies to the tevent
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "replace.h"
25 #include "system/filesys.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
28
29 int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
30 {
31         enum tevent_req_state state;
32         uint64_t error;
33
34         if (!tevent_req_is_error(req, &state, &error)) {
35                 return 0;
36         }
37
38         switch (state) {
39         case TEVENT_REQ_NO_MEMORY:
40                 *perrno = ENOMEM;
41                 return -1;
42         case TEVENT_REQ_TIMED_OUT:
43                 *perrno = ETIMEDOUT;
44                 return -1;
45         case TEVENT_REQ_USER_ERROR:
46                 *perrno = (int)error;
47                 return -1;
48         default:
49                 *perrno = EIO;
50                 return -1;
51         }
52
53         *perrno = EIO;
54         return -1;
55 }
56
57 struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
58                                                 const struct tsocket_address_ops *ops,
59                                                 void *pstate,
60                                                 size_t psize,
61                                                 const char *type,
62                                                 const char *location)
63 {
64         void **ppstate = (void **)pstate;
65         struct tsocket_address *addr;
66
67         addr = talloc_zero(mem_ctx, struct tsocket_address);
68         if (!addr) {
69                 return NULL;
70         }
71         addr->ops = ops;
72         addr->location = location;
73         addr->private_data = talloc_size(addr, psize);
74         if (!addr->private_data) {
75                 talloc_free(addr);
76                 return NULL;
77         }
78         talloc_set_name_const(addr->private_data, type);
79
80         *ppstate = addr->private_data;
81         return addr;
82 }
83
84 char *tsocket_address_string(const struct tsocket_address *addr,
85                              TALLOC_CTX *mem_ctx)
86 {
87         if (!addr) {
88                 return talloc_strdup(mem_ctx, "NULL");
89         }
90         return addr->ops->string(addr, mem_ctx);
91 }
92
93 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
94                                               TALLOC_CTX *mem_ctx,
95                                               const char *location)
96 {
97         return addr->ops->copy(addr, mem_ctx, location);
98 }
99
100 struct tdgram_context {
101         const char *location;
102         const struct tdgram_context_ops *ops;
103         void *private_data;
104
105         struct tevent_req *recvfrom_req;
106         struct tevent_req *sendto_req;
107 };
108
109 static int tdgram_context_destructor(struct tdgram_context *dgram)
110 {
111         if (dgram->recvfrom_req) {
112                 tevent_req_received(dgram->recvfrom_req);
113         }
114
115         if (dgram->sendto_req) {
116                 tevent_req_received(dgram->sendto_req);
117         }
118
119         return 0;
120 }
121
122 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
123                                         const struct tdgram_context_ops *ops,
124                                         void *pstate,
125                                         size_t psize,
126                                         const char *type,
127                                         const char *location)
128 {
129         struct tdgram_context *dgram;
130         void **ppstate = (void **)pstate;
131         void *state;
132
133         dgram = talloc(mem_ctx, struct tdgram_context);
134         if (dgram == NULL) {
135                 return NULL;
136         }
137         dgram->location         = location;
138         dgram->ops              = ops;
139         dgram->recvfrom_req     = NULL;
140         dgram->sendto_req       = NULL;
141
142         state = talloc_size(dgram, psize);
143         if (state == NULL) {
144                 talloc_free(dgram);
145                 return NULL;
146         }
147         talloc_set_name_const(state, type);
148
149         dgram->private_data = state;
150
151         talloc_set_destructor(dgram, tdgram_context_destructor);
152
153         *ppstate = state;
154         return dgram;
155 }
156
157 void *_tdgram_context_data(struct tdgram_context *dgram)
158 {
159         return dgram->private_data;
160 }
161
162 struct tdgram_recvfrom_state {
163         const struct tdgram_context_ops *ops;
164         struct tdgram_context *dgram;
165         uint8_t *buf;
166         size_t len;
167         struct tsocket_address *src;
168 };
169
170 static int tdgram_recvfrom_destructor(struct tdgram_recvfrom_state *state)
171 {
172         if (state->dgram) {
173                 state->dgram->recvfrom_req = NULL;
174         }
175
176         return 0;
177 }
178
179 static void tdgram_recvfrom_done(struct tevent_req *subreq);
180
181 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
182                                         struct tevent_context *ev,
183                                         struct tdgram_context *dgram)
184 {
185         struct tevent_req *req;
186         struct tdgram_recvfrom_state *state;
187         struct tevent_req *subreq;
188
189         req = tevent_req_create(mem_ctx, &state,
190                                 struct tdgram_recvfrom_state);
191         if (req == NULL) {
192                 return NULL;
193         }
194
195         state->ops = dgram->ops;
196         state->dgram = dgram;
197         state->buf = NULL;
198         state->len = 0;
199         state->src = NULL;
200
201         if (dgram->recvfrom_req) {
202                 tevent_req_error(req, EBUSY);
203                 goto post;
204         }
205         dgram->recvfrom_req = req;
206
207         talloc_set_destructor(state, tdgram_recvfrom_destructor);
208
209         subreq = state->ops->recvfrom_send(state, ev, dgram);
210         if (tevent_req_nomem(subreq, req)) {
211                 goto post;
212         }
213         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
214
215         return req;
216
217  post:
218         tevent_req_post(req, ev);
219         return req;
220 }
221
222 static void tdgram_recvfrom_done(struct tevent_req *subreq)
223 {
224         struct tevent_req *req = tevent_req_callback_data(subreq,
225                                  struct tevent_req);
226         struct tdgram_recvfrom_state *state = tevent_req_data(req,
227                                               struct tdgram_recvfrom_state);
228         ssize_t ret;
229         int sys_errno;
230
231         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
232                                         &state->buf, &state->src);
233         if (ret == -1) {
234                 tevent_req_error(req, sys_errno);
235                 return;
236         }
237
238         state->len = ret;
239
240         tevent_req_done(req);
241 }
242
243 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
244                              int *perrno,
245                              TALLOC_CTX *mem_ctx,
246                              uint8_t **buf,
247                              struct tsocket_address **src)
248 {
249         struct tdgram_recvfrom_state *state = tevent_req_data(req,
250                                               struct tdgram_recvfrom_state);
251         ssize_t ret;
252
253         ret = tsocket_simple_int_recv(req, perrno);
254         if (ret == 0) {
255                 *buf = talloc_move(mem_ctx, &state->buf);
256                 ret = state->len;
257                 if (src) {
258                         *src = talloc_move(mem_ctx, &state->src);
259                 }
260         }
261
262         tevent_req_received(req);
263         return ret;
264 }
265
266 struct tdgram_sendto_state {
267         const struct tdgram_context_ops *ops;
268         struct tdgram_context *dgram;
269         ssize_t ret;
270 };
271
272 static int tdgram_sendto_destructor(struct tdgram_sendto_state *state)
273 {
274         if (state->dgram) {
275                 state->dgram->sendto_req = NULL;
276         }
277
278         return 0;
279 }
280
281 static void tdgram_sendto_done(struct tevent_req *subreq);
282
283 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
284                                       struct tevent_context *ev,
285                                       struct tdgram_context *dgram,
286                                       const uint8_t *buf, size_t len,
287                                       const struct tsocket_address *dst)
288 {
289         struct tevent_req *req;
290         struct tdgram_sendto_state *state;
291         struct tevent_req *subreq;
292
293         req = tevent_req_create(mem_ctx, &state,
294                                 struct tdgram_sendto_state);
295         if (req == NULL) {
296                 return NULL;
297         }
298
299         state->ops = dgram->ops;
300         state->dgram = dgram;
301         state->ret = -1;
302
303         if (len == 0) {
304                 tevent_req_error(req, EINVAL);
305                 goto post;
306         }
307
308         if (dgram->sendto_req) {
309                 tevent_req_error(req, EBUSY);
310                 goto post;
311         }
312         dgram->sendto_req = req;
313
314         talloc_set_destructor(state, tdgram_sendto_destructor);
315
316         subreq = state->ops->sendto_send(state, ev, dgram,
317                                          buf, len, dst);
318         if (tevent_req_nomem(subreq, req)) {
319                 goto post;
320         }
321         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
322
323         return req;
324
325  post:
326         tevent_req_post(req, ev);
327         return req;
328 }
329
330 static void tdgram_sendto_done(struct tevent_req *subreq)
331 {
332         struct tevent_req *req = tevent_req_callback_data(subreq,
333                                  struct tevent_req);
334         struct tdgram_sendto_state *state = tevent_req_data(req,
335                                             struct tdgram_sendto_state);
336         ssize_t ret;
337         int sys_errno;
338
339         ret = state->ops->sendto_recv(subreq, &sys_errno);
340         if (ret == -1) {
341                 tevent_req_error(req, sys_errno);
342                 return;
343         }
344
345         state->ret = ret;
346
347         tevent_req_done(req);
348 }
349
350 ssize_t tdgram_sendto_recv(struct tevent_req *req,
351                            int *perrno)
352 {
353         struct tdgram_sendto_state *state = tevent_req_data(req,
354                                             struct tdgram_sendto_state);
355         ssize_t ret;
356
357         ret = tsocket_simple_int_recv(req, perrno);
358         if (ret == 0) {
359                 ret = state->ret;
360         }
361
362         tevent_req_received(req);
363         return ret;
364 }
365
366 struct tdgram_disconnect_state {
367         const struct tdgram_context_ops *ops;
368 };
369
370 static void tdgram_disconnect_done(struct tevent_req *subreq);
371
372 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
373                                           struct tevent_context *ev,
374                                           struct tdgram_context *dgram)
375 {
376         struct tevent_req *req;
377         struct tdgram_disconnect_state *state;
378         struct tevent_req *subreq;
379
380         req = tevent_req_create(mem_ctx, &state,
381                                 struct tdgram_disconnect_state);
382         if (req == NULL) {
383                 return NULL;
384         }
385
386         state->ops = dgram->ops;
387
388         if (dgram->recvfrom_req || dgram->sendto_req) {
389                 tevent_req_error(req, EBUSY);
390                 goto post;
391         }
392
393         subreq = state->ops->disconnect_send(state, ev, dgram);
394         if (tevent_req_nomem(subreq, req)) {
395                 goto post;
396         }
397         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
398
399         return req;
400
401  post:
402         tevent_req_post(req, ev);
403         return req;
404 }
405
406 static void tdgram_disconnect_done(struct tevent_req *subreq)
407 {
408         struct tevent_req *req = tevent_req_callback_data(subreq,
409                                  struct tevent_req);
410         struct tdgram_disconnect_state *state = tevent_req_data(req,
411                                                 struct tdgram_disconnect_state);
412         int ret;
413         int sys_errno;
414
415         ret = state->ops->disconnect_recv(subreq, &sys_errno);
416         if (ret == -1) {
417                 tevent_req_error(req, sys_errno);
418                 return;
419         }
420
421         tevent_req_done(req);
422 }
423
424 int tdgram_disconnect_recv(struct tevent_req *req,
425                            int *perrno)
426 {
427         int ret;
428
429         ret = tsocket_simple_int_recv(req, perrno);
430
431         tevent_req_received(req);
432         return ret;
433 }
434
435 struct tstream_context {
436         const char *location;
437         const struct tstream_context_ops *ops;
438         void *private_data;
439
440         struct tevent_req *readv_req;
441         struct tevent_req *writev_req;
442 };
443
444 static int tstream_context_destructor(struct tstream_context *stream)
445 {
446         if (stream->readv_req) {
447                 tevent_req_received(stream->readv_req);
448         }
449
450         if (stream->writev_req) {
451                 tevent_req_received(stream->writev_req);
452         }
453
454         return 0;
455 }
456
457 struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
458                                         const struct tstream_context_ops *ops,
459                                         void *pstate,
460                                         size_t psize,
461                                         const char *type,
462                                         const char *location)
463 {
464         struct tstream_context *stream;
465         void **ppstate = (void **)pstate;
466         void *state;
467
468         stream = talloc(mem_ctx, struct tstream_context);
469         if (stream == NULL) {
470                 return NULL;
471         }
472         stream->location        = location;
473         stream->ops             = ops;
474         stream->readv_req       = NULL;
475         stream->writev_req      = NULL;
476
477         state = talloc_size(stream, psize);
478         if (state == NULL) {
479                 talloc_free(stream);
480                 return NULL;
481         }
482         talloc_set_name_const(state, type);
483
484         stream->private_data = state;
485
486         talloc_set_destructor(stream, tstream_context_destructor);
487
488         *ppstate = state;
489         return stream;
490 }
491
492 void *_tstream_context_data(struct tstream_context *stream)
493 {
494         return stream->private_data;
495 }
496
497 ssize_t tstream_pending_bytes(struct tstream_context *stream)
498 {
499         return stream->ops->pending_bytes(stream);
500 }
501
502 struct tstream_readv_state {
503         const struct tstream_context_ops *ops;
504         struct tstream_context *stream;
505         int ret;
506 };
507
508 static int tstream_readv_destructor(struct tstream_readv_state *state)
509 {
510         if (state->stream) {
511                 state->stream->readv_req = NULL;
512         }
513
514         return 0;
515 }
516
517 static void tstream_readv_done(struct tevent_req *subreq);
518
519 struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
520                                       struct tevent_context *ev,
521                                       struct tstream_context *stream,
522                                       struct iovec *vector,
523                                       size_t count)
524 {
525         struct tevent_req *req;
526         struct tstream_readv_state *state;
527         struct tevent_req *subreq;
528         int to_read = 0;
529         size_t i;
530
531         req = tevent_req_create(mem_ctx, &state,
532                                 struct tstream_readv_state);
533         if (req == NULL) {
534                 return NULL;
535         }
536
537         state->ops = stream->ops;
538         state->stream = stream;
539         state->ret = -1;
540
541         /* first check if the input is ok */
542 #ifdef IOV_MAX
543         if (count > IOV_MAX) {
544                 tevent_req_error(req, EMSGSIZE);
545                 goto post;
546         }
547 #endif
548
549         for (i=0; i < count; i++) {
550                 int tmp = to_read;
551                 tmp += vector[i].iov_len;
552
553                 if (tmp < to_read) {
554                         tevent_req_error(req, EMSGSIZE);
555                         goto post;
556                 }
557
558                 to_read = tmp;
559         }
560
561         if (to_read == 0) {
562                 tevent_req_error(req, EINVAL);
563                 goto post;
564         }
565
566         if (stream->readv_req) {
567                 tevent_req_error(req, EBUSY);
568                 goto post;
569         }
570         stream->readv_req = req;
571
572         talloc_set_destructor(state, tstream_readv_destructor);
573
574         subreq = state->ops->readv_send(state, ev, stream, vector, count);
575         if (tevent_req_nomem(subreq, req)) {
576                 goto post;
577         }
578         tevent_req_set_callback(subreq, tstream_readv_done, req);
579
580         return req;
581
582  post:
583         tevent_req_post(req, ev);
584         return req;
585 }
586
587 static void tstream_readv_done(struct tevent_req *subreq)
588 {
589         struct tevent_req *req = tevent_req_callback_data(subreq,
590                                  struct tevent_req);
591         struct tstream_readv_state *state = tevent_req_data(req,
592                                             struct tstream_readv_state);
593         ssize_t ret;
594         int sys_errno;
595
596         ret = state->ops->readv_recv(subreq, &sys_errno);
597         if (ret == -1) {
598                 tevent_req_error(req, sys_errno);
599                 return;
600         }
601
602         state->ret = ret;
603
604         tevent_req_done(req);
605 }
606
607 int tstream_readv_recv(struct tevent_req *req,
608                        int *perrno)
609 {
610         struct tstream_readv_state *state = tevent_req_data(req,
611                                             struct tstream_readv_state);
612         int ret;
613
614         ret = tsocket_simple_int_recv(req, perrno);
615         if (ret == 0) {
616                 ret = state->ret;
617         }
618
619         tevent_req_received(req);
620         return ret;
621 }
622
623 struct tstream_writev_state {
624         const struct tstream_context_ops *ops;
625         struct tstream_context *stream;
626         int ret;
627 };
628
629 static int tstream_writev_destructor(struct tstream_writev_state *state)
630 {
631         if (state->stream) {
632                 state->stream->writev_req = NULL;
633         }
634
635         return 0;
636 }
637
638 static void tstream_writev_done(struct tevent_req *subreq);
639
640 struct tevent_req *tstream_writev_send(TALLOC_CTX *mem_ctx,
641                                        struct tevent_context *ev,
642                                        struct tstream_context *stream,
643                                        const struct iovec *vector,
644                                        size_t count)
645 {
646         struct tevent_req *req;
647         struct tstream_writev_state *state;
648         struct tevent_req *subreq;
649         int to_write = 0;
650         size_t i;
651
652         req = tevent_req_create(mem_ctx, &state,
653                                 struct tstream_writev_state);
654         if (req == NULL) {
655                 return NULL;
656         }
657
658         state->ops = stream->ops;
659         state->stream = stream;
660         state->ret = -1;
661
662         /* first check if the input is ok */
663 #ifdef IOV_MAX
664         if (count > IOV_MAX) {
665                 tevent_req_error(req, EMSGSIZE);
666                 goto post;
667         }
668 #endif
669
670         for (i=0; i < count; i++) {
671                 int tmp = to_write;
672                 tmp += vector[i].iov_len;
673
674                 if (tmp < to_write) {
675                         tevent_req_error(req, EMSGSIZE);
676                         goto post;
677                 }
678
679                 to_write = tmp;
680         }
681
682         if (to_write == 0) {
683                 tevent_req_error(req, EINVAL);
684                 goto post;
685         }
686
687         if (stream->writev_req) {
688                 tevent_req_error(req, EBUSY);
689                 goto post;
690         }
691         stream->writev_req = req;
692
693         talloc_set_destructor(state, tstream_writev_destructor);
694
695         subreq = state->ops->writev_send(state, ev, stream, vector, count);
696         if (tevent_req_nomem(subreq, req)) {
697                 goto post;
698         }
699         tevent_req_set_callback(subreq, tstream_writev_done, req);
700
701         return req;
702
703  post:
704         tevent_req_post(req, ev);
705         return req;
706 }
707
708 static void tstream_writev_done(struct tevent_req *subreq)
709 {
710         struct tevent_req *req = tevent_req_callback_data(subreq,
711                                  struct tevent_req);
712         struct tstream_writev_state *state = tevent_req_data(req,
713                                              struct tstream_writev_state);
714         ssize_t ret;
715         int sys_errno;
716
717         ret = state->ops->writev_recv(subreq, &sys_errno);
718         if (ret == -1) {
719                 tevent_req_error(req, sys_errno);
720                 return;
721         }
722
723         state->ret = ret;
724
725         tevent_req_done(req);
726 }
727
728 int tstream_writev_recv(struct tevent_req *req,
729                        int *perrno)
730 {
731         struct tstream_writev_state *state = tevent_req_data(req,
732                                              struct tstream_writev_state);
733         int ret;
734
735         ret = tsocket_simple_int_recv(req, perrno);
736         if (ret == 0) {
737                 ret = state->ret;
738         }
739
740         tevent_req_received(req);
741         return ret;
742 }
743
744 struct tstream_disconnect_state {
745         const struct tstream_context_ops *ops;
746 };
747
748 static void tstream_disconnect_done(struct tevent_req *subreq);
749
750 struct tevent_req *tstream_disconnect_send(TALLOC_CTX *mem_ctx,
751                                            struct tevent_context *ev,
752                                            struct tstream_context *stream)
753 {
754         struct tevent_req *req;
755         struct tstream_disconnect_state *state;
756         struct tevent_req *subreq;
757
758         req = tevent_req_create(mem_ctx, &state,
759                                 struct tstream_disconnect_state);
760         if (req == NULL) {
761                 return NULL;
762         }
763
764         state->ops = stream->ops;
765
766         if (stream->readv_req || stream->writev_req) {
767                 tevent_req_error(req, EBUSY);
768                 goto post;
769         }
770
771         subreq = state->ops->disconnect_send(state, ev, stream);
772         if (tevent_req_nomem(subreq, req)) {
773                 goto post;
774         }
775         tevent_req_set_callback(subreq, tstream_disconnect_done, req);
776
777         return req;
778
779  post:
780         tevent_req_post(req, ev);
781         return req;
782 }
783
784 static void tstream_disconnect_done(struct tevent_req *subreq)
785 {
786         struct tevent_req *req = tevent_req_callback_data(subreq,
787                                  struct tevent_req);
788         struct tstream_disconnect_state *state = tevent_req_data(req,
789                                                  struct tstream_disconnect_state);
790         int ret;
791         int sys_errno;
792
793         ret = state->ops->disconnect_recv(subreq, &sys_errno);
794         if (ret == -1) {
795                 tevent_req_error(req, sys_errno);
796                 return;
797         }
798
799         tevent_req_done(req);
800 }
801
802 int tstream_disconnect_recv(struct tevent_req *req,
803                            int *perrno)
804 {
805         int ret;
806
807         ret = tsocket_simple_int_recv(req, perrno);
808
809         tevent_req_received(req);
810         return ret;
811 }
812