diff options
Diffstat (limited to 'frontend_svr.c')
-rw-r--r-- | frontend_svr.c | 224 |
1 files changed, 131 insertions, 93 deletions
diff --git a/frontend_svr.c b/frontend_svr.c index f225c490..d26120be 100644 --- a/frontend_svr.c +++ b/frontend_svr.c @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: frontend_svr.c,v 1.30 2006-12-15 16:58:05 phintuka Exp $ + * $Id: frontend_svr.c,v 1.31 2006-12-19 18:17:33 phintuka Exp $ * */ @@ -62,9 +62,27 @@ enum { ctDetecting = 0, ctControl, ctHttp, - ctRtsp + ctHttpPlay, // client can't access file that is just played -> stream over http + ctRtsp, + ctRtspMux // multiplexed RTSP control + RTP/RTCP data/control }; +// (data) connection types +enum { + dtPipe = 0x01, + dtTcp = 0x02, + dtUdp = 0x04, + dtRtp = 0x08, + dtHttp = 0x10, + dtRtspMux = 0x20, +}; + +// (data) connection properties +#define DATA_STREAM(dt) ((dt) & (dtPipe | dtTcp | dtHttp | dtRtspMux)) +#define DATA_DATAGRAM(dt) ((dt) & (dtUdp | dtRtp)) +#define DATA_NOPOLL(dt) ((dt) & (dtHttp | dtRtspMux)) +#define DATA_NOCONTROL(dt) ((dt) & (dtHttp | dtRtspMux)) + cXinelibServer::cXinelibServer(int listen_port) : cXinelibThread("Remote decoder/display server (cXinelibServer)") { @@ -80,6 +98,7 @@ cXinelibServer::cXinelibServer(int listen_port) : } m_Port = listen_port; + m_ServerId = time(NULL) ^ getpid(); fd_listen = -1; fd_discovery = -1; @@ -95,9 +114,9 @@ cXinelibServer::cXinelibServer(int listen_port) : cString Base(cPlugin::ConfigDirectory()); if(*Base) - m_PipesDir = cString::sprintf("%s/xineliboutput/pipes", *Base); + m_PipesDir = cString::sprintf("%s/xineliboutput/pipes.%d", *Base, getpid()); else - m_PipesDir = cString("/tmp/xineliboutput/pipes"); + m_PipesDir = cString::sprintf("/tmp/xineliboutput/pipes.%d", getpid()); m_Token = 1; } @@ -740,8 +759,10 @@ uchar *cXinelibServer::GrabImage(int &Size, bool Jpeg, Lock(); /* Check if there are any clients */ - if(!HasClients()) + if(!HasClients()) { + Unlock(); return NULL; + } sprintf(cmd, "GRAB %s %d %d %d\r\n", Jpeg ? "JPEG" : "PNM", Quality, SizeX, SizeY); @@ -794,7 +815,7 @@ void cXinelibServer::Handle_Control_PIPE(int cli, const char *arg) if(!xc.remote_usepipe) { LOGMSG("PIPE transport disabled in configuration"); - write_cmd(fd_control[cli], "PIPE NONE\r\n"); + write_cmd(fd_control[cli], "PIPE: Pipe transport disabled in config.\r\n"); return; } @@ -814,7 +835,7 @@ void cXinelibServer::Handle_Control_PIPE(int cli, const char *arg) if(i>=10) { LOGERR("Pipe creation failed (%s)", pipeName); RemoveFileOrDir(*m_PipesDir, false); - write_cmd(fd_control[cli], "PIPE NONE\r\n"); + write_cmd(fd_control[cli], "PIPE: Pipe creation failed.\r\n"); return; } @@ -836,7 +857,7 @@ void cXinelibServer::Handle_Control_PIPE(int cli, const char *arg) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK); - LOGDBG("cXinelibServer::Handle_Control: pipe %s open", pipeName); + //LOGDBG("cXinelibServer::Handle_Control: pipe %s open", pipeName); unlink(pipeName); /* safe to remove now, both ends are open or closed. */ RemoveFileOrDir(*m_PipesDir, false); @@ -850,63 +871,92 @@ void cXinelibServer::Handle_Control_PIPE(int cli, const char *arg) void cXinelibServer::Handle_Control_DATA(int cli, const char *arg) { + int clientId = -1, oldId = cli, fd = fd_control[cli]; + unsigned int ipc, portc; + LOGDBG("Data connection (TCP) requested"); CloseDataConnection(cli); if(!xc.remote_usetcp) { LOGMSG("TCP transports disabled in configuration"); + write_cmd(fd, "TCP: TCP transport disabled in config.\r\n"); CloseConnection(cli); /* actually closes the new data connection */ return; } - int clientId = -1, oldId = cli, fd = fd_control[cli]; - if(1 == sscanf(arg, "%d", &clientId) && - clientId >= 0 && clientId < MAXCLIENTS && - fd_control[clientId] >= 0) { + /* validate client ID */ + if(3 != sscanf(arg, "%d 0x%x:%d", &clientId, &ipc, &portc) || + clientId < 0 || + clientId >= MAXCLIENTS || + fd_control[clientId] < 0) { + write_cmd(fd, "TCP: Error in request (ClientId).\r\n"); + LOGDBG("Invalid data connection (TCP) request"); + /* close only new data connection, no control connection */ + CloseConnection(cli); + return; + } + + /* check client IP's */ + struct sockaddr_in sinc, sind; + socklen_t len = sizeof(sinc); + sinc.sin_addr.s_addr = 0; + sind.sin_addr.s_addr = ~0; + getpeername(fd_control[cli], (struct sockaddr *)&sind, &len); + getpeername(fd_control[clientId], (struct sockaddr *)&sinc, &len); + if(sinc.sin_addr.s_addr != sind.sin_addr.s_addr) { + write_cmd(fd, "TCP: Error in request (IP does not match).\r\n"); + LOGMSG("Invalid data connection (TCP) request: IP does not match"); + CloseConnection(cli); + return; + } + if(htonl(ipc) != sinc.sin_addr.s_addr || htons(portc) != sinc.sin_port) { + write_cmd(fd, "TCP: Error in request (invalid IP:port).\r\n"); + LOGMSG("Invalid data connection (TCP) request: control IP:port does not match"); + CloseConnection(cli); + return; + } - CloseDataConnection(clientId); + /* close old data connection */ + CloseDataConnection(clientId); - fd_control[oldId] = -1; - cli = clientId; - - write_cmd(fd, "DATA\r\n"); - - CREATE_NEW_WRITER; + /* change connection type */ - fd_data[cli] = fd; - - /* not anymore control connection, so dec primary device reference counter */ - cXinelibDevice::Instance().ForcePrimaryDevice(false); + fd_control[oldId] = -1; + cli = clientId; + + write_cmd(fd, "DATA\r\n"); - return; - } + CREATE_NEW_WRITER; - LOGDBG("Invalid data connection (TCP) request"); /* closes new data conn., no ctrl conn. */ - CloseConnection(cli); + fd_data[cli] = fd; + + /* not anymore control connection, so dec primary device reference counter */ + cXinelibDevice::Instance().ForcePrimaryDevice(false); } void cXinelibServer::Handle_Control_RTP(int cli, const char *arg) { - if(xc.remote_usertp) { - char buf[256]; - LOGDBG("Trying RTP connection ..."); - - CloseDataConnection(cli); + char buf[256]; - sprintf(buf, "RTP %s:%d\r\n", xc.remote_rtp_addr, xc.remote_rtp_port); - write_cmd(fd_control[cli], buf); + LOGDBG("Trying RTP connection ..."); - if(!m_iMulticastMask && !xc.remote_rtp_always_on) - m_Scheduler->AddRtp(); + CloseDataConnection(cli); - m_bMulticast[cli] = true; - m_iMulticastMask |= (1<<cli); - - } else { + if(!xc.remote_usertp) { + write_cmd(fd_control[cli], "RTP: RTP transport disabled in configuration.\r\n"); LOGMSG("RTP transports disabled"); - write_cmd(fd_control[cli], "RTP NONE\r\n"); + return; } + + sprintf(buf, "RTP %s:%d\r\n", xc.remote_rtp_addr, xc.remote_rtp_port); + write_cmd(fd_control[cli], buf); + + if(!m_iMulticastMask && !xc.remote_rtp_always_on) + m_Scheduler->AddRtp(); + + m_bMulticast[cli] = true; + m_iMulticastMask |= (1<<cli); } void cXinelibServer::Handle_Control_UDP(int cli, const char *arg) @@ -916,18 +966,19 @@ void cXinelibServer::Handle_Control_UDP(int cli, const char *arg) CloseDataConnection(cli); if(!xc.remote_useudp) { - LOGMSG("UDP transports disabled in configuration"); - //CloseConnection(cli); + write_cmd(fd_control[cli], "UDP: UDP transport disabled in configuration.\r\n"); + LOGMSG("UDP transport disabled in configuration"); return; } int fd = sock_connect(fd_control[cli], atoi(arg), SOCK_DGRAM); if(fd < 0) { LOGERR("socket() for UDP failed"); - //CloseConnection(cli); + write_cmd(fd_control[cli], "UDP: Socked failed.\r\n"); return; } + write_cmd(fd_control[cli], "UDP OK\r\n"); m_bUdp[cli] = true; fd_data[cli] = fd; m_Scheduler->AddHandle(fd); @@ -935,34 +986,30 @@ void cXinelibServer::Handle_Control_UDP(int cli, const char *arg) void cXinelibServer::Handle_Control_KEY(int cli, const char *arg) { - char buf[256], buf2[256]; - bool repeat=false, release=false; + TRACE("cXinelibServer received KEY " << buf); if(!xc.use_remote_keyboard) { LOGMSG("Handle_Control_KEY(%s): Remote keyboard disabled in config", arg); return; } + char buf[256], *pt, *key; + bool repeat = false, release = false; strcpy(buf, arg); - //*strstr(buf, "\r\n") = 0; - TRACE("cXinelibServer received KEY " << buf); int n = strlen(buf)-1; - while(buf[n]==' ') buf[n--]=0; - - if(strchr(buf, ' ')) { - strcpy(buf2,strchr(buf, ' ')+1); - *strchr(buf, ' ') = 0; - - char *pt = strchr(buf, ' '); - if(pt) { + while(n && buf[n]==' ') buf[n--]=0; /* trailing spaces */ + if(NULL != (key=strchr(buf, ' '))) { + while(*key == ' ') + *(key++) = 0; + if(NULL != (pt = strchr(key, ' '))) { *(pt++) = 0; if(strstr(pt, "Repeat")) repeat = true; if(strstr(pt, "Release")) release = true; } - cXinelibThread::KeypressHandler(buf, buf2, repeat, release); + cXinelibThread::KeypressHandler(buf, key, repeat, release); } else { cXinelibThread::KeypressHandler(NULL, buf, repeat, release); } @@ -1186,9 +1233,9 @@ void cXinelibServer::Handle_Control(int cli, const char *cmd) } } - } else if(!strncmp(cmd, "TRACKMAP ", 9)) { + } else if(!strncmp(cmd, "INFO ", 5)) { if(!*xc.local_frontend || strncmp(xc.local_frontend, "none", 4)) - cXinelibThread::InfoHandler(cmd); + cXinelibThread::InfoHandler(cmd+5); } else if(!strncasecmp(cmd, "GRAB ", 5)) { Handle_Control_GRAB(cli, cmd+5); @@ -1217,7 +1264,7 @@ void cXinelibServer::Read_Control(int cli) return; } - if( m_CtrlBufPos[cli] > 2 && + if( m_CtrlBufPos[cli] > 1 && m_CtrlBuf[ cli ][ m_CtrlBufPos[cli] - 2 ] == '\r' && m_CtrlBuf[ cli ][ m_CtrlBufPos[cli] - 1 ] == '\n') { @@ -1237,6 +1284,7 @@ void cXinelibServer::Read_Control(int cli) void cXinelibServer::Handle_ClientConnected(int fd) { + char buf[64]; struct sockaddr_in sin; socklen_t len = sizeof(sin); int cli; @@ -1251,11 +1299,8 @@ void cXinelibServer::Handle_ClientConnected(int fd) return; } - uint32_t tmp = ntohl(sin.sin_addr.s_addr); - LOGMSG("Client %d connected: %d.%d.%d.%d:%d", cli, - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff), - ntohs(sin.sin_port)); + LOGMSG("Client %d connected: %s", cli, + ip2txt(sin.sin_addr.s_addr, sin.sin_port, buf)); bool accepted = SVDRPhosts.Acceptable(sin.sin_addr.s_addr); if(!accepted) { @@ -1289,53 +1334,46 @@ void cXinelibServer::Handle_ClientConnected(int fd) void cXinelibServer::Handle_Discovery_Broadcast() { - char buf[1024]; + char buf[1024], ip[64]; struct sockaddr_in from; socklen_t fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - memset(buf, 0, sizeof(buf)); - errno=0; - - int n = recvfrom(fd_discovery, buf, 1023, 0, - (struct sockaddr *)&from, &fromlen); if(!xc.remote_usebcast) { LOGDBG("BROADCASTS disabled in configuration"); + CLOSESOCKET(fd_discovery); return; } - if(n==0) { - LOGDBG("fd_discovery recv() 0 bytes"); - return; - } else if(n<0) { - LOGERR("fd_discovery recv() error"); + memset(&from, 0, sizeof(from)); + memset(buf, 0, sizeof(buf)); + errno = 0; + + int n = recvfrom(fd_discovery, buf, 1023, 0, + (struct sockaddr *)&from, &fromlen); + + if(n<=0) { + LOGDBG("fd_discovery recv() error"); //CLOSESOCKET(fd_discovery); return; } - - uint32_t tmp = ntohl(from.sin_addr.s_addr); - LOGDBG("BROADCAST: (%d bytes from %d.%d.%d.%d): %s", n, - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff), - buf); char *id_string = DISCOVERY_1_0_HDR "Client:"; - if(!strncmp(id_string, buf, strlen(id_string))) { - LOGMSG("Received valid discovery message from %d.%d.%d.%d", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); - if(udp_discovery_broadcast(fd_discovery, m_Port) < 0) { - //LOGERR("Discovery broadcast send error"); - } else { - //LOGMSG("Discovery broadcast (announce) sent"); - } + if(!strncmp(id_string, buf, strlen(id_string))) { + LOGMSG("Received valid discovery message from %s", + ip2txt(from.sin_addr.s_addr, from.sin_port, ip)); + + if(udp_discovery_broadcast(fd_discovery, m_Port) < 0) + LOGERR("Discovery broadcast send error"); + } else { + LOGDBG("BROADCAST: (%d bytes from %s): %s", n, + ip2txt(from.sin_addr.s_addr, from.sin_port, ip), + buf); } } void cXinelibServer::Action(void) { - TRACEF("cXinelibServer::Action"); int i, fds=0; |