ISIS Logo
ISISBEAM
ISIS Beam Information
1st_nd_lib.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <sys/types.h>
5 #ifdef _WIN32
6 # include <winsock2.h>
7 # include <ws2tcpip.h>
8 # define INTERNET_SOCKET PF_INET
9 #else
10 # include <unistd.h>
11 # include <sys/socket.h>
12 # include <netdb.h>
13 # include <netinet/in.h>
14 # include <arpa/inet.h>
15 # include <pwd.h>
16 # define SOCKET int
17 # define INVALID_SOCKET -1
18 # define INTERNET_SOCKET AF_INET
19 # define closesocket close
20 #endif
21 #include <string.h>
22 #ifdef _WIN32
23 #include <time.h>
24 #else
25 #include <sys/time.h>
26 #endif /* _WIN32 */
27 
28 #ifdef x__VMS
29 struct ip_mreq {
30  struct in_addr imr_multiaddr; /* IP multicast address of group */
31  struct in_addr imr_interface; /* local IP address of interface */
32 };
33 #endif /* __VMS */
34 
35 #include "1st_nd_post.h"
36 
37 SOCKET open_connection(const char* servers[], short port)
38 {
39  int i, n, nfds, replen, max_replen, connected = 0;
40  int setkeepalive = 1;
41  struct timeval timeout = { 0, 0 };
43  struct hostent *hostp;
44  struct sockaddr_in address;
45  int enable = 1, disable = 0;
46  for(i=0; !connected && (servers[i] != NULL) && (strlen(servers[i]) > 0) ; i++)
47  {
48  printf("open_connection: trying to establish connection to \"%s\"\n", servers[i]);
49  if ((sd = socket(INTERNET_SOCKET, SOCK_STREAM, 0)) == INVALID_SOCKET)
50  {
51  perror("open_connection: socket");
52  return INVALID_SOCKET;
53  }
54  if ( setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &setkeepalive, sizeof(setkeepalive)) == -1 )
55  {
56  perror("setsockopt: keepalive");
57  closesocket(sd);
58  return INVALID_SOCKET;
59  }
60  timeout.tv_sec = 3;
61  if ( setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) == -1 )
62  {
63  perror("setsockopt: sndtimeo");
64  closesocket(sd);
65  return INVALID_SOCKET;
66  }
67  timeout.tv_sec = 10;
68  if ( setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1 )
69  {
70  perror("setsockopt: rcvtimeo");
71  closesocket(sd);
72  return INVALID_SOCKET;
73  }
74 // if (ioctl(sd, FIONBIO, &enable) == -1)
75 // {
76 // perror("ioctl: FIONBIO");
77 // closesocket(sd);
78 // return INVALID_SOCKET;
79 // }
80  memset(&address, 0, sizeof(struct sockaddr_in));
81  address.sin_family = AF_INET;
82  if ((hostp = gethostbyname(servers[i])) == NULL)
83  {
84  printf("open_connection: gethostbyname failed for \"%s\"\n", servers[i]);
85  closesocket(sd);
86  sd = INVALID_SOCKET;
87  continue;
88  }
89  memcpy(&(address.sin_addr.s_addr), hostp->h_addr, hostp->h_length);
90  address.sin_port = htons(port);
91  if (connect(sd, (struct sockaddr*)&address, sizeof(address)) == -1)
92  {
93  perror("open_connection: connect");
94  closesocket(sd);
95  sd = INVALID_SOCKET;
96  }
97  else
98  {
99 #if 0
100  if (ioctl(sd, FIONBIO, &disable) == -1)
101  {
102  perror("ioctl: FIONBIO");
103  closesocket(sd);
104  sd = INVALID_SOCKET;
105  }
106  else
107  {
108  connected = 1;
109  }
110 #else
111  connected = 1;
112 #endif
113  }
114  }
115  if (connected)
116  {
117  return sd;
118  }
119  else
120  {
121  if (sd != INVALID_SOCKET)
122  {
123  closesocket(sd);
124  }
125  return INVALID_SOCKET;
126  }
127 }
128 
129 int initialise_data_packet(data_header* dh, short major, short minor)
130 {
131  dh->major = major;
132  dh->minor = minor;
133  dh->len = 0;
134  return 0;
135 }
136 
137 int send_packet(SOCKET sd, const char* data, int n)
138 {
139  struct timeval delay = { 5, 0};
140  int numfds = FD_SETSIZE;
141  int stat;
142  fd_set writefds;
143  if (sd == INVALID_SOCKET)
144  {
145  return 1;
146  }
147  FD_ZERO(&writefds);
148  FD_SET(sd, &writefds);
149  if (select(numfds, NULL, &writefds, NULL, &delay) <= 0)
150  {
151  printf("send_packet: select timed out after %ld seconds\n", delay.tv_sec);
152  return 1;
153  }
154  stat = send(sd, data, n, 0);
155  if (stat != n)
156  {
157  perror("send");
158  return 1;
159  }
160  else
161  {
162  return 0;
163  }
164 }
165 
167 {
168  struct timeval delay = { 5, 0};
169  int numfds = FD_SETSIZE;
170  int stat, n;
171  char* data;
172  fd_set writefds;
173  FD_ZERO(&writefds);
174  FD_SET(sd, &writefds);
175  if (select(numfds, NULL, &writefds, NULL, &delay) <= 0)
176  {
177  printf("send_data: select timed out after %ld seconds\n", delay.tv_sec);
178  return 1;
179  }
180  n = dp->header.len + sizeof(dp->header) + sizeof(dp->check);
181  data = (char*)malloc(n);
182  memcpy(data, &(dp->header), sizeof(dp->header));
183  memcpy(data+sizeof(dp->header), &(dp->data), dp->header.len);
184  memcpy(data+sizeof(dp->header)+dp->header.len, &(dp->check), sizeof(dp->check));
185  stat = send(sd, data, n, 0);
186  free(data);
187  if (stat != n)
188  {
189  return 1;
190  }
191  else
192  {
193  return 0;
194  }
195 }
196 
197 /* wait until have n bytes of data */
198 int receive_data_pattern(SOCKET sd, void* data, int maxdata, const char* pattern)
199 {
200  int stat, nread = 0, numfds, sock_size;
201  struct sockaddr_in sockin;
202  fd_set readfds;
203  struct timeval delay = { 180, 0};
204  numfds = FD_SETSIZE;
205  while(1)
206  {
207  FD_ZERO(&readfds);
208  FD_SET(sd, &readfds);
209  if (select(numfds, &readfds, NULL, NULL, &delay) <= 0)
210  {
211  printf("receive_data_pattern: select timed out after %ld seconds\n", delay.tv_sec);
212  return 1;
213  }
214  stat = recv(sd, (char*)data + nread, maxdata - nread, 0);
215  if (stat <= 0)
216  {
217  perror("recv");
218  return 1;
219  }
220  nread += stat;
221  if (nread == maxdata)
222  {
223  printf("too much data\n");
224  return 1;
225  }
226  ((char*)data)[nread] = '\0';
227  if (strstr((char*)data, pattern) != NULL)
228  {
229  return 0;
230  }
231  }
232 }
233 
234 
235 /* wait until have n bytes of data */
236 int receive_data_size(SOCKET sd, void* data, int n)
237 {
238  int stat, nread = 0, numfds, sock_size;
239  struct sockaddr_in sockin;
240  fd_set readfds;
241  struct timeval delay = { 30, 0};
242  numfds = FD_SETSIZE;
243  while(1)
244  {
245  FD_ZERO(&readfds);
246  FD_SET(sd, &readfds);
247  if (select(numfds, &readfds, NULL, NULL, &delay) <= 0)
248  {
249  printf("receive_data_size: select timed out after %ld seconds\n", delay.tv_sec);
250  return 1;
251  }
252  stat = recv(sd, (char*)data + nread, n - nread, 0);
253 #if 0
254  chsr * address = inet_ntoa(sockin.sin_addr);
255  unsigned long add = sockin.sin_addr.s_addr; /* address in network order */
256  host = gethostbyaddr((char*)&add, 4, AF_INET);
257  print host->h_name
258 #endif
259  if (stat <= 0)
260  {
261  return 1;
262  }
263  nread += stat;
264  if (nread == n)
265  {
266  return 0;
267  }
268  }
269 }
270 
272 {
273  char* data;
274  if (receive_data_size(sd, &(dp->header), sizeof(dp->header)) != 0)
275  {
276  printf("receive_data: error reading header\n");
277  return 1;
278  }
279  if (dp->header.len != sizeof(dp->data))
280  {
281  printf("receive_data: packet size mismatch (got %d, expected %d)\n", dp->header.len, sizeof(dp->data));
282  printf("receive_data: there is probably a mismatch in the data_packet_1_0 definitions on this and\n");
283  printf("receive_data: the ISIS controls sending computer\n");
284  return 1;
285  }
286  data = (char*)malloc(dp->header.len);
287  if (receive_data_size(sd, data, dp->header.len) != 0)
288  {
289  printf("receive_data: error reading data\n");
290  free(data);
291  return 1;
292  }
293  if (receive_data_size(sd, &(dp->check), sizeof(dp->check)) != 0)
294  {
295  printf("receive_data: error reading checksum\n");
296  free(data);
297  return 1;
298  }
299  memcpy(&(dp->data), data, sizeof(dp->data));
300  free(data);
301  return 0;
302 }
303 
304 int receive_data_udp(SOCKET sd, char* dp, int n)
305 {
306  struct sockaddr_in sockin;
307  int stat;
308 #ifndef __unix
309  unsigned sock_size;
310 #else
311  socklen_t sock_size;
312 #endif
313  sock_size = sizeof(sockin);
314  stat = recvfrom(sd, dp, n, 0, (struct sockaddr*)&sockin, &sock_size);
315  if (stat <= 0)
316  {
317  return -1;
318  }
319  else
320  {
321  return stat;
322  }
323 }
324 
325 SOCKET setup_socket(unsigned short port, int num_listen)
326 {
327  SOCKET sd;
328  struct sockaddr_in sin;
329  if ( (sd = socket(INTERNET_SOCKET, SOCK_STREAM, 0)) == -1)
330  {
331  perror("socket");
332  return INVALID_SOCKET;
333  }
334  memset(&sin, 0, sizeof(sin));
335  sin.sin_family = INTERNET_SOCKET;
336  sin.sin_addr.s_addr = INADDR_ANY;
337  sin.sin_port = htons(port);
338  if (bind(sd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
339  {
340  perror("bind");
341  closesocket(sd);
342  return INVALID_SOCKET;
343  }
344  if (listen(sd, num_listen) == -1)
345  {
346  perror("listen");
347  closesocket(sd);
348  return INVALID_SOCKET;
349  }
350  return sd;
351 }
352 
353 SOCKET setup_udp_socket(unsigned short port, int multicast)
354 {
355  int setreuse = 1;
356  SOCKET sd;
357  struct sockaddr_in sin;
358  struct ip_mreq mreq;
359  if ( (sd = socket(INTERNET_SOCKET, SOCK_DGRAM, 0)) == -1 )
360  {
361  perror("socket");
362  return INVALID_SOCKET;
363  }
364 #ifdef __VMS
365  if ( setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &setreuse, sizeof(setreuse)) == -1 )
366  {
367  perror("setsockopt: reuseport");
368  closesocket(sd);
369  return INVALID_SOCKET;
370  }
371 #else
372  if ( setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &setreuse, sizeof(setreuse)) == -1 )
373  {
374  perror("setsockopt: reuseaddr");
375  closesocket(sd);
376  return INVALID_SOCKET;
377  }
378 #endif
379  memset(&sin, 0, sizeof(sin));
380  sin.sin_family = INTERNET_SOCKET;
381  sin.sin_addr.s_addr = INADDR_ANY;
382  sin.sin_port = htons(port);
383  if (bind(sd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
384  {
385  perror("bind");
386  closesocket(sd);
387  return INVALID_SOCKET;
388  }
389  if (multicast)
390  {
391  mreq.imr_multiaddr.s_addr = inet_addr(ND_MULTICAST_ADDRESS);
392  mreq.imr_interface.s_addr = INADDR_ANY;
393  if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
394  {
395  perror("setsockopt: add multicast membership");
396  closesocket(sd);
397  return INVALID_SOCKET;
398  }
399  }
400  return sd;
401 }
402 
403 // On success, return socket file descriptor and populate sockaddr_in
404 // On error, Return -1
405 SOCKET setup_broadcast_socket(const char* address, short port, struct sockaddr_in* sockin, int multicast)
406 {
407  SOCKET s;
408  int one = 1;
409  u_char ttl;
410  struct hostent* hostp;
411  struct in_addr ifaddress;
412 #ifdef _WIN32
413  typedef unsigned long in_addr_t;
414 #endif
415  in_addr_t add;
416  add = inet_addr(address);
417  if ( add == (in_addr_t)-1 )
418  {
419  return -1;
420  }
421  if (multicast)
422  {
423  ifaddress.s_addr = add;
424  }
425  hostp = malloc(sizeof(struct hostent));
426  hostp->h_addr_list = malloc(sizeof(char*));
427  hostp->h_addr_list[0] = (char*)&add;
428  hostp->h_length = sizeof(in_addr_t);
429  if ( (s = socket(INTERNET_SOCKET, SOCK_DGRAM, 0)) == -1 )
430  {
431  return -1;
432  }
433  memset(sockin, 0, sizeof(struct sockaddr_in));
434  sockin->sin_family = AF_INET;
435  sockin->sin_port = htons(port);
436  memcpy(&(sockin->sin_addr.s_addr), hostp->h_addr_list[0], hostp->h_length);
437  if (multicast)
438  {
439  ttl = 2;
440  if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1)
441  {
442  perror("setsockopt: multicast ttl");
443  }
444 #if 0
445  if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddress, sizeof(ifaddress)) == -1)
446  {
447  perror("setsockopt: multicast if");
448  }
449 #endif
450  }
451  else
452  {
453  if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) == -1)
454  {
455  perror("setsockopt: broadcast");
456  }
457  }
458  return s;
459 }
460 
461 
462 /*
463  * simple XML parser
464  * xml_parse("<beam>10.0</beam>","beam") will return a malloced "10.0"
465  * returns NULL on error
466  */
467 char* xml_parse(const char* input_string, const char* token)
468 {
469  char *start_token, *end_token, *result = NULL;
470  char *start_pos, *end_pos;
471  int n, len_tok;
472  if (input_string == NULL || token == NULL)
473  {
474  return NULL;
475  }
476  len_tok = strlen(token);
477  start_token = malloc(len_tok+2+1);
478  if (start_token == NULL)
479  {
480  return NULL;
481  }
482  end_token = malloc(len_tok+3+1);
483  if (end_token == NULL)
484  {
485  return NULL;
486  }
487  sprintf(start_token, "<%s>", token);
488  sprintf(end_token, "</%s>", token);
489  start_pos = strstr(input_string, start_token);
490  end_pos = strstr(input_string, end_token);
491  if (start_pos != NULL && end_pos != NULL)
492  {
493  n = (end_pos - start_pos) - len_tok - 2;
494  result = malloc(n+1);
495  if (result != NULL)
496  {
497  strncpy(result, start_pos + len_tok + 2, n);
498  result[n] = '\0';
499  }
500  }
501  free(start_token);
502  free(end_token);
503  return result;
504 }
505 
506 static void junk_reply(sd)
507 {
508  static char buffer[1024];
509  struct timeval delay = { 2, 0};
510  int nread = 1, numfds;
511  fd_set readfds;
512  while(nread > 0)
513  {
514  FD_ZERO(&readfds);
515  FD_SET(sd, &readfds);
516  numfds = FD_SETSIZE;
517  nread = 0;
518  if (select(numfds, &readfds, NULL, NULL, &delay) > 0)
519  {
520  nread = recv(sd, buffer, sizeof(buffer), 0);
521  buffer[nread] = '\0';
522 /* printf("receive: %s\n", buffer); */
523  }
524  }
525 }
526 
527 static void send_mess(SOCKET sd, const char* format, ... )
528 {
529  static char buffer[1024];
530  va_list ap;
531  va_start(ap, format);
532  vsprintf(buffer, format, ap);
533  va_end(ap);
534 /* printf("send: %s", buffer); */
535  send(sd, buffer, strlen(buffer), 0);
536  junk_reply(sd);
537 }
538 
539 void send_mail(const char* from, const char* to, const char* message)
540 {
541  SOCKET sd;
542  char host_name[256];
543  const char* servers[] = { "localhost", "hathor.nd.rl.ac.uk", "thoth.nd.rl.ac.uk", NULL };
544  if (gethostname(host_name, sizeof(host_name)) != 0)
545  {
546  strcpy(host_name, "localhost");
547  }
548  sd = open_connection(servers, 25);
549  if (sd != INVALID_SOCKET)
550  {
551  send_mess(sd, "HELO %s\r\n", host_name);
552  send_mess(sd, "MAIL FROM:<%s>\r\n", from);
553  send_mess(sd, "RCPT TO:<%s>\r\n", to);
554  send_mess(sd, "DATA\r\n");
555  send_mess(sd, "%s\r\n.\r\n", message);
556  send_mess(sd, "QUIT\r\n");
557  closesocket(sd);
558  }
559  else
560  {
561  printf("send_mail: error opening connection\n");
562  }
563 }
char * xml_parse(const char *input_string, const char *token)
Definition: 1st_nd_lib.c:467
#define SOCKET
Definition: 1st_nd_lib.c:16
int send_packet(SOCKET sd, const char *data, int n)
Definition: 1st_nd_lib.c:137
short major
Definition: 1st_nd_post.h:50
int initialise_data_packet(data_header *dh, short major, short minor)
Definition: 1st_nd_lib.c:129
#define INVALID_SOCKET
Definition: 1st_nd_lib.c:17
static void send_mess(SOCKET sd, const char *format,...)
Definition: 1st_nd_lib.c:527
int receive_data_udp(SOCKET sd, char *dp, int n)
Definition: 1st_nd_lib.c:304
data_header header
Definition: 1st_nd_post.h:136
#define ND_MULTICAST_ADDRESS
Definition: 1st_nd_post.h:42
#define INTERNET_SOCKET
Definition: 1st_nd_lib.c:18
SOCKET setup_socket(unsigned short port, int num_listen)
Definition: 1st_nd_lib.c:325
SOCKET setup_broadcast_socket(const char *address, short port, struct sockaddr_in *sockin, int multicast)
Definition: 1st_nd_lib.c:405
int receive_data_pattern(SOCKET sd, void *data, int maxdata, const char *pattern)
Definition: 1st_nd_lib.c:198
int receive_data_size(SOCKET sd, void *data, int n)
Definition: 1st_nd_lib.c:236
#define closesocket
Definition: 1st_nd_lib.c:19
void send_mail(const char *from, const char *to, const char *message)
Definition: 1st_nd_lib.c:539
static void junk_reply(sd)
Definition: 1st_nd_lib.c:506
short minor
Definition: 1st_nd_post.h:51
int send_data(SOCKET sd, data_packet_1_0 *dp)
Definition: 1st_nd_lib.c:166
SOCKET setup_udp_socket(unsigned short port, int multicast)
Definition: 1st_nd_lib.c:353
SOCKET open_connection(const char *servers[], short port)
Definition: 1st_nd_lib.c:37
int receive_data(SOCKET sd, data_packet_1_0 *dp)
Definition: 1st_nd_lib.c:271
Copyright © 2013 Science and Technology Facilities Council | Generated by   doxygen 1.8.5