LCOV - code coverage report
Current view: top level - lib/tsocket - tsocket_helpers.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 190 215 88.4 %
Date: 2024-02-28 12:06:22 Functions: 16 16 100.0 %

          Line data    Source code
       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             : struct tdgram_sendto_queue_state {
      30             :         /* this structs are owned by the caller */
      31             :         struct {
      32             :                 struct tevent_context *ev;
      33             :                 struct tdgram_context *dgram;
      34             :                 const uint8_t *buf;
      35             :                 size_t len;
      36             :                 const struct tsocket_address *dst;
      37             :         } caller;
      38             :         ssize_t ret;
      39             : };
      40             : 
      41             : static void tdgram_sendto_queue_trigger(struct tevent_req *req,
      42             :                                          void *private_data);
      43             : static void tdgram_sendto_queue_done(struct tevent_req *subreq);
      44             : 
      45       34595 : struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
      46             :                                             struct tevent_context *ev,
      47             :                                             struct tdgram_context *dgram,
      48             :                                             struct tevent_queue *queue,
      49             :                                             const uint8_t *buf,
      50             :                                             size_t len,
      51             :                                             struct tsocket_address *dst)
      52             : {
      53        1242 :         struct tevent_req *req;
      54        1242 :         struct tdgram_sendto_queue_state *state;
      55        1242 :         struct tevent_queue_entry *e;
      56             : 
      57       34595 :         req = tevent_req_create(mem_ctx, &state,
      58             :                                 struct tdgram_sendto_queue_state);
      59       34595 :         if (!req) {
      60           0 :                 return NULL;
      61             :         }
      62             : 
      63       34595 :         state->caller.ev     = ev;
      64       34595 :         state->caller.dgram  = dgram;
      65       34595 :         state->caller.buf    = buf;
      66       34595 :         state->caller.len    = len;
      67       34595 :         state->caller.dst    = dst;
      68       34595 :         state->ret           = -1;
      69             : 
      70             :         /*
      71             :          * we use tevent_queue_add_optimize_empty() with allow_direct
      72             :          * in order to optimize for the empty queue case.
      73             :          */
      74       34595 :         e = tevent_queue_add_optimize_empty(
      75             :                                 queue,
      76             :                                 ev,
      77             :                                 req,
      78             :                                 tdgram_sendto_queue_trigger,
      79             :                                 NULL);
      80       34595 :         if (tevent_req_nomem(e, req)) {
      81           0 :                 return tevent_req_post(req, ev);
      82             :         }
      83       34595 :         if (!tevent_req_is_in_progress(req)) {
      84           0 :                 return tevent_req_post(req, ev);
      85             :         }
      86             : 
      87       33353 :         return req;
      88             : }
      89             : 
      90       34595 : static void tdgram_sendto_queue_trigger(struct tevent_req *req,
      91             :                                          void *private_data)
      92             : {
      93       34595 :         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
      94             :                                         struct tdgram_sendto_queue_state);
      95        1242 :         struct tevent_req *subreq;
      96             : 
      97       34595 :         subreq = tdgram_sendto_send(state,
      98             :                                     state->caller.ev,
      99             :                                     state->caller.dgram,
     100             :                                     state->caller.buf,
     101             :                                     state->caller.len,
     102             :                                     state->caller.dst);
     103       34595 :         if (tevent_req_nomem(subreq, req)) {
     104           0 :                 return;
     105             :         }
     106       34595 :         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
     107             : }
     108             : 
     109       34595 : static void tdgram_sendto_queue_done(struct tevent_req *subreq)
     110             : {
     111       34595 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     112             :                                  struct tevent_req);
     113       34595 :         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
     114             :                                         struct tdgram_sendto_queue_state);
     115        1242 :         ssize_t ret;
     116        1242 :         int sys_errno;
     117             : 
     118       34595 :         ret = tdgram_sendto_recv(subreq, &sys_errno);
     119       34595 :         talloc_free(subreq);
     120       34595 :         if (ret == -1) {
     121          10 :                 tevent_req_error(req, sys_errno);
     122          10 :                 return;
     123             :         }
     124       34585 :         state->ret = ret;
     125             : 
     126       34585 :         tevent_req_done(req);
     127             : }
     128             : 
     129       32159 : ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
     130             : {
     131       32159 :         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
     132             :                                         struct tdgram_sendto_queue_state);
     133        1206 :         ssize_t ret;
     134             : 
     135       32159 :         ret = tsocket_simple_int_recv(req, perrno);
     136       32159 :         if (ret == 0) {
     137       32149 :                 ret = state->ret;
     138             :         }
     139             : 
     140       32159 :         tevent_req_received(req);
     141       32159 :         return ret;
     142             : }
     143             : 
     144             : struct tstream_readv_pdu_state {
     145             :         /* this structs are owned by the caller */
     146             :         struct {
     147             :                 struct tevent_context *ev;
     148             :                 struct tstream_context *stream;
     149             :                 tstream_readv_pdu_next_vector_t next_vector_fn;
     150             :                 void *next_vector_private;
     151             :         } caller;
     152             : 
     153             :         /*
     154             :          * Each call to the callback resets iov and count
     155             :          * the callback allocated the iov as child of our state,
     156             :          * that means we are allowed to modify and free it.
     157             :          *
     158             :          * we should call the callback every time we filled the given
     159             :          * vector and ask for a new vector. We return if the callback
     160             :          * ask for 0 bytes.
     161             :          */
     162             :         struct iovec *vector;
     163             :         size_t count;
     164             : 
     165             :         /*
     166             :          * the total number of bytes we read,
     167             :          * the return value of the _recv function
     168             :          */
     169             :         int total_read;
     170             : };
     171             : 
     172             : static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req);
     173             : static void tstream_readv_pdu_readv_done(struct tevent_req *subreq);
     174             : 
     175     6202670 : struct tevent_req *tstream_readv_pdu_send(TALLOC_CTX *mem_ctx,
     176             :                                 struct tevent_context *ev,
     177             :                                 struct tstream_context *stream,
     178             :                                 tstream_readv_pdu_next_vector_t next_vector_fn,
     179             :                                 void *next_vector_private)
     180             : {
     181       42256 :         struct tevent_req *req;
     182       42256 :         struct tstream_readv_pdu_state *state;
     183             : 
     184     6202670 :         req = tevent_req_create(mem_ctx, &state,
     185             :                                 struct tstream_readv_pdu_state);
     186     6202670 :         if (!req) {
     187           0 :                 return NULL;
     188             :         }
     189             : 
     190     6202670 :         state->caller.ev                     = ev;
     191     6202670 :         state->caller.stream                 = stream;
     192     6202670 :         state->caller.next_vector_fn         = next_vector_fn;
     193     6202670 :         state->caller.next_vector_private    = next_vector_private;
     194             : 
     195     6202670 :         state->vector                = NULL;
     196     6202670 :         state->count         = 0;
     197     6202670 :         state->total_read    = 0;
     198             : 
     199     6202670 :         tstream_readv_pdu_ask_for_next_vector(req);
     200     6202670 :         if (!tevent_req_is_in_progress(req)) {
     201           0 :                 goto post;
     202             :         }
     203             : 
     204     6160414 :         return req;
     205             : 
     206           0 :  post:
     207           0 :         return tevent_req_post(req, ev);
     208             : }
     209             : 
     210    17141675 : static void tstream_readv_pdu_ask_for_next_vector(struct tevent_req *req)
     211             : {
     212    17141675 :         struct tstream_readv_pdu_state *state = tevent_req_data(req,
     213             :                                             struct tstream_readv_pdu_state);
     214      123494 :         int ret;
     215    17141675 :         size_t to_read = 0;
     216      123494 :         size_t i;
     217      123494 :         struct tevent_req *subreq;
     218    17141675 :         bool optimize = false;
     219    17141675 :         bool save_optimize = false;
     220             : 
     221    17141675 :         if (state->count > 0) {
     222             :                 /*
     223             :                  * This is not the first time we asked for a vector,
     224             :                  * which means parts of the pdu already arrived.
     225             :                  *
     226             :                  * In this case it make sense to enable
     227             :                  * a syscall/performance optimization if the
     228             :                  * low level tstream implementation supports it.
     229             :                  */
     230    10939005 :                 optimize = true;
     231             :         }
     232             : 
     233    17141675 :         TALLOC_FREE(state->vector);
     234    17141675 :         state->count = 0;
     235             : 
     236    17141675 :         ret = state->caller.next_vector_fn(state->caller.stream,
     237             :                                            state->caller.next_vector_private,
     238             :                                            state, &state->vector, &state->count);
     239    17141675 :         if (ret == -1) {
     240           0 :                 tevent_req_error(req, errno);
     241           0 :                 return;
     242             :         }
     243             : 
     244    17141675 :         if (state->count == 0) {
     245     6066182 :                 tevent_req_done(req);
     246     6066182 :                 return;
     247             :         }
     248             : 
     249    23853623 :         for (i=0; i < state->count; i++) {
     250    12778130 :                 size_t tmp = to_read;
     251    12778130 :                 tmp += state->vector[i].iov_len;
     252             : 
     253    12778130 :                 if (tmp < to_read) {
     254           0 :                         tevent_req_error(req, EMSGSIZE);
     255           0 :                         return;
     256             :                 }
     257             : 
     258    12778130 :                 to_read = tmp;
     259             :         }
     260             : 
     261             :         /*
     262             :          * this is invalid the next vector function should have
     263             :          * reported count == 0.
     264             :          */
     265    11075493 :         if (to_read == 0) {
     266           0 :                 tevent_req_error(req, EINVAL);
     267           0 :                 return;
     268             :         }
     269             : 
     270    11075493 :         if (state->total_read + to_read < state->total_read) {
     271           0 :                 tevent_req_error(req, EMSGSIZE);
     272           0 :                 return;
     273             :         }
     274             : 
     275    11075493 :         if (optimize) {
     276             :                 /*
     277             :                  * If the low level stream is a bsd socket
     278             :                  * we will get syscall optimization.
     279             :                  *
     280             :                  * If it is not a bsd socket
     281             :                  * tstream_bsd_optimize_readv() just returns.
     282             :                  */
     283     4872823 :                 save_optimize = tstream_bsd_optimize_readv(state->caller.stream,
     284             :                                                            true);
     285             :         }
     286    11075493 :         subreq = tstream_readv_send(state,
     287             :                                     state->caller.ev,
     288             :                                     state->caller.stream,
     289             :                                     state->vector,
     290             :                                     state->count);
     291    11075493 :         if (optimize) {
     292     4872823 :                 tstream_bsd_optimize_readv(state->caller.stream,
     293             :                                            save_optimize);
     294             :         }
     295    11075493 :         if (tevent_req_nomem(subreq, req)) {
     296           0 :                 return;
     297             :         }
     298    11075493 :         tevent_req_set_callback(subreq, tstream_readv_pdu_readv_done, req);
     299             : }
     300             : 
     301    11075065 : static void tstream_readv_pdu_readv_done(struct tevent_req *subreq)
     302             : {
     303    11075065 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     304             :                                  struct tevent_req);
     305    11075065 :         struct tstream_readv_pdu_state *state = tevent_req_data(req,
     306             :                                             struct tstream_readv_pdu_state);
     307       82848 :         int ret;
     308       82848 :         int sys_errno;
     309             : 
     310    11075065 :         ret = tstream_readv_recv(subreq, &sys_errno);
     311    11075065 :         TALLOC_FREE(subreq);
     312    11075065 :         if (ret == -1) {
     313      136060 :                 tevent_req_error(req, sys_errno);
     314      135566 :                 return;
     315             :         }
     316             : 
     317    10939005 :         state->total_read += ret;
     318             : 
     319             :         /* ask the callback for a new vector we should fill */
     320    10939005 :         tstream_readv_pdu_ask_for_next_vector(req);
     321             : }
     322             : 
     323     6202242 : int tstream_readv_pdu_recv(struct tevent_req *req, int *perrno)
     324             : {
     325     6202242 :         struct tstream_readv_pdu_state *state = tevent_req_data(req,
     326             :                                             struct tstream_readv_pdu_state);
     327       42229 :         int ret;
     328             : 
     329     6202242 :         ret = tsocket_simple_int_recv(req, perrno);
     330     6202242 :         if (ret == 0) {
     331     6066182 :                 ret = state->total_read;
     332             :         }
     333             : 
     334     6202242 :         tevent_req_received(req);
     335     6202242 :         return ret;
     336             : }
     337             : 
     338             : struct tstream_readv_pdu_queue_state {
     339             :         /* this structs are owned by the caller */
     340             :         struct {
     341             :                 struct tevent_context *ev;
     342             :                 struct tstream_context *stream;
     343             :                 tstream_readv_pdu_next_vector_t next_vector_fn;
     344             :                 void *next_vector_private;
     345             :         } caller;
     346             :         int ret;
     347             : };
     348             : 
     349             : static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
     350             :                                          void *private_data);
     351             : static void tstream_readv_pdu_queue_done(struct tevent_req *subreq);
     352             : 
     353     1582962 : struct tevent_req *tstream_readv_pdu_queue_send(TALLOC_CTX *mem_ctx,
     354             :                                 struct tevent_context *ev,
     355             :                                 struct tstream_context *stream,
     356             :                                 struct tevent_queue *queue,
     357             :                                 tstream_readv_pdu_next_vector_t next_vector_fn,
     358             :                                 void *next_vector_private)
     359             : {
     360        7323 :         struct tevent_req *req;
     361        7323 :         struct tstream_readv_pdu_queue_state *state;
     362        7323 :         struct tevent_queue_entry *e;
     363             : 
     364     1582962 :         req = tevent_req_create(mem_ctx, &state,
     365             :                                 struct tstream_readv_pdu_queue_state);
     366     1582962 :         if (!req) {
     367           0 :                 return NULL;
     368             :         }
     369             : 
     370     1582962 :         state->caller.ev                     = ev;
     371     1582962 :         state->caller.stream                 = stream;
     372     1582962 :         state->caller.next_vector_fn         = next_vector_fn;
     373     1582962 :         state->caller.next_vector_private    = next_vector_private;
     374     1582962 :         state->ret                           = -1;
     375             : 
     376             :         /*
     377             :          * we use tevent_queue_add_optimize_empty() with allow_direct
     378             :          * in order to optimize for the empty queue case.
     379             :          */
     380     1582962 :         e = tevent_queue_add_optimize_empty(
     381             :                                 queue,
     382             :                                 ev,
     383             :                                 req,
     384             :                                 tstream_readv_pdu_queue_trigger,
     385             :                                 NULL);
     386     1582962 :         if (tevent_req_nomem(e, req)) {
     387           0 :                 return tevent_req_post(req, ev);
     388             :         }
     389     1582962 :         if (!tevent_req_is_in_progress(req)) {
     390           0 :                 return tevent_req_post(req, ev);
     391             :         }
     392             : 
     393     1575639 :         return req;
     394             : }
     395             : 
     396     1582962 : static void tstream_readv_pdu_queue_trigger(struct tevent_req *req,
     397             :                                          void *private_data)
     398             : {
     399     1582962 :         struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
     400             :                                         struct tstream_readv_pdu_queue_state);
     401        7323 :         struct tevent_req *subreq;
     402             : 
     403     1582962 :         subreq = tstream_readv_pdu_send(state,
     404             :                                         state->caller.ev,
     405             :                                         state->caller.stream,
     406             :                                         state->caller.next_vector_fn,
     407             :                                         state->caller.next_vector_private);
     408     1582962 :         if (tevent_req_nomem(subreq, req)) {
     409           0 :                 return;
     410             :         }
     411     1582962 :         tevent_req_set_callback(subreq, tstream_readv_pdu_queue_done ,req);
     412             : }
     413             : 
     414     1582961 : static void tstream_readv_pdu_queue_done(struct tevent_req *subreq)
     415             : {
     416     1582961 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     417             :                                  struct tevent_req);
     418     1582961 :         struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
     419             :                                         struct tstream_readv_pdu_queue_state);
     420        7323 :         int ret;
     421        7323 :         int sys_errno;
     422             : 
     423     1582961 :         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
     424     1582961 :         talloc_free(subreq);
     425     1582961 :         if (ret == -1) {
     426          15 :                 tevent_req_error(req, sys_errno);
     427          15 :                 return;
     428             :         }
     429     1582946 :         state->ret = ret;
     430             : 
     431     1582946 :         tevent_req_done(req);
     432             : }
     433             : 
     434     1582961 : int tstream_readv_pdu_queue_recv(struct tevent_req *req, int *perrno)
     435             : {
     436     1582961 :         struct tstream_readv_pdu_queue_state *state = tevent_req_data(req,
     437             :                                         struct tstream_readv_pdu_queue_state);
     438        7323 :         int ret;
     439             : 
     440     1582961 :         ret = tsocket_simple_int_recv(req, perrno);
     441     1582961 :         if (ret == 0) {
     442     1582946 :                 ret = state->ret;
     443             :         }
     444             : 
     445     1582961 :         tevent_req_received(req);
     446     1582961 :         return ret;
     447             : }
     448             : 
     449             : struct tstream_writev_queue_state {
     450             :         /* this structs are owned by the caller */
     451             :         struct {
     452             :                 struct tevent_context *ev;
     453             :                 struct tstream_context *stream;
     454             :                 const struct iovec *vector;
     455             :                 size_t count;
     456             :         } caller;
     457             :         int ret;
     458             : };
     459             : 
     460             : static void tstream_writev_queue_trigger(struct tevent_req *req,
     461             :                                          void *private_data);
     462             : static void tstream_writev_queue_done(struct tevent_req *subreq);
     463             : 
     464     3860024 : struct tevent_req *tstream_writev_queue_send(TALLOC_CTX *mem_ctx,
     465             :                                              struct tevent_context *ev,
     466             :                                              struct tstream_context *stream,
     467             :                                              struct tevent_queue *queue,
     468             :                                              const struct iovec *vector,
     469             :                                              size_t count)
     470             : {
     471       27428 :         struct tevent_req *req;
     472       27428 :         struct tstream_writev_queue_state *state;
     473       27428 :         struct tevent_queue_entry *e;
     474             : 
     475     3860024 :         req = tevent_req_create(mem_ctx, &state,
     476             :                                 struct tstream_writev_queue_state);
     477     3860024 :         if (!req) {
     478           0 :                 return NULL;
     479             :         }
     480             : 
     481     3860024 :         state->caller.ev     = ev;
     482     3860024 :         state->caller.stream = stream;
     483     3860024 :         state->caller.vector = vector;
     484     3860024 :         state->caller.count  = count;
     485     3860024 :         state->ret           = -1;
     486             : 
     487             :         /*
     488             :          * we use tevent_queue_add_optimize_empty() with allow_direct
     489             :          * in order to optimize for the empty queue case.
     490             :          */
     491     3860024 :         e = tevent_queue_add_optimize_empty(
     492             :                                 queue,
     493             :                                 ev,
     494             :                                 req,
     495             :                                 tstream_writev_queue_trigger,
     496             :                                 NULL);
     497     3860024 :         if (tevent_req_nomem(e, req)) {
     498           0 :                 return tevent_req_post(req, ev);
     499             :         }
     500     3860024 :         if (!tevent_req_is_in_progress(req)) {
     501           0 :                 return tevent_req_post(req, ev);
     502             :         }
     503             : 
     504     3832596 :         return req;
     505             : }
     506             : 
     507     3860009 : static void tstream_writev_queue_trigger(struct tevent_req *req,
     508             :                                          void *private_data)
     509             : {
     510     3860009 :         struct tstream_writev_queue_state *state = tevent_req_data(req,
     511             :                                         struct tstream_writev_queue_state);
     512       27425 :         struct tevent_req *subreq;
     513             : 
     514     3860009 :         subreq = tstream_writev_send(state,
     515             :                                      state->caller.ev,
     516             :                                      state->caller.stream,
     517             :                                      state->caller.vector,
     518             :                                      state->caller.count);
     519     3860009 :         if (tevent_req_nomem(subreq, req)) {
     520           0 :                 return;
     521             :         }
     522     3860009 :         tevent_req_set_callback(subreq, tstream_writev_queue_done ,req);
     523             : }
     524             : 
     525     3859923 : static void tstream_writev_queue_done(struct tevent_req *subreq)
     526             : {
     527     3859923 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     528             :                                  struct tevent_req);
     529     3859923 :         struct tstream_writev_queue_state *state = tevent_req_data(req,
     530             :                                         struct tstream_writev_queue_state);
     531       27425 :         int ret;
     532       27425 :         int sys_errno;
     533             : 
     534     3859923 :         ret = tstream_writev_recv(subreq, &sys_errno);
     535     3859923 :         talloc_free(subreq);
     536     3859923 :         if (ret == -1) {
     537          31 :                 tevent_req_error(req, sys_errno);
     538          31 :                 return;
     539             :         }
     540     3859892 :         state->ret = ret;
     541             : 
     542     3859892 :         tevent_req_done(req);
     543             : }
     544             : 
     545     3859923 : int tstream_writev_queue_recv(struct tevent_req *req, int *perrno)
     546             : {
     547     3859923 :         struct tstream_writev_queue_state *state = tevent_req_data(req,
     548             :                                         struct tstream_writev_queue_state);
     549       27425 :         int ret;
     550             : 
     551     3859923 :         ret = tsocket_simple_int_recv(req, perrno);
     552     3859923 :         if (ret == 0) {
     553     3859892 :                 ret = state->ret;
     554             :         }
     555             : 
     556     3859923 :         tevent_req_received(req);
     557     3859923 :         return ret;
     558             : }
     559             : 

Generated by: LCOV version 1.14