Have just started on this too. Here is my understanding:
Sitelinks are retrieved with the FeedItemService. That gives the sitelinks with all their data.
But it also retrieves other types of FeedItems (phone numbers, offers, etc).
You need to use the FeedMappingService to generically tell if a feed item is a sitelink (by checking for PlaceHolderId=1). There are assumption based shortcuts you could use such as looking at the FeedService::feedName, but I don't like risk - and not sure about other language accounts.
Feed Items (including sitelinks) exist "above" campaigns.
Then the campaignFeedService (or AdgroupFeedService) is used to link these sitelink feed items to multiple campaigns and/or adgroups.
So the approach I am looking to implement is:
1 - FeedMappingService::get
Store the results in a hash keyed on feedMappingId
2 - FeedItemService::get
For each one look up validationDetails.feedMappingId in the hash. If the hashed placeholderId == 1 its a sitelink
Save the sitelinks to our system
3 - CampaignFeedService::get / AdgroupFeedService::get
Find the matching feedItemIds (think this will have to be the matching function)
Store the links between sitelinks and campaigns/adgroups in our system
4 - FeedItemService::put
If you want to modify the sitelinks themselves (change URLs etc)
5 - CampaignFeedService::put / AdgroupFeedService::put
If you want to change which Campaigns/Adgroups the sitelinks are attached to
Now Google have made this all MUCH more complicated than it was. So I am assuming there has to be some kind of payoff for it coming down the track. I guess the advantage for them is they don't need to keep adding new services as they come up with new AdExtensions. But this new Feed model is VERY generic and thus quite daunting when you first start. As I said I've just started on this and am learning each day myself.
Good luck