Coverage Report

Created: 2026-07-12 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pupnp/upnp/src/ssdp/ssdp_ctrlpt.c
Line
Count
Source
1
/**************************************************************************
2
 *
3
 * Copyright (c) 2000-2003 Intel Corporation
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright notice,
10
 * this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright notice,
12
 * this list of conditions and the following disclaimer in the documentation
13
 * and/or other materials provided with the distribution.
14
 * - Neither name of Intel Corporation nor the names of its contributors
15
 * may be used to endorse or promote products derived from this software
16
 * without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
22
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 *
30
 **************************************************************************/
31
32
/*!
33
 * \addtogroup SSDPlib
34
 *
35
 * @{
36
 *
37
 * \file
38
 */
39
40
#include "Callback.h"
41
#include "LinkedList.h"
42
#include "TimerThread.h"
43
#include "UpnpDiscovery.h"
44
#include "UpnpString.h"
45
#include "config.h"
46
47
#include "ithread.h"
48
#include "membuffer.h"
49
#include "upnp.h"
50
#include "upnpdebug.h"
51
#include "upnpdebug_internal.h"
52
#include "upnputil.h"
53
#include <errno.h>
54
#include <stdlib.h>
55
#include <string.h>
56
57
#ifndef _WIN32
58
  #include <poll.h>
59
0
  #define _poll(fds, nfds, timeout) poll(fds, nfds, timeout)
60
#endif
61
62
#ifdef INCLUDE_CLIENT_APIS
63
  #if EXCLUDE_SSDP == 0
64
65
    #include "SSDPResultData.h"
66
    #include "SSDPResultDataCallback.h"
67
    #include "ThreadPool.h"
68
    #include "UpnpInet.h"
69
    #include "httpparser.h"
70
    #include "ssdplib.h"
71
    #include "statcodes.h"
72
    #include "upnpapi.h"
73
74
    #include <stdio.h>
75
76
    #include "posix_overwrites.h" // IWYU pragma: keep
77
78
/*!
79
 * \brief Sends a callback to the control point application with a SEARCH
80
 * result.
81
 */
82
static void send_search_result(
83
  /* [in] Search reply from the device. */
84
  void *data)
85
0
{
86
0
  SSDPResultData *temp = (SSDPResultData *)data;
87
88
0
  SSDPResultData_Callback(temp);
89
0
  SSDPResultData_delete(temp);
90
0
}
91
92
void ssdp_handle_ctrlpt_msg(
93
  http_message_t *hmsg, struct sockaddr_storage *dest_addr, int timeout)
94
0
{
95
0
  int handle;
96
0
  int handle_start;
97
0
  struct Handle_Info *ctrlpt_info = NULL;
98
0
  memptr hdr_value;
99
  /* byebye or alive */
100
0
  int is_byebye;
101
0
  UpnpDiscovery *param = UpnpDiscovery_new();
102
0
  int expires;
103
0
  int ret;
104
0
  SsdpEvent event;
105
0
  int nt_found;
106
0
  int usn_found;
107
0
  int st_found;
108
0
  char save_char;
109
0
  Upnp_EventType event_type;
110
0
  Upnp_FunPtr ctrlpt_callback;
111
0
  void *ctrlpt_cookie;
112
0
  ListNode *node = NULL;
113
0
  SsdpSearchArg *searchArg = NULL;
114
0
  int matched = 0;
115
0
  SSDPResultData *threadData = NULL;
116
0
  ThreadPoolJob job;
117
118
  /* we are assuming that there can be only one client supported at a time
119
   */
120
0
  HandleReadLock(__FILE__, __LINE__);
121
122
0
  if (GetClientHandleInfo(&handle_start, &ctrlpt_info) != HND_CLIENT) {
123
0
    HandleUnlock(__FILE__, __LINE__);
124
0
    goto end_ssdp_handle_ctrlpt_msg;
125
0
  }
126
0
  HandleUnlock(__FILE__, __LINE__);
127
  /* search timeout */
128
0
  if (timeout) {
129
0
    for (handle = handle_start; handle < NUM_HANDLE; handle++) {
130
0
      HandleLock(__FILE__, __LINE__);
131
132
      /* get client info */
133
0
      if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
134
0
        HandleUnlock(__FILE__, __LINE__);
135
0
        continue;
136
0
      }
137
      /* copy */
138
0
      ctrlpt_callback = ctrlpt_info->Callback;
139
0
      ctrlpt_cookie = ctrlpt_info->Cookie;
140
0
      HandleUnlock(__FILE__, __LINE__);
141
142
0
      ctrlpt_callback(UPNP_DISCOVERY_SEARCH_TIMEOUT,
143
0
        NULL,
144
0
        ctrlpt_cookie);
145
0
    }
146
0
    goto end_ssdp_handle_ctrlpt_msg;
147
0
  }
148
149
0
  UpnpDiscovery_set_ErrCode(param, UPNP_E_SUCCESS);
150
  /* MAX-AGE, assume error */
151
0
  expires = -1;
152
0
  UpnpDiscovery_set_Expires(param, expires);
153
0
  if (httpmsg_find_hdr(hmsg, HDR_CACHE_CONTROL, &hdr_value) != NULL) {
154
0
    ret = matchstr(hdr_value.buf,
155
0
      hdr_value.length,
156
0
      "%imax-age = %d%0",
157
0
      &expires);
158
0
    UpnpDiscovery_set_Expires(param, expires);
159
0
    if (ret != PARSE_OK)
160
0
      goto end_ssdp_handle_ctrlpt_msg;
161
0
  }
162
  /* DATE */
163
0
  if (httpmsg_find_hdr(hmsg, HDR_DATE, &hdr_value) != NULL) {
164
0
    UpnpDiscovery_strcpy_Date(param, hdr_value.buf);
165
0
  }
166
  /* dest addr */
167
0
  UpnpDiscovery_set_DestAddr(param, dest_addr);
168
  /* EXT */
169
0
  if (httpmsg_find_hdr(hmsg, HDR_EXT, &hdr_value) != NULL) {
170
0
    UpnpDiscovery_strncpy_Ext(
171
0
      param, hdr_value.buf, hdr_value.length);
172
0
  }
173
  /* LOCATION */
174
0
  if (httpmsg_find_hdr(hmsg, HDR_LOCATION, &hdr_value) != NULL) {
175
0
    UpnpDiscovery_strncpy_Location(
176
0
      param, hdr_value.buf, hdr_value.length);
177
0
  }
178
  /* SERVER / USER-AGENT */
179
0
  if (httpmsg_find_hdr(hmsg, HDR_SERVER, &hdr_value) != NULL ||
180
0
    httpmsg_find_hdr(hmsg, HDR_USER_AGENT, &hdr_value) != NULL) {
181
0
    UpnpDiscovery_strncpy_Os(
182
0
      param, hdr_value.buf, hdr_value.length);
183
0
  }
184
  /* clear everything */
185
0
  event.UDN[0] = '\0';
186
0
  event.DeviceType[0] = '\0';
187
0
  event.ServiceType[0] = '\0';
188
0
  nt_found = 0;
189
0
  if (httpmsg_find_hdr(hmsg, HDR_NT, &hdr_value) != NULL) {
190
0
    save_char = hdr_value.buf[hdr_value.length];
191
0
    hdr_value.buf[hdr_value.length] = '\0';
192
0
    nt_found = (ssdp_request_type(hdr_value.buf, &event) == 0);
193
0
    hdr_value.buf[hdr_value.length] = save_char;
194
0
  }
195
0
  usn_found = 0;
196
0
  if (httpmsg_find_hdr(hmsg, HDR_USN, &hdr_value) != NULL) {
197
0
    save_char = hdr_value.buf[hdr_value.length];
198
0
    hdr_value.buf[hdr_value.length] = '\0';
199
0
    usn_found = (unique_service_name(hdr_value.buf, &event) == 0);
200
0
    hdr_value.buf[hdr_value.length] = save_char;
201
0
  }
202
0
  if (nt_found || usn_found) {
203
0
    UpnpDiscovery_strcpy_DeviceID(param, event.UDN);
204
0
    UpnpDiscovery_strcpy_DeviceType(param, event.DeviceType);
205
0
    UpnpDiscovery_strcpy_ServiceType(param, event.ServiceType);
206
0
  }
207
  /* ADVERT. OR BYEBYE */
