void SDLFrontend::renderImage (Texture* texture, int x, int y, int w, int h, int16_t angle, float alpha) { assert(_renderer); if (!texture->isValid()) return; getTrimmed(texture, x, y, w, h); const SDL_Rect destRect = { x, y, w, h }; const TextureRect& r = texture->getSourceRect(); const SDL_Rect srcRect = { r.x, r.y, r.w, r.h }; SDL_Texture *t = static_cast<SDL_Texture*>(texture->getData()); SDL_SetTextureAlphaMod(t, alpha * 255); SDL_SetTextureColorMod(t, _color[0] * 255, _color[1] * 255, _color[2] * 255); if (_softwareRenderer) { // angle is 0 here - because on the fly rotating is really expensive // TODO: create a lockup map here? if (SDL_RenderCopyEx(_renderer, t, &srcRect, &destRect, 0.0, nullptr, texture->isMirror() ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE) != 0) { error(LOG_CLIENT, "could not render texture " + texture->getName()); texture->setData(nullptr); } } else { if (SDL_RenderCopyEx(_renderer, t, &srcRect, &destRect, static_cast<double>(angle), nullptr, texture->isMirror() ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE) != 0) { error(LOG_CLIENT, "could not render texture " + texture->getName()); texture->setData(nullptr); } } }
char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL) { int tAdditionalSize = 0; if(pEndStr) tAdditionalSize++; if(pAddNL) tAdditionalSize++; char *tTrimDest = malloc(sizeof(char) * (pSize + tAdditionalSize)); return getTrimmed(pChar, pSize, pEndStr, pAddNL, tTrimDest); }
//parseMessage(tConn->recv.data, tConn->recv.mark, &tConn->resp, ipstr, pHWADDR, tConn->keys); int parseMessage(struct connection *pConn, unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWID) { int tReturn = 0; // 0 = good, 1 = Needs More Data, -1 = close client socket. if(pConn->resp.data == NULL) { initBuffer(&(pConn->resp), MAX_SIZE); } char *tContent = getFromHeader(pConn->recv.data, "Content-Length", NULL); if(tContent != NULL) { int tContentSize = atoi(tContent); if(pConn->recv.marker == 0 || strlen(pConn->recv.data+pConn->recv.marker) != tContentSize) { if(isLogEnabledFor(HEADER_LOG_LEVEL)) { slog(HEADER_LOG_LEVEL, "Content-Length: %s value -> %d\n", tContent, tContentSize); if(pConn->recv.marker != 0) { slog(HEADER_LOG_LEVEL, "ContentPtr has %d, but needs %d\n", strlen(pConn->recv.data+pConn->recv.marker), tContentSize); } } // check if value in tContent > 2nd read from client. return 1; // means more content-length needed } } else { slog(LOG_DEBUG_VV, "No content, header only\n"); } // "Creates" a new Response Header for our response message addToShairBuffer(&(pConn->resp), "RTSP/1.0 200 OK\r\n"); if(isLogEnabledFor(LOG_INFO)) { int tLen = strchr(pConn->recv.data, ' ') - pConn->recv.data; if(tLen < 0 || tLen > 20) { tLen = 20; } slog(LOG_INFO, "********** RECV %.*s **********\n", tLen, pConn->recv.data); } if(pConn->password != NULL) { } if(buildAppleResponse(pConn, pIpBin, pIpBinLen, pHWID)) // need to free sig { slog(LOG_DEBUG_V, "Added AppleResponse to Apple-Challenge request\n"); } // Find option, then based on option, do different actions. if(strncmp(pConn->recv.data, "OPTIONS", 7) == 0) { propogateCSeq(pConn); addToShairBuffer(&(pConn->resp), "Public: ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER\r\n"); } else if(!strncmp(pConn->recv.data, "ANNOUNCE", 8)) { char *tContent = pConn->recv.data + pConn->recv.marker; int tSize = 0; char *tHeaderVal = getFromContent(tContent, "a=aesiv", &tSize); // Not allocated memory, just pointing if(tSize > 0) { int tKeySize = 0; char tEncodedAesIV[tSize + 2]; getTrimmed(tHeaderVal, tSize, TRUE, TRUE, tEncodedAesIV); slog(LOG_DEBUG_VV, "AESIV: [%.*s] Size: %d Strlen: %d\n", tSize, tEncodedAesIV, tSize, strlen(tEncodedAesIV)); char *tDecodedIV = decode_base64((unsigned char*) tEncodedAesIV, tSize, &tSize); // grab the key, copy it out of the receive buffer tHeaderVal = getFromContent(tContent, "a=rsaaeskey", &tKeySize); char tEncodedAesKey[tKeySize + 2]; // +1 for nl, +1 for \0 getTrimmed(tHeaderVal, tKeySize, TRUE, TRUE, tEncodedAesKey); slog(LOG_DEBUG_VV, "AES KEY: [%s] Size: %d Strlen: %d\n", tEncodedAesKey, tKeySize, strlen(tEncodedAesKey)); // remove base64 coding from key char *tDecodedAesKey = decode_base64((unsigned char*) tEncodedAesKey, tKeySize, &tKeySize); // Need to free DecodedAesKey // Grab the formats int tFmtpSize = 0; char *tFmtp = getFromContent(tContent, "a=fmtp", &tFmtpSize); // Don't need to free tFmtp = getTrimmedMalloc(tFmtp, tFmtpSize, TRUE, FALSE); // will need to free slog(LOG_DEBUG_VV, "Format: %s\n", tFmtp); RSA *rsa = loadKey(); // Decrypt the binary aes key char *tDecryptedKey = malloc(RSA_size(rsa) * sizeof(char)); // Need to Free Decrypted key //char tDecryptedKey[RSA_size(rsa)]; if(RSA_private_decrypt(tKeySize, (unsigned char *)tDecodedAesKey, (unsigned char*) tDecryptedKey, rsa, RSA_PKCS1_OAEP_PADDING) >= 0) { slog(LOG_DEBUG, "Decrypted AES key from RSA Successfully\n"); } else { slog(LOG_INFO, "Error Decrypting AES key from RSA\n"); } free(tDecodedAesKey); RSA_free(rsa); setKeys(pConn->keys, tDecodedIV, tDecryptedKey, tFmtp); propogateCSeq(pConn); } } else if(!strncmp(pConn->recv.data, "SETUP", 5)) { // Setup pipes // struct comms *tComms = pConn->hairtunes; // if (! (pipe(tComms->in) == 0 && pipe(tComms->out) == 0)) // { // slog(LOG_INFO, "Error setting up hairtunes communications...some things probably wont work very well.\n"); // } // Setup fork char tPort[8] = "6000"; // get this from dup()'d stdout of child pid printf("******** SETUP!!!!!\n"); #ifndef BOXEE int tPid = fork(); if(tPid == 0) { #endif int tDataport=0; char tCPortStr[8] = "59010"; char tTPortStr[8] = "59012"; int tSize = 0; char *tFound =getFromSetup(pConn->recv.data, "control_port", &tSize); getTrimmed(tFound, tSize, 1, 0, tCPortStr); tFound = getFromSetup(pConn->recv.data, "timing_port", &tSize); getTrimmed(tFound, tSize, 1, 0, tTPortStr); slog(LOG_DEBUG_VV, "converting %s and %s from str->int\n", tCPortStr, tTPortStr); int tControlport = atoi(tCPortStr); int tTimingport = atoi(tTPortStr); slog(LOG_DEBUG_V, "Got %d for CPort and %d for TPort\n", tControlport, tTimingport); char *tRtp = NULL; char *tPipe = NULL; char *tAoDriver = NULL; char *tAoDeviceName = NULL; char *tAoDeviceId = NULL; struct keyring *tKeys = pConn->keys; #ifndef BOXEE // ************************************************* // ** Setting up Pipes, AKA no more debug/output ** // ************************************************* dup2(tComms->in[0],0); // Input to child closePipe(&(tComms->in[0])); closePipe(&(tComms->in[1])); dup2(tComms->out[1], 1); // Output from child closePipe(&(tComms->out[1])); closePipe(&(tComms->out[0])); pConn->keys = NULL; pConn->hairtunes = NULL; // Free up any recv buffers, etc.. if(pConn->clientSocket != -1) { close(pConn->clientSocket); pConn->clientSocket = -1; } cleanupBuffers(pConn); #endif hairtunes_init(tKeys->aeskey, tKeys->aesiv, tKeys->fmt, tControlport, tTimingport, tDataport, tRtp, tPipe, tAoDriver, tAoDeviceName, tAoDeviceId); #ifndef BOXEE // Quit when finished. slog(LOG_DEBUG, "Returned from hairtunes init....returning -1, should close out this whole side of the fork\n"); return -1; } else if(tPid >0) { // Ensure Connection has access to the pipe. closePipe(&(tComms->in[0])); closePipe(&(tComms->out[1])); char tFromHairtunes[80]; int tRead = read(tComms->out[0], tFromHairtunes, 80); if(tRead <= 0) { slog(LOG_INFO, "Error reading port from hairtunes function, assuming default port: %d\n", tPort); } else { int tSize = 0; char *tPortStr = getFromHeader(tFromHairtunes, "port", &tSize); if(tPortStr != NULL) { getTrimmed(tPortStr, tSize, TRUE, FALSE, tPort); } else { slog(LOG_INFO, "Read %d bytes, Error translating %s into a port\n", tRead, tFromHairtunes); } } int tSize; #endif // READ Ports from here?close(pConn->hairtunes_pipes[0]); propogateCSeq(pConn); tSize = 0; char *tTransport = getFromHeader(pConn->recv.data, "Transport", &tSize); addToShairBuffer(&(pConn->resp), "Transport: "); addNToShairBuffer(&(pConn->resp), tTransport, tSize); // Append server port: addToShairBuffer(&(pConn->resp), ";server_port="); addToShairBuffer(&(pConn->resp), tPort); addToShairBuffer(&(pConn->resp), "\r\nSession: DEADBEEF\r\n"); #ifndef BOXEE } else { slog(LOG_INFO, "Error forking process....dere' be errors round here.\n"); return -1; } #endif } else if(!strncmp(pConn->recv.data, "TEARDOWN", 8)) { // Be smart? Do more finish up stuff... addToShairBuffer(&(pConn->resp), "Connection: close\r\n"); propogateCSeq(pConn); #ifndef BOXEE close(pConn->hairtunes->in[1]); slog(LOG_DEBUG, "Tearing down connection, closing pipes\n"); #else hairtunes_cleanup(); #endif //close(pConn->hairtunes->out[0]); tReturn = -1; // Close client socket, but sends an ACK/OK packet first } else if(!strncmp(pConn->recv.data, "FLUSH", 5)) { // TBD FLUSH #ifndef BOXEE write(pConn->hairtunes->in[1], "flush\n", 6); #else hairtunes_flush(); #endif propogateCSeq(pConn); } else if(!strncmp(pConn->recv.data, "SET_PARAMETER", 13)) { propogateCSeq(pConn); int tSize = 0; char *tVol = getFromHeader(pConn->recv.data, "volume", &tSize); slog(LOG_DEBUG_VV, "About to write [vol: %.*s] data to hairtunes\n", tSize, tVol); // TBD VOLUME #ifndef BOXEE write(pConn->hairtunes->in[1], "vol: ", 5); write(pConn->hairtunes->in[1], tVol, tSize); write(pConn->hairtunes->in[1], "\n", 1); #else hairtunes_setvolume(atof(tVol)); #endif slog(LOG_DEBUG_VV, "Finished writing data write data to hairtunes\n"); } else { slog(LOG_DEBUG, "\n\nUn-Handled recv: %s\n", pConn->recv.data); propogateCSeq(pConn); } addToShairBuffer(&(pConn->resp), "\r\n"); return tReturn; }
// Handles compiling the Apple-Challenge, HWID, and Server IP Address // Into the response the airplay client is expecting. int buildAppleResponse(struct connection *pConn, unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWID) { // Find Apple-Challenge char *tResponse = NULL; int tFoundSize = 0; char* tFound = getFromHeader(pConn->recv.data, "Apple-Challenge", &tFoundSize); if(tFound != NULL) { char tTrim[tFoundSize + 2]; getTrimmed(tFound, tFoundSize, TRUE, TRUE, tTrim); slog(LOG_DEBUG_VV, "HeaderChallenge: [%s] len: %d sizeFound: %d\n", tTrim, strlen(tTrim), tFoundSize); int tChallengeDecodeSize = 16; char *tChallenge = decode_base64((unsigned char *)tTrim, tFoundSize, &tChallengeDecodeSize); slog(LOG_DEBUG_VV, "Challenge Decode size: %d expected 16\n", tChallengeDecodeSize); int tCurSize = 0; unsigned char tChalResp[38]; memcpy(tChalResp, tChallenge, tChallengeDecodeSize); tCurSize += tChallengeDecodeSize; memcpy(tChalResp+tCurSize, pIpBin, pIpBinLen); tCurSize += pIpBinLen; memcpy(tChalResp+tCurSize, pHWID, HWID_SIZE); tCurSize += HWID_SIZE; int tPad = 32 - tCurSize; if (tPad > 0) { memset(tChalResp+tCurSize, 0, tPad); tCurSize += tPad; } char *tTmp = encode_base64((unsigned char *)tChalResp, tCurSize); slog(LOG_DEBUG_VV, "Full sig: %s\n", tTmp); free(tTmp); // RSA Encrypt RSA *rsa = loadKey(); // Free RSA int tSize = RSA_size(rsa); unsigned char tTo[tSize]; RSA_private_encrypt(tCurSize, (unsigned char *)tChalResp, tTo, rsa, RSA_PKCS1_PADDING); // Wrap RSA Encrypted binary in Base64 encoding tResponse = encode_base64(tTo, tSize); int tLen = strlen(tResponse); while(tLen > 1 && tResponse[tLen-1] == '=') { tResponse[tLen-1] = '\0'; } free(tChallenge); RSA_free(rsa); } if(tResponse != NULL) { // Append to current response addToShairBuffer(&(pConn->resp), "Apple-Response: "); addToShairBuffer(&(pConn->resp), tResponse); addToShairBuffer(&(pConn->resp), "\r\n"); free(tResponse); return TRUE; } return FALSE; }