LIBSSDP
 All Classes Files Functions Variables Typedefs Macros
ssdp_prober.c
Go to the documentation of this file.
1 
7 #include <arpa/inet.h> /* inet_pton() */
8 #include <errno.h>
9 #include <netdb.h> /* struct addrinfo */
10 #include <netinet/in.h>
11 #include <stdlib.h>
12 #include <string.h> /* memset() */
13 #include <sys/socket.h> /* struct sockaddr_storage */
14 #include <unistd.h> /* close() */
15 
16 #include "common_definitions.h"
17 #include "configuration.h"
18 #include "log.h"
19 #include "net_definitions.h"
20 #include "net_utils.h"
21 #include "socket_helpers.h"
23 #include "ssdp_common.h"
24 #include "ssdp_filter.h"
25 #include "ssdp_listener.h"
26 #include "ssdp_message.h"
27 #include "ssdp_prober.h"
28 #include "ssdp_static_defs.h"
29 
31 #define PROBE_MSG \
32  "M-SEARCH * HTTP/1.1\r\n" \
33  "Host:239.255.255.250:1900\r\n" \
34  "ST:urn:axis-com:service:BasicService:1\r\n" \
35  "Man:\"ssdp:discover\"\r\n" \
36  "MX:0\r\n\r\n"
37 
38 const char *ssdp_probe_message_create(void) {
39  return PROBE_MSG;
40 }
41 
43  PRINT_DEBUG("ssdp_prober_init()");
44  if (!prober) {
45  PRINT_ERROR("Prober is empty");
46  }
47 
48  memset(prober, 0, sizeof *prober);
49 
50  if (conf->forward_address) {
51  if (parse_address(conf->forward_address, &prober->forwarder)) {
52  PRINT_WARN("Errnoeous forward address");
53  return 1;
54  }
55  }
56 
57  /* init sending socket */
58  socket_conf_s sock_conf = {
59  conf->use_ipv6, // BOOL is_ipv6
60  TRUE, // BOOL is_udp
61  TRUE, // BOOL is_multicast
62  conf->interface, // char *interface
63  conf->ip, // char *IP
64  NULL, // struct sockaddr_storage *sa
65  (conf->use_ipv6 ? SSDP_ADDR6_LL : SSDP_ADDR), // const char *ip
66  SSDP_PORT, // int port
67  FALSE, // BOOL is_server
68  1, // int queue_len
69  FALSE, // BOOL keepalive
70  conf->ttl, // int ttl
71  conf->enable_loopback, // BOOL loopback
72  0, // Receive timeout
73  0 // Send timeout
74  };
75 
76  if ((prober->sock = setup_socket(&sock_conf)) == SOCKET_ERROR) {
77  PRINT_DEBUG("Could not create socket");
78  return errno;
79  }
80  PRINT_DEBUG("ssdp_prober has been initialized");
81 
82  return 0;
83 }
84 
86  PRINT_DEBUG("ssdp_prober_close()");
87  if (!prober)
88  return;
89 
90  if (prober->sock > 0)
91  close(prober->sock);
92 }
93 
95  PRINT_DEBUG("ssdp_prober_start()");
96 
97  /* The structure contining all the filters information */
98  filters_factory_s *filters_factory = NULL;
99 
100  /* Parse the filters */
101  PRINT_DEBUG("parse_filters()");
102  parse_filters(conf->filter, &filters_factory, TRUE & (~conf->quiet_mode));
103 
104  /* Create a SSDP probe message */
105  const char *request = ssdp_probe_message_create();
106 
107  BOOL drop_message;
108 
109  /* Client (mcast group) address */
110  PRINT_DEBUG("creating multicast address");
111  //struct addrinfo *addri;
112  //struct addrinfo hint;
113  //memset(&hint, 0, sizeof(hint));
114  //hint.ai_family = (conf->use_ipv6 ? AF_INET6 : AF_INET);
115  //hint.ai_socktype = SOCK_DGRAM;
116  //hint.ai_protocol = IPPROTO_UDP;
117  //hint.ai_canonname = NULL;
118  //hint.ai_addr = NULL;
119  //hint.ai_next = NULL;
120  //char *port_str = (char *)malloc(sizeof(char) * 6);
121  //memset(port_str, '\0', 6);
122  //sprintf(port_str, "%d", SSDP_PORT);
123 
124  //int err = 0;
125 
126  //if ((err = getaddrinfo((conf->use_ipv6 ? SSDP_ADDR6_LL : SSDP_ADDR),
127  // port_str, &hint, &addri)) != 0) {
128  // PRINT_ERROR("getaddrinfo(): %s\n", gai_strerror(err));
129  // free(port_str);
130  // return err;
131  //}
132  //free(port_str);
133 
134  /*****************
135  This is the temp solution until the
136  commented-out sendto() code below (and above) is fixed */
137  struct sockaddr_in sa;
138  sa.sin_family = AF_INET;
139  sa.sin_port = htons(SSDP_PORT);
140  inet_pton(AF_INET, SSDP_ADDR, &sa.sin_addr);
141  /*****************/
142 
143  /* Send the UPnP request */
144  PRINT_DEBUG("sending request");
145  int sent_bytes;
146  //sent_bytes = sendto(prober->sock, request, strlen(request), 0,
147  // (struct sockaddr *)&addri->ai_addr, addri->ai_addrlen);
148  sent_bytes = sendto(prober->sock, request, strlen(request), 0,
149  (struct sockaddr *)&sa, sizeof(sa));
150 
151  if (sent_bytes < 0) {
152  PRINT_DEBUG("sendto(): Failed sending any data");
153  return errno;
154  }
155 
156 
157  size_t sento_addr_len = sizeof(struct sockaddr_storage);
158  struct sockaddr_storage *sendto_addr = malloc(sento_addr_len);
159  memset(sendto_addr, 0, sento_addr_len);
160  int response_port = 0;
161 
162  if (getsockname(prober->sock, (struct sockaddr *)sendto_addr,
163  (socklen_t *)&sento_addr_len) < 0) {
164  PRINT_ERROR("Could not get sendto() port, going to miss the replies");
165  }
166  else {
167  response_port = get_port_from_sock_address(sendto_addr);
168  PRINT_DEBUG("sendto() port is %d", response_port);
169  }
170  free(sendto_addr);
171  close(prober->sock);
172  PRINT_DEBUG("sent %d bytes", sent_bytes);
173  //freeaddrinfo(addri);
174  drop_message = FALSE;
175 
176  /* init listening socket */
177  PRINT_DEBUG("setup_socket() listening");
178 
179  // TODO: fix this listener, its acting weird
180  ssdp_listener_s response_listener;
181  ssdp_active_listener_init(&response_listener, conf, response_port);
182 
183  ssdp_message_s *ssdp_message;
184  ssdp_recv_node_s recv_node;
185 
186  do {
187  memset(&recv_node, 0, sizeof recv_node);
188 
189  /* Wait for an answer */
190  PRINT_DEBUG("Waiting for a response");
191  ssdp_listener_read(&response_listener, &recv_node);
192  PRINT_DEBUG("Recived %d bytes%s",
193  (recv_node.recv_bytes < 0 ? 0 : recv_node.recv_bytes),
194  (recv_node.recv_bytes < 0 ? " (wait time limit reached)" : ""));
195 
196  if(recv_node.recv_bytes < 0) {
197  continue;
198  }
199 
200  ssdp_message = NULL;
201 
202  /* Initialize and build ssdp_message */
203  if(!init_ssdp_message(&ssdp_message)) {
204  PRINT_ERROR("Failed to initialize SSDP message holder structure");
205  continue;
206  }
207 
208  if (!build_ssdp_message(ssdp_message, recv_node.from_ip,
209  recv_node.from_mac, recv_node.recv_bytes, recv_node.recv_data)) {
210  continue;
211  }
212 
213  // TODO: Make it recognize both AND and OR (search for ; inside a ,)!!!
214  // TODO: add "request" string filtering
215  /* Check if notification should be used (to print and possibly send to the given destination) */
216  ssdp_header_s *ssdp_headers = ssdp_message->headers;
217  if (filters_factory != NULL) {
218  int fc;
219  for (fc = 0; fc < filters_factory->filters_count; fc++) {
220  if ((strcmp(filters_factory->filters[fc].header, "ip") == 0) &&
221  strstr(ssdp_message->ip,
222  filters_factory->filters[fc].value) == NULL) {
223  drop_message = TRUE;
224  break;
225  }
226 
227  while (ssdp_headers) {
228  if ((strcmp(get_header_string(ssdp_headers->type, ssdp_headers),
229  filters_factory->filters[fc].header) == 0) &&
230  strstr(ssdp_headers->contents,
231  filters_factory->filters[fc].value) == NULL) {
232  drop_message = TRUE;
233  break;
234  }
235  ssdp_headers = ssdp_headers->next;
236  }
237  ssdp_headers = ssdp_message->headers;
238 
239  if (drop_message) {
240  break;;
241  }
242  }
243  }
244 
245  if (filters_factory == NULL || !drop_message) {
246 
247  /* Fetch custom fields */
248  if (conf->fetch_info && !fetch_custom_fields(conf, ssdp_message)) {
249  PRINT_DEBUG("Could not fetch custom fields");
250  }
251 
252  /* Print the message */
253  if (conf->xml_output) {
254  char *xml_string = malloc(sizeof(char) * XML_BUFFER_SIZE);
255  to_xml(ssdp_message, TRUE, xml_string, XML_BUFFER_SIZE);
256  printf("%s\n", xml_string);
257  free(xml_string);
258  } else if (conf->oneline_output) {
259  char *oneline_string = to_oneline(ssdp_message, conf->monochrome);
260  if (oneline_string) {
261  printf("%s\n", oneline_string);
262  free(oneline_string);
263  }
264  } else {
265  printf("\n\n\n----------BEGIN NOTIFICATION------------\n");
266  printf("Time received: %s\n", ssdp_message->datetime);
267  printf("Origin-MAC: %s\n", (ssdp_message->mac != NULL ?
268  ssdp_message->mac : "(Could not be determined)"));
269  printf("Origin-IP: %s\nMessage length: %d Bytes\n", ssdp_message->ip,
270  ssdp_message->message_length);
271  printf("Request: %s\nProtocol: %s\n", ssdp_message->request,
272  ssdp_message->protocol);
273 
274  int hc = 0;
275  while (ssdp_headers) {
276  printf("Header[%d][type:%d;%s]: %s\n", hc, ssdp_headers->type,
277  get_header_string(ssdp_headers->type, ssdp_headers),
278  ssdp_headers->contents);
279  ssdp_headers = ssdp_headers->next;
280  hc++;
281  }
282  ssdp_headers = NULL;
283  printf("-----------END NOTIFICATION-------------\n");
284  }
285  /* TODO: Send the message back to -a (or not support that for probing?)*/
286 
287  }
288 
289  if (ssdp_message)
290  free_ssdp_message(&ssdp_message);
291  } while(recv_node.recv_bytes > 0);
292 
293  //TODO: ssdp_listener_close(&response_listener) ?
294  free_ssdp_filters_factory(filters_factory);
295 
296  PRINT_DEBUG("scan_for_upnp_devices end");
297 
298  return 0;
299 }
300 
SOCKET setup_socket(socket_conf_s *conf)
const char * get_header_string(const unsigned int header_type, const ssdp_header_s *header)
Definition: ssdp_message.c:402
char ip[IPv6_STR_MAX_SIZE]
Definition: configuration.h:18
int parse_address(const char *raw_address, struct sockaddr_storage *address)
Definition: net_utils.c:33
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
struct ssdp_header_struct * headers
Definition: ssdp_message.h:108
void free_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:608
int fetch_custom_fields(configuration_s *conf, ssdp_message_s *ssdp_message)
Definition: ssdp_message.c:157
unsigned char filters_count
Definition: ssdp_filter.h:29
BOOL build_ssdp_message(ssdp_message_s *message, char *ip, char *mac, int message_length, const char *raw_message)
Definition: ssdp_message.c:498
#define TRUE
#define FALSE
int ssdp_active_listener_init(ssdp_listener_s *listener, configuration_s *conf, int port)
unsigned int to_xml(const ssdp_message_s *ssdp_message, BOOL full_xml, char *xml_buffer, int xml_buffer_size)
#define PROBE_MSG
Definition: ssdp_prober.c:31
char from_ip[IPv6_STR_MAX_SIZE]
Definition: ssdp_common.h:20
const char * ssdp_probe_message_create(void)
Definition: ssdp_prober.c:38
char from_mac[MAC_STR_MAX_SIZE]
Definition: ssdp_common.h:22
unsigned char ttl
Definition: configuration.h:50
#define SSDP_ADDR6_LL
BOOL init_ssdp_message(ssdp_message_s **message_pointer)
Definition: ssdp_message.c:431
char recv_data[SSDP_RECV_DATA_LEN]
Definition: ssdp_common.h:26
char * to_oneline(const ssdp_message_s *message, BOOL monochrome)
void ssdp_prober_close(ssdp_prober_s *prober)
Definition: ssdp_prober.c:85
void free_ssdp_filters_factory(filters_factory_s *factory)
Definition: ssdp_filter.c:16
#define XML_BUFFER_SIZE
Definition: ssdp_message.h:16
char * header
Definition: ssdp_filter.h:15
int BOOL
#define SSDP_ADDR
static configuration_s conf
Definition: main.c:73
int ssdp_prober_start(ssdp_prober_s *prober, configuration_s *conf)
Definition: ssdp_prober.c:94
#define SOCKET_ERROR
#define SSDP_PORT
char * value
Definition: ssdp_filter.h:17
int ssdp_prober_init(ssdp_prober_s *prober, configuration_s *conf)
Definition: ssdp_prober.c:42
int get_port_from_sock_address(const struct sockaddr_storage *saddr)
Definition: net_utils.c:729
void ssdp_listener_read(ssdp_listener_s *listener, ssdp_recv_node_s *recv_node)
void parse_filters(char *raw_filter, filters_factory_s **filters_factory, BOOL print_filters)
Definition: ssdp_filter.c:38