Re: Socket Blocking Question
Re: Socket Blocking Question
- Subject: Re: Socket Blocking Question
- From: Steven Degutis <email@hidden>
- Date: Wed, 20 Jan 2010 15:27:01 -0600
In my implementation of this solution, it is a slight danger of code
injection, but only in the sense that *existing methods can be called with
bunk data*. Methods that are not implemented by the protocol (and thus
destination) are ignored when received over the network. However, this
connection between 2 Cocoa apps can further be secured by using SSL with
AsyncSocket (it just uses CFSocket and friends, so it should be fairly
straightforward, at least as far as SSL goes).
-Steven
On Wed, Jan 20, 2010 at 3:15 PM, nicolas berloquin <email@hidden>wrote:
> This is a genuine question/remark that pops up. No check is done on what
> selector or object is returned or is it ?
> If this is done on a public service (web server or other), couldn't code
> injection be too easilly done that way ? (easy hacking, wilfull crash etc) ?
>
>
> Le 20 janv. 2010 à 19:47, Steven Degutis <email@hidden> a
> écrit :
>
> Oops, correction: the downside is that all arguments and return values
>> need
>> to conform to NSCoder protocol. So, it's even more strict than I described
>> earlier. But it's still cool :)
>>
>> -Steven
>>
>> On Wed, Jan 20, 2010 at 12:40 PM, Steven Degutis
>> <email@hidden>wrote:
>>
>> Recently I had the same issue you were having, sort of. And I came up
>>> with
>>> a solution I really liked.
>>>
>>> When I was playing with Distributed Objects, I fell in love with the
>>> abstract simplicity. However, it blocks and that's bad. It's even worse
>>> when
>>> the server stops responding, because you could potentially have a 60
>>> second
>>> timeout before the single method will return. It's a potential disaster.
>>>
>>> So, I wrote an elegant compromise. Code is still written inline, no
>>> callbacks or delegate messages needed. But, it requires Blocks (and thus
>>> 10.6) to work.
>>>
>>> Essentially, I wrote some code on top of AsyncSocket (which is a
>>> brilliant
>>> framework by the way) that allows me to wrap up ObjC messages as NSData,
>>> send it across the server, and unpack it on the other side. The other
>>> side
>>> then responds to the ObjC message as if it was called right inside the
>>> application. (All this is thanks to NSInvocation's ability to introspect
>>> an
>>> ObjC message, by the way).
>>>
>>> The problem came when I had to return values. As long as the return value
>>> was void, this worked like a charm. But once I wanted to return an array
>>> of
>>> strings or a number, I had to define a method in the sender's protocol to
>>> receive such information. This is akin to your "thousands of delegate
>>> messages" you would have to implement, as you stated.
>>>
>>> So, using Blocks and NSInvocation and AsyncSocket, I ended up writing
>>> code
>>> that allows me to write code like this:
>>>
>>>
>>> // protocol.h
>>>
>>> @protocol ServerProtocol
>>>
>>> - (NSNumber*) calculatePiAndKillTime:(NSNumber*)shouldKillTime;
>>>
>>> @end
>>>
>>>
>>> // client.m
>>>
>>> - (void) someMethod {
>>> id <ServerProtocol> server;
>>> NSNumber *sure = [NSNumber numberWithBool:YES];
>>> [[server calculatePiAndKillTime: sure]
>>> returnedValue:^(id value) {
>>> // this will be called later on at some point
>>> NSLog(@"pi = %@", value);
>>> }]
>>> }
>>>
>>>
>>> // server.m
>>>
>>> - (NSNumber*) calculatePiAndKillTime:(NSNumber*)shouldKillTime {
>>> if ([shouldKillTime boolValue])
>>> // synchronously watch some film
>>> [self goWatchTheNewStarTrekFilmFrom2009];
>>>
>>> return [NSNumber numberWithFloat: 3.14];
>>> }
>>>
>>>
>>>
>>> All methods sent to a destination's proxy are sent asynchronously. And,
>>> as
>>> you can see, the return value of the method -calculatePiAndKillTime: is
>>> not
>>> actually an NSNumber, but rather a proxy that waits for a response from
>>> the
>>> destination. When the destination responds to the source with a return
>>> value, the method -returnedValue: is called with the value.
>>>
>>> But that's only half of the coolness.
>>>
>>> The other half is that methods can simply return the value they want
>>> right
>>> inside the method, no hacks necessary or anything by the programmer. In
>>> this
>>> case, we just use this line of code: return [NSNumber numberWithFloat:
>>> 3.14]; and then the NSNumber object is packaged up and sent back to the
>>> source through the proxy, all automagically.
>>>
>>> The main downfall of this is that every argument and return value must be
>>> an ObjC type, no scalars or structs or anything else will work with this
>>> system. (Mike Ash explains pretty well on this blog why trying to support
>>> those things can lead to some unfixable trickiness, which I just wanted
>>> to
>>> avoid altogether.)
>>>
>>> If you can't support 10.6, then, this won't work. But hopefully you can
>>> soon ;)
>>>
>>> Good luck.
>>>
>>> -Steven
>>>
>>>
>>>
>>> On Wed, Jan 20, 2010 at 11:39 AM, Carter R. Harrison <
>>> email@hidden> wrote:
>>>
>>> I need some folks experienced with cocoa and socket programming to weigh
>>>> in for me on some design problems I've been having. I'm designing an
>>>> application that acts as a client in a client-server model. The client
>>>> communicates with the server over the network by issuing a request and
>>>> then
>>>> receiving a response. Requests can only be issued one at a time,
>>>> meaning
>>>> that a request cannot be sent until a response from any outstanding
>>>> request
>>>> is first received. My application works in such a way that the it could
>>>> request a handle to an object on the server and then use that handle in
>>>> subsequent requests to retrieve additional information about the object.
>>>> I
>>>> see two ways of modeling the application - I've tried both and I'm not
>>>> particularly happy with either.
>>>>
>>>> The first is to send a request, and then have the socket block until a
>>>> response is received. This benefit to this model is that it is so much
>>>> easier to write the higher level application code. The issue with this
>>>> model is that over a slow network connection it can take a considerable
>>>> amount of time for the response to come back from the server and while
>>>> that
>>>> is happening my CPU usage is through the roof b/c the thread is
>>>> blocking.
>>>>
>>>> The second way is to send a request and then let the NSInputStream call
>>>> a
>>>> delegate method when the response data is available. The response data
>>>> is
>>>> then pushed up through my protocol stack and finally up to the higher
>>>> level
>>>> application code. The benefit to this method is that CPU usage is
>>>> minimal
>>>> due to the fact that I'm no longer blocking, but the downside is that
>>>> the
>>>> higher level application code is so much more difficult to write because
>>>> I
>>>> have to write about a thousand methods to act as a callback for each
>>>> request
>>>> in a series of requests.
>>>>
>>>> I've provided an example of how I see each working below. My first
>>>> question is, is there other ways to design an application around this
>>>> client-server model that I'm not thinking about? My 2nd question is, if
>>>> there aren't other ways, how can I adapt either method that I have
>>>> outlined
>>>> to make it work a little bit better?
>>>>
>>>> As an example let's say the server knows about the following objects:
>>>>
>>>> 1. VendingMachine
>>>> - An object that represents a vending machine.
>>>> - A vending machine contains Soft Drink objects.
>>>> 2. SoftDrink
>>>> - Has the following properties: drink name, price, number of
>>>> calories.
>>>>
>>>> If I use the blocking model, I could write my code like this. The code
>>>> is
>>>> simple to write but I'm forced to wait for the server to respond with
>>>> information on pretty much every line of code. If the vending machine
>>>> had
>>>> enough soft drinks it could take a long time to iterate over each one
>>>> and
>>>> have the server respond with the drink's name of each drink.
>>>>
>>>> -(void)printDrinkNames
>>>> {
>>>> VendingMachine *machine = [server fetchVendingMachine];
>>>> NSArray *softDrinks = [machine getSoftDrinks];
>>>> for (int i = 0 ; i < softDrinks.count ; i++)
>>>> {
>>>> NSString *drinkName = [[softDrinks objectAtIndex:i] name];
>>>> NSLog(@"Found a drink named %@", drinkName);
>>>> }
>>>> }
>>>>
>>>> Likewise if I do the non-blocking approach I would have to have a method
>>>> that gets called for each step in the process (see below). This model
>>>> drives me crazy b/c the higher level application code is long, has tons
>>>> of
>>>> methods, and is just difficult to read and maintain. The example I have
>>>> provided is simple enough to get the point across, but in reality some
>>>> of
>>>> the processes I'm trying to drive are much more complex and require
>>>> numerous
>>>> callback methods to pull off.
>>>>
>>>> -(void)printDrinkNames
>>>> {
>>>> [server fetchVendingMachineWithCallBackObject:self
>>>> selector:@selector(didFetchVendingMachine:)
>>>> }
>>>>
>>>> -(void)didFetchVendingMachine:(VendingMachine *)machine
>>>> {
>>>> [machine fetchSoftDrinksWithCallBackObject:self selector:@selector
>>>> (didFetchSoftDrinks:)];
>>>> }
>>>>
>>>> -(void)didFetchSoftDrinks:(NSArray *)drinks
>>>> {
>>>> for (int i = 0 ; i < drinks.count ; i++)
>>>> {
>>>> SoftDrink *drink = [drinks objectAtIndex:i];
>>>> [drink fetchNameWithCallBackObject:self selector:@selector
>>>> (didFetchDrinkName:)]
>>>> }
>>>> }
>>>>
>>>> -(void)didFetchDrinkName:(NSString *)name
>>>> {
>>>> NSLog(@"Drink name is %@", name);
>>>> }
>>>>
>>>> _______________________________________________
>>>>
>>>> Cocoa-dev mailing list (email@hidden)
>>>>
>>>> Please do not post admin requests or moderator comments to the list.
>>>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>>>
>>>> Help/Unsubscribe/Update your Subscription:
>>>>
>>>>
>>>>
>>>> This email sent to email@hidden
>>>>
>>>>
>>>
>>>
>>> --
>>> Steven Degutis
>>> http://www.thoughtfultree.com/
>>> http://www.degutis.org/
>>>
>>>
>>
>>
>> --
>> Steven Degutis
>> http://www.thoughtfultree.com/
>> http://www.degutis.org/
>> _______________________________________________
>>
>> Cocoa-dev mailing list (email@hidden)
>>
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>
>> Help/Unsubscribe/Update your Subscription:
>>
>> This email sent to email@hidden
>>
>
--
Steven Degutis
http://www.thoughtfultree.com/
http://www.degutis.org/
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden