#include #include #include #include #define BROADCAST 0xFFFFFFFF //since it is a palendrome we dont need endian casts #define ANY 0 const char* SIGReq = "TessesBcReq"; const char* SIGResp = "TessesBcResp"; bool _sleep(void* user,int times) { return true; } char* broadcast_fromconst(const char* text) { size_t len =strlen(text); char* textnew = (char*)malloc(len+1); snprintf(textnew,len,text); return textnew; } typedef union { in_addr_t addr; uint8_t bytes[4]; } ip_t; char* fix127(char* url,struct sockaddr_in* addr) { if(addr->sin_addr.s_addr == ANY) { return url; } size_t _strlen = strlen(url); char* schemeDel=strstr(url,"://"); if(schemeDel) { char* hostname_begin = schemeDel+3; if(hostname_begin > url + _strlen) return url; char* hostname_port_end = strstr(hostname_begin,"/"); if(!hostname_port_end || hostname_port_end > url + _strlen) hostname_port_end = _strlen + url; char* hostname_port_begin = strstr(hostname_begin,":"); if(hostname_port_begin && hostname_port_begin >= hostname_port_end) hostname_port_begin=NULL; if(hostname_port_begin) *hostname_port_begin=0; if(hostname_port_end) *hostname_port_end=0; if(memcmp(hostname_begin,"127.",4) == 0) { *schemeDel = 0; if(hostname_port_begin) *hostname_port_begin = ':'; if(hostname_port_end) *hostname_port_end='/'; char* right = hostname_port_begin ? hostname_port_begin : hostname_port_end ? hostname_port_end : ""; size_t url2len=strlen(right)+strlen(url)+35; char* url2 =(char*)malloc(url2len); ip_t ip; ip.addr = addr->sin_addr.s_addr; snprintf(url2,url2len,"%s://%u.%u.%u.%u%s",url,ip.bytes[0],ip.bytes[1],ip.bytes[2],ip.bytes[3],right); free(url); return url2; } else if(strcmp(hostname_begin,"localhost") == 0) { *schemeDel = 0; if(hostname_port_begin) *hostname_port_begin = ':'; if(hostname_port_end) *hostname_port_end='/'; char* right = hostname_port_begin ? hostname_port_begin : hostname_port_end ? hostname_port_end : ""; size_t url2len=strlen(right)+strlen(url)+35; char* url2 =(char*)malloc(url2len); ip_t ip; ip.addr = addr->sin_addr.s_addr; snprintf(url2,url2len,"%s://%u.%u.%u.%u%s",url,ip.bytes[0],ip.bytes[1],ip.bytes[2],ip.bytes[3],right); free(url); return url2; } else { if(hostname_port_begin) *hostname_port_begin = ':'; if(hostname_port_end) *hostname_port_end='/'; } } return url; } void broadcast_client(const char* serviceName,uint16_t port,void* user,broadcast_sleep_t sleepcb,broadcast_client_device_t deviceCb) { if(!sleepcb) sleepcb=_sleep; size_t sigreqLen = strlen(SIGReq); size_t sigrespLen = strlen(SIGResp); size_t namelen = strlen(serviceName); if(sigreqLen+2+namelen > 4096) return; int sock = socket(AF_INET,SOCK_DGRAM,0); int broadcast=1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast); struct sockaddr_in bindAddr, bcAddr; memset(&bindAddr,0,sizeof(bindAddr)); memset(&bcAddr,0,sizeof(bcAddr)); bindAddr.sin_family = AF_INET; bindAddr.sin_port = 0; //get new port bindAddr.sin_addr.s_addr = ANY; bcAddr.sin_addr.s_addr = BROADCAST; bcAddr.sin_family = AF_INET; bcAddr.sin_port = htons(port); bind(sock,(struct sockaddr*)&bindAddr,(socklen_t)sizeof(bindAddr)); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)); //timeout thanks to https://stackoverflow.com/a/13547864 uint8_t message[4096]; memcpy(message,SIGReq,sigreqLen); message[sigreqLen] = (uint8_t)((namelen >> 8) & 0xFF); message[sigreqLen+1] = (uint8_t)(namelen & 0xFF); memcpy(message+sigreqLen+2,serviceName,namelen); sendto(sock,message,sigreqLen+2+namelen,0,(struct sockaddr*)&bcAddr,(socklen_t)sizeof(bcAddr)); int times=0; int retval; do{ ssize_t len=0; struct sockaddr addr; socklen_t addrlen; do{ errno=0; len = recvfrom(sock,message,4096,0,&addr,&addrlen); if(len == -1) { if(errno == ETIMEDOUT || errno == EAGAIN) { if(!sleepcb(user,times)) { close(sock); return; } } else { close(sock); return; } } else { break; } }while(true); if(len < sigrespLen+2) continue; if(memcmp(SIGResp,message,sigrespLen) != 0) continue; int deviceNameLen= (message[sigrespLen] << 8) | message[sigrespLen+1]; if(len 4096) { if(ctx.serviceUrl) free(ctx.serviceUrl); if(ctx.deviceName) free(ctx.deviceName); free(name); continue; } memcpy(message,SIGResp,sigrespLen); message[sigrespLen] = (uint8_t)((deviceNameLen >> 8) & 0xFF); message[sigrespLen+1] = (uint8_t)(deviceNameLen & 0xFF); memcpy(message+sigrespLen+2,deviceName,deviceNameLen); message[sigrespLen+2+deviceNameLen] = (uint8_t)((serviceUrlLen >> 8) & 0xFF); message[sigrespLen+3+deviceNameLen] = (uint8_t)(serviceUrlLen & 0xFF); memcpy(message+sigrespLen+4+deviceNameLen,serviceUrl,serviceUrlLen); ip_t ip; struct sockaddr_in* addrin=(struct sockaddr_in*)&addr; ip.addr = addrin->sin_addr.s_addr; printf("SENDING to: %u.%u.%u.%u:%u\n",ip.bytes[0],ip.bytes[1],ip.bytes[2],ip.bytes[3],ntohs(addrin->sin_port)); sendto(sock,message,msgLen,0,&addr,addrlen); } if(ctx.serviceUrl) free(ctx.serviceUrl); if(ctx.deviceName) free(ctx.deviceName); free(name); } }