winlin

srs-librtmp support hijack io apis for st-load. 2.0.42.

@@ -485,6 +485,7 @@ Supported operating systems and hardware: @@ -485,6 +485,7 @@ Supported operating systems and hardware:
485 * 2013-10-17, Created.<br/> 485 * 2013-10-17, Created.<br/>
486 486
487 ## History 487 ## History
  488 +* v2.0, 2014-12-02, srs-librtmp support hijack io apis for st-load. 2.0.42.
488 * v2.0, 2014-12-01, for [#237](https://github.com/winlinvip/simple-rtmp-server/issues/237), refine syscall for recv, supports 1.5k clients. 2.0.41. 489 * v2.0, 2014-12-01, for [#237](https://github.com/winlinvip/simple-rtmp-server/issues/237), refine syscall for recv, supports 1.5k clients. 2.0.41.
489 * v2.0, 2014-11-30, add qtcreate project file trunk/src/qt/srs/srs-qt.pro. 2.0.39. 490 * v2.0, 2014-11-30, add qtcreate project file trunk/src/qt/srs/srs-qt.pro. 2.0.39.
490 * v2.0, 2014-11-29, fix [#235](https://github.com/winlinvip/simple-rtmp-server/issues/235), refine handshake, replace union with template method. 2.0.38. 491 * v2.0, 2014-11-29, fix [#235](https://github.com/winlinvip/simple-rtmp-server/issues/235), refine handshake, replace union with template method. 2.0.38.
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 41 34 +#define VERSION_REVISION 42
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -43,50 +43,72 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -43,50 +43,72 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 #define ST_UTIME_NO_TIMEOUT -1 43 #define ST_UTIME_NO_TIMEOUT -1
44 #endif 44 #endif
45 45
46 -SimpleSocketStream::SimpleSocketStream()  
47 -{  
48 - SOCKET_RESET(fd); 46 +// when io not hijacked, use simple socket, the block sync stream.
  47 +#ifndef SRS_HIJACK_IO
  48 + struct SrsBlockSyncSocket
  49 + {
  50 + SOCKET fd;
  51 + int64_t recv_timeout;
  52 + int64_t send_timeout;
  53 + int64_t recv_bytes;
  54 + int64_t send_bytes;
  55 +
  56 + SrsBlockSyncSocket() {
49 send_timeout = recv_timeout = ST_UTIME_NO_TIMEOUT; 57 send_timeout = recv_timeout = ST_UTIME_NO_TIMEOUT;
50 recv_bytes = send_bytes = 0; 58 recv_bytes = send_bytes = 0;
  59 +
  60 + SOCKET_RESET(fd);
51 SOCKET_SETUP(); 61 SOCKET_SETUP();
52 -} 62 + }
53 63
54 -SimpleSocketStream::~SimpleSocketStream()  
55 -{ 64 + virtual ~SrsBlockSyncSocket() {
56 SOCKET_CLOSE(fd); 65 SOCKET_CLOSE(fd);
57 SOCKET_CLEANUP(); 66 SOCKET_CLEANUP();
58 -} 67 + }
  68 + };
  69 + srs_hijack_io_t srs_hijack_io_create()
  70 + {
  71 + SrsBlockSyncSocket* skt = new SrsBlockSyncSocket();
  72 + return skt;
  73 + }
  74 + void srs_hijack_io_destroy(srs_hijack_io_t ctx)
  75 + {
  76 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  77 + srs_freep(skt);
  78 + }
  79 + int srs_hijack_io_create_socket(srs_hijack_io_t ctx)
  80 + {
  81 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
59 82
60 -int SimpleSocketStream::create_socket()  
61 -{  
62 - fd = ::socket(AF_INET, SOCK_STREAM, 0);  
63 - if (!SOCKET_VALID(fd)) { 83 + skt->fd = ::socket(AF_INET, SOCK_STREAM, 0);
  84 + if (!SOCKET_VALID(skt->fd)) {
64 return ERROR_SOCKET_CREATE; 85 return ERROR_SOCKET_CREATE;
65 } 86 }
66 87
67 return ERROR_SUCCESS; 88 return ERROR_SUCCESS;
68 -} 89 + }
  90 + int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port)
  91 + {
  92 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
69 93
70 -int SimpleSocketStream::connect(const char* server_ip, int port)  
71 -{  
72 sockaddr_in addr; 94 sockaddr_in addr;
73 addr.sin_family = AF_INET; 95 addr.sin_family = AF_INET;
74 addr.sin_port = htons(port); 96 addr.sin_port = htons(port);
75 addr.sin_addr.s_addr = inet_addr(server_ip); 97 addr.sin_addr.s_addr = inet_addr(server_ip);
76 98
77 - if(::connect(fd, (const struct sockaddr*)&addr, sizeof(sockaddr_in)) < 0){ 99 + if(::connect(skt->fd, (const struct sockaddr*)&addr, sizeof(sockaddr_in)) < 0){
78 return ERROR_SOCKET_CONNECT; 100 return ERROR_SOCKET_CONNECT;
79 } 101 }
80 102
81 return ERROR_SUCCESS; 103 return ERROR_SUCCESS;
82 -} 104 + }
  105 + int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread)
  106 + {
  107 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
83 108
84 -// ISrsBufferReader  
85 -int SimpleSocketStream::read(void* buf, size_t size, ssize_t* nread)  
86 -{  
87 int ret = ERROR_SUCCESS; 109 int ret = ERROR_SUCCESS;
88 110
89 - ssize_t nb_read = ::recv(fd, (char*)buf, size, 0); 111 + ssize_t nb_read = ::recv(skt->fd, (char*)buf, size, 0);
90 112
91 if (nread) { 113 if (nread) {
92 *nread = nb_read; 114 *nread = nb_read;
@@ -106,48 +128,47 @@ int SimpleSocketStream::read(void* buf, size_t size, ssize_t* nread) @@ -106,48 +128,47 @@ int SimpleSocketStream::read(void* buf, size_t size, ssize_t* nread)
106 return ERROR_SOCKET_READ; 128 return ERROR_SOCKET_READ;
107 } 129 }
108 130
109 - recv_bytes += nb_read; 131 + skt->recv_bytes += nb_read;
110 132
111 return ret; 133 return ret;
112 -}  
113 -  
114 -// ISrsProtocolReader  
115 -void SimpleSocketStream::set_recv_timeout(int64_t timeout_us)  
116 -{  
117 - recv_timeout = timeout_us;  
118 -}  
119 -  
120 -int64_t SimpleSocketStream::get_recv_timeout()  
121 -{  
122 - return recv_timeout;  
123 -}  
124 -  
125 -int64_t SimpleSocketStream::get_recv_bytes()  
126 -{  
127 - return recv_bytes;  
128 -}  
129 -  
130 -// ISrsProtocolWriter  
131 -void SimpleSocketStream::set_send_timeout(int64_t timeout_us)  
132 -{  
133 - send_timeout = timeout_us;  
134 -}  
135 -  
136 -int64_t SimpleSocketStream::get_send_timeout()  
137 -{  
138 - return send_timeout;  
139 -}  
140 -  
141 -int64_t SimpleSocketStream::get_send_bytes()  
142 -{  
143 - return send_bytes;  
144 -} 134 + }
  135 + void srs_hijack_io_set_recv_timeout(srs_hijack_io_t ctx, int64_t timeout_us)
  136 + {
  137 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  138 + skt->recv_timeout = timeout_us;
  139 + }
  140 + int64_t srs_hijack_io_get_recv_timeout(srs_hijack_io_t ctx)
  141 + {
  142 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  143 + return skt->recv_timeout;
  144 + }
  145 + int64_t srs_hijack_io_get_recv_bytes(srs_hijack_io_t ctx)
  146 + {
  147 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  148 + return skt->recv_bytes;
  149 + }
  150 + void srs_hijack_io_set_send_timeout(srs_hijack_io_t ctx, int64_t timeout_us)
  151 + {
  152 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  153 + skt->send_timeout = timeout_us;
  154 + }
  155 + int64_t srs_hijack_io_get_send_timeout(srs_hijack_io_t ctx)
  156 + {
  157 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  158 + return skt->send_timeout;
  159 + }
  160 + int64_t srs_hijack_io_get_send_bytes(srs_hijack_io_t ctx)
  161 + {
  162 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
  163 + return skt->send_bytes;
  164 + }
  165 + int srs_hijack_io_writev(srs_hijack_io_t ctx, const iovec *iov, int iov_size, ssize_t* nwrite)
  166 + {
  167 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
145 168
146 -int SimpleSocketStream::writev(const iovec *iov, int iov_size, ssize_t* nwrite)  
147 -{  
148 int ret = ERROR_SUCCESS; 169 int ret = ERROR_SUCCESS;
149 170
150 - ssize_t nb_write = ::writev(fd, iov, iov_size); 171 + ssize_t nb_write = ::writev(skt->fd, iov, iov_size);
151 172
152 if (nwrite) { 173 if (nwrite) {
153 *nwrite = nb_write; 174 *nwrite = nb_write;
@@ -165,19 +186,18 @@ int SimpleSocketStream::writev(const iovec *iov, int iov_size, ssize_t* nwrite) @@ -165,19 +186,18 @@ int SimpleSocketStream::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
165 return ERROR_SOCKET_WRITE; 186 return ERROR_SOCKET_WRITE;
166 } 187 }
167 188
168 - send_bytes += nb_write; 189 + skt->send_bytes += nb_write;
169 190
170 return ret; 191 return ret;
171 -}  
172 -  
173 -// ISrsProtocolReaderWriter  
174 -bool SimpleSocketStream::is_never_timeout(int64_t timeout_us)  
175 -{ 192 + }
  193 + bool srs_hijack_io_is_never_timeout(srs_hijack_io_t ctx, int64_t timeout_us)
  194 + {
176 return timeout_us == (int64_t)ST_UTIME_NO_TIMEOUT; 195 return timeout_us == (int64_t)ST_UTIME_NO_TIMEOUT;
177 -} 196 + }
  197 + int srs_hijack_io_read_fully(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread)
  198 + {
  199 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
178 200
179 -int SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread)  
180 -{  
181 int ret = ERROR_SUCCESS; 201 int ret = ERROR_SUCCESS;
182 202
183 size_t left = size; 203 size_t left = size;
@@ -187,7 +207,7 @@ int SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread) @@ -187,7 +207,7 @@ int SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread)
187 char* this_buf = (char*)buf + nb_read; 207 char* this_buf = (char*)buf + nb_read;
188 ssize_t this_nread; 208 ssize_t this_nread;
189 209
190 - if ((ret = this->read(this_buf, left, &this_nread)) != ERROR_SUCCESS) { 210 + if ((ret = srs_hijack_io_read(ctx, this_buf, left, &this_nread)) != ERROR_SUCCESS) {
191 return ret; 211 return ret;
192 } 212 }
193 213
@@ -198,16 +218,17 @@ int SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread) @@ -198,16 +218,17 @@ int SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread)
198 if (nread) { 218 if (nread) {
199 *nread = nb_read; 219 *nread = nb_read;
200 } 220 }
201 - recv_bytes += nb_read; 221 + skt->recv_bytes += nb_read;
202 222
203 return ret; 223 return ret;
204 -} 224 + }
  225 + int srs_hijack_io_write(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nwrite)
  226 + {
  227 + SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
205 228
206 -int SimpleSocketStream::write(void* buf, size_t size, ssize_t* nwrite)  
207 -{  
208 int ret = ERROR_SUCCESS; 229 int ret = ERROR_SUCCESS;
209 230
210 - ssize_t nb_write = ::send(fd, (char*)buf, size, 0); 231 + ssize_t nb_write = ::send(skt->fd, (char*)buf, size, 0);
211 232
212 if (nwrite) { 233 if (nwrite) {
213 *nwrite = nb_write; 234 *nwrite = nb_write;
@@ -222,9 +243,105 @@ int SimpleSocketStream::write(void* buf, size_t size, ssize_t* nwrite) @@ -222,9 +243,105 @@ int SimpleSocketStream::write(void* buf, size_t size, ssize_t* nwrite)
222 return ERROR_SOCKET_WRITE; 243 return ERROR_SOCKET_WRITE;
223 } 244 }
224 245
225 - send_bytes += nb_write; 246 + skt->send_bytes += nb_write;
226 247
227 return ret; 248 return ret;
  249 + }
  250 +#endif
  251 +
  252 +SimpleSocketStream::SimpleSocketStream()
  253 +{
  254 + io = srs_hijack_io_create();
  255 +}
  256 +
  257 +SimpleSocketStream::~SimpleSocketStream()
  258 +{
  259 + if (io) {
  260 + srs_hijack_io_destroy(io);
  261 + io = NULL;
  262 + }
  263 +}
  264 +
  265 +int SimpleSocketStream::create_socket()
  266 +{
  267 + srs_assert(io);
  268 + return srs_hijack_io_create_socket(io);
  269 +}
  270 +
  271 +int SimpleSocketStream::connect(const char* server_ip, int port)
  272 +{
  273 + srs_assert(io);
  274 + return srs_hijack_io_connect(io, server_ip, port);
  275 +}
  276 +
  277 +// ISrsBufferReader
  278 +int SimpleSocketStream::read(void* buf, size_t size, ssize_t* nread)
  279 +{
  280 + srs_assert(io);
  281 + return srs_hijack_io_read(io, buf, size, nread);
  282 +}
  283 +
  284 +// ISrsProtocolReader
  285 +void SimpleSocketStream::set_recv_timeout(int64_t timeout_us)
  286 +{
  287 + srs_assert(io);
  288 + srs_hijack_io_set_recv_timeout(io, timeout_us);
  289 +}
  290 +
  291 +int64_t SimpleSocketStream::get_recv_timeout()
  292 +{
  293 + srs_assert(io);
  294 + return srs_hijack_io_get_recv_timeout(io);
  295 +}
  296 +
  297 +int64_t SimpleSocketStream::get_recv_bytes()
  298 +{
  299 + srs_assert(io);
  300 + return srs_hijack_io_get_recv_bytes(io);
  301 +}
  302 +
  303 +// ISrsProtocolWriter
  304 +void SimpleSocketStream::set_send_timeout(int64_t timeout_us)
  305 +{
  306 + srs_assert(io);
  307 + srs_hijack_io_set_send_timeout(io, timeout_us);
  308 +}
  309 +
  310 +int64_t SimpleSocketStream::get_send_timeout()
  311 +{
  312 + srs_assert(io);
  313 + return srs_hijack_io_get_send_timeout(io);
  314 +}
  315 +
  316 +int64_t SimpleSocketStream::get_send_bytes()
  317 +{
  318 + srs_assert(io);
  319 + return srs_hijack_io_get_send_bytes(io);
  320 +}
  321 +
  322 +int SimpleSocketStream::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
  323 +{
  324 + srs_assert(io);
  325 + return srs_hijack_io_writev(io, iov, iov_size, nwrite);
  326 +}
  327 +
  328 +// ISrsProtocolReaderWriter
  329 +bool SimpleSocketStream::is_never_timeout(int64_t timeout_us)
  330 +{
  331 + srs_assert(io);
  332 + return srs_hijack_io_is_never_timeout(io, timeout_us);
  333 +}
  334 +
  335 +int SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread)
  336 +{
  337 + srs_assert(io);
  338 + return srs_hijack_io_read_fully(io, buf, size, nread);
  339 +}
  340 +
  341 +int SimpleSocketStream::write(void* buf, size_t size, ssize_t* nwrite)
  342 +{
  343 + srs_assert(io);
  344 + return srs_hijack_io_write(io, buf, size, nwrite);
228 } 345 }
229 346
230 347
@@ -40,11 +40,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -40,11 +40,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 class SimpleSocketStream : public ISrsProtocolReaderWriter 40 class SimpleSocketStream : public ISrsProtocolReaderWriter
41 { 41 {
42 private: 42 private:
43 - int64_t recv_timeout;  
44 - int64_t send_timeout;  
45 - int64_t recv_bytes;  
46 - int64_t send_bytes;  
47 - SOCKET fd; 43 + srs_hijack_io_t io;
48 public: 44 public:
49 SimpleSocketStream(); 45 SimpleSocketStream();
50 virtual ~SimpleSocketStream(); 46 virtual ~SimpleSocketStream();
@@ -49,7 +49,7 @@ using namespace std; @@ -49,7 +49,7 @@ using namespace std;
49 #include <srs_lib_bandwidth.hpp> 49 #include <srs_lib_bandwidth.hpp>
50 50
51 // if want to use your log, define the folowing macro. 51 // if want to use your log, define the folowing macro.
52 -#ifndef SRS_RTMP_USER_DEFINED_LOG 52 +#ifndef SRS_HIJACK_LOG
53 // kernel module. 53 // kernel module.
54 ISrsLog* _srs_log = new ISrsLog(); 54 ISrsLog* _srs_log = new ISrsLog();
55 ISrsThreadContext* _srs_context = new ISrsThreadContext(); 55 ISrsThreadContext* _srs_context = new ISrsThreadContext();
@@ -930,6 +930,93 @@ extern const char* srs_human_format_time(); @@ -930,6 +930,93 @@ extern const char* srs_human_format_time();
930 #define srs_human_verbose(msg, ...) printf("[%s] ", srs_human_format_time());printf(msg, ##__VA_ARGS__);printf("\n") 930 #define srs_human_verbose(msg, ...) printf("[%s] ", srs_human_format_time());printf(msg, ##__VA_ARGS__);printf("\n")
931 #define srs_human_raw(msg, ...) printf(msg, ##__VA_ARGS__) 931 #define srs_human_raw(msg, ...) printf(msg, ##__VA_ARGS__)
932 932
  933 +/*************************************************************
  934 +**************************************************************
  935 +* IO hijack, use your specified io functions.
  936 +**************************************************************
  937 +*************************************************************/
  938 +// the void* will convert to your handler for io hijack.
  939 +typedef void* srs_hijack_io_t;
  940 +// define the following macro and functions in your module to hijack the io.
  941 +// the example @see https://github.com/winlinvip/st-load
  942 +// which use librtmp but use its own io(use st also).
  943 +#ifdef SRS_HIJACK_IO
  944 + /**
  945 + * create hijack.
  946 + * @return NULL for error; otherwise, ok.
  947 + */
  948 + extern srs_hijack_io_t srs_hijack_io_create();
  949 + /**
  950 + * destroy the context, user must close the socket.
  951 + */
  952 + extern void srs_hijack_io_destroy(srs_hijack_io_t ctx);
  953 + /**
  954 + * create socket, not connect yet.
  955 + * @return 0, success; otherswise, failed.
  956 + */
  957 + extern int srs_hijack_io_create_socket(srs_hijack_io_t ctx);
  958 + /**
  959 + * connect socket at server_ip:port.
  960 + * @return 0, success; otherswise, failed.
  961 + */
  962 + extern int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port);
  963 + /**
  964 + * read from socket.
  965 + * @return 0, success; otherswise, failed.
  966 + */
  967 + extern int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread);
  968 + /**
  969 + * set the socket recv timeout.
  970 + * @return 0, success; otherswise, failed.
  971 + */
  972 + extern void srs_hijack_io_set_recv_timeout(srs_hijack_io_t ctx, int64_t timeout_us);
  973 + /**
  974 + * get the socket recv timeout.
  975 + * @return 0, success; otherswise, failed.
  976 + */
  977 + extern int64_t srs_hijack_io_get_recv_timeout(srs_hijack_io_t ctx);
  978 + /**
  979 + * get the socket recv bytes.
  980 + * @return 0, success; otherswise, failed.
  981 + */
  982 + extern int64_t srs_hijack_io_get_recv_bytes(srs_hijack_io_t ctx);
  983 + /**
  984 + * set the socket send timeout.
  985 + * @return 0, success; otherswise, failed.
  986 + */
  987 + extern void srs_hijack_io_set_send_timeout(srs_hijack_io_t ctx, int64_t timeout_us);
  988 + /**
  989 + * get the socket send timeout.
  990 + * @return 0, success; otherswise, failed.
  991 + */
  992 + extern int64_t srs_hijack_io_get_send_timeout(srs_hijack_io_t ctx);
  993 + /**
  994 + * get the socket send bytes.
  995 + * @return 0, success; otherswise, failed.
  996 + */
  997 + extern int64_t srs_hijack_io_get_send_bytes(srs_hijack_io_t ctx);
  998 + /**
  999 + * writev of socket.
  1000 + * @return 0, success; otherswise, failed.
  1001 + */
  1002 + extern int srs_hijack_io_writev(srs_hijack_io_t ctx, const iovec *iov, int iov_size, ssize_t* nwrite);
  1003 + /**
  1004 + * whether the timeout is never timeout.
  1005 + * @return 0, success; otherswise, failed.
  1006 + */
  1007 + extern bool srs_hijack_io_is_never_timeout(srs_hijack_io_t ctx, int64_t timeout_us);
  1008 + /**
  1009 + * read fully, fill the buf exactly size bytes.
  1010 + * @return 0, success; otherswise, failed.
  1011 + */
  1012 + extern int srs_hijack_io_read_fully(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread);
  1013 + /**
  1014 + * write bytes to socket.
  1015 + * @return 0, success; otherswise, failed.
  1016 + */
  1017 + extern int srs_hijack_io_write(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nwrite);
  1018 +#endif
  1019 +
933 #ifdef __cplusplus 1020 #ifdef __cplusplus
934 } 1021 }
935 #endif 1022 #endif