1 /*
2  * Copyright (C) 2011 Raphael Coeffic
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 #include <string.h>
29 
30 #include "RtmpServer.h"
31 #include "RtmpConnection.h"
32 #include "log.h"
33 
34 #include "librtmp/rtmp.h"
35 #include "librtmp/log.h"
36 
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 
41 #define CONN_BACKLOG 4
42 
43 #define SAv4(addr) \
44             ((struct sockaddr_in*)addr)
45 
46 
_RtmpServer()47 _RtmpServer::_RtmpServer()
48   : AmThread(), fds_num(0)
49 {
50 }
51 
~_RtmpServer()52 _RtmpServer::~_RtmpServer()
53 {
54   if(fds_num) {
55     for(unsigned int i=0; i<fds_num; i++)
56       ::close(fds[i].fd);
57   }
58 }
59 
listen(const char * addr,unsigned short port)60 int _RtmpServer::listen(const char* addr, unsigned short port)
61 {
62   int listen_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
63   if(listen_fd < 0){
64     ERROR("socket() failed: %s\n",strerror(errno));
65     return -1;
66   }
67   int onoff=1;
68   if(setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&onoff,sizeof(onoff))<0){
69     ERROR("setsockopt(...,SO_REUSEADDR,...) failed: %s\n",strerror(errno));
70     close(listen_fd);
71     return -1;
72   }
73 
74   memset(&listen_addr,0,sizeof(listen_addr));
75 
76   listen_addr.ss_family = AF_INET;
77 #if defined(BSD44SOCKETS)
78   listen_addr.ss_len = sizeof(struct sockaddr_in);
79 #endif
80   SAv4(&listen_addr)->sin_port = htons(port);
81 
82   if(inet_aton(addr,&SAv4(&listen_addr)->sin_addr)<0){
83 
84     ERROR("inet_aton: %s\n",strerror(errno));
85     return -1;
86   }
87 
88   if(bind(listen_fd,(const sockaddr*)&listen_addr,sizeof(struct sockaddr_in)) < 0){
89     ERROR("bind() failed: %s\n",strerror(errno));
90     close(listen_fd);
91     return -1;
92   }
93 
94   if(::listen(listen_fd,CONN_BACKLOG)<0){
95     ERROR("listen() failed: %s\n",strerror(errno));
96     close(listen_fd);
97     return -1;
98   }
99 
100   fds[0].fd = listen_fd;
101   fds[0].events = POLLIN | POLLERR;
102   fds_num++;
103 
104   return 0;
105 }
106 
run()107 void _RtmpServer::run()
108 {
109   RTMP_LogSetLevel(RTMP_LOGDEBUG);
110 
111   INFO("RTMP server started (%s:%i)\n",
112        inet_ntoa(SAv4(&listen_addr)->sin_addr),
113        ntohs(SAv4(&listen_addr)->sin_port));
114 
115   while(fds_num){
116     int ret = poll(fds,fds_num,500/*ms*/);
117     if(ret == 0){
118       continue;
119     }
120 
121     if(ret<0){
122       switch(errno){
123       case EAGAIN:
124       case EINTR:
125 	continue;
126       default:
127 	ERROR("poll() failed: %s\n",strerror(errno));
128 	return;
129       }
130     }
131 
132     for(unsigned int i=0; i<fds_num; i++){
133       if(fds[i].revents != 0){
134 	if(i == 0){
135 	  if(fds[i].revents & POLLIN){
136 	    struct sockaddr_in remote_addr;
137 	    socklen_t remote_addr_len = sizeof(remote_addr);
138 	    int new_fd = accept(fds[i].fd,(struct sockaddr*)&remote_addr,
139 				&remote_addr_len);
140 	    if(new_fd < 0){
141 	      ERROR("accept() failed: %s\n",strerror(errno));
142 	      continue;
143 	    }
144 	    RtmpConnection * conn = new RtmpConnection(new_fd);
145 	    conn->start();
146 	  } else {
147 	    // POLLERR or POLLHUP
148 	    ERROR("on socket %i",fds[i].fd);
149 	    close(fds[i].fd);
150 	    if(fds_num != 1){
151 	      fds[i] = fds[fds_num-1];
152 	    }
153 	    memset(&(fds[fds_num-1]),0,sizeof(struct pollfd));
154 	    fds_num--;
155 	  }
156 	}
157       }
158     }
159   }
160 
161   INFO("RTMP event loop finished/n");
162 }
163 
on_stop()164 void _RtmpServer::on_stop()
165 {
166   ERROR("not yet supported!\n");
167 }
168 
dispose()169 void _RtmpServer::dispose()
170 {
171   ERROR("not yet supported!\n");
172 }
173