208
0
  if (hmsg->is_request) {
209
    /* use NTS hdr to determine advert., or byebye */
210
0
    if (httpmsg_find_hdr(hmsg, HDR_NTS, &hdr_value) == NULL) {
211
      /* error; NTS header not found */
212
0
      goto end_ssdp_handle_ctrlpt_msg;
213
0
    }
214
0
    if (memptr_cmp(&hdr_value, "ssdp:alive") == 0) {
215
0
      is_byebye = 0;
216
0
    } else if (memptr_cmp(&hdr_value, "ssdp:byebye") == 0) {
217
0
      is_byebye = 1;
218
0
    } else {
219
      /* bad value */
220
0
      goto end_ssdp_handle_ctrlpt_msg;
221
0
    }
222
0
    if (is_byebye) {
223
      /* check device byebye */
224
0
      if (!nt_found || !usn_found) {
225
        /* bad byebye */
226
0
        goto end_ssdp_handle_ctrlpt_msg;
227
0
      }
228
0
      event_type = UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE;
229
0
    } else {
230
      /* check advertisement.
231
       * Expires is valid if positive. This is for testing
232
       * only. Expires should be greater than 1800 (30 mins)
233
       */
234
0
      if (!nt_found || !usn_found ||
235
0
        UpnpString_get_Length(
236
0
          UpnpDiscovery_get_Location(param)) ==
237
0
          0 ||
238
0
        UpnpDiscovery_get_Expires(param) <= 0) {
239
        /* bad advertisement */
240
0
        goto end_ssdp_handle_ctrlpt_msg;
241
0
      }
242
0
      event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE;
243
0
    }
244
    /* call callback */
245
0
    for (handle = handle_start; handle < NUM_HANDLE; handle++) {
246
0
      HandleLock(__FILE__, __LINE__);
247
248
      /* get client info */
249
0
      if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
250
0
        HandleUnlock(__FILE__, __LINE__);
251
0
        continue;
252
0
      }
253
      /* copy */
254
0
      ctrlpt_callback = ctrlpt_info->Callback;
255
0
      ctrlpt_cookie = ctrlpt_info->Cookie;
256
0
      HandleUnlock(__FILE__, __LINE__);
257
258
0
      ctrlpt_callback(event_type, param, ctrlpt_cookie);
259
0
    }
260
0
  } else {
261
    /* reply (to a SEARCH) */
262
    /* only checking to see if there is a valid ST header */
263
0
    st_found = 0;
264
0
    if (httpmsg_find_hdr(hmsg, HDR_ST, &hdr_value) != NULL) {
265
0
      save_char = hdr_value.buf[hdr_value.length];
266
0
      hdr_value.buf[hdr_value.length] = '\0';
267
0
      st_found =
268
0
        ssdp_request_type(hdr_value.buf, &event) == 0;
269
0
      hdr_value.buf[hdr_value.length] = save_char;
270
0
    }
271
0
    if (hmsg->status_code != HTTP_OK ||
272
0
      UpnpDiscovery_get_Expires(param) <= 0 ||
273
0
      UpnpString_get_Length(
274
0
        UpnpDiscovery_get_Location(param)) == 0 ||
275
0
      !usn_found || !st_found) {
276
      /* bad reply */
277
0
      goto end_ssdp_handle_ctrlpt_msg;
278
0
    }
279
    /* check each current search */
280
0
    for (handle = handle_start; handle < NUM_HANDLE; handle++) {
281
0
      HandleLock(__FILE__, __LINE__);
282
283
      /* get client info */
284
0
      if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
285
0
        HandleUnlock(__FILE__, __LINE__);
286
0
        continue;
287
0
      }
288
      /* copy */
289
0
      ctrlpt_callback = ctrlpt_info->Callback;
290
0
      ctrlpt_cookie = ctrlpt_info->Cookie;
291
292
0
      node = ListHead(&ctrlpt_info->SsdpSearchList);
293
      /* temporary add null termination */
294
      /*save_char = hdr_value.buf[ hdr_value.length ]; */
295
      /*hdr_value.buf[ hdr_value.length ] = '\0'; */
296
0
      while (node != NULL) {
297
0
        searchArg = node->item;
298
        /* check for match of ST header and search
299
         * target */
300
0
        switch (searchArg->requestType) {
301
0
        case SSDP_ALL:
302
0
          matched = 1;
303
0
          break;
304
0
        case SSDP_ROOTDEVICE:
305
0
          matched = (event.RequestType ==
306
0
               SSDP_ROOTDEVICE);
307
0
          break;
308
0
        case SSDP_DEVICEUDN:
309
0
          matched = !strncmp(
310
0
            searchArg->searchTarget,
311
0
            hdr_value.buf,
312
0
            hdr_value.length);
313
0
          break;
314
0
        case SSDP_DEVICETYPE: {
315
0
          size_t m = min(hdr_value.length,
316
0
            strlen(searchArg->searchTarget));
317
0
          matched = !strncmp(
318
0
            searchArg->searchTarget,
319
0
            hdr_value.buf,
320
0
            m);
321
0
          break;
322
0
        }
323
0
        case SSDP_SERVICE: {
324
0
          size_t m = min(hdr_value.length,
325
0
            strlen(searchArg->searchTarget));
326
0
          matched = !strncmp(
327
0
            searchArg->searchTarget,
328
0
            hdr_value.buf,
329
0
            m);
330
0
          break;
331
0
        }
332
0
        default:
333
0
          matched = 0;
334
0
          break;
335
0
        }
336
0
        if (matched) {
337
          /* schedule call back */
338
0
          threadData = SSDPResultData_new();
339
0
          if (threadData != NULL) {
340
0
            SSDPResultData_set_Param(
341
0
              threadData, param);
342
0
            SSDPResultData_set_Cookie(
343
0
              threadData,
344
0
              searchArg->cookie);
345
0
            SSDPResultData_set_CtrlptCallback(
346
0
              threadData,
347
0
              ctrlpt_callback);
348
0
            memset(&job, 0, sizeof(job));
349
350
0
            TPJobInit(&job,
351
0
              (start_routine)
352
0
                send_search_result,
353
0
              threadData);
354
0
            TPJobSetPriority(
355
0
              &job, MED_PRIORITY);
356
0
            TPJobSetFreeFunction(&job,
357
0
              (free_routine)free);
358
0
            if (ThreadPoolAdd(
359
0
                  &gRecvThreadPool,
360
0
                  &job,
361
0
                  NULL) != 0) {
362
0
              SSDPResultData_delete(
363
0
                threadData);
364
0
            }
365
0
          }
366
0
        }
367
0
        node = ListNext(
368
0
          &ctrlpt_info->SsdpSearchList, node);
369
0
      }
370
371
0
      HandleUnlock(__FILE__, __LINE__);
372
      /*ctrlpt_callback( UPNP_DISCOVERY_SEARCH_RESULT, param,
373
       * ctrlpt_cookie ); */
374
0
    }
