PageRenderTime 25ms CodeModel.GetById 8ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lirc_srv.c

http://bdremote-ng.googlecode.com/
C | 257 lines | 170 code | 43 blank | 44 comment | 21 complexity | 257cd6a1ff0ee5b398e85da473dbef19 MD5 | raw file
  1/*
  2 *  bdremoteng - helper daemon for Sony(R) BD Remote Control
  3 *  Based on bdremoted, written by Anton Starikov <antst@mail.ru>.
  4 *
  5 *  Copyright (C) 2009  Michael Wojciechowski <wojci@wojci.dk>
  6 *
  7 *
  8 *  This program is free software; you can redistribute it and/or modify
  9 *  it under the terms of the GNU General Public License as published by
 10 *  the Free Software Foundation; either version 2 of the License, or
 11 *  (at your option) any later version.
 12 *
 13 *  This program is distributed in the hope that it will be useful,
 14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 *  GNU General Public License for more details.
 17 *
 18 *  You should have received a copy of the GNU General Public License
 19 *  along with this program; if not, write to the Free Software
 20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 21 *
 22 */
 23
 24/** \ingroup LIRC */
 25/*@{*/
 26
 27/*! \file lirc_srv.c
 28  \brief Implements a LIRC server.
 29  
 30  This file implements a LIRC server. This means listening for a
 31  socket for connections from LIRC and accepting new clients. Added
 32  client are broadcast keypresses in other part of this application -
 33  see lirc_thr.c.
 34
 35  The lirc_server() function is the one to examine in order to
 36  understand how this module works.
 37
 38*/
 39
 40#include "lirc_srv.h"
 41
 42#include <globaldefs.h>
 43#define _GNU_SOURCE
 44#include <stdio.h>
 45#include <errno.h>
 46#include <fcntl.h>
 47#include <unistd.h>
 48#include <stdlib.h>
 49#include <string.h>
 50#include <syslog.h>
 51#include <signal.h>
 52#include <getopt.h>
 53#ifndef __USE_GNU
 54/* Define this to avoid a warning about implicit definition of
 55   ppoll.*/
 56#  define __USE_GNU
 57#endif
 58#include <sys/poll.h>
 59#include <sys/ioctl.h>
 60#include <sys/socket.h>
 61/* #include <poll.h> */
 62#include <netinet/in.h>
 63#include <assert.h>
 64
 65static const unsigned int moduleMask = MODULEMASK_LIRC_SOCK;
 66
 67/** Indicates that a TERM signal was received which interrupted IO. */
 68volatile sig_atomic_t __io_canceled = 0;
 69
 70void add_client(lirc_data* _lircdata);
 71int create_listener(configuration* _config, lirc_data* _lircdata);
 72
 73void initLircData(lirc_data* _ld, const configuration* _config)
 74{
 75  assert(_config != NULL);
 76  assert(
 77         pthread_mutex_init (&_ld->dataMutex, NULL) == 0
 78         );
 79
 80#if BDREMOTE_DEBUG
 81  _ld->magic0 = 0x15;
 82#endif /* BDREMOTE_DEBUG */
 83  _ld->config   = _config;
 84  _ld->sockinet = -1;
 85
 86  _ld->charge_percent     = 100;
 87  _ld->charge_percent_set = 0;
 88
 89  pthread_mutex_lock (&_ld->dataMutex);
 90
 91  memset(&_ld->clis[0], 0, MAX_CLIENTS);
 92  _ld->clin = 0;
 93
 94  pthread_mutex_unlock (&_ld->dataMutex);
 95
 96  assert(queueInit(&_ld->qu) == Q_OK);
 97}
 98
 99void destroyLircData(lirc_data* _ld)
