MNE-CPP  beta 1.0
shmemsocket.cpp
1 //=============================================================================================================
36 //*************************************************************************************************************
37 //=============================================================================================================
38 // INCLUDES
39 //=============================================================================================================
40 
41 #include "shmemsocket.h"
42 
43 
44 //*************************************************************************************************************
45 //=============================================================================================================
46 // UNIX INCLUDES
47 //=============================================================================================================
48 
49 #include <stdio.h> // fopen
50 #include <string.h> // memcpy
51 #include <unistd.h> // unlink, close
52 
53 #include <sys/stat.h> //umask
54 #include <sys/un.h> //sockaddr_un
55 #include <sys/socket.h> //AF_UNIX
56 #include <sys/shm.h> //shmdt
57 
58 
59 //*************************************************************************************************************
60 //=============================================================================================================
61 // USED NAMESPACES
62 //=============================================================================================================
63 
64 using namespace NeuromagPlugin;
65 
66 
67 //*************************************************************************************************************
68 //=============================================================================================================
69 // DEFINE MEMBER METHODS
70 //=============================================================================================================
71 
72 ShmemSocket::ShmemSocket(QObject *parent)
73 : QObject(parent)
74 , shmid(-1)
75 , shmptr(NULL)
76 , m_iShmemSock(-1)
77 , m_iShmemId(CLIENT_ID)
78 , fd(NULL)
79 , shmem_fd(NULL)
80 , filename(NULL)
81 {
82  filter_kinds = NULL; /* Filter these tags */
83  nfilt = 0; /* How many are they */
84 }
85 
86 
87 //*************************************************************************************************************
88 
89 ShmemSocket::~ShmemSocket()
90 {
91  delete[] filter_kinds;
92  free (filename);
93 }
94 
95 
96 //*************************************************************************************************************
97 //=============================================================================================================
98 // client_socket.c
99 //=============================================================================================================
100 
101 int ShmemSocket::receive_tag (FiffTag::SPtr& p_pTag)
102 {
103  struct sockaddr_un from; /* Address (not used) */
104  socklen_t fromlen;
105 
106  dacqDataMessageRec mess; /* This is the kind of message we receive */
107  int rlen;
108  int data_ok = 0;
109 
110  p_pTag = FiffTag::SPtr(new FiffTag());
111  dacqShmBlock shmem = this->get_shmem();
112  dacqShmBlock shmBlock;
113  dacqShmClient shmClient;
114  int k;
115 
116 
117  long read_loc;
118 
119  if (m_iShmemSock < 0)
120  return (OK);
121 
122  //
123  // read from the socket
124  //
125  fromlen = sizeof(from);
126  rlen = recvfrom(m_iShmemSock, (void *)(&mess), DATA_MESS_SIZE, 0, (sockaddr *)(&from), &fromlen);
127 
128 // qDebug() << "Mess Kind: " << mess.kind << " Type: " << mess.type << "Size: " << mess.size;
129 
130  //
131  // Parse received message
132  //
133  if (rlen == -1)
134  {
135  printf("recvfrom");//dacq_perror("recvfrom");
136  this->close_socket ();
137  return (FAIL);
138  }
139 
140  /* A sanity check to survive at least some crazy messages */
141 
142  if (mess.kind > 20000 || (unsigned long) mess.size > (size_t) 100000000)
143  {
144  printf("ALERT: Unreasonable data received, skipping! (size=%d)(kind=%d)", mess.kind, mess.size);
145  //dacq_log("ALERT: Unreasonable data received, skipping! (size=%d)(kind=%d)", mess.kind, mess.size);
146  mess.size = 0;
147  mess.kind = FIFF_NOP;
148  }
149 
150  p_pTag->kind = mess.kind;
151  p_pTag->type = mess.type;
152  p_pTag->next = 0;
153 
154  if ((unsigned long) mess.size > (size_t) 0)
155  {
156  p_pTag->resize(mess.size);
157  }
158 
159 // qDebug() << mess.loc << " " << mess.size << " " << mess.shmem_buf << " " << mess.shmem_loc;
160 
161  if (mess.loc < 0 && (unsigned long) mess.size > (size_t) 0 && mess.shmem_buf < 0 && mess.shmem_loc < 0)
162  {
163  fromlen = sizeof(from);
164  rlen = recvfrom(m_iShmemSock, (void *)p_pTag->data(), mess.size, 0, (sockaddr *)(&from), &fromlen);
165  if (rlen == -1)
166  {
167  printf("recvfrom");//dacq_perror("recvfrom");
168  this->close_socket();
169  return (FAIL);
170  }
171  data_ok = 1;
172 // if (mess.type == FIFFT_STRING)
173 // data[mess.size] = '\0';
174  }
175  else if ((unsigned long) mess.size > (size_t) 0) {
176  /*
177  * Copy data from shared memory
178  */
179  if (mess.shmem_buf >= 0 && m_iShmemId/10000 > 0)
180  {
181  shmBlock = shmem + mess.shmem_buf;
182  shmClient = shmBlock->clients;
183 
184  if (interesting_data(mess.kind))
185  {
186  memcpy(p_pTag->data(),shmBlock->data,mess.size);
187  data_ok = 1;
188  #ifdef DEBUG
189  printf("client # %d read shmem buffer # %d\n", m_iShmemId, mess.shmem_buf);//dacq_log("client # %d read shmem buffer # %d\n", id,mess.shmem_buf);
190  #endif
191  }
192  /*
193  * Indicate that this client has processed the data
194  */
195  for (k = 0; k < SHM_MAX_CLIENT; k++,shmClient++)
196  if (shmClient->client_id == m_iShmemId)
197  shmClient->done = 1;
198  }
199  /*
200  * Read data from file
201  */
202  else {
203  /*
204  * Possibly read from shmem file
205  */
206  if (m_iShmemId/10000 > 0 && mess.shmem_loc >= 0) {
207  read_fd = shmem_fd;
208  read_loc = mess.shmem_loc;
209  }
210  else {
211  read_fd = fd;
212  read_loc = mess.loc;
213  }
214  if (interesting_data(mess.kind)) {
215  if (read_fif (read_fd,read_loc,mess.size,(char *)p_pTag->data()) == -1) {
216  printf("Could not read data (tag = %d, size = %d, pos = %li)!\n", mess.kind,mess.size,read_loc);//dacq_log("Could not read data (tag = %d, size = %d, pos = %d)!\n", mess.kind,mess.size,read_loc);
217  //dacq_log("%s\n",err_get_error());
218  }
219  else {
220  data_ok = 1;
221 // if (mess.type == FIFFT_STRING)
222 // data[mess.size] = '\0';
223  FiffTag::convert_tag_data(p_pTag,FIFFV_BIG_ENDIAN,FIFFV_NATIVE_ENDIAN);
224  }
225  }
226  }
227  }
228 
229  /*
230  * Special case: close old input file
231  */
232  if (mess.kind == FIFF_CLOSE_FILE) {
233  if (fd != NULL) {
234  printf("File to be closed (lib/FIFF_CLOSE_FILE).\n");//dacq_log("File to be closed (lib/FIFF_CLOSE_FILE).\n");
235  (void)fclose(fd);
236  fd = NULL;
237  }
238  else
239  printf("No file to close (lib/FIFF_CLOSE_FILE).\n");//dacq_log("No file to close (lib/FIFF_CLOSE_FILE).\n");
240  }
241  /*
242  * Another special case: open new input file
243  */
244  else if (mess.kind == FIFF_NEW_FILE) {
245  if (fd != NULL) {
246  (void)fclose(fd);
247  printf("File closed (lib/FIFF_NEW_FILE).\n");//dacq_log("File closed (lib/FIFF_NEW_FILE).\n");
248  }
249  fd = open_fif((char *)p_pTag->data());
250  free (filename);
251  filename = strdup((char *)p_pTag->data());
252 
253  if (shmem_fd == NULL)
254  shmem_fd = open_fif (SHM_FAIL_FILE);
255  }
256 
257  if (p_pTag->size() <= 0)
258  {
259  data_ok = 0;
260  return (FAIL);
261  }
262  return (OK);
263 }
264 
265 
266 //*************************************************************************************************************
267 
268 FILE *ShmemSocket::open_fif (char *name)
269 
270 {
271  FILE *fd;
272  printf("Open %s... ",name);//dacq_log ("should open %s\n",name);
273 
274  if ((fd = fopen(name,"r")) == NULL) {
275  printf ("failed!\r\n");//dacq_log ("failed to open %s\n",name);
276  //dacq_perror(name);
277  }
278  else
279  printf ("[done]\r\n");
280 
281  return (fd);
282 }
283 
284 
285 //*************************************************************************************************************
286 
287 int ShmemSocket::read_fif (FILE *fd, long pos, size_t size, char *data)
288 {
289  if (fd == NULL) {
290  printf("Cannot read from NULL fd.");//err_set_error("Cannot read from NULL fd.");
291  return (FAIL);
292  }
293  if (fseek(fd,pos,SEEK_SET) == -1) {
294  printf("fseek");//err_set_sys_error("fseek");
295  return (FAIL);
296  }
297  if (fread(data,size,1,fd) != (size_t) 1) {
298  printf("Data not available.");//err_set_error("Data not available.");
299  return (FAIL);
300  }
301  return (OK);
302 }
303 
304 
305 //*************************************************************************************************************
306 
307 bool ShmemSocket::connect_client ()
308 {
309  printf("About to connect to the Neuromag DACQ shared memory on this workstation (client ID %d)... ", m_iShmemId);//dacq_log("About to connect to the Neuromag DACQ shared memory on this workstation (client ID %d)...\n", shmem_id);
310  int old_umask = umask(SOCKET_UMASK);
311  int id = m_iShmemId;
312 
313  struct sockaddr_un clntaddr; /* address of client */
314  char client_path[200]; /* This our path */
315  int sock = -1; /* This is the UNIX domain socket */
316 
317  sprintf (client_path,"%s%d",SOCKET_PATHCLNT,id);
318  /*
319  * Is this safe?
320  */
321  (void)unlink(client_path);
322 
323  /* Create a UNIX datagram socket for client */
324 
325  if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
326  //dacq_perror("socket");
327  printf("socket error");
328  umask(old_umask);
329  m_iShmemSock = -1;
330  return false;
331  }
332  /* Client will bind to an address so server will get
333  * an address in its recvfrom call and can use it to
334  * send data back to the client.
335  */
336  bzero(&clntaddr, sizeof(clntaddr));
337  clntaddr.sun_family = AF_UNIX;
338  strcpy(clntaddr.sun_path, client_path);
339 
340  if (bind(sock, (sockaddr *)(&clntaddr), sizeof(clntaddr)) < 0) {
341  close(sock);
342  //dacq_perror("bind");
343  printf("bind error");
344  umask(old_umask);
345  m_iShmemSock = -1;
346  return false;
347  }
348  if (connect_disconnect(sock,id) == FAIL)
349  {
350  m_iShmemSock = -1;
351  umask(old_umask);
352  return false;
353  }
354  else
355  {
356  m_iShmemSock = sock;
357  return true;
358  printf("[done]\r\n");//dacq_log("Connection ok\n");
359  }
360 }
361 
362 
363 //*************************************************************************************************************
364 
365 int ShmemSocket::disconnect_client ()
366 {
367  int sock = m_iShmemSock;
368  int id = m_iShmemId;
369 
370  int result = connect_disconnect(sock,-id);
371  this->close_socket ();
372  return (result);
373 }
374 
375 
376 //*************************************************************************************************************
377 
378 void ShmemSocket::set_data_filter (int *kinds, int nkind)
379 {
380  if (nkind <= 0) {
381  free (filter_kinds);
382  delete[] filter_kinds;
383  nfilt = 0;
384  }
385  else {
386  nfilt = nkind;
387  if(filter_kinds)
388  delete[] filter_kinds;
389  filter_kinds = new int[nfilt];
390  memcpy(filter_kinds,kinds,nfilt*sizeof(int));
391  }
392  return;
393 }
394 
395 
396 //*************************************************************************************************************
397 
398 void ShmemSocket::close_socket ()
399 {
400  int sock = m_iShmemSock;
401  int id = m_iShmemId;
402 
403 
404  char client_path[200]; /* This our path */
405 
406  if (sock != -1) {
407  /*
408  * Use unlink to remove the file (inode) so that the name
409  * will be available for the next run.
410  */
411  sprintf (client_path,"%s%d",SOCKET_PATHCLNT,id);
412  unlink(client_path);
413  close(sock);
414  }
415  (void) release_shmem();
416  //dacq_log ("Connection closed.\n");
417  printf ("Connection closed.\r\n");
418 }
419 
420 
421 //*************************************************************************************************************
422 
423 int ShmemSocket::connect_disconnect (int sock,int id)
424 {
425  struct sockaddr_un servaddr; /* address of server */
426  struct sockaddr_un from;
427 
428  socklen_t fromlen;
429  int result;
430  int slen, rlen;
431 
432  if (sock < 0)
433  return (OK);
434  /*
435  * Set up address structure for server socket
436  */
437  bzero(&servaddr, sizeof(servaddr));
438  servaddr.sun_family = AF_UNIX;
439  strcpy(servaddr.sun_path, SOCKET_PATH);
440 
441  slen = sendto(sock, (void *)(&id), sizeof(int), 0,
442  (sockaddr *)(&servaddr), sizeof(servaddr));
443  if (slen<0) {
444  printf("sendto error");//dacq_perror("sendto");
445  this->close_socket ();
446  return (FAIL);
447  }
448  else {
449  fromlen = sizeof(from);
450  rlen = recvfrom(sock, (void *)(&result), sizeof(int), 0,
451  (sockaddr *)(&from), &fromlen);
452  if (rlen == -1) {
453  printf("recvfrom");//dacq_perror("recvfrom");
454  this->close_socket ();
455  return (FAIL);
456  }
457  else
458  return result;
459  }
460 }
461 
462 
463 //*************************************************************************************************************
464 
465 int ShmemSocket::interesting_data (int kind)
466 {
467  int k;
468  for (k = 0; k < nfilt; k++)
469  if (kind == filter_kinds[k])
470  return (0);
471  return (1);
472 }
473 
474 
475 //*************************************************************************************************************
476 //=============================================================================================================
477 // shmem.c
478 //=============================================================================================================
479 
480 dacqShmBlock ShmemSocket::get_shmem()
481 {
482  if (init_shmem() == -1)
483  return(NULL);
484  else
485  return(shmptr);
486 }
487 
488 
489 //*************************************************************************************************************
490 
491 int ShmemSocket::init_shmem()
492 {
493  key_t key = ftok(SHM_FILE,'A');
494 
495  if (shmid == -1) {
496  if ((shmid = shmget(key,SHM_SIZE,IPC_CREAT | 0666)) == -1) {
497  printf("shmget");//err_set_sys_error("shmget");
498  return (-1);
499  }
500  }
501  if (shmptr == NULL) {
502  if (!(shmptr = (dacqShmBlockRec*)shmat(shmid,0,0))) {
503  printf("shmat");//err_set_sys_error("shmat");
504  shmptr = NULL;
505  return (-1);
506  }
507  }
508  return (0);
509 }
510 
511 
512 //*************************************************************************************************************
513 
514 int ShmemSocket::release_shmem()
515 {
516  if (shmid == -1)
517  return (0);
518  if (shmptr != NULL) {
519  if (shmdt(shmptr) == -1) {
520  //err_set_sys_error("shmdt");
521  printf("shmdt");
522  return (-1);
523  }
524  shmptr = NULL;
525  }
526  return (0);
527 }
QSharedPointer< FiffTag > SPtr
Definition: fiff_tag.h:166
static void convert_tag_data(FiffTag::SPtr tag, int from_endian, int to_endian)
Definition: fiff_tag.cpp:617
#define SOCKET_UMASK
FIFF data tag.
Definition: fiff_tag.h:163
implementation of the ShmemSocket Class.
#define CLIENT_ID