375
0
  }
376
377
0
end_ssdp_handle_ctrlpt_msg:
378
0
  UpnpDiscovery_delete(param);
379
0
}
380
381
/*!
382
 * \brief Creates a HTTP search request packet depending on the input
383
 * parameter.
384
 */
385
static int CreateClientRequestPacket(
386
  /*! [in,out] Output string in HTTP format. */
387
  char *RqstBuf,
388
  /*! [in] RqstBuf size. */
389
  size_t RqstBufSize,
390
  /*! [in] Search Target. */
391
  int Mx,
392
  /*! [in] Number of seconds to wait to collect all the responses. */
393
  char *SearchTarget,
394
  /*! [in] search address family. */
395
  int AddressFamily)
396
0
{
397
0
  int rc;
398
0
  size_t offset = 0;
399
400
0
  switch (AddressFamily) {
401
0
  case AF_INET:
402
0
    rc = snprintf(RqstBuf,
403
0
      RqstBufSize,
404
0
      "M-SEARCH * HTTP/1.1\r\n"
405
0
      "HOST: %s:%d\r\n"
406
0
      "MAN: \"ssdp:discover\"\r\n",
407
0
      SSDP_IP,
408
0
      SSDP_PORT);
409
0
    break;
410
0
  case AF_INET6:
411
0
    rc = snprintf(RqstBuf,
412
0
      RqstBufSize,
413
0
      "M-SEARCH * HTTP/1.1\r\n"
414
0
      "HOST: [%s]:%d\r\n"
415
0
      "MAN: \"ssdp:discover\"\r\n",
416
0
      SSDP_IPV6_LINKLOCAL,
417
0
      SSDP_PORT);
418
0
    break;
419
0
  default:
420
0
    return UPNP_E_INVALID_ARGUMENT;
421
0
  }
422
0
  if (rc < 0 || (size_t)rc >= RqstBufSize)
423
0
    return UPNP_E_INTERNAL_ERROR;
424
0
  offset = (size_t)rc;
425
426
0
  if (Mx > 0) {
427
0
    rc = snprintf(RqstBuf + offset,
428
0
      RqstBufSize - offset,
429
0
      "MX: %d\r\n",
430
0
      Mx);
431
0
    if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
432
0
      return UPNP_E_BUFFER_TOO_SMALL;
433
0
    offset += (size_t)rc;
434
0
  }
435
436
0
  if (SearchTarget) {
437
0
    rc = snprintf(RqstBuf + offset,
438
0
      RqstBufSize - offset,
439
0
      "ST: %s\r\n",
440
0
      SearchTarget);
441
0
    if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
442
0
      return UPNP_E_BUFFER_TOO_SMALL;
443
0
    offset += (size_t)rc;
444
0
  }
445
446
0
  rc = snprintf(RqstBuf + offset, RqstBufSize - offset, "\r\n");
447
0
  if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
448
0
    return UPNP_E_BUFFER_TOO_SMALL;
449
450
0
  return UPNP_E_SUCCESS;
451
0
}
452
453
    /*!
454
     * \brief
455
     */
456
    #ifdef UPNP_ENABLE_IPV6
457
static int CreateClientRequestPacketUlaGua(
458
  /*! [in,out] . */
459
  char *RqstBuf,
460
  /*! [in] . */
461
  size_t RqstBufSize,
462
  /*! [in] . */
463
  int Mx,
464
  /*! [in] . */
465
  char *SearchTarget,
466
  /*! [in] . */
467
  int AddressFamily)