100{
101  queueDeinit(&_ld->qu);
102
103  _ld->config = NULL;
104
105  assert(_ld->clin == 0);
106  assert(_ld->sockinet == BDREMOTE_FAIL);
107
108  pthread_mutex_destroy (&_ld->dataMutex);
109}
110
111int lirc_server(configuration* _config, lirc_data* _lircdata)
112{
113  struct pollfd p;
114  sigset_t sigs;
115  int i = 0;
116
117  if (create_listener(_config, _lircdata) == BDREMOTE_FAIL)
118    {
119      return BDREMOTE_FAIL;
120    }
121
122  sigfillset(&sigs);
123  sigdelset(&sigs, SIGCHLD);
124  sigdelset(&sigs, SIGPIPE);
125  sigdelset(&sigs, SIGTERM);
126  sigdelset(&sigs, SIGINT);
127  sigdelset(&sigs, SIGHUP);
128
129  p.fd = _lircdata->sockinet;
130  p.events = POLLIN | POLLERR | POLLHUP;
131
132  while (!__io_canceled)
133    {
134      p.revents = 0;
135      if (ppoll(&p, 1, NULL, &sigs) < 1)
136        {
137          continue;
138        }
139      if (p.events & POLLIN)
140        {
141          BDREMOTE_DBG(_config->debug, "new client accepted.");
142          add_client(_lircdata);
143        }
144    }
145
146  pthread_mutex_lock (&_lircdata->dataMutex);
147
148  /* Close all client sockets. */
149  for(i=0;i<_lircdata->clin;i++)
150    {
151      shutdown(_lircdata->clis[i],2);
152      close(_lircdata->clis[i]);
153    }
154
155  _lircdata->clin = 0;
156
157  pthread_mutex_unlock (&_lircdata->dataMutex);
158
159  shutdown(_lircdata->sockinet,2);
160  close(_lircdata->sockinet);
161
162  _lircdata->sockinet = BDREMOTE_FAIL;
163
164  return BDREMOTE_OK;
165}
166
167int create_listener(configuration* _config, lirc_data* _lircdata)
168{
169  int enable=1;
170  unsigned short int port=_config->listen_port;
171  struct sockaddr_in serv_addr_in;
172  /* create socket*/
173  _lircdata->sockinet=socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
174  if (_lircdata->sockinet==-1)
175    {
176      perror("socket");
177      BDREMOTE_DBG(_config->debug, "Could not create TCP/IP socket.");
178      return BDREMOTE_FAIL;
179    }
180  (void) setsockopt(_lircdata->sockinet,SOL_SOCKET,SO_REUSEADDR,&enable,sizeof(enable));
181  serv_addr_in.sin_family      = AF_INET;
182  serv_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
183  serv_addr_in.sin_port        = htons(port);
184
185  if (bind(_lircdata->sockinet,(struct sockaddr *) &serv_addr_in,
186           sizeof(serv_addr_in))==-1)
187    {
188      BDREMOTE_DBG(_config->debug, "Could not assign address to socket\n");
189      perror("bind");
190      close(_lircdata->sockinet);
191      return BDREMOTE_FAIL;
192    }
193
194  listen(_lircdata->sockinet,3);
195  nolinger(_lircdata->sockinet);
196
197  return BDREMOTE_OK;
198}
199
200void add_client(lirc_data* _lircdata)
201{
202  struct sockaddr client_addr;
203  socklen_t clilen = sizeof(client_addr);
204  int flags  = 0;
205  int fd     = accept(_lircdata->sockinet,(struct sockaddr *)&client_addr, &clilen);
206
207  if (fd==-1)
208    {
209      BDREMOTE_DBG(_lircdata->config->debug,
210                   "accept() failed for new client.");
211      perror("accept");
212    };
213
214  if(fd>=FD_SETSIZE || _lircdata->clin>=MAX_CLIENTS)
215    {
216      BDREMOTE_DBG(_lircdata->config->debug,
217                   "Connection rejected.");
218      shutdown(fd,2);
219      close(fd);
220      return;
221    }
222  nolinger(fd);
223
224  flags=fcntl(fd, F_GETFL, 0);
225  if(flags!=-1)
226    {
227      fcntl(fd,F_SETFL,flags|O_NONBLOCK);
228    }
229  pthread_mutex_lock (&_lircdata->dataMutex);
230  _lircdata->clis[_lircdata->clin++]=fd;
231  pthread_mutex_unlock (&_lircdata->dataMutex);
232}
233
234/* Only called from LIRC thread, mutex already locked. */
235void remove_client(lirc_data* _lircdata, int fd)
236{
237  int i;
238  for(i=0;i<_lircdata->clin;i++)
239    {
240      if(_lircdata->clis[i] == fd)
241        {
242          shutdown(_lircdata->clis[i],2);
243          close(_lircdata->clis[i]);
244
245          _lircdata->clin--;
246
247          for(;i<_lircdata->clin;i++)
248            {
249              _lircdata->clis[i]=_lircdata->clis[i+1];
250            }
251          return;
252        }
253    }
254}
255
256/*@}*/
257