Message Sent To Deallocated Instantce - ios

I'm using game center to send data between two players. For some reason I keep getting a deallocated instance message. Here's the code:
- (void)sendGameMove:(uint32_t)i andj:(NSString *)j {
MessageMove message;
message.message.messageType = kMessageTypeMove;
message.i = 1;
message.j = #"Testing 1 2 3s";
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageMove)];
MessageMove * messageMove = (MessageMove *) [data bytes];
NSLog(#"Message I: %i", messageMove->i);
NSLog(#"Message J: %#", messageMove->j);
[self sendData:data];
}
(I Filled in the i and j arguments for what i'm passing). In this method the NSLog statements both log what they're supposed to after creating the NSData object but when I sent that NSData object to the method [self sendData:data]:
- (void)sendData:(NSData *)data {
MessageMove * messageMove = (MessageMove *) [data bytes];
NSLog(#"Message I: %i", messageMove->i);
NSLog(#"Message J: %#", messageMove->j);
NSError *error;
BOOL success = [[GCHelper sharedInstance].match sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error];
if (!success) {
[self matchEnded];
}
}
In the NSLog statement the first one works fine so I get:
"Message I: 1"
in the console but for the second log statement I get :
"*** -[ respondsToSelector:]: message sent to deallocated instance"
the code to break down the data object is the exact same in the second method as in the first. Any ideas?

I'm guessing that MessageMove is a struct like:
typedef struct {
int i;
NSString *j;
} MessageMove;
The problem is that you're sending only the contents of the struct itself. In memory and on the network, it'd look something like this:
01000000 07FCA700
-----------------
i j
When the second device receives the message and tries to read the j pointer, it crashes because there's nothing there: that pointer was only valid on the origin device. The struct didn't even contain the contents of the string at all.
To fix this, you need to actually send the string in the message. Flexible array members are one way of storing a string directly in the struct:
typedef struct {
int32_t i; // explicit integer sizes are a good idea for network protocols
int32_t j_length;
char j[]; // the flexible array member
} MessageMove;
Send:
NSString *s = #"Testing 1 2 3s";
NSData *d = [s dataUsingEncoding:NSUTF8StringEncoding];
size_t messageSize = sizeof(MessageMove) + [d length];
MessageMove *mm = calloc(1, messageSize);
mm->i = 1;
mm->j_length = [d length];
memcpy(mm->j, [d bytes], [d length]);
[self sendData:[NSData dataWithBytes:mm length:messageSize]];
Receive:
MessageMove *mm = (MessageMove *)[data bytes];
assert(mm->j_length == [data length] - offsetof(MessageMove, j));
NSString *j = [[NSString alloc] initWithBytes:mm->j length:mm->j_length encoding:NSUTF8StringEncoding];
The assertion prevents reading past the end of the data buffer. offsetof is a macro from <stddef.h>.
For anything more complicated than this, I'd recommend serializing to and sending plist or JSON instead. They handle all the string copying details for you and let you send arrays and dictionary too.

Related

Send hexString Data through UDP

I'm developing an iOS app. I've come across a problem.
I am trying to send a hexString data through UDP to an wifi camera, which will response while getting correct data. My code is shown below. However I can't get any response from my wifi camera. (I'm using
https://github.com/robbiehanson/CocoaAsyncSocket)
NSString *sendMsg = #"6745000005000000000000000000000000000000000000001400000067450000140000000A";
NSData *bytes = [sendMsg dataUsingEncoding:NSUTF16BigEndianStringEncoding];
NSString *host = #"255.255.255.255";
[self.udpSocket sendData:bytes toHost:host port:ListenPort withTimeout:-1 tag:1];
Beside, I've try send my data through PacketSender (an app can send UDP data), which has a correct response.
enter image description here
Problem has been solved. The problem is while converting NSString to NSData. It's hex string which need to convert to NSData. Below is my code which works.
- (NSData *)dataFromHexString:(NSString *)hexString {
NSAssert((hexString.length > 0) && (hexString.length % 2 == 0), #"hexString.length mod 2 != 0");
NSMutableData *data = [[NSMutableData alloc] init];
for (NSUInteger i=0; i<hexString.length; i+=2) {
NSRange tempRange = NSMakeRange(i, 2);
NSString *tempStr = [hexString substringWithRange:tempRange];
NSScanner *scanner = [NSScanner scannerWithString:tempStr];
unsigned int tempIntValue;
[scanner scanHexInt:&tempIntValue];
[data appendBytes:&tempIntValue length:1];
}
return data;}

How do I see the true contents of this string?

Please bear with me here since this question is not so easy to explain and word correctly.
I am using the following code in order to get data from a USB connected barcode reader, the scanner works fine and data is passed in as expected but my DB lookups fail and I believe they are failing because the data I am passing into the DBLookup method is incorrect but I am unable to see why, I think NSLog is helping me to show clear text data when in fact it isn't and I am stuck at debugging further.
Here is my code
- (void)didBarcodeDataReceive:(StarIoExtManager *)manager data:(NSData *)data {
NSLog(#"%s", __PRETTY_FUNCTION__);
NSMutableString *text = [NSMutableString stringWithString:#""];
const uint8_t *p = data.bytes;
for (int i = 0; i < data.length; i++) {
uint8_t ch = *(p + i);
[text appendFormat:#"%c", (char) ch];
}
NSLog(#"Scanned info as NSData was: %#", data); // raw NSData
//NSString *stringWithData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSString *stringWithData = [[NSString alloc] initWithBytes:(char *)data.bytes length:data.length encoding:NSUTF8StringEncoding];
NSLog(#"Scanned info as StringFromData was: %#", stringWithData);
NSLog(#"Scanned ch conversion is: %#", text);
int createTransactionResult = -1;
createTransactionResult = [NWBarCodeHelper createTransactionRowFromBarCode:text];
if ([NWTillHelper isDebug] == 1) {
NSLog(#"mPOP delegate holds barcode: %#", stringWithData);
if(createTransactionResult != 0) {
NSLog(#"TransactionListView:mPOPDelegate:createTransactionFrombarCode failed with errorCode %i", createTransactionResult);
}
}
}
My Debug outputs shows the correct data as follows
2017-04-19 10:19:01.868198 NWMobileTill[3751:1638657] Scanned info as NSData was: <30393235 38333834 33393439 35310d0a>
2017-04-19 10:19:01.868439 NWMobileTill[3751:1638657] Scanned info as StringFromData was: 09258384394951
2017-04-19 10:19:01.868652 NWMobileTill[3751:1638657] Scanned ch conversion is: 09258384394951
2017-04-19 10:19:01.868979 NWMobileTill[3751:1638657] NWBarCodeHelper:createTransactionRowFromBarcode:barcode = 09258384394951
2017-04-19 10:19:01.875938 NWMobileTill[3751:1638657] NWBarcodeHelper:CreateTransactionRowFromBarcode: 0 or more than one row returned, basic data error, item count = 0
But as you can see the last rows shows the DB lookup failing, I KNOW the method is correct cause when I scan using the iPhone camera and passing that data to the same method it works just fine on the same barcode so it must be something with the string that is passed in from the USB scanner that is tricking me out but I am unable to understand why and I think NSLog is trying to help me but not showing me the encoded data or something?
Your string contains a \r\n at the end. Have a look at the following code:
unsigned char bytes[] = {0x30, 0x39, 0x32, 0x35, 0x38, 0x33, 0x38, 0x34, 0x33, 0x39 ,0x34, 0x39, 0x35, 0x31, 0x0d, 0x0a};
NSData *data = [NSData dataWithBytes:bytes length:16];
NSString *stringWithData = [[NSString alloc] initWithBytes:(char *)data.bytes length:data.length encoding:NSUTF8StringEncoding];
NSLog(#"%#", stringWithData); // 09258384394951
NSLog(#"%lu", (unsigned long)[stringWithData length]); // 16
// remove \r\n at the end which gets added by the barcode scanner
NSString *string = [stringWithData stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"%#", string); // 09258384394951
NSLog(#"%lu", (unsigned long)[string length]); // 14
Or if you want to use your appendFormat approach you can just check if it is a valid digit before adding it to the string instead of removing it later.
To actually see the contents of your string you can either output the code point of each character in the string one by one or you can just set a breakpoint and Xcode will show it in the debugger:

Encrypt data with RSA public key not giving expected results

I'm trying to encrypt data with an RSA public key using openssl.
I have the Java implementation of what I need to do in Objective-C.
Here's what I have so far:
- (RSA *)rsaFromExponent:(NSString *)exponent modulus:(NSString *)modulus
{
RSA *rsa_pub = RSA_new();
const char *N = [modulus UTF8String];
const char *E = [exponent UTF8String];
if (!BN_hex2bn(&rsa_pub->n, N))
{
// TODO
}
printf("N: %s\n", N);
printf("n: %s\n", BN_bn2dec(rsa_pub->n));
if (!BN_hex2bn(&rsa_pub->e, E))
{
// TODO
}
printf("E: %s\n", E);
printf("e: %s\n", BN_bn2dec(rsa_pub->e));
return rsa_pub;
}
- (NSString *)cleanString:(NSString *)input
{
NSString *output = input;
output = [output stringByReplacingOccurrencesOfString:#"<" withString:#""];
output = [output stringByReplacingOccurrencesOfString:#">" withString:#""];
output = [output stringByReplacingOccurrencesOfString:#" " withString:#""];
return output;
}
// main code
NSString *exponentB64 = #"AQAB";
NSString *modulusB64 = #"AKDbnFpblq7LHfWDfGTR48B34MKaHQosMwVu8cCc6fH2pZ8Ypx/OgzG6VJlKHXeELtlo5tddBSJpwnkEQdvkkmwuOpCkacTTLon6EHqX4WwFW+waqHxmj419SxiDDlo9tsbg7vfFIMpKyGzq1zvTAN3TroW+MxogZfZD3/N6dNTzvBoXe/Ca1e/zVwYXKbiegLMjNwsruz/WvuMiNKTK4U3GEmb0gIODd1shAH10ube8Nrz/e1u9kr25VQ+7kZAFjnkPTp2AvNGYHQt35m1TRMQhTylVwTZqFkHC/jMt7WxuS8q7ftjM828wa1fEWTgWYrdkzmqZSK5CHBYSys/N1Ws=";
// 1. decode base64 (http://projectswithlove.com/projects/NSData_Base64.zip)
NSData *exponent = [NSData dataFromBase64String:exponentB64];
NSData *modulus = [NSData dataFromBase64String:modulusB64];
NSString *exponentHex = [self cleanString:[exponent description]];
NSString *modulusHex = [self cleanString:[modulus description]];
// 2. create RSA public key
RSA *rsa_pub = [self rsaFromExponent:exponentHex modulus:modulusHex];
NSString *user = #"TEST";
// 3. encode base 64
NSData *userData = [user dataUsingEncoding:NSASCIIStringEncoding];
NSString *userB64String = [userData base64EncodedString];
// 4. encrypt
const unsigned char *from = (const unsigned char *)[userB64String cStringUsingEncoding:NSASCIIStringEncoding];
int flen = strlen((const char *)from);
unsigned char *to = (unsigned char *) malloc(RSA_size(rsa_pub));
int padding = RSA_PKCS1_PADDING;
int result = RSA_public_encrypt(flen, from, to, rsa_pub, padding);
if (-1 == result)
{
NSLog(#"WAT?");
}
else
{
NSLog(#"from: %s", from); // echo VEVTVA==
NSLog(#"to: %s", to); // echo something strange with characters like: ~™Ÿû—...
}
// 5. encode base 64
NSString *cipherString = [NSString stringWithCString:(const char *)to
encoding:NSASCIIStringEncoding];
NSData *cipherData = [cipherString dataUsingEncoding:NSASCIIStringEncoding];
NSString *cipherDataB64 = [cipherData base64EncodedString];
NSLog(#"user encrypted b64: %#", cipherDataB64); // echo null :-(
In Java, I have no problem to base64 encode the encrypted data.
I'm sure I'm doing something wrong but I don't know where because it's not something I do everyday.
Or if you know another way to do this with iOS frameworks like Security.framework.
Thanks in advance.
Someone else helped me figure it out. I don't know why but I was assuming that the output buffer from RSA_public_encrypt function would be an ascii string. Though it's just bytes as the documentation says too. The char * type often leads me to think it's gonna store a string (it's so wrong I think it's the last time I make this kind of error).
So from step 5:
// 5. encode base 64
NSData *cipherData = [NSData dataWithBytes:(const void *)to length:result];
NSString *cipherDataB64 = [cipherData base64EncodedString];
NSLog(#"user encrypted b64: %#", cipherDataB64); // now echo the expected value

How to receive data from APNS feedback server in objective c

Hello I'm trying to to something rather simple I think.
I have made an cocoa application that sends data using APNS, getting the tokens from my database, everything is set up and running perfect.
Now I want to check the APNS feedback server and remove any tokens received from my database.
I have found dozens of examples in php, javascript and so forth, but nothing in Objective C. I have read the programming guide from apple but can't figure out how to do it.
I am establishing a connection to APNS feedback but I don't know how to read the data.
I'm new to cocoa so please explain in detail :)
This is how I connect to the feedback server, it's the same way I connect when sending, just using another host.
- (void)connectToFeedBackServer
{
if(self.certificate == nil)
{
return;
}
NSString *feedBackHost = #"feedback.push.apple.com";
const char *cHost = [feedBackHost UTF8String];
NSLog(#"The size of cHost is: %lu", strlen(cHost));
NSLog(#"Host is: %s", cHost);
// Define result variable.
OSStatus result;
// Establish connection to server.
PeerSpec peer;
result = MakeServerConnection(cHost, 2196, &socket, &peer);
//NSLog(#"MakeServerConnection(): %d", result);
// Create new SSL context.
result = SSLNewContext(false, &context); //NSLog(#"SSLNewContext(): %d", result);
// Set callback functions for SSL context.
result = SSLSetIOFuncs(context, SocketRead, SocketWrite);
// NSLog(#"SSLSetIOFuncs(): %d", result);
// Set SSL context connection.
result = SSLSetConnection(context, socket);
// NSLog(#"SSLSetConnection(): %d", result);
// Set server domain name.
//result = SSLSetPeerDomainName(context, cHost, sizeof(cHost));
NSLog(#"SSLSetPeerDomainName(): %d", result);
result = SSLSetPeerDomainName(context, cHost, strlen(cHost));
result = SecIdentityCopyCertificate(_theIdentity, &(certificate));
// Set client certificate.
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)&_theIdentity, 1, NULL);
result = SSLSetCertificate(context, certificates);// NSLog(#"SSLSetCertificate(): %d", result);
CFRelease(certificates);
// Perform SSL handshake.
do
{
result = SSLHandshake(context); NSLog(#"SSLHandshake(): %d", result);
} while(result == errSSLWouldBlock);
}
And how I try to read the data and save the received the tokens in an array
- (NSMutableArray *)CheckFeedBackServer
{
char feedback[38];
size_t feedBackSize = sizeof(feedback);
size_t processed = 0;
NSMutableData *feedbackData = [[NSMutableData alloc]init];
NSString *token = [[NSString alloc]init];
NSMutableArray *tokenArray = [[NSMutableArray alloc]init];
[self connectToFeedBackServer];
while ([self getSSLContext])
{
int bytesLength = SSLRead([self getSSLContext], &feedback, feedBackSize, &processed);
[feedbackData appendBytes:feedback length:bytesLength];
while ([feedbackData length] > 38)
{
NSData *deviceToken = [NSData dataWithBytes:[feedbackData bytes] + 6 length:32];
token = [self deviceTokenToString:deviceToken];
[tokenArray addObject:token];
[feedbackData replaceBytesInRange: NSMakeRange(0, 38) withBytes: "" length: 0];
}
}
return tokenArray;
}
- (NSString *)deviceTokenToString: (NSData *)deviceToken;
{
NSString *tmpToken = [NSString stringWithFormat:#"%#", deviceToken];
NSUInteger loc_begin = [tmpToken rangeOfString: #"<"].location+1;
NSUInteger loc_end = [tmpToken rangeOfString: #">"].location-1;
return [tmpToken substringWithRange: NSMakeRange(loc_begin, loc_end)];
}
Just if anyone need to do something similar I solved my problem like this.
I use Apples ioSock class, and I have set the certificate in my code by calling the keychain
First I connect to the feedback server with this code
- (void)connectToFeedBackServer
{
if(self.certificate == nil)
{
return;
}
// Get the global variable feedbackHost and make it to a char
const char *cHost = [feedbackHost UTF8String];
NSLog(#"The size of cHost is: %lu", strlen(cHost));
NSLog(#"Host is: %s", cHost);
// Define result variable.
OSStatus result;
// Establish connection to server.
PeerSpec peer;
result = MakeServerConnection(cHost, 2196, &socket, &peer);
// Create new SSL context.
result = SSLNewContext(false, &context);
// Set callback functions for SSL context.
result = SSLSetIOFuncs(context, SocketRead, SocketWrite);
// Set SSL context connection.
result = SSLSetConnection(context, socket);
// Set server domain name.
result = SSLSetPeerDomainName(context, cHost, strlen(cHost));
result = SecIdentityCopyCertificate(_theIdentity, &(certificate));
// Set client certificate.
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)&_theIdentity, 1, NULL);
result = SSLSetCertificate(context, certificates);
CFRelease(certificates);
do
{
result = SSLHandshake(context); NSLog(#"SSLHandshake(): %d", result);
} while(result == errSSLWouldBlock);
}
And then I read the feedback data and add the tokens to an array, like this
- (NSMutableArray *)CheckFeedBackServer
{
OSStatus result;
NSMutableArray *feedbackTokens = [[NSMutableArray alloc]init];
// Retrieve message from SSL.
size_t processed = 0;
char buffer[38];
do
{
// Fetch the next item
result = SSLRead(context, buffer, 38, &processed);
if (result) break;
char *b = buffer;
// Recover Device ID
NSMutableString *deviceID = [NSMutableString string];
b += 6;
for (int i = 0; i < 32; i++)
{
[deviceID appendFormat:#"%02x", (unsigned char)b[i]];
}
[feedbackTokens addObject:deviceID];
} while (processed > 0);
return feedbackTokens;
}

Saving the DeviceToken for Later Use in Apple Push Notification Services

In my iPhone app I am getting the device token from Apple which I am assigning a public property inside the Delegate file as shown below:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
self.dToken = [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding];
}
The dToken property is declared as shown below:
NSString *dToken;
#property (nonatomic,retain) NSString *dToken;
But when I try to retrieve the device token from another file I get the null value.
+(NSString *) getDeviceToken
{
NSString *deviceToken = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] dToken];
NSLog(#" getDeviceToken = %#",deviceToken); // This prints NULL
return deviceToken;
}
What am I doing wrong?
I suggest you to convert token to string in this way:
self.dToken = [[[deviceToken description]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]]
stringByReplacingOccurrencesOfString:#" "
withString:#""];
UPDATED:
As many people mentioned it is better to use next approach to convert NSData * to NSString *:
#implementation NSData (Conversion)
- (NSString *)hexadecimalString
{
const unsigned char *dataBuffer = (const unsigned char *)[self bytes];
if (!dataBuffer) {
return [NSString string];
}
NSUInteger dataLength = [self length];
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < dataLength; ++i) {
[hexString appendFormat:#"%02lx", (unsigned long)dataBuffer[i]];
}
return hexString;
}
#end
From the discussion at Best way to serialize an NSData into a hexadeximal string, here is a better way to do it. Is longer, but your code will be future-proof if Apple changes the way NSData emit debugger descriptions.
Extend NSData as follows:
#implementation NSData (Hex)
- (NSString*)hexString {
unichar* hexChars = (unichar*)malloc(sizeof(unichar) * (self.length*2));
unsigned char* bytes = (unsigned char*)self.bytes;
for (NSUInteger i = 0; i < self.length; i++) {
unichar c = bytes[i] / 16;
if (c < 10) c += '0';
else c += 'A' - 10;
hexChars[i*2] = c;
c = bytes[i] % 16;
if (c < 10) c += '0';
else c += 'A' - 10;
hexChars[i*2+1] = c;
}
NSString* retVal = [[NSString alloc] initWithCharactersNoCopy:hexChars
length:self.length*2
freeWhenDone:YES];
return [retVal autorelease];
}
#end
I know that this is an old question and that this may be new information that has come up since then, but I'd just like to point something out to all of the people who are claiming that using the description method is a really bad idea. In most cases, you'd be exactly right. The description property is generally just used for debugging, but for the NSData class, it's specifically defined as returning a hexadecimal representation of the receivers contents which is exactly what is needed here. Since Apple has put it in their documentation, I think you're pretty safe as far as them changing it.
This can be found in the NSData Class Reference here: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/Reference/Reference.html

Resources