468
0
{
469
0
  int rc;
470
0
  size_t offset = 0;
471
472
0
  switch (AddressFamily) {
473
0
  case AF_INET:
474
0
    rc = snprintf(RqstBuf,
475
0
      RqstBufSize,
476
0
      "M-SEARCH * HTTP/1.1\r\n"
477
0
      "HOST: %s:%d\r\n"
478
0
      "MAN: \"ssdp:discover\"\r\n",
479
0
      SSDP_IP,
480
0
      SSDP_PORT);
481
0
    break;
482
0
  case AF_INET6:
483
0
    rc = snprintf(RqstBuf,
484
0
      RqstBufSize,
485
0
      "M-SEARCH * HTTP/1.1\r\n"
486
0
      "HOST: [%s]:%d\r\n"
487
0
      "MAN: \"ssdp:discover\"\r\n",
488
0
      SSDP_IPV6_SITELOCAL,
489
0
      SSDP_PORT);
490
0
    break;
491
0
  default:
492
0
    return UPNP_E_INVALID_ARGUMENT;
493
0
  }
494
0
  if (rc < 0 || (size_t)rc >= RqstBufSize)
495
0
    return UPNP_E_INTERNAL_ERROR;
496
0
  offset = (size_t)rc;
497
498
0
  if (Mx > 0) {
499
0
    rc = snprintf(RqstBuf + offset,
500
0
      RqstBufSize - offset,
501
0
      "MX: %d\r\n",
502
0
      Mx);
503
0
    if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
504
0
      return UPNP_E_BUFFER_TOO_SMALL;
505
0
    offset += (size_t)rc;
506
0
  }
507
508
0
  if (SearchTarget) {
509
0
    rc = snprintf(RqstBuf + offset,
510
0
      RqstBufSize - offset,
511
0
      "ST: %s\r\n",
512
0
      SearchTarget);
513
0
    if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
514
0
      return UPNP_E_BUFFER_TOO_SMALL;
515
0
    offset += (size_t)rc;
516
0
  }
517
518
0
  rc = snprintf(RqstBuf + offset, RqstBufSize - offset, "\r\n");
519
0
  if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
520
0
    return UPNP_E_BUFFER_TOO_SMALL;
521
522
0
  return UPNP_E_SUCCESS;
523
0
}
524
    #endif /* UPNP_ENABLE_IPV6 */
525
526
/*!
527
 * \brief
528
 */
529
static void searchExpired(
530
  /* [in] . */
531
  void *arg)
532
0
{
533
0
  int id = ((SsdpSearchExpArg *)arg)->timeoutEventId;
534
0
  int handle = ((SsdpSearchExpArg *)arg)->handle;
535
0
  struct Handle_Info *ctrlpt_info = NULL;
536
537
  /* remove search Target from list and call client back */
538
0
  ListNode *node = NULL;
539
0
  SsdpSearchArg *item;
540
0
  Upnp_FunPtr ctrlpt_callback;
541
0
  void *cookie = NULL;
542
0
  int found = 0;
543
544
0
  HandleLock(__FILE__, __LINE__);
545
546
  /* remove search target from search list */
547
0
  if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
548
0
    free(arg);
549
0
    HandleUnlock(__FILE__, __LINE__);
550
0
    return;
551
0
  }
552
0
  ctrlpt_callback = ctrlpt_info->Callback;
553
0
  node = ListHead(&ctrlpt_info->SsdpSearchList);
554
0
  while (node != NULL) {
555
0
    item = (SsdpSearchArg *)node->item;
556
0
    if (item->timeoutEventId == id) {
557
0
      free(item->searchTarget);
558
0
      cookie = item->cookie;
559
0
      found = 1;
560
0
      item->searchTarget = NULL;
561
0
      free(item);
562
0
      ListDelNode(&ctrlpt_info->SsdpSearchList, node, 0);
563
0
      break;
564
0
    }
565
0
    node = ListNext(&ctrlpt_info->SsdpSearchList, node);
566
0
  }
567
0
  HandleUnlock(__FILE__, __LINE__);
568
569
0
  if (found)
570
0
    ctrlpt_callback(UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie);
571
572
0
  free(arg);
