s3-waf: add check for TIME_T_MAX.
[samba.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 tsocket
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                 break;
50         }
51
52         *perrno = EIO;
53         return -1;
54 }
55
56 struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
57                                                 const struct tsocket_address_ops *ops,
58                                                 void *pstate,
59                                                 size_t psize,
60                                                 const char *type,
61                                                 const char *location)
62 {
63         void **ppstate = (void **)pstate;
64         struct tsocket_address *addr;
65
66         addr = talloc_zero(mem_ctx, struct tsocket_address);
67         if (!addr) {
68                 return NULL;
69         }
70         addr->ops = ops;
71         addr->location = location;
72         addr->private_data = talloc_size(addr, psize);
73         if (!addr->private_data) {
74                 talloc_free(addr);
75                 return NULL;
76         }
77         talloc_set_name_const(addr->private_data, type);
78
79         *ppstate = addr->private_data;
80         return addr;
81 }
82
83 char *tsocket_address_string(const struct tsocket_address *addr,
84                              TALLOC_CTX *mem_ctx)
85 {
86         if (!addr) {
87                 return talloc_strdup(mem_ctx, "NULL");
88         }
89         return addr->ops->string(addr, mem_ctx);
90 }
91
92 struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
93                                               TALLOC_CTX *mem_ctx,
94                                               const char *location)
95 {
96         return addr->ops->copy(addr, mem_ctx, location);
97 }
98
99 struct tdgram_context {
100         const char *location;
101         const struct tdgram_context_ops *ops;
102         void *private_data;
103
104         struct tevent_req *recvfrom_req;
105         struct tevent_req *sendto_req;
106 };
107
108 static int tdgram_context_destructor(struct tdgram_context *dgram)
109 {
110         if (dgram->recvfrom_req) {
111                 tevent_req_received(dgram->recvfrom_req);
112         }
113
114         if (dgram->sendto_req) {
115                 tevent_req_received(dgram->sendto_req);
116         }
117
118         return 0;
119 }
120
121 struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
122                                         const struct tdgram_context_ops *ops,
123                                         void *pstate,
124                                         size_t psize,
125                                         const char *type,
126                                         const char *location)
127 {
128         struct tdgram_context *dgram;
129         void **ppstate = (void **)pstate;
130         void *state;
131
132         dgram = talloc(mem_ctx, struct tdgram_context);
133         if (dgram == NULL) {
134                 return NULL;
135         }
136         dgram->location         = location;
137         dgram->ops              = ops;
138         dgram->recvfrom_req     = NULL;
139         dgram->sendto_req       = NULL;
140
141         state = talloc_size(dgram, psize);
142         if (state == NULL) {
143                 talloc_free(dgram);
144                 return NULL;
145         }
146         talloc_set_name_const(state, type);
147
148         dgram->private_data = state;
149
150         talloc_set_destructor(dgram, tdgram_context_destructor);
151
152         *ppstate = state;
153         return dgram;
154 }
155
156 void *_tdgram_context_data(struct tdgram_context *dgram)
157 {
158         return dgram->private_data;
159 }
160
161 struct tdgram_recvfrom_state {
162         const struct tdgram_context_ops *ops;
163         struct tdgram_context *dgram;
164         uint8_t *buf;
165         size_t len;
166         struct tsocket_address *src;
167 };
168
169 static int tdgram_recvfrom_destructor(struct tdgram_recvfrom_state *state)
170 {
171         if (state->dgram) {
172                 state->dgram->recvfrom_req = NULL;
173         }
174
175         return 0;
176 }
177
178 static void tdgram_recvfrom_done(struct tevent_req *subreq);
179
180 struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
181                                         struct tevent_context *ev,
182                                         struct tdgram_context *dgram)
183 {
184         struct tevent_req *req;
185         struct tdgram_recvfrom_state *state;
186         struct tevent_req *subreq;
187
188         req = tevent_req_create(mem_ctx, &state,
189                                 struct tdgram_recvfrom_state);
190         if (req == NULL) {
191                 return NULL;
192         }
193
194         state->ops = dgram->ops;
195         state->dgram = dgram;
196         state->buf = NULL;
197         state->len = 0;
198         state->src = NULL;
199
200         if (dgram->recvfrom_req) {
201                 tevent_req_error(req, EBUSY);
202                 goto post;
203         }
204         dgram->recvfrom_req = req;
205
206         talloc_set_destructor(state, tdgram_recvfrom_destructor);
207
208         subreq = state->ops->recvfrom_send(state, ev, dgram);
209         if (tevent_req_nomem(subreq, req)) {
210                 goto post;
211         }
212         tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
213
214         return req;
215
216  post:
217         tevent_req_post(req, ev);
218         return req;
219 }
220
221 static void tdgram_recvfrom_done(struct tevent_req *subreq)
222 {
223         struct tevent_req *req = tevent_req_callback_data(subreq,
224                                  struct tevent_req);
225         struct tdgram_recvfrom_state *state = tevent_req_data(req,
226                                               struct tdgram_recvfrom_state);
227         ssize_t ret;
228         int sys_errno;
229
230         ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
231                                         &state->buf, &state->src);
232         if (ret == -1) {
233                 tevent_req_error(req, sys_errno);
234                 return;
235         }
236
237         state->len = ret;
238
239         tevent_req_done(req);
240 }
241
242 ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
243                              int *perrno,
244                              TALLOC_CTX *mem_ctx,
245                              uint8_t **buf,
246                              struct tsocket_address **src)
247 {
248         struct tdgram_recvfrom_state *state = tevent_req_data(req,
249                                               struct tdgram_recvfrom_state);
250         ssize_t ret;
251
252         ret = tsocket_simple_int_recv(req, perrno);
253         if (ret == 0) {
254                 *buf = talloc_move(mem_ctx, &state->buf);
255                 ret = state->len;
256                 if (src) {
257                         *src = talloc_move(mem_ctx, &state->src);
258                 }
259         }
260
261         tevent_req_received(req);
262         return ret;
263 }
264
265 struct tdgram_sendto_state {
266         const struct tdgram_context_ops *ops;
267         struct tdgram_context *dgram;
268         ssize_t ret;
269 };
270
271 static int tdgram_sendto_destructor(struct tdgram_sendto_state *state)
272 {
273         if (state->dgram) {
274                 state->dgram->sendto_req = NULL;
275         }
276
277         return 0;
278 }
279
280 static void tdgram_sendto_done(struct tevent_req *subreq);
281
282 struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
283                                       struct tevent_context *ev,
284                                       struct tdgram_context *dgram,
285                                       const uint8_t *buf, size_t len,
286                                       const struct tsocket_address *dst)
287 {
288         struct tevent_req *req;
289         struct tdgram_sendto_state *state;
290         struct tevent_req *subreq;
291
292         req = tevent_req_create(mem_ctx, &state,
293                                 struct tdgram_sendto_state);
294         if (req == NULL) {
295                 return NULL;
296         }
297
298         state->ops = dgram->ops;
299         state->dgram = dgram;
300         state->ret = -1;
301
302         if (len == 0) {
303                 tevent_req_error(req, EINVAL);
304                 goto post;
305         }
306
307         if (dgram->sendto_req) {
308                 tevent_req_error(req, EBUSY);
309                 goto post;
310         }
311         dgram->sendto_req = req;
312
313         talloc_set_destructor(state, tdgram_sendto_destructor);
314
315         subreq = state->ops->sendto_send(state, ev, dgram,
316                                          buf, len, dst);
317         if (tevent_req_nomem(subreq, req)) {
318                 goto post;
319         }
320         tevent_req_set_callback(subreq, tdgram_sendto_done, req);
321
322         return req;
323
324  post:
325         tevent_req_post(req, ev);
326         return req;
327 }
328
329 static void tdgram_sendto_done(struct tevent_req *subreq)
330 {
331         struct tevent_req *req = tevent_req_callback_data(subreq,
332                                  struct tevent_req);
333         struct tdgram_sendto_state *state = tevent_req_data(req,
334                                             struct tdgram_sendto_state);
335         ssize_t ret;
336         int sys_errno;
337
338         ret = state->ops->sendto_recv(subreq, &sys_errno);
339         if (ret == -1) {
340                 tevent_req_error(req, sys_errno);
341                 return;
342         }
343
344         state->ret = ret;
345
346         tevent_req_done(req);
347 }
348
349 ssize_t tdgram_sendto_recv(struct tevent_req *req,
350                            int *perrno)
351 {
352         struct tdgram_sendto_state *state = tevent_req_data(req,
353                                             struct tdgram_sendto_state);
354         ssize_t ret;
355
356         ret = tsocket_simple_int_recv(req, perrno);
357         if (ret == 0) {
358                 ret = state->ret;
359         }
360
361         tevent_req_received(req);
362         return ret;
363 }
364
365 struct tdgram_disconnect_state {
366         const struct tdgram_context_ops *ops;
367 };
368
369 static void tdgram_disconnect_done(struct tevent_req *subreq);
370
371 struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
372                                           struct tevent_context *ev,
373                                           struct tdgram_context *dgram)
374 {
375         struct tevent_req *req;
376         struct tdgram_disconnect_state *state;
377         struct tevent_req *subreq;
378
379         req = tevent_req_create(mem_ctx, &state,
380                                 struct tdgram_disconnect_state);
381         if (req == NULL) {
382                 return NULL;
383         }
384
385         state->ops = dgram->ops;
386
387         if (dgram->recvfrom_req || dgram->sendto_req) {
388                 tevent_req_error(req, EBUSY);
389                 goto post;
390         }
391
392         subreq = state->ops->disconnect_send(state, ev, dgram);
393         if (tevent_req_nomem(subreq, req)) {
394                 goto post;
395         }
396         tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
397
398         return req;
399
400  post:
401         tevent_req_post(req, ev);
402         return req;
403 }
404
405 static void tdgram_disconnect_done(struct tevent_req *subreq)
406 {
407         struct tevent_req *req = tevent_req_callback_data(subreq,
408                                  struct tevent_req);
409         struct tdgram_disconnect_state *state = tevent_req_data(req,
410                                                 struct tdgram_disconnect_state);
411         int ret;
412         int sys_errno;
413
414         ret = state->ops->disconnect_recv(subreq, &sys_errno);
415         if (ret == -1) {
416                 tevent_req_error(req, sys_errno);
417                 return;
418         }
419
420         tevent_req_done(req);
421 }
422
423 int tdgram_disconnect_recv(struct tevent_req *req,
424                            int *perrno)
425 {
426         int ret;
427
428         ret = tsocket_simple_int_recv(req, perrno);
429
430         tevent_req_received(req);
431         return ret;
432 }
433
434 struct tstream_context {
435         const char *location;
436         const struct tstream_context_ops *ops;
437         void *private_data;
438
439         struct tevent_req *readv_req;
440         struct tevent_req *writev_req;
441 };
442
443 static int tstream_context_destructor(struct tstream_context *stream)
444 {
445         if (stream->readv_req) {
446                 tevent_req_received(stream->readv_req);
447         }
448
449         if (stream->writev_req) {
450                 tevent_req_received(stream->writev_req);
451         }
452
453         return 0;
454 }
455
456 struct tstream_context *_tstream_context_create(TALLOC_CTX *mem_ctx,
457                                         const struct tstream_context_ops *ops,
458                                         void *pstate,
459                                         size_t psize,
460                                         const char *type,
461                                         const char *location)
462 {
463         struct tstream_context *stream;
464         void **ppstate = (void **)pstate;
465         void *state;
466
467         stream = talloc(mem_ctx, struct tstream_context);
468         if (stream == NULL) {
469                 return NULL;
470         }
471         stream->location        = location;
472         stream->ops             = ops;
473         stream->readv_req       = NULL;
474         stream->writev_req      = NULL;
475
476         state = talloc_size(stream, psize);
477         if (state == NULL) {
478                 talloc_free(stream);
479                 return NULL;
480         }
481         talloc_set_name_const(state, type);
482
483         stream->private_data = state;
484
485         talloc_set_destructor(stream, tstream_context_destructor);
486
487         *ppstate = state;
488         return stream;
489 }
490
491 void *_tstream_context_data(struct tstream_context *stream)
492 {
493         return stream->private_data;
494 }
495
496 ssize_t tstream_pending_bytes(struct tstream_context *stream)
497 {
498         return stream->ops->pending_bytes(stream);
499 }
500
501 struct tstream_readv_state {
502         const struct tstream_context_ops *ops;
503         struct tstream_context *stream;
504         int ret;
505 };
506
507 static int tstream_readv_destructor(struct tstream_readv_state *state)
508 {
509         if (state->stream) {
510                 state->stream->readv_req = NULL;
511         }
512
513         return 0;
514 }
515
516 static void tstream_readv_done(struct tevent_req *subreq);
517
518 struct tevent_req *tstream_readv_send(TALLOC_CTX *mem_ctx,
519                                       struct tevent_context *ev,
520                                       struct tstream_context *stream,
521                                       struct iovec *vector,
522                                       size_t count)
523 {
524         struct tevent_req *req;
525         struct tstream_readv_state *state;
526         struct tevent_req *subreq;
527         int to_read = 0;
528         size_t i;
529
530         req = tevent_req_create(mem_ctx, &state,
531                                 struct tstream_readv_state);
532         if (req == NULL) {
533                 return NULL;
534         }
535
536         state->ops = stream->ops;
537         state->stream = stream;
538         state->ret = -1;
539
540         /* first check if the input is ok */
541 #ifdef IOV_MAX
542         if (count > IOV_MAX) {
543                 tevent_req_error(req, EMSGSIZE);
544                 goto post;
545         }
546 #endif
547
548         for (i=0; i < count; i++) {
549                 int tmp = to_read;
550                 tmp += vector[i].iov_len;
551
552                 if (tmp < to_read) {
553                         tevent_req_error(req, EMSGSIZE);
554                         goto post;
555                 }
556
557                 to_read = tmp;
558         }
559
560         if (to_read == 0) {
561                 tevent_req_error(req, EINVAL);
562                 goto post;
563         }
564
565         if (stream->readv_req) {
566                 tevent_req_error(req, EBUSY);
567                 goto post;
568         }
569         stream->readv_req = req;
570
571         talloc_set_destructor(state, tstream_readv_destructor);
572
573         subreq = state->ops->readv_send(state, ev, stream, vector, count);
574         if (tevent_req_nomem(subreq, req)) {
575                 goto post;
576         }
577         tevent_req_set_callback(subreq, tstream_readv_done, req);
578
579         return req;
580
581  post:
582         tevent_req_post(req, ev);
583         return req;
584 }
585
586 static void tstream_readv_done(struct tevent_req *subreq)
587 {
588         struct tevent_req *req = tevent_req_callback_data(subreq,
589                                  struct tevent_req);
590         struct tstream_readv_state *state = tevent_req_data(req,
591                                             struct tstream_readv_state);
592         ssize_t ret;
593         int sys_errno;
594
595         ret = state->ops->readv_recv(subreq, &sys_errno);
596         TALLOC_FREE(subreq);
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