1 #ifndef __XBMC_CLIENT_H__
2 #define __XBMC_CLIENT_H__
5 * Copyright (C) 2008-2009 Team XBMC http://www.xbmc.org
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
32 #include <arpa/inet.h>
41 #define MS_ABSOLUTE 0x01
42 //#define MS_RELATIVE 0x02
44 #define BTN_USE_NAME 0x01
47 #define BTN_USE_AMOUNT 0x08
48 #define BTN_QUEUE 0x10
49 #define BTN_NO_REPEAT 0x20
55 #define PT_BUTTON 0x03
58 #define PT_BROADCAST 0x06
59 #define PT_NOTIFICATION 0x07
62 #define PT_ACTION 0x0A
65 #define ICON_NONE 0x00
66 #define ICON_JPEG 0x01
70 #define MAX_PACKET_SIZE 1024
71 #define HEADER_SIZE 32
72 #define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - HEADER_SIZE)
74 #define MAJOR_VERSION 2
75 #define MINOR_VERSION 0
86 #define ACTION_EXECBUILTIN 0x01
87 #define ACTION_BUTTON 0x02
92 struct sockaddr_in m_Addr
;
94 CAddress(int Port
= STD_PORT
)
96 m_Addr
.sin_family
= AF_INET
;
97 m_Addr
.sin_port
= htons(Port
);
98 m_Addr
.sin_addr
.s_addr
= INADDR_ANY
;
99 memset(m_Addr
.sin_zero
, '\0', sizeof m_Addr
.sin_zero
);
102 CAddress(const char *Address
, int Port
= STD_PORT
)
104 m_Addr
.sin_port
= htons(Port
);
107 if (Address
== NULL
|| (h
=gethostbyname(Address
)) == NULL
)
110 printf("Error: Get host by name\n");
112 m_Addr
.sin_addr
.s_addr
= INADDR_ANY
;
113 m_Addr
.sin_family
= AF_INET
;
117 m_Addr
.sin_family
= h
->h_addrtype
;
118 m_Addr
.sin_addr
= *((struct in_addr
*)h
->h_addr
);
120 memset(m_Addr
.sin_zero
, '\0', sizeof m_Addr
.sin_zero
);
123 void SetPort(int port
)
125 m_Addr
.sin_port
= htons(port
);
128 const sockaddr
*GetAddress()
130 return ((struct sockaddr
*)&m_Addr
);
133 bool Bind(int Sockfd
)
135 return (bind(Sockfd
, (struct sockaddr
*)&m_Addr
, sizeof m_Addr
) == 0);
139 class XBMCClientUtils
143 ~XBMCClientUtils() {}
144 static unsigned int GetUniqueIdentifier()
146 static time_t id
= time(NULL
);
157 static bool Initialize()
161 if (WSAStartup(MAKEWORD(1, 1), &wsaData
))
170 /* Base class that implements a single event packet.
172 - Generic packet structure (maximum 1024 bytes per packet)
173 - Header is 32 bytes long, so 992 bytes available for payload
174 - large payloads can be split into multiple packets using H4 and H5
175 H5 should contain total no. of packets in such a case
176 - H6 contains length of P1, which is limited to 992 bytes
177 - if H5 is 0 or 1, then H4 will be ignored (single packet msg)
178 - H7 must be set to zeros for now
180 -----------------------------
181 | -H1 Signature ("XBMC") | - 4 x CHAR 4B
182 | -H2 Version (eg. 2.0) | - 2 x UNSIGNED CHAR 2B
183 | -H3 PacketType | - 1 x UNSIGNED SHORT 2B
184 | -H4 Sequence number | - 1 x UNSIGNED LONG 4B
185 | -H5 No. of packets in msg | - 1 x UNSIGNED LONG 4B
186 | -H6 Payload size | - 1 x UNSIGNED SHORT 2B
187 | -H7 Client's unique token | - 1 x UNSIGNED LONG 4B
188 | -H8 Reserved | - 10 x UNSIGNED CHAR 10B
189 |---------------------------|
191 -----------------------------
201 bool Send(int Socket
, CAddress
&Addr
, unsigned int UID
= XBMCClientUtils::GetUniqueIdentifier())
203 if (m_Payload
.size() == 0)
205 bool SendSuccessfull
= true;
206 int NbrOfPackages
= (m_Payload
.size() / MAX_PAYLOAD_SIZE
) + 1;
209 int Left
= m_Payload
.size();
210 for (int Package
= 1; Package
<= NbrOfPackages
; Package
++)
212 if (Left
> MAX_PAYLOAD_SIZE
)
214 Send
= MAX_PAYLOAD_SIZE
;
223 ConstructHeader(m_PacketType
, NbrOfPackages
, Package
, Send
, UID
, m_Header
);
224 char t
[MAX_PACKET_SIZE
];
226 for (i
= 0; i
< 32; i
++)
229 for (j
= 0; j
< Send
; j
++)
230 t
[(32 + j
)] = m_Payload
[j
+ Sent
];
232 int rtn
= sendto(Socket
, t
, (32 + Send
), 0, Addr
.GetAddress(), sizeof(struct sockaddr
));
234 if (rtn
!= (32 + Send
))
235 SendSuccessfull
= false;
239 return SendSuccessfull
;
242 char m_Header
[HEADER_SIZE
];
243 unsigned short m_PacketType
;
245 std::vector
<char> m_Payload
;
247 static void ConstructHeader(int PacketType
, int NumberOfPackets
, int CurrentPacket
, unsigned short PayloadSize
, unsigned int UniqueToken
, char *Header
)
249 sprintf(Header
, "XBMC");
250 for (int i
= 4; i
< HEADER_SIZE
; i
++)
252 Header
[4] = MAJOR_VERSION
;
253 Header
[5] = MINOR_VERSION
;
254 if (CurrentPacket
== 1)
256 Header
[6] = ((PacketType
& 0xff00) >> 8);
257 Header
[7] = (PacketType
& 0x00ff);
261 Header
[6] = ((PT_BLOB
& 0xff00) >> 8);
262 Header
[7] = (PT_BLOB
& 0x00ff);
264 Header
[8] = ((CurrentPacket
& 0xff000000) >> 24);
265 Header
[9] = ((CurrentPacket
& 0x00ff0000) >> 16);
266 Header
[10] = ((CurrentPacket
& 0x0000ff00) >> 8);
267 Header
[11] = (CurrentPacket
& 0x000000ff);
269 Header
[12] = ((NumberOfPackets
& 0xff000000) >> 24);
270 Header
[13] = ((NumberOfPackets
& 0x00ff0000) >> 16);
271 Header
[14] = ((NumberOfPackets
& 0x0000ff00) >> 8);
272 Header
[15] = (NumberOfPackets
& 0x000000ff);
274 Header
[16] = ((PayloadSize
& 0xff00) >> 8);
275 Header
[17] = (PayloadSize
& 0x00ff);
277 Header
[18] = ((UniqueToken
& 0xff000000) >> 24);
278 Header
[19] = ((UniqueToken
& 0x00ff0000) >> 16);
279 Header
[20] = ((UniqueToken
& 0x0000ff00) >> 8);
280 Header
[21] = (UniqueToken
& 0x000000ff);
283 virtual void ConstructPayload()
287 class CPacketHELO
: public CPacket
289 /************************************************************************/
291 /* %s - device name (max 128 chars) */
292 /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */
293 /* %s - my port ( 0=>not listening ) */
294 /* %d - reserved1 ( 0 ) */
295 /* %d - reserved2 ( 0 ) */
296 /* XX - imagedata ( can span multiple packets ) */
297 /************************************************************************/
299 std::vector
<char> m_DeviceName
;
300 unsigned short m_IconType
;
302 unsigned short m_IconSize
;
304 virtual void ConstructPayload()
308 for (unsigned int i
= 0; i
< m_DeviceName
.size(); i
++)
309 m_Payload
.push_back(m_DeviceName
[i
]);
311 m_Payload
.push_back('\0');
313 m_Payload
.push_back(m_IconType
);
315 m_Payload
.push_back(0);
316 m_Payload
.push_back('\0');
318 for (int j
= 0; j
< 8; j
++)
319 m_Payload
.push_back(0);
321 for (int ico
= 0; ico
< m_IconSize
; ico
++)
322 m_Payload
.push_back(m_IconData
[ico
]);
325 CPacketHELO(const char *DevName
, unsigned short IconType
, const char *IconFile
= NULL
) : CPacket()
327 m_PacketType
= PT_HELO
;
329 unsigned int len
= strlen(DevName
);
330 for (unsigned int i
= 0; i
< len
; i
++)
331 m_DeviceName
.push_back(DevName
[i
]);
333 m_IconType
= IconType
;
335 if (IconType
== ICON_NONE
|| IconFile
== NULL
)
342 std::ifstream::pos_type size
;
344 std::ifstream
file (IconFile
, std::ios::in
|std::ios::binary
|std::ios::ate
);
348 m_IconData
= new char [size
];
349 file
.seekg (0, std::ios::beg
);
350 file
.read (m_IconData
, size
);
356 m_IconType
= ICON_NONE
;
361 virtual ~CPacketHELO()
363 m_DeviceName
.clear();
369 class CPacketNOTIFICATION
: public CPacket
371 /************************************************************************/
372 /* Payload format: */
375 /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */
376 /* %d - reserved ( 0 ) */
377 /* XX - imagedata ( can span multiple packets ) */
378 /************************************************************************/
380 std::vector
<char> m_Title
;
381 std::vector
<char> m_Message
;
382 unsigned short m_IconType
;
384 unsigned short m_IconSize
;
386 virtual void ConstructPayload()
390 for (unsigned int i
= 0; i
< m_Title
.size(); i
++)
391 m_Payload
.push_back(m_Title
[i
]);
393 m_Payload
.push_back('\0');
395 for (unsigned int i
= 0; i
< m_Message
.size(); i
++)
396 m_Payload
.push_back(m_Message
[i
]);
398 m_Payload
.push_back('\0');
400 m_Payload
.push_back(m_IconType
);
402 for (int i
= 0; i
< 4; i
++)
403 m_Payload
.push_back(0);
405 for (int ico
= 0; ico
< m_IconSize
; ico
++)
406 m_Payload
.push_back(m_IconData
[ico
]);
409 CPacketNOTIFICATION(const char *Title
, const char *Message
, unsigned short IconType
, const char *IconFile
= NULL
) : CPacket()
411 m_PacketType
= PT_NOTIFICATION
;
414 unsigned int len
= 0;
418 for (unsigned int i
= 0; i
< len
; i
++)
419 m_Title
.push_back(Title
[i
]);
424 len
= strlen(Message
);
425 for (unsigned int i
= 0; i
< len
; i
++)
426 m_Message
.push_back(Message
[i
]);
428 m_IconType
= IconType
;
430 if (IconType
== ICON_NONE
|| IconFile
== NULL
)
433 std::ifstream::pos_type size
;
435 std::ifstream
file (IconFile
, std::ios::in
|std::ios::binary
|std::ios::ate
);
439 m_IconData
= new char [size
];
440 file
.seekg (0, std::ios::beg
);
441 file
.read (m_IconData
, size
);
446 m_IconType
= ICON_NONE
;
449 virtual ~CPacketNOTIFICATION()
458 class CPacketBUTTON
: public CPacket
460 /************************************************************************/
462 /* %i - button code */
463 /* %i - flags 0x01 => use button map/name instead of code */
464 /* 0x02 => btn down */
466 /* 0x08 => use amount */
467 /* 0x10 => queue event */
468 /* 0x20 => do not repeat */
469 /* 0x40 => virtual key */
470 /* 0x40 => axis key */
471 /* %i - amount ( 0 => 65k maps to -1 => 1 ) */
472 /* %s - device map (case sensitive and required if flags & 0x01) */
473 /* "KB" - Standard keyboard map */
474 /* "XG" - Xbox Gamepad */
475 /* "R1" - Xbox Remote */
476 /* "R2" - Xbox Universal Remote */
477 /* "LI:devicename" - valid LIRC device map where 'devicename' */
478 /* is the actual name of the LIRC device */
479 /* "JS<num>:joyname" - valid Joystick device map where */
480 /* 'joyname' is the name specified in */
481 /* the keymap. JS only supports button code */
482 /* and not button name currently (!0x01). */
483 /* %s - button name (required if flags & 0x01) */
484 /************************************************************************/
486 std::vector
<char> m_DeviceMap
;
487 std::vector
<char> m_Button
;
488 unsigned short m_ButtonCode
;
489 unsigned short m_Amount
;
490 unsigned short m_Flags
;
492 virtual void ConstructPayload()
496 if (m_Button
.size() != 0)
498 if (!(m_Flags
& BTN_USE_NAME
)) // If the BTN_USE_NAME isn't flagged for some reason
499 m_Flags
|= BTN_USE_NAME
;
507 if (!(m_Flags
& BTN_USE_AMOUNT
))
508 m_Flags
|= BTN_USE_AMOUNT
;
510 if (!((m_Flags
& BTN_DOWN
) || (m_Flags
& BTN_UP
))) //If none of them are tagged.
513 m_Payload
.push_back(((m_ButtonCode
& 0xff00) >> 8));
514 m_Payload
.push_back( (m_ButtonCode
& 0x00ff));
516 m_Payload
.push_back(((m_Flags
& 0xff00) >> 8) );
517 m_Payload
.push_back( (m_Flags
& 0x00ff));
519 m_Payload
.push_back(((m_Amount
& 0xff00) >> 8) );
520 m_Payload
.push_back( (m_Amount
& 0x00ff));
523 for (unsigned int i
= 0; i
< m_DeviceMap
.size(); i
++)
524 m_Payload
.push_back(m_DeviceMap
[i
]);
526 m_Payload
.push_back('\0');
528 for (unsigned int i
= 0; i
< m_Button
.size(); i
++)
529 m_Payload
.push_back(m_Button
[i
]);
531 m_Payload
.push_back('\0');
534 CPacketBUTTON(const char *Button
, const char *DeviceMap
, unsigned short Flags
, unsigned short Amount
= 0) : CPacket()
536 m_PacketType
= PT_BUTTON
;
541 unsigned int len
= strlen(DeviceMap
);
542 for (unsigned int i
= 0; i
< len
; i
++)
543 m_DeviceMap
.push_back(DeviceMap
[i
]);
545 len
= strlen(Button
);
546 for (unsigned int i
= 0; i
< len
; i
++)
547 m_Button
.push_back(Button
[i
]);
550 CPacketBUTTON(unsigned short ButtonCode
, const char *DeviceMap
, unsigned short Flags
, unsigned short Amount
= 0) : CPacket()
552 m_PacketType
= PT_BUTTON
;
554 m_ButtonCode
= ButtonCode
;
557 unsigned int len
= strlen(DeviceMap
);
558 for (unsigned int i
= 0; i
< len
; i
++)
559 m_DeviceMap
.push_back(DeviceMap
[i
]);
562 CPacketBUTTON(unsigned short ButtonCode
, unsigned short Flags
, unsigned short Amount
= 0) : CPacket()
564 m_PacketType
= PT_BUTTON
;
566 m_ButtonCode
= ButtonCode
;
570 // Used to send a release event
571 CPacketBUTTON() : CPacket()
573 m_PacketType
= PT_BUTTON
;
579 virtual ~CPacketBUTTON()
585 inline unsigned short GetFlags() { return m_Flags
; }
586 inline unsigned short GetButtonCode() { return m_ButtonCode
; }
589 class CPacketPING
: public CPacket
591 /************************************************************************/
593 /************************************************************************/
595 CPacketPING() : CPacket()
597 m_PacketType
= PT_PING
;
599 virtual ~CPacketPING()
603 class CPacketBYE
: public CPacket
605 /************************************************************************/
607 /************************************************************************/
609 CPacketBYE() : CPacket()
611 m_PacketType
= PT_BYE
;
613 virtual ~CPacketBYE()
617 class CPacketMOUSE
: public CPacket
619 /************************************************************************/
622 /* - 0x01 absolute position */
623 /* %i - mousex (0-65535 => maps to screen width) */
624 /* %i - mousey (0-65535 => maps to screen height) */
625 /************************************************************************/
629 unsigned char m_Flag
;
631 CPacketMOUSE(int X
, int Y
, unsigned char Flag
= MS_ABSOLUTE
)
633 m_PacketType
= PT_MOUSE
;
639 virtual void ConstructPayload()
643 m_Payload
.push_back(m_Flag
);
645 m_Payload
.push_back(((m_X
& 0xff00) >> 8));
646 m_Payload
.push_back( (m_X
& 0x00ff));
648 m_Payload
.push_back(((m_Y
& 0xff00) >> 8));
649 m_Payload
.push_back( (m_Y
& 0x00ff));
652 virtual ~CPacketMOUSE()
656 class CPacketLOG
: public CPacket
658 /************************************************************************/
662 /************************************************************************/
664 std::vector
<char> m_Message
;
665 unsigned char m_LogLevel
;
668 CPacketLOG(int LogLevel
, const char *Message
, bool AutoPrintf
= true)
670 m_PacketType
= PT_LOG
;
672 unsigned int len
= strlen(Message
);
673 for (unsigned int i
= 0; i
< len
; i
++)
674 m_Message
.push_back(Message
[i
]);
676 m_LogLevel
= LogLevel
;
677 m_AutoPrintf
= AutoPrintf
;
680 virtual void ConstructPayload()
684 m_Payload
.push_back( (m_LogLevel
& 0x00ff) );
688 char* str
=&m_Message
[0];
691 for (unsigned int i
= 0; i
< m_Message
.size(); i
++)
692 m_Payload
.push_back(m_Message
[i
]);
694 m_Payload
.push_back('\0');
697 virtual ~CPacketLOG()
701 class CPacketACTION
: public CPacket
703 /************************************************************************/
705 /* %c - action type */
706 /* %s - action message */
707 /************************************************************************/
709 unsigned char m_ActionType
;
710 std::vector
<char> m_Action
;
712 CPacketACTION(const char *Action
, unsigned char ActionType
= ACTION_EXECBUILTIN
)
714 m_PacketType
= PT_ACTION
;
716 m_ActionType
= ActionType
;
717 unsigned int len
= strlen(Action
);
718 for (unsigned int i
= 0; i
< len
; i
++)
719 m_Action
.push_back(Action
[i
]);
722 virtual void ConstructPayload()
726 m_Payload
.push_back(m_ActionType
);
727 for (unsigned int i
= 0; i
< m_Action
.size(); i
++)
728 m_Payload
.push_back(m_Action
[i
]);
730 m_Payload
.push_back('\0');
733 virtual ~CPacketACTION()
744 CXBMCClient(const char *IP
= "127.0.0.1", int Port
= 9777, int Socket
= -1, unsigned int UID
= 0)
746 m_Addr
= CAddress(IP
, Port
);
748 m_Socket
= socket(AF_INET
, SOCK_DGRAM
, 0);
755 m_UID
= XBMCClientUtils::GetUniqueIdentifier();
758 void SendNOTIFICATION(const char *Title
, const char *Message
, unsigned short IconType
, const char *IconFile
= NULL
)
763 CPacketNOTIFICATION
notification(Title
, Message
, IconType
, IconFile
);
764 notification
.Send(m_Socket
, m_Addr
, m_UID
);
767 void SendHELO(const char *DevName
, unsigned short IconType
, const char *IconFile
= NULL
)
772 CPacketHELO
helo(DevName
, IconType
, IconFile
);
773 helo
.Send(m_Socket
, m_Addr
, m_UID
);
782 bye
.Send(m_Socket
, m_Addr
, m_UID
);
785 void SendButton(const char *Button
, const char *DeviceMap
, unsigned short Flags
, unsigned short Amount
= 0)
790 CPacketBUTTON
button(Button
, DeviceMap
, Flags
, Amount
);
791 button
.Send(m_Socket
, m_Addr
, m_UID
);
794 void SendButton(unsigned short ButtonCode
, const char *DeviceMap
, unsigned short Flags
, unsigned short Amount
= 0)
799 CPacketBUTTON
button(ButtonCode
, DeviceMap
, Flags
, Amount
);
800 button
.Send(m_Socket
, m_Addr
, m_UID
);
803 void SendButton(unsigned short ButtonCode
, unsigned Flags
, unsigned short Amount
= 0)
808 CPacketBUTTON
button(ButtonCode
, Flags
, Amount
);
809 button
.Send(m_Socket
, m_Addr
, m_UID
);
812 void SendMOUSE(int X
, int Y
, unsigned char Flag
= MS_ABSOLUTE
)
817 CPacketMOUSE
mouse(X
, Y
, Flag
);
818 mouse
.Send(m_Socket
, m_Addr
, m_UID
);
821 void SendLOG(int LogLevel
, const char *Message
, bool AutoPrintf
= true)
826 CPacketLOG
log(LogLevel
, Message
, AutoPrintf
);
827 log
.Send(m_Socket
, m_Addr
, m_UID
);
830 void SendACTION(const char *ActionMessage
, int ActionType
= ACTION_EXECBUILTIN
)
835 CPacketACTION
action(ActionMessage
, ActionType
);
836 action
.Send(m_Socket
, m_Addr
, m_UID
);