573
0
}
574
575
int SearchByTarget(int Hnd, int Mx, char *St, void *Cookie)
576
0
{
577
0
  char errorBuffer[ERROR_BUFFER_LEN];
578
0
  int *id = NULL;
579
0
  int ret = 0;
580
0
  char ReqBufv4[BUFSIZE];
581
0
    #ifdef UPNP_ENABLE_IPV6
582
0
  char ReqBufv6[BUFSIZE];
583
0
  char ReqBufv6UlaGua[BUFSIZE];
584
0
    #endif
585
0
  struct sockaddr_storage __ss_v4;
586
0
    #ifdef UPNP_ENABLE_IPV6
587
0
  struct sockaddr_storage __ss_v6;
588
0
    #endif
589
0
  struct sockaddr_in *destAddr4 = (struct sockaddr_in *)&__ss_v4;
590
0
    #ifdef UPNP_ENABLE_IPV6
591
0
  struct sockaddr_in6 *destAddr6 = (struct sockaddr_in6 *)&__ss_v6;
592
0
    #endif
593
0
  SsdpSearchArg *newArg = NULL;
594
0
  SsdpSearchExpArg *expArg = NULL;
595
0
  int timeTillRead = 0;
596
0
  struct Handle_Info *ctrlpt_info = NULL;
597
0
  enum SsdpSearchType requestType;
598
0
  struct in_addr addrv4;
599
0
  int retVal;
600
    #ifdef _WIN32
601
  SOCKET max_fd = 0;
602
  fd_set wrSet;
603
    #else
604
0
  int numCopies;
605
0
    #endif
606
607
  /*ThreadData *ThData; */
608
0
  ThreadPoolJob job;
609
610
0
  if (strlen(gIF_IPV4) > (size_t)0 &&
611
0
    !inet_pton(AF_INET, gIF_IPV4, &addrv4)) {
612
0
    return UPNP_E_INVALID_PARAM;
613
0
  }
614
615
0
  memset(&job, 0, sizeof(job));
616
617
0
  requestType = ssdp_request_type1(St);
618
0
  if (requestType == SSDP_SERROR)
619
0
    return UPNP_E_INVALID_PARAM;
620
0
  UpnpPrintf(
621
0
    UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n");
622
0
  timeTillRead = Mx;
623
0
  if (timeTillRead < MIN_SEARCH_TIME)
624
0
    timeTillRead = MIN_SEARCH_TIME;
625
0
  else if (timeTillRead > MAX_SEARCH_TIME)
626
0
    timeTillRead = MAX_SEARCH_TIME;
627
0
  retVal = CreateClientRequestPacket(
628
0
    ReqBufv4, sizeof(ReqBufv4), timeTillRead, St, AF_INET);
629
0
  if (retVal != UPNP_E_SUCCESS)
630
0
    return retVal;
631
0
    #ifdef UPNP_ENABLE_IPV6
632
0
  retVal = CreateClientRequestPacket(
633
0
    ReqBufv6, sizeof(ReqBufv6), timeTillRead, St, AF_INET6);
634
0
  if (retVal != UPNP_E_SUCCESS)
635
0
    return retVal;
636
0
  retVal = CreateClientRequestPacketUlaGua(ReqBufv6UlaGua,
637
0
    sizeof(ReqBufv6UlaGua),
638
0
    timeTillRead,
639
0
    St,
640
0
    AF_INET6);
641
0
  if (retVal != UPNP_E_SUCCESS)
642
0
    return retVal;
643
0
    #endif
644
645
0
  memset(&__ss_v4, 0, sizeof(__ss_v4));
646
0
  destAddr4->sin_family = (sa_family_t)AF_INET;
647
0
  inet_pton(AF_INET, SSDP_IP, &destAddr4->sin_addr);
648
0
  destAddr4->sin_port = htons(SSDP_PORT);
649
650
0
    #ifdef UPNP_ENABLE_IPV6
651
0
  memset(&__ss_v6, 0, sizeof(__ss_v6));
652
0
  destAddr6->sin6_family = (sa_family_t)AF_INET6;
653
0
  inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr);
654
0
  destAddr6->sin6_port = htons(SSDP_PORT);
655
0
  destAddr6->sin6_scope_id = gIF_INDEX;
656
0
    #endif
657
658
  /* add search criteria to list */
659
0
  HandleLock(__FILE__, __LINE__);
660
0
  if (GetHandleInfo(Hnd, &ctrlpt_info) != HND_CLIENT) {
661
0
    HandleUnlock(__FILE__, __LINE__);
662
0
    return UPNP_E_INTERNAL_ERROR;
663
0
  }
664
0
  newArg = (SsdpSearchArg *)malloc(sizeof(SsdpSearchArg));
665
0
  newArg->searchTarget = strdup(St);
666
0
  newArg->cookie = Cookie;
667
0
  newArg->requestType = requestType;
668
669
0
  expArg = (SsdpSearchExpArg *)malloc(sizeof(SsdpSearchExpArg));
670
0
  expArg->handle = Hnd;
671
0
  id = (int *)&(expArg->timeoutEventId);
672
0
  TPJobInit(&job, (start_routine)searchExpired, expArg);
673
0
  TPJobSetPriority(&job, MED_PRIORITY);
674
0
  TPJobSetFreeFunction(&job, (free_routine)free);
675
  /* Schedule a timeout event to remove search Arg */
676
0
  TimerThreadSchedule(
677
0
    &gTimerThread, timeTillRead, REL_SEC, &job, SHORT_TERM, id);
678
0
  newArg->timeoutEventId = *id;
679
0
  ListAddTail(&ctrlpt_info->SsdpSearchList, newArg);
680
0
  HandleUnlock(__FILE__, __LINE__);
681
    /* End of lock */
682
683
    #ifdef _WIN32
684
  FD_ZERO(&wrSet);
685
  if (gSsdpReqSocket4 != INVALID_SOCKET) {
686
    setsockopt(gSsdpReqSocket4,
687
      IPPROTO_IP,
688
      IP_MULTICAST_IF,
689
      (char *)&addrv4,
690
      sizeof(addrv4));
691
    FD_SET(gSsdpReqSocket4, &wrSet);
692
    max_fd = max(max_fd, gSsdpReqSocket4);
693
  }
694
      #ifdef UPNP_ENABLE_IPV6
695
  if (gSsdpReqSocket6 != INVALID_SOCKET) {
696
    setsockopt(gSsdpReqSocket6,
697
      IPPROTO_IPV6,
698
      IPV6_MULTICAST_IF,
699
      (char *)&gIF_INDEX,
700
      sizeof(gIF_INDEX));
701
    FD_SET(gSsdpReqSocket6, &wrSet);
702
    max_fd = max(max_fd, gSsdpReqSocket6);
703
  }
704
      #endif
705
  ret = select((int)max_fd + 1, NULL, &wrSet, NULL, NULL);
706
  if (ret == -1) {
707
    strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
708
    UpnpPrintf(UPNP_INFO,
709
      SSDP,
710
      __FILE__,
711
      __LINE__,
712
      "SSDP_LIB: Error in select(): %s\n",
713
      errorBuffer);
714
    UpnpCloseSocket(gSsdpReqSocket4);
715
      #ifdef UPNP_ENABLE_IPV6
716
    UpnpCloseSocket(gSsdpReqSocket6);
717
      #endif
718
    return UPNP_E_INTERNAL_ERROR;
719
  }
720
      #ifdef UPNP_ENABLE_IPV6
721
  if (gSsdpReqSocket6 != INVALID_SOCKET &&
722
    FD_ISSET(gSsdpReqSocket6, &wrSet)) {
723
    int NumCopy = 0;
724
    while (NumCopy < NUM_SSDP_COPY) {
725
      UpnpPrintf(UPNP_INFO,
726
        SSDP,
727
        __FILE__,
728
        __LINE__,
729
        ">>> SSDP SEND M-SEARCH >>>\n%s\n",
730
        ReqBufv6UlaGua);
731
      sendto(gSsdpReqSocket6,
732
        ReqBufv6UlaGua,
733
        (int)strlen(ReqBufv6UlaGua),
734
        0,
735
        (struct sockaddr *)&__ss_v6,
736
        sizeof(struct sockaddr_in6));
737
      imillisleep(SSDP_PAUSE);
738
      NumCopy++;
739
    }
740
    NumCopy = 0;
741
    inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr);
742
    while (NumCopy < NUM_SSDP_COPY) {
743
      UpnpPrintf(UPNP_INFO,
744
        SSDP,
745
        __FILE__,
746
        __LINE__,
747
        ">>> SSDP SEND M-SEARCH >>>\n%s\n",
748
        ReqBufv6);
749
      sendto(gSsdpReqSocket6,
750
        ReqBufv6,
751
        (int)strlen(ReqBufv6),
752
        0,
753
        (struct sockaddr *)&__ss_v6,
754
        sizeof(struct sockaddr_in6));
755
      imillisleep(SSDP_PAUSE);
756
      NumCopy++;
757
    }
758
  }
