LIBSSDP
 All Classes Files Functions Variables Typedefs Macros
ssdp_message.c
Go to the documentation of this file.
1 
5 #include <ctype.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <time.h>
10 
11 // TODO: move network knowledge to separate file
12 #include <unistd.h> // close()
13 #include <arpa/inet.h> // inet_pton()
14 
15 #include "common_definitions.h"
16 #include "configuration.h"
17 #include "net_definitions.h"
18 #include "net_utils.h"
19 #include "socket_helpers.h"
20 #include "ssdp_message.h"
21 #include "ssdp_static_defs.h"
22 #include "string_utils.h"
23 #include "log.h"
24 
33 static unsigned char get_header_type(const char *header_string) {
34  int headers_size;
35  int header_string_length = 0;
36  char *header_lower = NULL;
37  const char *header_strings[] = {
38  SSDP_HEADER_UNKNOWN_STR,
39  SSDP_HEADER_HOST_STR,
40  SSDP_HEADER_ST_STR,
41  SSDP_HEADER_MAN_STR,
42  SSDP_HEADER_MX_STR,
43  SSDP_HEADER_CACHE_STR,
44  SSDP_HEADER_LOCATION_STR,
45  SSDP_HEADER_HOST_STR,
46  SSDP_HEADER_OPT_STR,
47  SSDP_HEADER_01NLS_STR,
48  SSDP_HEADER_NT_STR,
49  SSDP_HEADER_NTS_STR,
50  SSDP_HEADER_SERVER_STR,
51  SSDP_HEADER_XUSERAGENT_STR,
52  SSDP_HEADER_USN_STR
53  };
54  headers_size = sizeof(header_strings)/sizeof(char *);
55 
56  header_string_length = strlen(header_string);
57  if(header_string_length < 1) {
58  PRINT_ERROR("Erroneous header string detected");
59  return (unsigned char)SSDP_HEADER_UNKNOWN;
60  }
61  header_lower = (char *)malloc(sizeof(char) * (header_string_length + 1));
62 
63  memset(header_lower, '\0', sizeof(char) * (header_string_length + 1));
64 
65  int i;
66  for(i = 0; header_string[i] != '\0'; i++){
67  header_lower[i] = tolower(header_string[i]);
68  }
69 
70  for(i = 0; i < headers_size; i++) {
71  if(strcmp(header_lower, header_strings[i]) == 0) {
72  free(header_lower);
73  return (unsigned char)i;
74  }
75  }
76  free(header_lower);
77  return (unsigned char)SSDP_HEADER_UNKNOWN;
78 }
79 
86 static void build_ssdp_header(ssdp_header_s *header, const char *raw_header) {
87  /*
88  [172.26.150.15][458B] "NOTIFY * HTTP/1.1
89  HOST: 239.255.255.250:1900
90  CACHE-CONTROL: max-age=1800
91  LOCATION: http://172.26.150.15:49154/rootdesc1.xml
92  OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01
93  01-NLS: 1966d9e6-1dd2-11b2-aa65-a2d9092ea049
94  NT: urn:axis-com:service:BasicService:1
95  NTS: ssdp:alive
96  SERVER: Linux/3.4.0, UPnP/1.0, Portable SDK for UPnP devices/1.6.18
97  X-User-Agent: redsonic
98  USN: uuid:Upnp-BasicDevice-1_0-00408C184D0E::urn:axis-com:service:BasicService:1
99 
100  "
101  */
102  int header_name_length = -1, header_contents_length = -1;
103  int raw_header_length = 0;
104  char *header_name;
105 
106  header_name_length = strpos(raw_header, ":");
107  if(header_name_length < 1) {
108  return;
109  }
110  header_name = (char *)malloc(header_name_length + 1);
111  memset(header_name, '\0', header_name_length + 1);
112  strncpy(header_name, raw_header, header_name_length);
113 
114  header->type = (unsigned char)get_header_type(header_name);
115  if(header->type == SSDP_HEADER_UNKNOWN) {
116  header->unknown_type = malloc(header_name_length + 1);
117  memset(header->unknown_type, '\0', header_name_length + 1);
118  strcpy(header->unknown_type, header_name);
119  }
120  else {
121  header->unknown_type = NULL;
122  }
123 
124  raw_header_length = strlen(raw_header);
125  header_contents_length = raw_header_length - header_name_length + 2;
126  header->contents = (char *)malloc(header_contents_length);
127  memset(header->contents, '\0', header_contents_length);
128  // avoid ": " in header contents
129  strcpy(header->contents, &raw_header[header_name_length + 1 +
130  (raw_header[header_name_length + 2] == ' ' ? 1 : 0)]);
131  free(header_name);
132 }
133 
135  const char *custom_field) {
136  ssdp_custom_field_s *cf = NULL;
137 
138  if(ssdp_message && custom_field) {
139  cf = ssdp_message->custom_fields;
140 
141  /* Loop through the custom-fields */
142  while(cf) {
143 
144  /* If anyone matches return its value */
145  if(0 == strcmp(custom_field, cf->name)) {
146  return cf;
147  }
148 
149  cf = cf->next;
150  }
151 
152  }
153 
154  return NULL;
155 }
156 
158  int bytes_received = 0;
159  char *location_header = NULL;
160  ssdp_header_s *ssdp_headers = ssdp_message->headers;
161 
162  if(ssdp_message->custom_fields) {
163  PRINT_DEBUG("Custom info has already been fetched for this device");
164  return 1;
165  }
166 
167  if(!ssdp_headers) {
168  PRINT_ERROR("Missing headers, cannot fetch custom info");
169  return 0;
170  }
171 
172  while(ssdp_headers) {
173  if(ssdp_headers->type == SSDP_HEADER_LOCATION) {
174  location_header = ssdp_headers->contents;
175  // Ex. location_header:
176  //http://10.83.128.46:2869/upnphost/udhisapi.dll?content=uuid:59e293c8-9179-4efb-ac32-3c9514238505
177  PRINT_DEBUG("found header_location: %s", location_header);
178  }
179  ssdp_headers = ssdp_headers->next;
180  }
181  ssdp_headers = NULL;
182 
183  if(location_header != NULL) {
184 
185  /* URL parsing allocations*/
186  PRINT_DEBUG("allocating for URL parsing");
187  char *ip = (char *)malloc(sizeof(char) * IPv6_STR_MAX_SIZE);
188  int port = 0;
189  char *rest = (char *)malloc(sizeof(char) * 256);
190  char *request = (char *)malloc(sizeof(char) * 1024); // 1KB
191  char *response = (char *)malloc(sizeof(char) * DEVICE_INFO_SIZE); // 8KB
192  memset(ip, '\0', IPv6_STR_MAX_SIZE);
193  memset(rest, '\0', 256);
194  memset(request, '\0', 1024);
195  memset(response, '\0', DEVICE_INFO_SIZE);
196 
197  /* Try to parse the location_header URL */
198  PRINT_DEBUG("trying to parse URL");
199  if(parse_url(location_header, ip, IPv6_STR_MAX_SIZE, &port, rest, 256)) {
200 
201  /* Create socket */
202  PRINT_DEBUG("creating socket");
203 
204  socket_conf_s sock_conf = {
205  conf->use_ipv6,
206  FALSE,
207  FALSE,
208  conf->interface,
209  conf->ip,
210  NULL,
211  NULL,
212  0,
213  FALSE,
214  0,
215  FALSE,
216  conf->ttl,
217  conf->enable_loopback
218  };
219  SOCKET fetch_sock = setup_socket(&sock_conf);
220 
221  if(fetch_sock == SOCKET_ERROR) {
222  PRINT_ERROR("fetch_custom_fields(); setup_socket(): (%d) %s", errno, strerror(errno));
223  free(ip);
224  free(rest);
225  free(request);
226  free(response);
227  return 0;
228  }
229 
230  if(set_receive_timeout(fetch_sock, 5) ||
231  set_send_timeout(fetch_sock, 1)) {
232  free(ip);
233  close(fetch_sock);
234  free(rest);
235  free(request);
236  free(response);
237  return 0;
238  }
239 
240  /* Setup socket destination address */
241  PRINT_DEBUG("setting up socket addresses");
242  struct sockaddr_storage *da = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
243  memset(da, 0, sizeof(struct sockaddr_storage));
244  da->ss_family = conf->use_ipv6 ? AF_INET6 : AF_INET;
245  if(!inet_pton(da->ss_family, ip, (da->ss_family == AF_INET ? (void *)&((struct sockaddr_in *)da)->sin_addr : (void *)&((struct sockaddr_in6 *)da)->sin6_addr))) {
246  int ip_length = strlen(ip);
247  if(ip_length < 1) {
248  PRINT_ERROR("The destination IP address could be determined (%s)\n", (ip_length < 1 ? "empty" : ip));
249  }
250  free(ip);
251  close(fetch_sock);
252  free(rest);
253  free(request);
254  free(response);
255  free(da);
256  return 0;
257  }
258 
259  if(da->ss_family == AF_INET) {
260  struct sockaddr_in *da_ipv4 = (struct sockaddr_in *)da;
261  da_ipv4->sin_port = htons(port);
262  }
263  else {
264  struct sockaddr_in6 *da_ipv6 = (struct sockaddr_in6 *)da;
265  da_ipv6->sin6_port = htons(port);
266  }
267 
268  /* Connect socket to destination */
269  #ifdef DEBUG___
270  char *tmp_ip = (char *)malloc(sizeof(char) * IPv6_STR_MAX_SIZE);
271  memset(tmp_ip, '\0', IPv6_STR_MAX_SIZE);
272  inet_ntop(da->ss_family, (da->ss_family == AF_INET ? (void *)&((struct sockaddr_in *)da)->sin_addr : (void *)&((struct sockaddr_in6 *)da)->sin6_addr), tmp_ip, IPv6_STR_MAX_SIZE);
273  PRINT_DEBUG("connecting to destination (%s; ss_family = %s [%d])", tmp_ip, (da->ss_family == AF_INET ? "AF_INET" : "AF_INET6"), da->ss_family);
274  free(tmp_ip);
275  tmp_ip = NULL;
276  #endif
277  if(connect(fetch_sock, (struct sockaddr*)da, sizeof(struct sockaddr)) == SOCKET_ERROR) {
278  PRINT_ERROR("fetch_custom_fields(); connect(): (%d) %s", errno, strerror(errno));
279  free(ip);
280  close(fetch_sock);
281  free(rest);
282  free(request);
283  free(response);
284  free(da);
285  return 0;
286  }
287 
288  free(da);
289  int used_length = 0;
290  /*
291  GET </path/file.html> HTTP/1.0\r\n
292  Host: <own_ip>\r\n
293  User-Agent: abused-<X>\r\n
294  \r\n
295  */
296  used_length += snprintf(request + used_length, 1024 - used_length, "GET %s HTTP/1.0\r\n", rest);
297  used_length += snprintf(request + used_length, 1024 - used_length, "Host: %s\r\n", ip);
298  snprintf(request + used_length, 1024 - used_length, "User-Agent: abused-%s\r\n\r\n", ABUSED_VERSION);
299  PRINT_DEBUG("sending string:\n%s", request);
300  int bytes = send(fetch_sock, request, strlen(request), 0);
301  PRINT_DEBUG("sent %d bytes", bytes);
302  do {
303  bytes = 0;
304  bytes = recv(fetch_sock, response + bytes_received, DEVICE_INFO_SIZE - bytes_received, 0);
305  bytes_received += bytes;
306  } while(bytes > 0);
307  PRINT_DEBUG("received %d bytes", bytes_received);
308  PRINT_DEBUG("%s", response);
309  PRINT_DEBUG("closing socket");
310  close(fetch_sock);
311  free(ip);
312  free(rest);
313  free(request);
314 
315  /* Init the ssdp_custom_field struct */
316  int i;
317  char *tmp_pointer = NULL;
318  int buffer_size = 0;
319 
320  const char *field[] = {
321  "serialNumber",
322  "friendlyName",
323  "manufacturer",
324  "manufacturerURL",
325  "modelName",
326  "modelNumber",
327  "modelURL"
328  };
329  int fields_size = sizeof(field) / sizeof(char *);
330  PRINT_DEBUG("fields_size: %d", fields_size);
331 
332  for(i = 0; i < fields_size; i++) {
333  ssdp_custom_field_s *cf = NULL;
334 
335  int field_length = strlen(field[i]);
336 
337  char needle[field_length + 4];
338  sprintf(needle, "<%s>", field[i]);
339  tmp_pointer = strstr(response, needle);
340 
341  if(tmp_pointer) {
342 
343  /* Create a new ssdp_custom_field_s */
344  cf = (ssdp_custom_field_s *)malloc(sizeof(ssdp_custom_field_s));
345  memset(cf, 0, sizeof(ssdp_custom_field_s));
346 
347  /* Set 'name' */
348  cf->name = (char *)malloc(sizeof(char) * field_length + 1);
349  strcpy(cf->name, field[i]);
350 
351  /* Parse 'contents' */
352  sprintf(needle, "</%s>", field[i]);
353  buffer_size = (int)(strstr(response, needle) - (tmp_pointer + field_length + 2) + 1);
354  cf->contents = (char *)malloc(sizeof(char) * buffer_size);
355  memset(cf->contents, '\0', buffer_size);
356  strncpy(cf->contents, (tmp_pointer + field_length + 2), buffer_size - 1);
357 
358  PRINT_DEBUG("Found expected custom field (%d) '%s' with value '%s'",
359  ssdp_message->custom_field_count,
360  cf->name,
361  cf->contents);
362  }
363  else {
364  PRINT_DEBUG("Expected custom field '%s' is missing", field[i]);
365  continue;
366  }
367 
368  /* If it is the first one then set this as the
369  start and set 'first' to it */
370  if(!ssdp_message->custom_fields) {
371  cf->first = cf;
372  }
373  /* Else set 'first' to previous 'first'
374  and this one as 'next' */
375  else {
376  cf->first = ssdp_message->custom_fields->first;
377  ssdp_message->custom_fields->next = cf;
378  }
379 
380  /* Add the custom field array to the ssdp_message */
381  ssdp_message->custom_fields = cf;
382 
383  /* Tell ssdp_message that we added one ssdp_custom_field_s */
384  ssdp_message->custom_field_count++;
385 
386  }
387 
388  if(ssdp_message->custom_fields) {
389  /* End the linked list and reset the pointer to the beginning */
390  ssdp_message->custom_fields->next = NULL;
391  ssdp_message->custom_fields = ssdp_message->custom_fields->first;
392  }
393 
394  }
395 
396  free(response);
397  }
398 
399  return bytes_received;
400 }
401 
402 const char *get_header_string(const unsigned int header_type,
403  const ssdp_header_s *header) {
404  const char *header_strings[] = {
405  SSDP_HEADER_UNKNOWN_STR,
406  SSDP_HEADER_HOST_STR,
407  SSDP_HEADER_ST_STR,
408  SSDP_HEADER_MAN_STR,
409  SSDP_HEADER_MX_STR,
410  SSDP_HEADER_CACHE_STR,
411  SSDP_HEADER_LOCATION_STR,
412  SSDP_HEADER_HOST_STR,
413  SSDP_HEADER_OPT_STR,
414  SSDP_HEADER_01NLS_STR,
415  SSDP_HEADER_NT_STR,
416  SSDP_HEADER_NTS_STR,
417  SSDP_HEADER_SERVER_STR,
418  SSDP_HEADER_XUSERAGENT_STR,
419  SSDP_HEADER_USN_STR
420  };
421 
422  if((header_type == 0 ||
423  (header_type > (sizeof(header_strings)/sizeof(char *) - 1))) &&
424  header != NULL && header->unknown_type != NULL) {
425  return header->unknown_type;
426  }
427 
428  return header_strings[header_type];
429 }
430 
432  if(NULL == *message_pointer) {
433  *message_pointer = malloc(sizeof(ssdp_message_s));
434  if(!*message_pointer) {
435  return FALSE;
436  }
437  memset(*message_pointer, 0, sizeof(ssdp_message_s));
438  }
439  ssdp_message_s *message = *message_pointer;
440  message->mac = (char *)malloc(sizeof(char) * MAC_STR_MAX_SIZE);
441  if(NULL == message->mac) {
442  free(message);
443  return FALSE;
444  }
445  memset(message->mac, '\0', MAC_STR_MAX_SIZE);
446  message->ip = (char *)malloc(sizeof(char) * IPv6_STR_MAX_SIZE);
447  if(NULL == message->ip) {
448  free(message->mac);
449  free(message);
450  return TRUE;
451  }
452  memset(message->ip, '\0', IPv6_STR_MAX_SIZE);
453  message->datetime = (char *)malloc(sizeof(char) * 20);
454  if(NULL == message->datetime) {
455  free(message->mac);
456  free(message->ip);
457  free(message);
458  return TRUE;
459  }
460  memset(message->datetime, '\0', 20);
461  message->request = (char *)malloc(sizeof(char) * 1024);
462  if(NULL == message->request) {
463  free(message->mac);
464  free(message->ip);
465  free(message->datetime);
466  free(message);
467  return FALSE;
468  }
469  memset(message->request, '\0', 1024);
470  message->protocol = (char *)malloc(sizeof(char) * 48);
471  if(NULL == message->protocol) {
472  free(message->mac);
473  free(message->ip);
474  free(message->datetime);
475  free(message->request);
476  free(message);
477  return FALSE;
478  }
479  memset(message->protocol, '\0', sizeof(char) * 48);
480  message->answer = (char *)malloc(sizeof(char) * 1024);
481  if(NULL == message->answer) {
482  free(message->mac);
483  free(message->ip);
484  free(message->datetime);
485  free(message->request);
486  free(message->protocol);
487  free(message);
488  return FALSE;
489  }
490  memset(message->answer, '\0', sizeof(char) * 1024);
491  message->info = NULL;
492  message->message_length = 0;
493  message->header_count = 0;
494 
495  return TRUE;
496 }
497 
498 BOOL build_ssdp_message(ssdp_message_s *message, char *ip, char *mac,
499  int message_length, const char *raw_message) {
500  char *raw_header;
501  int newline = 0, last_newline = 0;
502  int raw_message_left = strlen(raw_message);
503  time_t t;
504 
505  t = time(NULL);
506  strftime(message->datetime, 20, "%Y-%m-%d %H:%M:%S", localtime(&t));
507 
508  if(mac) {
509  strncpy(message->mac, mac, MAC_STR_MAX_SIZE);
510  }
511 
512  if(ip) {
513  strncpy(message->ip, ip, IPv6_STR_MAX_SIZE);
514  }
515  message->message_length = message_length;
516 
517  /* find end of request string */
518  last_newline = strpos(raw_message, "\r\n");
519  if(last_newline < 0) {
520  PRINT_DEBUG("build_ssdp_message() failed: last_newline < 0");
521  return FALSE;
522  }
523 
524  /* get past request string, point at first header row */
525  last_newline += 2;
526 
527  /* save request string and protocol */
528  /* TODO: make it search and save
529  * http-answer if present too
530  * eg. in "HTTP/1.1 200 OK",
531  * see if next is not newline and space
532  * and then save all the way to newline.
533  */
534  newline = strpos(raw_message, "HTTP");
535  if(newline < 0) {
536  free(message->datetime);
537  PRINT_DEBUG("build_ssdp_message() failed: newline < 0");
538  return FALSE;
539  }
540  strncpy(message->request, raw_message, (!newline? newline : newline - 1));
541  strncpy(message->protocol, &raw_message[newline], last_newline - 2 - newline);
542 
543  /* allocate starting header heap */
544  message->headers = (ssdp_header_s *)malloc(sizeof(ssdp_header_s));
545  message->headers->first = message->headers;
546 
547  BOOL has_next_header = TRUE;
548 
549  do {
550  int pos;
551 
552  /* find where new header ends in raw message */
553  pos = strpos(&raw_message[last_newline], "\r\n");
554  if(pos < 0) {
555  free(message->datetime);
556  PRINT_DEBUG("build_ssdp_message() failed: pos < 0");
557  return FALSE;
558  }
559  newline = last_newline + pos;
560  /* allocate new raw header (header name, contents and '\0') heap */
561  raw_header = (char *)malloc(sizeof(char) * (newline - last_newline + 1));
562  /* fill it with row from raw_message */
563  memset(raw_header, '\0', (newline - last_newline + 1));
564  strncpy(raw_header, &raw_message[last_newline], newline - last_newline);
565 
566  /* now lets go and build the header struct */
567  build_ssdp_header(message->headers, raw_header);
568  if(message->headers->contents) {
569  message->header_count++;
570  }
571 
572  free(raw_header);
573 
574  raw_message_left = strlen(&raw_message[newline]);
575  if(raw_message_left < 4 || (raw_message[newline] == '\r' && raw_message[newline + 1] == '\n' &&
576  raw_message[newline + 2] == '\r' && raw_message[newline + 3] == '\n')) {
577  has_next_header = FALSE;
578  }
579 
580  /* if there is another header */
581  if(has_next_header) {
582  /* make newline last_newline and skip "\r\n"*/
583  last_newline = newline + 2;
584  /* if this header was successfully created */
585  if(message->headers->contents) {
586  /* allocate next header heap */
587  message->headers->next = (ssdp_header_s *)malloc(sizeof(ssdp_header_s));
588  memset(message->headers->next, '\0', sizeof(ssdp_header_s));
589  /* pass over first header pointer */
590  message->headers->next->first = message->headers->first;
591  /* and move to it */
592  message->headers = message->headers->next;
593  }
594  }
595  else {
596  message->headers->next = NULL;
597  }
598 
599  } while(has_next_header);
600 
601  /* reset chain (linked list) */
602  message->headers = message->headers->first;
603 
604  return TRUE;
605 
606 }
607 
608 void free_ssdp_message(ssdp_message_s **message_pointer) {
609  ssdp_header_s *next_header = NULL;
610  ssdp_custom_field_s *next_custom_field = NULL;
611 
612  if(!message_pointer || !*message_pointer) {
613  PRINT_ERROR("Message was empty, nothing to free");
614  return;
615  }
616 
617  ssdp_message_s *message = *message_pointer;
618  *message_pointer = NULL;
619 
620  if(message->mac != NULL) {
621  free(message->mac);
622  message->mac = NULL;
623  }
624 
625  if(message->ip != NULL) {
626  free(message->ip);
627  message->ip = NULL;
628  }
629 
630  if(message->datetime != NULL) {
631  free(message->datetime);
632  message->datetime = NULL;
633  }
634 
635  if(message->request != NULL) {
636  free(message->request);
637  message->request = NULL;
638  }
639 
640  if(message->protocol != NULL) {
641  free(message->protocol);
642  message->protocol = NULL;
643  }
644 
645  if(message->answer != NULL) {
646  free(message->answer);
647  message->answer = NULL;
648  }
649 
650  if(message->info != NULL) {
651  free(message->info);
652  message->info = NULL;
653  }
654 
655  do {
656 
657  if(message->headers->contents != NULL) {
658  free(message->headers->contents);
659  message->headers->contents = NULL;
660  }
661 
662  if(message->headers->unknown_type != NULL) {
663  free(message->headers->unknown_type);
664  message->headers->unknown_type = NULL;
665  }
666 
667  next_header = message->headers->next;
668  free(message->headers);
669  message->headers = next_header;
670  next_header = NULL;
671 
672  } while (message->headers);
673 
674  while (message->custom_fields) {
675 
676  if (message->custom_fields->name != NULL) {
677  free(message->custom_fields->name);
678  message->custom_fields->name = NULL;
679  }
680 
681  if (message->custom_fields->contents != NULL) {
682  free(message->custom_fields->contents);
683  message->custom_fields->contents = NULL;
684  }
685 
686  next_custom_field = message->custom_fields->next;
687  free(message->custom_fields);
688  message->custom_fields = next_custom_field;
689  next_custom_field = NULL;
690 
691  };
692 
693  free(message);
694 }
695 
#define IPv6_STR_MAX_SIZE
SOCKET setup_socket(socket_conf_s *conf)
int fetch_custom_fields(configuration_s *conf, ssdp_message_s *ssdp_message)
Definition: ssdp_message.c:157
char ip[IPv6_STR_MAX_SIZE]
Definition: configuration.h:18
BOOL parse_url(const char *url, char *ip, int ip_size, int *port, char *rest, int rest_size)
Definition: net_utils.c:107
unsigned char header_count
Definition: ssdp_message.h:106
struct ssdp_custom_field_struct * custom_fields
Definition: ssdp_message.h:112
static void build_ssdp_header(ssdp_header_s *header, const char *raw_header)
Definition: ssdp_message.c:86
int SOCKET
char interface[IPv6_STR_MAX_SIZE]
Definition: configuration.h:16
unsigned char type
Definition: ssdp_message.h:58
struct ssdp_header_struct * next
Definition: ssdp_message.h:66
BOOL build_ssdp_message(ssdp_message_s *message, char *ip, char *mac, int message_length, const char *raw_message)
Definition: ssdp_message.c:498
static unsigned char get_header_type(const char *header_string)
Definition: ssdp_message.c:33
struct ssdp_header_struct * headers
Definition: ssdp_message.h:108
#define DEVICE_INFO_SIZE
Definition: ssdp_message.h:18
#define TRUE
#define FALSE
void free_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:608
unsigned char custom_field_count
Definition: ssdp_message.h:110
int set_receive_timeout(SOCKET sock, int timeout)
const char * get_header_string(const unsigned int header_type, const ssdp_header_s *header)
Definition: ssdp_message.c:402
ssdp_custom_field_s * get_custom_field(const ssdp_message_s *ssdp_message, const char *custom_field)
Definition: ssdp_message.c:134
struct ssdp_custom_field_struct * first
Definition: ssdp_message.h:76
unsigned char ttl
Definition: configuration.h:50
int strpos(const char *haystack, const char *needle)
Definition: string_utils.c:11
struct ssdp_header_struct * first
Definition: ssdp_message.h:64
int set_send_timeout(SOCKET sock, int timeout)
#define ABUSED_VERSION
int BOOL
static configuration_s conf
Definition: main.c:73
#define SOCKET_ERROR
#define MAC_STR_MAX_SIZE
BOOL init_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:431
struct ssdp_custom_field_struct * next
Definition: ssdp_message.h:78