/src/lirc_srv.c
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