40 #define __FILE_ID__ "ytcp" 41 #define _WINSOCK_DEPRECATED_NO_WARNINGS 44 #if defined(WINDOWS_API) && !defined(_MSC_VER) 45 #define _WIN32_WINNT 0x501 48 typedef int socklen_t;
49 #if defined(__BORLANDC__) 68 #if defined(_MSC_VER) || defined (__BORLANDC__) 69 #pragma comment(lib, "Ws2_32.lib") 72 #pragma comment(lib, "Ws2.lib") 85 #ifdef PERF_TCP_FUNCTIONS 101 yTcpPerfMonSt yTcpPerf;
104 #define YPERF_TCP_ENTER(NAME) {yTcpPerf.NAME.count++;yTcpPerf.NAME.tmp=yapiGetTickCount();} 105 #define YPERF_TCP_LEAVE(NAME) {yTcpPerf.NAME.leave++;yTcpPerf.NAME.totaltime += yapiGetTickCount()- yTcpPerf.NAME.tmp;} 108 void dumpYTcpPerf(
void)
112 dumpYPerfEntry(&yTcpPerf.TCPOpen_setsockopt_noblock,
"TCPOpen:sockopt_noblock");
113 dumpYPerfEntry(&yTcpPerf.TCPOpen_setsockopt_nodelay,
"TCPOpen:sockopt_nodelay");
122 #define YPERF_TCP_ENTER(NAME) 123 #define YPERF_TCP_LEAVE(NAME) 130 int len = (val ? (int)strlen(val)+1 : 1);
132 if(*storage)
yFree(*storage);
133 *storage = (
char*)
yMalloc(len);
135 memcpy(*storage, val, len);
149 #if defined(WINDOWS_API) && !defined(WINCE) 150 len=(int)strlen(errmsg);
152 FORMAT_MESSAGE_FROM_SYSTEM |
153 FORMAT_MESSAGE_IGNORE_INSERTS,
156 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
157 (LPSTR) (errmsg+len),
161 strcpy(errmsg+len, strerror((
int)err));
166 #define yNetLogErr() yNetLogErrEx(__LINE__,SOCK_ERR) 177 #ifdef DEBUG_SOCKET_USAGE 179 #define yclosesocket(skt) yclosesocket_ex(__FILE_ID__, __LINE__, skt) 180 void yclosesocket_ex(
const char *file,
int line,
YSOCKET skt)
182 dbglogf(file, line,
"close socket %x\n", skt);
187 #define ysocket(domain, type, protocol) ysocket_ex(__FILE_ID__, __LINE__, domain, type, protocol) 188 YSOCKET ysocket_ex(
const char *file,
int line,
int domain,
int type,
int protocol)
190 YSOCKET skt = socket(domain, type, protocol);
191 dbglogf(file, line,
"open socket %x (%x,%x,%x)\n", skt, domain, type, protocol);
195 #define ysend(skt, buf, len, flags) ysend_ex(__FILE_ID__, __LINE__, skt, buf, len, flags) 196 int ysend_ex(
const char * file,
int line,
YSOCKET skt,
const char* buffer,
int tosend,
int flags)
198 int res = (int)send(skt, buffer, tosend, flags);
203 #define yrecv(skt, buf, len, flags) yrecv_ex(__FILE_ID__, __LINE__, skt, buf, len, flags) 204 int yrecv_ex(
const char * file,
int line,
YSOCKET skt,
char *buf,
int len,
int flags)
206 int res = recv(skt, buf, len, flags);
212 #define yclosesocket(skt) closesocket(skt) 213 #define ysocket(domain, type, protocol) socket(domain, type, protocol) 214 #define ysend(skt, buf, len, flags) send(skt, buf, len, flags) 215 #define yrecv(skt, buf, len, flags) recv(skt, buf, len, flags) 228 socklen_t localh_size;
229 struct sockaddr_in localh;
240 setsockopt(wuce->
listensock,SOL_SOCKET,SO_REUSEADDR,(
char *)&optval,
sizeof(optval));
242 localh_size=
sizeof(localh);
244 memset(&localh,0,localh_size);
245 localh.sin_family = AF_INET;
246 localh.sin_addr.s_addr = inet_addr(
"127.0.0.1");
247 if (bind(wuce->
listensock,(
struct sockaddr *)&localh,localh_size)<0) {
250 if (getsockname(wuce->
listensock,(
struct sockaddr *)&localh,&localh_size)<0) {
257 if (connect(wuce->
signalsock,(
struct sockaddr *)&localh,localh_size)<0) {
300 struct addrinfo *infos,*p;
301 if(getaddrinfo(name,NULL,NULL,&infos)!=0){
307 for(p=infos; p != NULL ; p=p->ai_next) {
308 if (p->ai_family == AF_INET){
309 ipv4 = ((
struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr;
318 #define YDNS_CACHE_SIZE 16 319 #define YDNS_CACHE_VALIDITY 600000u //10 minutes 331 int i, firstFree = -1;
336 if (dnsCache[i].url == url) {
343 if (i< YDNS_CACHE_SIZE) {
345 return dnsCache[i].
ip;
351 if (ip != 0 && firstFree < YDNS_CACHE_SIZE) {
352 dnsCache[firstFree].
url = url;
353 dnsCache[firstFree].
ip = ip;
370 int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
386 #ifdef PERF_TCP_FUNCTIONS 395 #define DEFAULT_TCP_ROUND_TRIP_TIME 30 396 #define DEFAULT_TCP_MAX_WINDOW_SIZE (4*65536) 400 struct sockaddr_in clientService;
404 fd_set readfds, writefds, exceptfds;
405 struct timeval timeout;
418 TCPLOG(
"yTcpOpen %p [dst=%x:%d %dms]\n", newskt, ip, port, mstimeout);
422 skt =
ysocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
430 memset(&clientService, 0,
sizeof(clientService));
434 clientService.sin_family = AF_INET;
435 clientService.sin_addr.s_addr = ip;
436 clientService.sin_port = htons( port );
444 ioctlsocket(skt, FIONBIO, &flags);
446 flags = fcntl(skt, F_GETFL, 0);
447 fcntl(skt, F_SETFL, flags | O_NONBLOCK);
449 setsockopt(skt, SOL_SOCKET, SO_NOSIGPIPE, (
void *)&noSigpipe,
sizeof(
int));
453 connect(skt, (
struct sockaddr *) &clientService,
sizeof(clientService) );
456 memset(&timeout, 0,
sizeof(timeout));
457 if (mstimeout != 0) {
458 u64 nbsec = mstimeout / 1000;
459 timeout.tv_sec = (long)nbsec;
460 timeout.tv_usec = ((int) (mstimeout - (nbsec * 1000))) * 1000;
467 FD_SET(skt, &readfds);
468 FD_SET(skt, &writefds);
469 FD_SET(skt, &exceptfds);
470 iResult = select((
int)skt + 1, &readfds, &writefds, &exceptfds, &timeout);
476 if (FD_ISSET(skt, &exceptfds)) {
480 if (!FD_ISSET(skt, &writefds)) {
491 if(setsockopt(skt, IPPROTO_TCP, TCP_NODELAY, &noDelay,
sizeof(noDelay)) < 0) {
495 dbglog(
"The argument sockfd is not a valid descriptor.\n");
498 dbglog(
"The address pointed to by optval is not in a valid part of the process address space. For getsockopt(), " 499 "this error may also be returned if optlen is not in a valid part of the process address space.\n");
502 dbglog(
"optlen invalid in setsockopt(). In some cases this error can also occur for an invalid value in optval " 503 "(e.g., for the IP_ADD_MEMBERSHIP option described in ip(7)).\n");
506 dbglog(
"The option is unknown at the level indicated.\n");
509 dbglog(
"The argument sockfd is a file, not a socket.\n");
513 dbglog(
"SetSockOpt TCP_NODELAY failed %d\n",errno);
518 optlen =
sizeof(tcp_sendbuffer);
519 if (getsockopt(skt, SOL_SOCKET, SO_SNDBUF, (
void*)&tcp_sendbuffer, &optlen) >= 0) {
521 dbglog(
"Default windows size is %d\n", tcp_sendbuffer);
526 if (setsockopt(skt, SOL_SOCKET, SO_SNDBUF, (
void*)&tcp_sendbuffer,
sizeof(tcp_sendbuffer)) < 0) {
530 dbglog(
"The argument sockfd is not a valid descriptor.\n");
533 dbglog(
"The address pointed to by optval is not in a valid part of the process address space. For getsockopt(), " 534 "this error may also be returned if optlen is not in a valid part of the process address space.\n");
537 dbglog(
"optlen invalid in setsockopt(). In some cases this error can also occur for an invalid value in optval " 538 "(e.g., for the IP_ADD_MEMBERSHIP option described in ip(7)).\n");
541 dbglog(
"The option is unknown at the level indicated.\n");
544 dbglog(
"The argument sockfd is a file, not a socket.\n");
548 dbglog(
"SetSockOpt SO_SNDBUF %d failed %d\n", tcp_sendbuffer, errno);
552 dbglog(
"getsockopt: unable to get tcp buffer size\n");
572 fd_set readfds,writefds,exceptfds;
573 struct timeval timeout;
579 memset(&timeout,0,
sizeof(timeout));
583 FD_SET(skt,&readfds);
584 FD_SET(skt,&writefds);
585 FD_SET(skt,&exceptfds);
586 res = select((
int)skt+1,&readfds,&writefds,&exceptfds,&timeout);
599 if (FD_ISSET(skt,&exceptfds)) {
603 if (!FD_ISSET(skt,&writefds)) {
608 if (FD_ISSET(skt,&readfds)) {
610 iResult = (int)
yrecv(skt, buffer,
sizeof(buffer), 0);
614 }
if ( iResult < 0 ){
630 const char * p = buffer;
651 struct timeval timeout;
653 memset(&timeout,0,
sizeof(timeout));
659 res = select((
int)skt+1,NULL,&fds,NULL,&timeout);
669 }
else if (res == 0) {
681 int iResult = (int)
yrecv(skt, (
char*)buffer, len, 0);
685 }
else if ( iResult < 0 ){
702 int yTcpDownload(
const char *host,
const char *url, u8 **out_buffer, u32 mstimeout,
char *errmsg)
709 int replybufsize = 512;
720 if (
yTcpOpen(&skt, ip, 80, mstimeout, errmsg)<0) {
725 len =
YSPRINTF(request,512,
"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n" 726 "Accept-Encoding:\r\nUser-Agent: Yoctopuce\r\n\r\n",url,host);
728 res =
yTcpWrite(skt, request, len, errmsg);
733 struct timeval timeout;
735 memset(&timeout,0,
sizeof(timeout));
736 timeout.tv_sec = (long) ms / 1000;
737 timeout.tv_usec = (int)(ms % 1000) *1000;
741 res = select((
int)skt+1,&fds,NULL,NULL,&timeout);
753 if(replysize + 256 >= replybufsize) {
755 int newsize = replybufsize << 1;
756 u8 *newbuf = (u8*)
yMalloc(newsize);
758 memcpy(newbuf, replybuf, replysize);
762 replybufsize = newsize;
764 readed =
yTcpRead(skt, replybuf + replysize, replybufsize - replysize, errmsg);
784 *out_buffer = replybuf;
796 u64 duration = now - req->
open_tm;
798 u64 idle_durration = now -last_io;
803 #ifdef DEBUG_SLOW_TCP 806 u64 last_rd = now - req->
read_tm;
808 dbglog(
"Long Idle TCP request %p = %"FMTu64
"ms total = %"FMTu64
"ms (read=%"FMTu64
"ms write=%"FMTu64
")\n",
809 req, idle_durration, duration, last_rd, last_wr);
817 #ifdef DEBUG_SLOW_TCP 820 dbglog(
"Slow TCP request %p = %dms\n",req,duration);
856 ip = inet_addr(buffer);
889 while(*p && *p !=
'\r') p++;
893 while(*p ==
'\r' && *(p+1)==
'\n' && *(p+2)!=
'\r') {
895 while(*p && *p !=
'\r') p++;
896 if (
YSTRNCMP(last,
"\r\nContent-Type",strlen(
"\r\nContent-Type"))==0){
897 unsigned len = (unsigned)(p - last);
899 memcpy(end,last,len);
905 *end++ =
'\r'; *end++ =
'\n';
913 for (uri = method; *uri !=
' '; uri++);
916 for(p = uri; *p !=
' '; p++);
924 end = auth+strlen(auth);
945 TCPLOG(
"yTcpOpenReqEx write failed for Req %p[%x]\n", req, req->
http.
skt);
961 TCPLOG(
"yHTTPCloseReqEx %p[%d]\n",req, canReuseSocket);
979 if (canReuseSocket) {
993 struct timeval timeout;
997 memset(&timeout, 0,
sizeof(timeout));
998 timeout.tv_sec = (long)ms/1000;
999 timeout.tv_usec = (int)(ms % 1000) *1000;
1010 for (i = 0; i < size; i++) {
1026 res = select((
int)sktmax + 1, &fds, NULL, NULL, &timeout);
1035 for (i = 0; i < size; i++) {
1036 TCPLOG(
"yHTTPSelectReq %p[%X] (%s)\n", reqs[i], reqs[i]->
http.
skt, errmsg);
1042 if (wuce && FD_ISSET(wuce->
listensock,&fds)) {
1045 for (i = 0; i < size; i++) {
1048 if (FD_ISSET(req->
http.
skt, &fds)) {
1053 u8 *newbuf = (u8*)
yMalloc(newsize);
1067 TCPLOG(
"yHTTPSelectReq %p[%x] connection closed by peer\n",req,req->
http.
skt);
1069 }
else if (res > 0) {
1074 TCPLOG(
"yHTTPSelectReq %p[%x] untrashort reply\n",req,req->
http.
skt);
1084 if(memcmp(req->
replybuf,
"HTTP/1.1 401", 12) != 0) {
1089 char *method = NULL, *realm = NULL, *qop = NULL, *nonce = NULL, *opaque = NULL;
1099 if (!strcmp(method,
"Digest") && !strcmp(qop,
"auth")) {
1170 memcpy(p,
"\r\n\r\n", 4);
1206 REQLOG(
"ws_req:%p: select for %d ms %d\n", req, (
int)mstimeout, done);
1222 #ifdef DEBUG_WEBSOCKET 1249 while(r && r !=req) {
1273 #ifdef TRACE_TCP_REQ 1275 static void dumpTCPReq(
const char *fileid,
int lineno,
struct _RequestSt *req)
1282 dbglog(
"dump TCPReq %p from %s:%d\n", req, fileid, lineno);
1290 switch (req->
state) {
1292 state =
"state=REQ_CLOSED";
1295 state =
"state=REQ_OPEN";
1298 state =
"state=REQ_CLOSED_BY_HUB";
1301 state =
"state=REQ_CLOSED_BY_API";
1304 state =
"state=REQ_ERROR";
1316 default: proto =
"unk";
break;
1328 dbglog(
"finished=%d\n", w);
1348 switch (req->
proto) {
1362 int yReqOpen(
struct _RequestSt *req,
int wait_for_start,
int tcpchan,
const char *request,
int reqlen, u64 mstimeout,
yapiRequestAsyncCallback callback,
void *
context,
RequestProgress progress_cb,
void *progress_ctx,
char *
errmsg)
1368 if (wait_for_start <= 0) {
1383 if (duration > wait_for_start) {
1384 dbglog(
"Last request in not finished after %"FMTu64
" ms\n", duration);
1385 #ifdef TRACE_TCP_REQ 1398 if (request[0] ==
'G' && request[1] ==
'E' && request[2] ==
'T') {
1400 for (i = 0; i < reqlen; i++) {
1401 if (request[i] ==
'\r') {
1407 if (request[i - 3] ==
'&' && request[i - 2] ==
'.' && request[i - 1] ==
' ') {
1413 const char *p = request;
1414 int bodylen = reqlen - 4;
1416 while (bodylen > 0 && (p[0] !=
'\r' || p[1] !=
'\n' ||
1417 p[2] !=
'\r' || p[3] !=
'\n')) {
1421 reqlen = (int)(p - request);
1428 memcpy(req->
bodybuf, p, bodylen);
1433 minlen = reqlen + 400;
1439 memcpy(req->
headerbuf, request, reqlen);
1492 }
else if(req->
errcode == 0) {
1563 TCPLOG(
"yTcpCloseReq %p\n", req);
1567 u64 duration = now - req->
open_tm;
1571 dbglog(
"request %p total=%"FMTu64
"ms (read=%"FMTu64
"ms write=%"FMTu64
")\n",
1572 req, duration, last_rd, last_wr);
1585 dbglog(
"request.ws %p first_write=%"FMTu64
"ms last_write=%"FMTu64
")\n",
1608 TCPLOG(
"yTcpFreeReq %p\n",req);
1669 static const char*
ws_header_start =
" HTTP/1.1\r\nSec-WebSocket-Version: 13\r\nUser-Agent: Yoctopuce\r\nSec-WebSocket-Key: ";
1670 static const char*
ws_header_end =
"\r\nConnection: keep-alive, Upgrade\r\nUpgrade: websocket\r\n\r\n";
1672 #define YRand32() rand() 1702 static u16
Base64Encode(
const u8* cSourceData, u16 wSourceLen, u8* cDestData, u16 wDestLen)
1709 while (wDestLen >= 4u)
1718 if (wSourceLen == 0u)
1722 vOutput[0] = (i & 0xFC) >> 2;
1723 vOutput[1] = (i & 0x03) << 4;
1728 vOutput[1] |= (i & 0xF0) >> 4;
1729 vOutput[2] = (i & 0x0F) << 2;
1734 vOutput[2] |= (i & 0xC0) >> 6;
1735 vOutput[3] = i & 0x3F;
1740 for (i = 0; i < 4u; i++)
1807 if (hdrlen >=
sizeof(buf)) {
1808 #ifndef MICROCHIP_API 1809 dbglog(
"Bad WebSocket header (%d)\n", hdrlen);
1815 memcpy(buf, reference, reference_len);
1816 #ifdef USE_FAR_YFSTR 1817 apiGetStr(magic.hofs, (
char*)buf + CbCtx.websocketkey.len);
1821 sha1 =
ySHA1((
char *)buf);
1823 if (memcmp(buf, data, hdrlen) == 0) {
1836 #define WS_CONNEXION_TIMEOUT 10000 1837 #define WS_MAX_DATA_LEN 124 1849 u8 *p = (u8*)buffer_32;
1850 #ifdef DEBUG_SLOW_TCP 1856 #ifdef DEBUG_WEBSOCKET 1865 p[1] = (u8)(datalen + 1) | 0x80;;
1866 p[2] = ((u8*)&mask)[2];
1867 p[3] = ((u8*)&mask)[3];
1869 p[4] = ((u8*)&mask)[0];
1870 p[5] = ((u8*)&mask)[1];
1873 p[6] = strym.
encaps ^ p[2];
1875 p[7] = *data ^ p[3];
1878 memcpy(buffer_32 + 2, data + 1, datalen - 1);
1879 for (i = 0; i < (datalen - 1 + 3) >> 2; i++) {
1880 buffer_32[i + 2] ^= mask;
1883 tcp_write_res =
yTcpWrite(hub->
ws.
skt, (
char*)p, datalen + 7, errmsg);
1884 #ifdef DEBUG_SLOW_TCP 1887 dbglog(
"WS: yTcpWrite took %"FMTu64
"ms (stream=%d chan=%d res=%d)\n", delta, strym.
stream, strym.
tcpchan, tcp_write_res);
1890 return tcp_write_res;
1962 #ifdef DEBUG_WEBSOCKET 1967 strym.
encaps = buffer[0];
1978 fwrite(buffer, 1, pktlen, f);
1997 int asyncid = buffer[pktlen - 1];
2000 dbglog(
"WS: Incorrect async-close signature on tcpChan %d (%d)\n", strym.
tcpchan, asyncid);
2021 WSLOG(
"req(%s:%p) unable to ack remote close (%d/%s)\n", req->
hub->
name, req, res, errmsg);
2060 #ifdef DEBUG_WEBSOCKET 2090 WSLOG(
"hub(%s): connected as %s\n", hub->
name, user);
2101 WSLOG(
"hub(%s): connected\n",hub->
name);
2139 WSLOG(
"delta bytes=%d time=%"FMTu64
"ms\n",deltaBytes, deltaTime);
2142 if (deltaTime < 500) {
2146 if (deltaTime < 1000 && deltaBytes < 65536) {
2155 newRate = (u32)(deltaBytes * 1000 / deltaTime);
2157 WSLOG(
"New rate: %.2f KB/s (based on %.2f KB in %.2fs)\n", hub->
ws.
uploadRate / 1000.0, deltaBytes / 1000.0, deltaTime / 1000.0);
2237 throttle_end = 2108;
2252 u64 toBeSent = 2 * uploadRate + 1024 - bytesOnTheAir + (uploadRate * timeOnTheAir / 1000);
2256 WSLOG(
"throttling: %d bytes/s (%"FMTu64
" + %d = %"FMTu64
")\n", hub->
ws.
uploadRate, toBeSent, bytesOnTheAir, bytesOnTheAir + toBeSent);
2257 if (toBeSent < 64) {
2258 u64 waitTime = 1000 * (128 - toBeSent) / hub->
ws.
uploadRate;
2259 if (waitTime < 2) waitTime = 2;
2261 WSLOG(
"WS: %d sent %"FMTu64
"ms ago, waiting %"FMTu64
"ms...\n", bytesOnTheAir, timeOnTheAir, waitTime);
2266 if (toBeSent > 124) {
2267 toBeSent = (toBeSent / 124) * 124;
2306 res =
ws_sendFrame(hub, stream, tcpchan, tmp_data, datalen + 1, errmsg);
2328 if (waitTime < 2) waitTime = 2;
2330 WSLOG(
"Sent %dbytes, waiting %"FMTu64
"ms...\n", sent, waitTime);
2374 ip = inet_addr(buffer);
2383 res =
yTcpOpen(&hub->
skt, ip, port, mstimout, errmsg);
2397 res =
yTcpWrite(hub->
skt, request, request_len, errmsg);
2458 struct timeval timeout;
2462 memset(&timeout, 0,
sizeof(timeout));
2463 timeout.tv_sec = (long)ms / 1000;
2464 timeout.tv_usec = (int)(ms % 1000) * 1000;
2475 FD_SET(base_req->
skt, &fds);
2476 if (base_req->
skt > sktmax)
2477 sktmax = base_req->
skt;
2482 res = select((
int)sktmax + 1, &fds, NULL, NULL, &timeout);
2495 if (wuce && FD_ISSET(wuce->
listensock, &fds)) {
2500 if (FD_ISSET(base_req->
skt, &fds)) {
2508 readed =
yTcpRead(base_req->
skt, buffer, avail, errmsg);
2527 #ifdef DEBUG_WEBSOCKET 2544 int first_notification_connection = 1;
2548 int continue_processing;
2552 WSLOG(
"hub(%s) start thread \n", hub->
name);
2568 if (first_notification_connection) {
2569 YSPRINTF(request, 256,
"GET /not.byn");
2582 WSLOG(
"hub(%s) base socket opened (skt=%x)\n", hub->
name, hub->
ws.
skt);
2589 continue_processing = 1;
2601 WSLOG(
"hub(%s) ws_thread_select error %d:%s\n", hub->
name, res, errmsg);
2605 int need_more_data = 0;
2609 int websocket_ok = 0;
2617 if (pos == 0xffff) {
2624 }
else if (pos >= 2044) {
2632 if (
YSTRNCMP(buffer,
"HTTP/1.1 ", 9) != 0) {
2649 if (pos > 22 &&
YSTRNICMP(buffer,
"Sec-WebSocket-Accept: ", 22) == 0) {
2684 rw = (avail < 7 ? avail : 7);
2686 pktlen =
header[1] & 0x7f;
2696 if (avail < hdrlen + pktlen) {
2700 memcpy(&mask,
header + 2,
sizeof(u32));
2704 if (avail < hdrlen + pktlen) {
2711 if ((
header[0] & 0x7f) != 0x02) {
2719 memcpy(
header + 2, &mask,
sizeof(u32));
2720 header[6] = 0x03 ^ ((u8 *)&mask)[0];
2721 header[7] = 0xe8 ^ ((u8 *)&mask)[1];
2727 #ifdef DEBUG_WEBSOCKET 2728 dbglog(
"WS: io error on base socket of %s(%X): %s\n", hub->
name, hub->
url, errmsg);
2743 for (i = 0; i < (pktlen + 1 + 3) >> 2; i++) {
2744 buffer[buffer_ofs + i] ^= mask;
2751 strym.
encaps = buffer[buffer_ofs];
2754 dbglog(
"Warning:fragmented META\n");
2757 buffer_ofs += pktlen;
2763 WSLOG(
"hub(%s) ws_parseIncommingFrame error %d:%s\n", hub->
name, res, errmsg);
2771 }
while (!need_more_data && !
YISERR(res));
2776 WSLOG(
"hub(%s) ws_processRequests error %d:%s\n", hub->
name, res, errmsg);
2781 continue_processing = 0;
2783 continue_processing = 0;
2785 }
while (continue_processing);
2787 WSLOG(
"hub(%s) io error %d:%s\n", hub->
name,res, errmsg);
2793 WSLOG(
"hub(%s) close base socket %d:%s\n", hub->
name, res, errmsg);
2799 WSLOG(
"hub(%s) exit thread \n", hub->
name);
2821 DWORD returnedSize, nbifaces, i;
2825 memset(detectedIfaces, 0,
sizeof(detectedIfaces));
2826 sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
2831 if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, winIfaces,
sizeof(winIfaces), &returnedSize, NULL, NULL)<0){
2836 nbifaces = returnedSize /
sizeof(INTERFACE_INFO);
2837 for (i = 0; i<nbifaces; i++){
2838 if (winIfaces[i].iiFlags & IFF_LOOPBACK)
2840 if (winIfaces[i].iiFlags & IFF_UP){
2841 if (winIfaces[i].iiFlags & IFF_MULTICAST)
2843 if (only_ip != 0 && only_ip != winIfaces[i].iiAddress.AddressIn.sin_addr.S_un.S_addr){
2846 detectedIfaces[
nbDetectedIfaces].
ip = winIfaces[i].iiAddress.AddressIn.sin_addr.S_un.S_addr;
2857 #include <ifaddrs.h> 2860 struct ifaddrs *if_addrs = NULL;
2861 struct ifaddrs *p = NULL;
2864 memset(detectedIfaces, 0,
sizeof(detectedIfaces));
2865 if (getifaddrs(&if_addrs) != 0){
2871 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET) {
2872 struct sockaddr_in *tmp;
2874 tmp = (
struct sockaddr_in*)p->ifa_addr;
2875 ip = tmp->sin_addr.s_addr;
2876 if (only_ip != 0 && only_ip != ip){
2880 tmp = (
struct sockaddr_in*)p->ifa_netmask;
2881 netmask = tmp->sin_addr.s_addr;
2882 if ((p->ifa_flags & IFF_LOOPBACK) == 0){
2883 if (p->ifa_flags & IFF_UP && p->ifa_flags & IFF_RUNNING){
2884 #ifdef DEBUG_NET_DETECTION 2885 ylogf(
"%s : ", p->ifa_name);
2889 ylogf(
" (%X)\n", p->ifa_flags);
2891 if (p->ifa_flags & IFF_MULTICAST){
2899 #ifdef DEBUG_NET_DETECTION 2901 ylogf(
"drop %s : ", p->ifa_name);
2905 ylogf(
" (%X)\n", p->ifa_flags);
2914 memset(detectedIfaces, 0,
sizeof(detectedIfaces));
2916 detectedIfaces[0].
ip = INADDR_ANY;
2927 "M-SEARCH * HTTP/1.1\r\n" 2929 "MAN:\"ssdp:discover\"\r\n" 2935 #define SSDP_NOTIFY "NOTIFY * HTTP/1.1\r\n" 2936 #define SSDP_M_SEARCH "M-SEARCH * HTTP/1.1\r\n" 2937 #define SSDP_HTTP "HTTP/1.1 200 OK\r\n" 2938 #define SSDP_LINE_MAX_LEN 80u 2940 #define UDP_IN_FIFO yFifoBuf 2946 hi = ((u8)(hi_c)& 0x1f) ^ 0x10;
2947 lo = ((u8)(lo_c) & 0x1f) ^ 0x10;
2948 if (hi & 0x10) hi -= 7;
2949 if (lo & 0x10) lo -= 7;
2950 return (hi << 4) + lo;
2958 const char *u = uuid;
2960 for (i = 0, u = uuid; i < 4; i++, u += 2){
2964 for (; i< 6; i++, u += 2){
2968 for (; i< 8; i++, u += 2){
2972 u = strstr(uuid,
"-COFF-EE");
2977 while (*u ==
'0') u++;
2984 for (i = len; i < padlen; i++) {
2997 if(cacheValidity<=0)
2998 cacheValidity = 1800;
2999 cacheValidity*=1000;
3007 p->
maxAge = cacheValidity;
3022 if (i < NB_SSDP_CACHE_ENTRY){
3031 p->
maxAge = cacheValidity;
3063 char *p,*
start,*lastsep;
3064 char *location=NULL;
3079 start = p = lastsep= message +len;
3081 while( msg_len && *p ){
3084 if (lastsep == start){
3091 if(msg_len>1) msg_len=1;
3095 if (lastsep == start){
3100 if (*lastsep==
' ') lastsep++;
3102 if (strcmp(start,
"LOCATION")==0){
3104 }
else if (strcmp(start,
"USN")==0){
3106 }
else if (strcmp(start,
"CACHE-CONTROL")==0){
3111 start =lastsep= p+1;
3117 if(location && usn && cache){
3118 const char *uuid,*urn;
3124 while (*p && *p++!=
':');
3128 while (*p && *p++!=
':');
3129 if (*p !=
':')
return;
3134 if(
YSTRNCMP(location,
"http://",7)==0){
3138 while (*p && *p !=
'/') p++;
3142 while (*p && *p++!=
'=');
3152 dbglog(
"SSDP drop invalid message:\n%s\n",message);
3165 struct timeval timeout;
3166 int res, received, i;
3172 yFifoInit(&inFifo,buffer,
sizeof(buffer));
3175 memset(&timeout,0,
sizeof(timeout));
3176 timeout.tv_sec = (long)1;
3177 timeout.tv_usec = (int)0;
3193 res = select((
int)sktmax + 1, &fds, NULL, NULL, &timeout);
3211 received = (int)
yrecv(SSDP->
request_sock[i], (
char*)buffer,
sizeof(buffer)-1, 0);
3213 buffer[received] = 0;
3218 received = (int)
yrecv(SSDP->
notify_sock[i], (
char *)buffer,
sizeof(buffer)-1, 0);
3220 buffer[received] = 0;
3236 struct sockaddr_in sockaddr_dst;
3239 memset(&sockaddr_dst, 0,
sizeof(
struct sockaddr_in));
3240 sockaddr_dst.sin_family = AF_INET;
3244 sent = (int)sendto(SSDP->
request_sock[i],
discovery, len, 0, (
struct sockaddr *)&sockaddr_dst,
sizeof(
struct sockaddr_in));
3258 struct sockaddr_in sockaddr;
3259 struct ip_mreq mcast_membership;
3276 setsockopt(SSDP->
request_sock[i], SOL_SOCKET, SO_REUSEADDR, (
char *)&optval,
sizeof(optval));
3278 setsockopt(SSDP->
request_sock[i], SOL_SOCKET, SO_REUSEPORT, (
char *)&optval,
sizeof(optval));
3282 socksize =
sizeof(sockaddr);
3283 memset(&sockaddr, 0, socksize);
3284 sockaddr.sin_family = AF_INET;
3285 sockaddr.sin_addr.s_addr = detectedIfaces[i].
ip;
3286 if (bind(SSDP->
request_sock[i], (
struct sockaddr*) &sockaddr, socksize) < 0) {
3296 setsockopt(SSDP->
notify_sock[i], SOL_SOCKET, SO_REUSEADDR, (
char *)&optval,
sizeof(optval));
3298 setsockopt(SSDP->
notify_sock[i], SOL_SOCKET, SO_REUSEPORT, (
char *)&optval,
sizeof(optval));
3302 socksize =
sizeof(sockaddr);
3303 memset(&sockaddr, 0, socksize);
3304 sockaddr.sin_family = AF_INET;
3306 sockaddr.sin_addr.s_addr = INADDR_ANY;
3307 if (bind(SSDP->
notify_sock[i], (
struct sockaddr *)&sockaddr, socksize) < 0) {
3312 mcast_membership.imr_interface.s_addr = INADDR_ANY;
3313 if (setsockopt(SSDP->
notify_sock[i], IPPROTO_IP, IP_ADD_MEMBERSHIP, (
void*)&mcast_membership,
sizeof(mcast_membership)) < 0){
3314 dbglog(
"Unable to add multicat membership for SSDP");
#define YOCTO_SERIAL_SEED_SIZE
static int GenereateWebSockeyKey(const u8 *url, u32 urllen, char *buffer)
#define ysend(skt, buf, len, flags)
YSOCKET request_sock[NB_OS_IFACES]
static void yHTTPCloseReqEx(struct _RequestSt *req, int canReuseSocket)
void yThreadKill(yThread *yth)
int handleNetNotification(HubSt *hub)
#define YOCTO_WEBSOCKET_MAGIC_LEN
static void * ySSDP_thread(void *ctx)
static int VerifyWebsocketKey(const char *data, u16 hdrlen, const char *reference, u16 reference_len)
int yWaitForEvent(yEvent *ev, int time)
#define YERRMSG(code, message)
#define yrecv(skt, buf, len, flags)
void * ws_thread(void *ctx)
YSOCKET notify_sock[NB_OS_IFACES]
void dumpYPerfEntry(yPerfMon *entry, const char *name)
#define YSTREAM_TCP_ASYNCCLOSE
void yReqFree(struct _RequestSt *req)
static int ws_parseIncommingFrame(HubSt *hub, u8 *buffer, int pktlen, char *errmsg)
struct _RequestSt * requests
void yInitializeCriticalSection(yCRITICAL_SECTION *cs)
void yFifoCleanup(yFifoBuf *buf)
int yReqIsAsync(struct _RequestSt *req)
int yReqSelect(struct _RequestSt *tcpreq, u64 ms, char *errmsg)
static int ws_sendAuthenticationMeta(HubSt *hub, char *errmsg)
static int ws_sendFrame(HubSt *hub, int stream, int tcpchan, const u8 *data, int datalen, char *errmsg)
int ySSDPDiscover(SSDPInfos *SSDP, char *errmsg)
#define USB_META_WS_ANNOUNCE
static int yTcpCheckSocketStillValid(YSOCKET skt, char *errmsg)
int yReqGet(struct _RequestSt *req, u8 **buffer)
int yStartWakeUpSocket(WakeUpSocket *wuce, char *errmsg)
u16 yPushFifo(yFifoBuf *buf, const u8 *data, u16 datalen)
#define TCPLOG(fmt, args...)
int yReqRead(struct _RequestSt *req, u8 *buffer, int len)
ssdpHubDiscoveryCallback callback
static int ws_requestStillPending(HubSt *hub)
u16 yPeekFifo(yFifoBuf *buf, u8 *data, u16 datalen, u16 startofs)
#define WSLOG(fmt, args...)
#define WS_CONNEXION_TIMEOUT
#define USB_META_ACK_UPLOAD
static const char * ws_header_end
#define YOCTO_BASE_SERIAL_LEN
#define YSTRCAT(dst, dstsize, src)
static const char * discovery
#define yFifoInit(fifo, buffer, len)
#define REQLOG(fmt, args...)
void(* RequestProgress)(void *context, u32 acked, u32 totalbytes)
static int ws_thread_select(struct _WSNetHubSt *base_req, u64 ms, WakeUpSocket *wuce, char *errmsg)
WSChanSt chan[MAX_ASYNC_TCPCHAN]
u8 * ySHA1(const char *text)
int yThreadCreate(yThread *yth, void *(*fun)(void *), void *arg)
int yReqMultiSelect(struct _RequestSt **tcpreq, int size, u64 ms, WakeUpSocket *wuce, char *errmsg)
#define MAX_ASYNC_TCPCHAN
static int uuidToSerial(const char *uuid, char *serial)
static void ws_closeBaseSocket(struct _WSNetHubSt *base_req)
std_msgs::Header * header(M &m)
u16 yFifoGetUsed(yFifoBuf *buf)
#define USB_META_WS_AUTHENTICATION_SIZE
int ySetErr(int code, char *outmsg, const char *erreur, const char *file, u32 line)
DnsCache dnsCache[YDNS_CACHE_SIZE]
yAsbUrlType yHashGetUrlPort(yUrlRef urlref, char *url, u16 *port, yAsbUrlProto *proto, yStrRef *user, yStrRef *password)
void yLeaveCriticalSection(yCRITICAL_SECTION *cs)
char errmsg[YOCTO_ERRMSG_LEN]
char serial[YOCTO_SERIAL_LEN]
static int yHTTPOpenReqEx(struct _RequestSt *req, u64 mstimout, char *errmsg)
#define USB_META_WS_PROTO_V2
char * yHashGetStrPtr(yHash yhash)
#define YSTRNICMP(A, B, len)
static int yWSSelectReq(struct _RequestSt *req, u64 mstimeout, char *errmsg)
int yTcpDownload(const char *host, const char *url, u8 **out_buffer, u32 mstimeout, char *errmsg)
int yDringWakeUpSocket(WakeUpSocket *wuce, u8 signal, char *errmsg)
static int ws_processRequests(HubSt *hub, char *errmsg)
static void ws_appendTCPData(RequestSt *req, u8 *buffer, int pktlen, int isClose)
#define YSTREAM_REPORT_V2
#define DEFAULT_TCP_MAX_WINDOW_SIZE
#define USB_META_WS_AUTH_FLAGS_RW
#define YSTREAM_NOTICE_V2
int yReqOpen(struct _RequestSt *req, int wait_for_start, int tcpchan, const char *request, int reqlen, u64 mstimeout, yapiRequestAsyncCallback callback, void *context, RequestProgress progress_cb, void *progress_ctx, char *errmsg)
#define YSTREAM_TCP_CLOSE
enum WS_BASE_STATE base_state
void ySSDPStop(SSDPInfos *SSDP)
os_ifaces detectedIfaces[NB_OS_IFACES]
static int yTcpOpen(YSOCKET *newskt, u32 ip, u16 port, u64 mstimeout, char *errmsg)
void yFreeWakeUpSocket(WakeUpSocket *wuce)
static int yHTTPMultiSelectReq(struct _RequestSt **reqs, int size, u64 ms, WakeUpSocket *wuce, char *errmsg)
void MD5Calculate(HASH_SUM *ctx, u8 digest[16])
void yDupSet(char **storage, const char *val)
void yThreadRequestEnd(yThread *yth)
#define yApproximateSleep(ms)
#define YSTRCPY(dst, dstsize, src)
int ySSDPStart(SSDPInfos *SSDP, ssdpHubDiscoveryCallback callback, char *errmsg)
static void ySSDP_parseSSPDMessage(SSDPInfos *SSDP, char *message, int msg_len)
static int yTcpRead(YSOCKET skt, u8 *buffer, int len, char *errmsg)
#define YSSDP_MCAST_ADDR_STR
#define USB_META_WS_PROTO_V1
#define YERRTO(code, buffer)
static void yTcpClose(YSOCKET skt)
void yInitWakeUpSocket(WakeUpSocket *wuce)
RequestProgress progressCb
static void ySSDPCheckExpiration(SSDPInfos *SSDP)
YSTATIC int yDetectNetworkInterfaces(u32 only_ip)
int yReqHasPending(struct _HubSt *hub)
#define USB_META_WS_ANNOUNCE_SIZE
#define YSSDP_URN_YOCTOPUCE
#define YDNS_CACHE_VALIDITY
static int ws_openBaseSocket(struct _WSNetHubSt *hub, yUrlRef url, const char *request, int request_len, int mstimout, char *errmsg)
static u32 resolveDNSCache(yUrlRef url, char *errmsg)
SSDP_CACHE_ENTRY * SSDPCache[NB_SSDP_CACHE_ENTRY]
u16 yFifoGetFree(yFifoBuf *buf)
int dbglogf(const char *fileid, int line, const char *fmt,...)
void yDigestAuthorization(char *buf, int bufsize, const char *user, const char *realm, const u8 *ha1, const char *nonce, const char *opaque, u32 *nc, const char *method, const char *uri)
void yResetEvent(yEvent *ev)
void yEnterCriticalSection(yCRITICAL_SECTION *cs)
#define YPERF_TCP_ENTER(NAME)
void(* ssdpHubDiscoveryCallback)(const char *serial, const char *urlToRegister, const char *urlToUnregister)
static int yNetLogErrEx(u32 line, unsigned err)
void(* yapiRequestAsyncCallback)(void *context, const u8 *result, u32 resultlen, int retcode, const char *errmsg)
int yConsumeWakeUpSocket(WakeUpSocket *wuce, char *errmsg)
int CheckWSAuth(u32 nonce, const u8 *ha1, const u8 *to_verify, u8 *out)
char errmsg[YOCTO_ERRMSG_LEN]
static u16 Base64Encode(const u8 *cSourceData, u16 wSourceLen, u8 *cDestData, u16 wDestLen)
char serial[YOCTO_SERIAL_LEN]
#define YPERF_TCP_LEAVE(NAME)
void ComputeAuthHA1(u8 *ha1, const char *user, const char *pass, const char *realm)
void yDeleteCriticalSection(yCRITICAL_SECTION *cs)
static int yWSOpenReqEx(struct _RequestSt *req, int tcpchan, u64 mstimeout, char *errmsg)
void MD5Initialize(HASH_SUM *ctx)
int yTryEnterCriticalSection(yCRITICAL_SECTION *cs)
#define YSTREAM_TCP_NOTIF
static char hexatochar(char hi_c, char lo_c)
static void ySSDPUpdateCache(SSDPInfos *SSDP, const char *uuid, const char *url, int cacheValidity)
void ySetEvent(yEvent *ev)
int yNetSetErrEx(u32 line, unsigned err, char *errmsg)
void yReqClose(struct _RequestSt *req)
static int yTcpCheckReqTimeout(struct _RequestSt *req, char *errmsg)
void yCreateManualEvent(yEvent *ev, int initialState)
RequestSt * tcpreq[ALLOC_YDX_PER_HUB]
struct _RequestSt * yReqAlloc(struct _HubSt *hub)
u64 YAPI_FUNCTION_EXPORT yapiGetTickCount(void)
#define ysocket(domain, type, protocol)
static const char * ws_header_start
#define YOCTO_HOSTNAME_NAME
u32 yResolveDNS(const char *name, char *errmsg)
void yThreadSignalEnd(yThread *yth)
#define USB_META_WS_AUTH_FLAGS_VALID
int yParseWWWAuthenticate(char *replybuf, int replysize, char **method, char **realm, char **qop, char **nonce, char **opaque)
int yTcpInit(char *errmsg)
yapiRequestAsyncCallback callback
void yCloseEvent(yEvent *ev)
void YAPI_FUNCTION_EXPORT yapiUnregisterHub(const char *url)
static int yTcpWrite(YSOCKET skt, const char *buffer, int len, char *errmsg)
#define YOCTO_WEBSOCKET_MAGIC
#define YIO_IDLE_TCP_TIMEOUT
int yThreadMustEnd(yThread *yth)
#define USB_META_WS_AUTHENTICATION
#define yclosesocket(skt)
static void ws_threadUpdateRetryCount(HubSt *hub)
#define YSTRNCMP(A, B, len)
int yThreadIsRunning(yThread *yth)
#define ALLOC_YDX_PER_HUB
void yThreadSignalStart(yThread *yth)
#define DEFAULT_TCP_ROUND_TRIP_TIME
u16 ySeekFifo(yFifoBuf *buf, const u8 *pattern, u16 patlen, u16 startofs, u16 searchlen, u8 bTextCompare)
#define NB_SSDP_CACHE_ENTRY
u16 yPopFifo(yFifoBuf *buf, u8 *data, u16 datalen)
int yReqIsEof(struct _RequestSt *req, char *errmsg)
int YFOPEN(FILE **f, const char *filename, const char *mode)
#define OS_IFACE_CAN_MCAST
void MD5AddData(HASH_SUM *ctx, const u8 *buf, u32 len)
static void yWSCloseReqEx(struct _RequestSt *req, int takeCS)
#define USB_META_WS_ERROR