759
      #endif /* IPv6 */
760
  if (gSsdpReqSocket4 != INVALID_SOCKET &&
761
    FD_ISSET(gSsdpReqSocket4, &wrSet)) {
762
    int NumCopy = 0;
763
    while (NumCopy < NUM_SSDP_COPY) {
764
      UpnpPrintf(UPNP_INFO,
765
        SSDP,
766
        __FILE__,
767
        __LINE__,
768
        ">>> SSDP SEND M-SEARCH >>>\n%s\n",
769
        ReqBufv4);
770
      sendto(gSsdpReqSocket4,
771
        ReqBufv4,
772
        (int)strlen(ReqBufv4),
773
        0,
774
        (struct sockaddr *)&__ss_v4,
775
        sizeof(struct sockaddr_in));
776
      imillisleep(SSDP_PAUSE);
777
      NumCopy++;
778
    }
779
  }
780
    #else /* _WIN32 */
781
0
  {
782
0
    struct pollfd fds[2];
783
0
    nfds_t nfds = 0;
784
785
0
    if (gSsdpReqSocket4 != INVALID_SOCKET) {
786
0
      setsockopt(gSsdpReqSocket4,
787
0
        IPPROTO_IP,
788
0
        IP_MULTICAST_IF,
789
0
        (char *)&addrv4,
790
0
        sizeof(addrv4));
791
0
      fds[nfds].fd = gSsdpReqSocket4;
792
0
      fds[nfds].events = POLLOUT;
793
0
      nfds++;
794
0
    }
795
0
      #ifdef UPNP_ENABLE_IPV6
796
0
    if (gSsdpReqSocket6 != INVALID_SOCKET) {
797
0
      setsockopt(gSsdpReqSocket6,
798
0
        IPPROTO_IPV6,
799
0
        IPV6_MULTICAST_IF,
800
0
        (char *)&gIF_INDEX,
801
0
        sizeof(gIF_INDEX));
802
0
      fds[nfds].fd = gSsdpReqSocket6;
803
0
      fds[nfds].events = POLLOUT;
804
0
      nfds++;
805
0
    }
806
0
      #endif
807
0
    ret = _poll(fds, nfds, -1);
808
0
    if (ret == -1) {
809
0
      strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
810
0
      UpnpPrintf(UPNP_INFO,
811
0
        SSDP,
812
0
        __FILE__,
813
0
        __LINE__,
814
0
        "SSDP_LIB: Error in _poll(): %s\n",
815
0
        errorBuffer);
816
0
      UpnpCloseSocket(gSsdpReqSocket4);
817
0
      #ifdef UPNP_ENABLE_IPV6
818
0
      UpnpCloseSocket(gSsdpReqSocket6);
819
0
      #endif
820
0
      return UPNP_E_INTERNAL_ERROR;
821
0
    }
822
0
      #ifdef UPNP_ENABLE_IPV6
823
0
    if (gSsdpReqSocket6 != INVALID_SOCKET &&
824
0
      (fds[nfds - 1].revents & POLLOUT)) {
825
0
      for (numCopies = 0; numCopies < NUM_SSDP_COPY;
826
0
        numCopies++) {
827
0
        UpnpPrintf(UPNP_INFO,
828
0
          SSDP,
829
0
          __FILE__,
830
0
          __LINE__,
831
0
          ">>> SSDP SEND M-SEARCH >>>\n%s\n",
832
0
          ReqBufv6UlaGua);
833
0
        sendto(gSsdpReqSocket6,
834
0
          ReqBufv6UlaGua,
835
0
          strlen(ReqBufv6UlaGua),
836
0
          0,
837
0
          (struct sockaddr *)&__ss_v6,
838
0
          sizeof(struct sockaddr_in6));
839
0
        imillisleep(SSDP_PAUSE);
840
0
      }
841
0
      inet_pton(AF_INET6,
842
0
        SSDP_IPV6_LINKLOCAL,
843
0
        &destAddr6->sin6_addr);
844
0
      for (numCopies = 0; numCopies < NUM_SSDP_COPY;
845
0
        numCopies++) {
846
0
        UpnpPrintf(UPNP_INFO,
847
0
          SSDP,
848
0
          __FILE__,
849
0
          __LINE__,
850
0
          ">>> SSDP SEND M-SEARCH >>>\n%s\n",
851
0
          ReqBufv6);
852
0
        sendto(gSsdpReqSocket6,
853
0
          ReqBufv6,
854
0
          strlen(ReqBufv6),
855
0
          0,
856
0
          (struct sockaddr *)&__ss_v6,
857
0
          sizeof(struct sockaddr_in6));
858
0
        imillisleep(SSDP_PAUSE);
859
0
      }
860
0
    }
861
0
      #endif /* IPv6 */
862
0
    if (gSsdpReqSocket4 != INVALID_SOCKET &&
863
0
      (fds[0].revents & POLLOUT)) {
864
0
      for (numCopies = 0; numCopies < NUM_SSDP_COPY;
865
0
        numCopies++) {
866
0
        UpnpPrintf(UPNP_INFO,
867
0
          SSDP,
868
0
          __FILE__,
869
0
          __LINE__,
870
0
          ">>> SSDP SEND M-SEARCH >>>\n%s\n",
871
0
          ReqBufv4);
872
0
        sendto(gSsdpReqSocket4,
873
0
          ReqBufv4,
874
0
          strlen(ReqBufv4),
875
0
          0,
876
0
          (struct sockaddr *)&__ss_v4,
877
0
          sizeof(struct sockaddr_in));
878
0
        imillisleep(SSDP_PAUSE);
879
0
      }
880
0
    }
881
0
  }
882
0
    #endif         /* _WIN32 */
883
0
  return 1;
884
0
}
885
  #endif /* EXCLUDE_SSDP */
886
#endif         /* INCLUDE_CLIENT_APIS */
887
888
/* @} SSDPlib */