LCOV - code coverage report
Current view: top level - libcli/echo - echo.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 46 73 63.0 %
Date: 2024-04-21 15:09:00 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Echo example async client library
       5             : 
       6             :    Copyright (C) 2010 Kai Blin  <kai@samba.org>
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "replace.h"
      23             : #include "system/network.h"
      24             : #include <tevent.h>
      25             : #include "lib/tsocket/tsocket.h"
      26             : #include "libcli/util/ntstatus.h"
      27             : #include "libcli/echo/libecho.h"
      28             : #include "lib/util/tevent_ntstatus.h"
      29             : #include "libcli/util/error.h"
      30             : 
      31             : /*
      32             :  * Following the Samba convention for async functions, set up a state struct
      33             :  * for this set of calls. The state is always called function_name_state for
      34             :  * the set of async functions related to function_name_send().
      35             :  */
      36             : struct echo_request_state {
      37             :         struct tevent_context *ev;
      38             :         ssize_t orig_len;
      39             :         struct tdgram_context *dgram;
      40             :         char *message;
      41             : };
      42             : 
      43             : /* Declare callback functions used below. */
      44             : static void echo_request_get_reply(struct tevent_req *subreq);
      45             : static void echo_request_done(struct tevent_req *subreq);
      46             : 
      47           1 : struct tevent_req *echo_request_send(TALLOC_CTX *mem_ctx,
      48             :                                      struct tevent_context *ev,
      49             :                                      const char *server_addr_string,
      50             :                                      const char *message)
      51             : {
      52           0 :         struct tevent_req *req, *subreq;
      53           0 :         struct echo_request_state *state;
      54           0 :         struct tsocket_address *local_addr, *server_addr;
      55           0 :         struct tdgram_context *dgram;
      56           0 :         int ret;
      57             : 
      58             :         /*
      59             :          * Creating the initial tevent_req is the only place where returning
      60             :          * NULL is allowed. Everything after that should return a more
      61             :          * meaningful error using tevent_req_post().
      62             :          */
      63           1 :         req = tevent_req_create(mem_ctx, &state, struct echo_request_state);
      64           1 :         if (req == NULL) {
      65           0 :                 return NULL;
      66             :         }
      67             : 
      68             :         /*
      69             :          * We need to dispatch new async functions in the callbacks, hold
      70             :          * on to the event context.
      71             :          */
      72           1 :         state->ev = ev;
      73             : 
      74             :         /* libecho uses connected UDP sockets, take care of this here */
      75           1 :         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
      76             :                                                 &local_addr);
      77           1 :         if (ret != 0) {
      78           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
      79           0 :                 return tevent_req_post(req, ev);
      80             :         }
      81             : 
      82           1 :         ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
      83             :                                                 ECHO_PORT, &server_addr);
      84           1 :         if (ret != 0) {
      85           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
      86           0 :                 return tevent_req_post(req, ev);
      87             :         }
      88             : 
      89           1 :         ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
      90           1 :         if (ret != 0) {
      91           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
      92           0 :                 return tevent_req_post(req, ev);
      93             :         }
      94             : 
      95           1 :         state->dgram = dgram;
      96           1 :         state->orig_len = strlen(message) + 1;
      97             : 
      98             :         /* Start of a subrequest for the actual data sending */
      99           1 :         subreq = tdgram_sendto_send(state, ev, dgram,
     100             :                                     (const uint8_t *) message,
     101           1 :                                     state->orig_len, NULL);
     102           1 :         if (tevent_req_nomem(subreq, req)) {
     103           0 :                 return tevent_req_post(req, ev);
     104             :         }
     105             : 
     106             :         /*
     107             :          * And tell tevent what to call when the subreq is done. Note that the
     108             :          * original req structure is passed into the callback as callback data.
     109             :          * This is used to get to the state struct in callbacks.
     110             :          */
     111           1 :         tevent_req_set_callback(subreq, echo_request_get_reply, req);
     112           1 :         return req;
     113             : }
     114             : 
     115             : /*
     116             :  * The following two callbacks both demonstrate the way of getting back the
     117             :  * state struct in a callback function.
     118             :  */
     119             : 
     120           1 : static void echo_request_get_reply(struct tevent_req *subreq)
     121             : {
     122             :         /* Get the parent request struct from the callback data */
     123           1 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     124             :                                                 struct tevent_req);
     125             :         /* And get the state struct from the parent request struct */
     126           1 :         struct echo_request_state *state = tevent_req_data(req,
     127             :                                                 struct echo_request_state);
     128           0 :         ssize_t len;
     129           1 :         int err = 0;
     130             : 
     131           1 :         len = tdgram_sendto_recv(subreq, &err);
     132           1 :         TALLOC_FREE(subreq);
     133             : 
     134           1 :         if (len == -1 && err != 0) {
     135           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(err));
     136           0 :                 return;
     137             :         }
     138             : 
     139           1 :         if (len != state->orig_len) {
     140           0 :                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_NETWORK_ERROR);
     141           0 :                 return;
     142             :         }
     143             : 
     144             :         /* Send off the second subreq here, this time to receive the reply */
     145           1 :         subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
     146           1 :         if (tevent_req_nomem(subreq, req)) {
     147           0 :                 return;
     148             :         }
     149             : 
     150             :         /* And set the new callback */
     151           1 :         tevent_req_set_callback(subreq, echo_request_done, req);
     152           1 :         return;
     153             : }
     154             : 
     155           1 : static void echo_request_done(struct tevent_req *subreq)
     156             : {
     157           1 :         struct tevent_req *req = tevent_req_callback_data(subreq,
     158             :                                                 struct tevent_req);
     159           1 :         struct echo_request_state *state = tevent_req_data(req,
     160             :                                                 struct echo_request_state);
     161             : 
     162           0 :         ssize_t len;
     163           1 :         int err = 0;
     164             : 
     165           1 :         len = tdgram_recvfrom_recv(subreq, &err, state,
     166           1 :                                    (uint8_t **)&state->message,
     167             :                                    NULL);
     168           1 :         TALLOC_FREE(subreq);
     169             : 
     170           1 :         if (len == -1 && err != 0) {
     171           0 :                 tevent_req_nterror(req, map_nt_error_from_unix_common(err));
     172           0 :                 return;
     173             :         }
     174             : 
     175           1 :         if (len != state->orig_len) {
     176           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     177           0 :                 return;
     178             :         }
     179             : 
     180           1 :         state->message[len-1] = '\0';
     181             :         /* Once the async function has completed, set tevent_req_done() */
     182           1 :         tevent_req_done(req);
     183             : }
     184             : 
     185             : /*
     186             :  * In the recv function, we usually need to move the data from the state struct
     187             :  * to the memory area owned by the caller. Also, the function
     188             :  * tevent_req_received() is called to take care of freeing the memory still
     189             :  * associated with the request.
     190             :  */
     191             : 
     192           1 : NTSTATUS echo_request_recv(struct tevent_req *req,
     193             :                            TALLOC_CTX *mem_ctx,
     194             :                            char **message)
     195             : {
     196           1 :         struct echo_request_state *state = tevent_req_data(req,
     197             :                         struct echo_request_state);
     198           0 :         NTSTATUS status;
     199             : 
     200           1 :         if (tevent_req_is_nterror(req, &status)) {
     201           0 :                 tevent_req_received(req);
     202           0 :                 return status;
     203             :         }
     204             : 
     205           1 :         *message = talloc_move(mem_ctx, &state->message);
     206           1 :         tevent_req_received(req);
     207             : 
     208           1 :         return NT_STATUS_OK;
     209             : }

Generated by: LCOV version 1.14