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