Kaidul

NSsocket_latest_2.mm

Nov 27th, 2014
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.08 KB | None | 0 0
  1. //
  2. //  NSsocket.cpp
  3. //  PAL
  4. //
  5. //  Created by Erfan on 4/23/14.
  6. //
  7. //
  8.  
  9. #import <Foundation/Foundation.h>
  10. #include "NSsocket.h"
  11. #import "mach/mach.h"
  12. #include <sys/time.h>
  13. #include <netdb.h>
  14. #include <sys/types.h>
  15. #include <sys/socket.h>
  16. #include "PALcritsec.h"
  17. #include <list>
  18. #include "winEmul.h"
  19.  
  20. #ifdef PHILIPS
  21. #define VERIFY_CERTIFICATE
  22. #endif
  23.  
  24. #define BUFFER_SIZE 4096
  25.  
  26. @interface NSsocket : NSObject <NSStreamDelegate> {
  27. @private volatile bool m_bConnected;
  28. @private volatile bool m_bHasSpaceAvailable;
  29. #ifdef VERIFY_CERTIFICATE
  30. @private volatile bool m_certificateChecked;
  31. #endif
  32.    
  33. @private NSInputStream *m_pInputStream;
  34. @private NSOutputStream *m_pOutputStream;
  35.    
  36. @private HANDLE m_hSocketError;
  37. @private HANDLE m_hSocketOpened;
  38. @private HANDLE m_hSocketDataReceived;
  39. @private HANDLE m_hSocketClosed;
  40.    
  41. @private PAL::Mutex* m_pReadMutex;
  42. @private PAL::Mutex* m_pWriteMutex;
  43.    
  44. @private std::list<std::string> recvMessageBuffer;
  45. @private std::list<std::string> sendMessageBuffer;
  46. }
  47.  
  48. -(NSStream *)GetStream:(bool)bInput;
  49. -(bool)CreateAndConnect:(const std::string&) serverAddress withPort:(const u_int16_t&) serverPort withTransportMode:(bool)bTLS;
  50. -(void)CloseConnection;
  51. -(void)CloseStreams;
  52. -(void)CloseEvents;
  53. -(bool)IsConnected;
  54. -(int)Send:(const std::string&)sDataToSend;
  55. -(int)Recv:(char *)dataReceived withBufferSize:(int)bufferSize;
  56. -(int)Select:(u_int64_t)uTimeoutValue;
  57. -(void)Signal;
  58.  
  59. @end
  60.  
  61. @implementation NSsocket
  62.  
  63. - (id)init
  64. {
  65.     self = [super init];
  66.     if(self)
  67.     {
  68.         // Must be created at the beginning, otherwise calling Select would cause a crash with NULL events
  69.         m_hSocketError = CreateEvent(NULL, FALSE, FALSE, NULL);
  70.         m_hSocketOpened = CreateEvent(NULL, FALSE, FALSE, NULL);
  71.         m_hSocketDataReceived = CreateEvent(NULL, FALSE, FALSE, NULL);
  72.         m_hSocketClosed = CreateEvent(NULL, FALSE, FALSE, NULL);
  73.        
  74.         m_pReadMutex = new PAL::Mutex;
  75.         m_pWriteMutex = new PAL::Mutex;
  76.     }
  77.    
  78.     return self;
  79. }
  80.  
  81. -(NSStream *)GetStream:(bool)bInput
  82. {
  83.     return bInput ? m_pInputStream : m_pOutputStream;
  84. }
  85.  
  86. -(bool)CreateAndConnect:(const std::string&) serverAddress withPort:(const u_int16_t&) serverPort withTransportMode:(bool)bTLS
  87. {
  88.     NSLog(@"NSStream %p connecting to: %s:%d in %s", self, serverAddress.c_str(), serverPort, bTLS ? "TLS" : "TCP");
  89.    
  90.     CFStringRef remoteHost = CFStringCreateWithCString(kCFAllocatorDefault, serverAddress.c_str(), kCFStringEncodingMacRoman);
  91.    
  92.     CFReadStreamRef readStream;
  93.     CFWriteStreamRef writeStream;
  94.    
  95.     CFStreamCreatePairWithSocketToHost(NULL, remoteHost, serverPort, &readStream, &writeStream);
  96.    
  97. #ifdef VERIFY_CERTIFICATE
  98.     m_certificateChecked = YES;
  99. #endif
  100.    
  101.     // Set options then bridge to ARC:
  102.     if(bTLS)
  103.     {
  104. #ifdef VERIFY_CERTIFICATE
  105.         m_certificateChecked = NO;
  106. #endif
  107.        
  108. #ifndef VERIFY_CERTIFICATE
  109.         NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
  110.                                   (id)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamPropertySocketSecurityLevel,
  111.                                   [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
  112.                                   [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
  113.                                   [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots,
  114.                                   [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
  115.                                   nil];
  116.        
  117.         CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)settings);
  118.         CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)settings);
  119. #else
  120.         // Set this kCFStreamPropertySocketSecurityLevel before setting kCFStreamPropertySSLSettings.
  121.         // Setting kCFStreamPropertySocketSecurityLevel appears to override previous settings in kCFStreamPropertySSLSettings
  122.         CFReadStreamSetProperty(readStream,
  123.                                 kCFStreamPropertySocketSecurityLevel,
  124.                                 kCFStreamSocketSecurityLevelNegotiatedSSL);
  125.         // this disables certificate chain validation in ssl settings.
  126.         NSDictionary *sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
  127.                                      (id)kCFBooleanFalse, (id)kCFStreamSSLValidatesCertificateChain,
  128.                                      nil];
  129.         CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)sslSettings);
  130.         CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)sslSettings);
  131.        
  132.         CFReadStreamOpen(readStream);
  133.         CFWriteStreamOpen(writeStream);
  134. #endif
  135.     }
  136.    
  137.     CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  138.     CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  139.    
  140.     m_pInputStream = (__bridge_transfer NSInputStream *)readStream;
  141.     m_pOutputStream = (__bridge_transfer NSOutputStream *)writeStream;
  142.    
  143.     [m_pInputStream setDelegate:self];
  144.     [m_pOutputStream setDelegate:self];
  145.    
  146.     recvMessageBuffer.clear();
  147.     sendMessageBuffer.clear();
  148.    
  149.     m_bConnected = false;
  150.     m_bHasSpaceAvailable = false;
  151.    
  152.     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
  153.     dispatch_async(queue, ^ {
  154.         // mainRunLoop used instead of currentRunLoop to avoid a crash on Logout
  155.         [m_pInputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
  156.         [m_pOutputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
  157.        
  158.         [m_pInputStream open];
  159.         [m_pOutputStream open];
  160.        
  161.         [[NSRunLoop currentRunLoop] run];
  162.     });
  163.    
  164.     return true;
  165. }
  166.  
  167. -(void)CloseConnection
  168. {
  169.     NSLog(@"NSStream %p closing connection", self);
  170.    
  171.     SetEvent(m_hSocketClosed);
  172.    
  173.     [self CloseStreams];
  174. }
  175.  
  176. -(void)CloseStreams
  177. {
  178.     m_bConnected = false;
  179.    
  180.     [m_pInputStream close];
  181.     [m_pOutputStream close];
  182.     [m_pInputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  183.     [m_pOutputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  184.    
  185.     recvMessageBuffer.clear();
  186.     sendMessageBuffer.clear();
  187. }
  188.  
  189. // Called as the destructor from the CNSsocket's destructor
  190. -(void)CloseEvents
  191. {
  192.     CloseEvent(m_hSocketError);
  193.     CloseEvent(m_hSocketOpened);
  194.     CloseEvent(m_hSocketDataReceived);
  195.     CloseEvent(m_hSocketClosed);
  196.    
  197.     delete m_pReadMutex;
  198.     delete m_pWriteMutex;
  199. }
  200.  
  201. -(bool)IsConnected
  202. {
  203.     return m_bConnected;
  204. }
  205.  
  206. -(int)Send:(const std::string&)sDataToSend
  207. {
  208.     PAL::Critical_Section cs(*m_pWriteMutex);
  209.     int iRet = sDataToSend.length();
  210.     if(m_bHasSpaceAvailable){
  211.         m_bHasSpaceAvailable = false;
  212.         //NSLog(@"NSStream %p sending data of length %lu", self, sDataToSend.length());
  213.         iRet = [m_pOutputStream write:(const uint8_t *)sDataToSend.c_str() maxLength:sDataToSend.length()];
  214.         //NSLog(@"NSStream %p sent length %d", self, iRet);
  215.     }
  216.     else{
  217.         sendMessageBuffer.push_back(sDataToSend);
  218.     }
  219.     return iRet;
  220. }
  221.  
  222. -(int)Recv:(char *)dataReceived withBufferSize:(int)bufferSize
  223. {
  224.     PAL::Critical_Section cs(*m_pReadMutex);
  225.     int dataLength = 0;
  226.     if (recvMessageBuffer.size() > 0)
  227.     {
  228.         std::string buffer = recvMessageBuffer.front();
  229.         recvMessageBuffer.pop_front();
  230.         dataLength = buffer.length() < bufferSize ? buffer.length() : bufferSize;
  231.         memcpy(dataReceived, buffer.c_str(), dataLength);
  232.         // TODO: if buffer.length is greater than bufferSize then the extra data should be stored back so that next time it returns this
  233.     }
  234.    
  235.     if(dataLength == 0 && [m_pInputStream streamStatus] >= NSStreamStatusClosed)
  236.     {
  237.         NSLog(@"NSStream %p recv error", self);
  238.         return -1;
  239.     }
  240.    
  241.     return dataLength;
  242.    
  243. }
  244.  
  245. -(int)Select:(u_int64_t)uTimeoutValue
  246. {
  247.     int iRet = 0;
  248.    
  249.     const int iNumEvents = 4;
  250.    
  251.     HANDLE EventArray[iNumEvents];
  252.     EventArray[0] = m_hSocketError;
  253.     EventArray[1] = m_hSocketOpened;
  254.     EventArray[2] = m_hSocketDataReceived;
  255.     EventArray[3] = m_hSocketClosed;
  256.    
  257.     DWORD dwWaitStatus = WaitForMultipleObjects(iNumEvents, EventArray, FALSE, uTimeoutValue);
  258.    
  259.     switch (dwWaitStatus)
  260.     {
  261.         case WAIT_FAILED:
  262.             break;
  263.            
  264.         case WAIT_OBJECT_0:
  265.             iRet = -1;
  266.             break;
  267.            
  268.         case WAIT_OBJECT_0 + 1:
  269.             iRet = 1;
  270.             break;
  271.            
  272.         case WAIT_OBJECT_0 + 2:
  273.             iRet = 1;
  274.             break;
  275.            
  276.         case WAIT_OBJECT_0 + 3:
  277.             iRet = 0;
  278.             break;
  279.            
  280.         default:
  281.             break;
  282.     }
  283.    
  284.     return iRet;
  285. }
  286.  
  287. -(void)Signal
  288. {
  289.     SetEvent(m_hSocketDataReceived);
  290. }
  291.  
  292. #ifdef VERIFY_CERTIFICATE
  293.  
  294. #define NS_ASSERT(X, ...) \
  295.     /*NSAssert(X, __VA_ARGS__);*/ \
  296.     if(!(X)){ \
  297.         NSLog(__VA_ARGS__); \
  298.         return NO; \
  299.     }
  300.  
  301. -(BOOL) VerifyCertificate: (NSStream *)aStream
  302. {
  303.     NSData *trustedCertData = nil;
  304.     BOOL result             = NO;
  305.     SecTrustRef trustRef    = NULL;
  306.    
  307.     NSString *root_certificate_name      = @"philips_trusted_cert";
  308.     NSString *root_certificate_extension = @"der";
  309.    
  310.     /** Reading root cetificate **/
  311.     NSBundle *bundle = [NSBundle bundleForClass:[self class]];
  312.     trustedCertData = [NSData dataWithContentsOfFile:[bundle pathForResource: root_certificate_name ofType: root_certificate_extension]];
  313.     NS_ASSERT(trustedCertData != nil, @"trustedCertData failed.");
  314.    
  315.     /** Reading server cetificate **/
  316.     trustRef = (__bridge SecTrustRef)[aStream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust];
  317.     NS_ASSERT(trustRef != NULL, @"Could not create a trust management object!");
  318.    
  319.     /* Check which certificate is identical to root certificate */
  320.     NSInteger numCerts = SecTrustGetCertificateCount(trustRef);
  321.     for (NSInteger i = 0; i < numCerts; i++) {
  322.         SecCertificateRef secCertRef = SecTrustGetCertificateAtIndex(trustRef, i);
  323.         NSData *certData = CFBridgingRelease(SecCertificateCopyData(secCertRef));
  324.         if ([trustedCertData isEqualToData: certData]) {
  325.             result = YES;
  326.             break;
  327.         }
  328.     }
  329.    
  330.     /** releasing memory **/
  331.     if(trustRef) CFRelease(trustRef);
  332.    
  333.     return result;
  334. }
  335. #endif
  336.  
  337. #pragma mark -
  338. #pragma mark NSStreamDelegate
  339.  
  340. - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
  341. {
  342.     // NSLog(@"NSStream %p eventCode: %d", self, (int)eventCode);
  343.    
  344.     switch (eventCode) {
  345.         case NSStreamEventNone:
  346.             // do nothing.
  347.             //NSLog(@"NSStreamEventNone");
  348.             break;
  349.            
  350.         case NSStreamEventEndEncountered:
  351.             NSLog(@"NSStreamEventEndEncountered %@", [aStream streamError]);
  352.             [self CloseStreams];
  353.             SetEvent(m_hSocketError);
  354.             break;
  355.            
  356.         case NSStreamEventErrorOccurred:
  357.             NSLog(@"NSStreamEventErrorOccurred %@", [aStream streamError]);
  358.             [self CloseStreams];
  359.             SetEvent(m_hSocketError);
  360.             break;
  361.            
  362.         case NSStreamEventHasBytesAvailable:
  363.         {
  364.             if (aStream == m_pInputStream)
  365.             {
  366.                 PAL::Critical_Section cs(*m_pReadMutex);
  367.                 uint8_t buffer[BUFFER_SIZE];
  368.                 NSInteger bytesRead = [m_pInputStream read:buffer maxLength:BUFFER_SIZE];
  369.                
  370.                 //NSLog(@"NSStreamEventHasBytesAvailable of length %d", bytesRead);
  371.                
  372.                 if (0 >= bytesRead)
  373.                     break;
  374.                
  375.                 NSString *nsStringRead = [[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding];
  376.                
  377.                 std::string sStringRead = [nsStringRead UTF8String];
  378.                 NSLog(@"recieved data: %s", sStringRead.c_str());
  379.                 recvMessageBuffer.push_back(sStringRead);
  380.                
  381.                 SetEvent(m_hSocketDataReceived);
  382.             }
  383.             break;
  384.         }
  385.         case NSStreamEventHasSpaceAvailable:
  386.         {
  387. #ifdef VERIFY_CERTIFICATE
  388.             if (!m_certificateChecked) {
  389.                 m_certificateChecked = YES;
  390.                 if ([self VerifyCertificate: aStream]) {
  391.                     NSLog(@"Certificate Verification Success.");
  392.                 } else
  393.                 {
  394.                     NSLog(@"Certificate Verification Failed.");
  395.                     [self CloseStreams];
  396.                     SetEvent(m_hSocketError);
  397.                     break;
  398.                 }
  399.             }
  400. #endif
  401.            
  402.             if(aStream == m_pOutputStream)
  403.             {
  404.                 PAL::Critical_Section cs(*m_pWriteMutex);
  405.                 m_bHasSpaceAvailable = true;
  406.                 if(sendMessageBuffer.size() > 0)
  407.                 {
  408.                     std::string sDataToSend = sendMessageBuffer.front();
  409.                     sendMessageBuffer.pop_front();
  410.                     int iWritten = 0;
  411.                     if(sDataToSend.length() > 0)
  412.                     {
  413.                         m_bHasSpaceAvailable = false;
  414.                         //NSLog(@"NSStream %p sending data of length %lu", self, sDataToSend.length());
  415.                         iWritten = [m_pOutputStream write:(const uint8_t *)sDataToSend.c_str() maxLength:sDataToSend.length()];
  416.                         //NSLog(@"NSStream %p sent length %d", self, iWritten);
  417.                     }
  418.                 }
  419.             }
  420.             // SetEvent(m_hSocketOpened);
  421.             break;
  422.         }
  423.         case NSStreamEventOpenCompleted:
  424.             NSLog(@"NSStreamEventOpenCompleted");
  425.             m_bConnected = true;
  426.             //SetEvent(m_hSocketOpened);
  427.             break;
  428.            
  429.         default:
  430.             //NSLog(@"NSStream default");
  431.             break;
  432.     }
  433. }
  434.  
  435. @end
  436.  
  437. /**********************************************************
  438.  CNSsocket implementation
  439.  **********************************************************/
  440.  
  441. CNSsocket::CNSsocket()
  442. {
  443.     m_pNSsocket = [[NSsocket alloc] init];
  444. }
  445.  
  446. CNSsocket::~CNSsocket()
  447. {
  448.     CloseConnection();
  449.     [m_pNSsocket CloseEvents];
  450. }
  451.  
  452. // [TODO] we MUST check the connection status
  453.  
  454. bool CNSsocket::CreateAndConnect(const std::string& serverAddress, const u_int16_t& serverPort, bool bTLS)
  455. {
  456.     return [m_pNSsocket CreateAndConnect:serverAddress withPort:serverPort withTransportMode:bTLS];
  457. }
  458.  
  459. void CNSsocket::GetLocalAddressAndPort(std::string& serverAddress, u_int16_t& serverPort)
  460. {
  461.     CFWriteStreamRef writeStream = (__bridge CFWriteStreamRef) [m_pNSsocket GetStream:false];
  462.    
  463.     // Get the native socket handle:
  464.     CFTypeRef socketTypeRef = CFWriteStreamCopyProperty(writeStream, kCFStreamPropertySocketNativeHandle);
  465.     if(socketTypeRef == NULL)
  466.     {
  467.         NSLog(@"Error in getting native socket handle");
  468.         serverAddress = "";
  469.         serverPort = 0;
  470.        
  471.         return;
  472.     }
  473.    
  474.     CFDataRef socketData = (CFDataRef)socketTypeRef;
  475.     CFSocketNativeHandle socket;
  476.     CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket);
  477.    
  478.     // Get the local socket address from the socket handle:
  479.     struct sockaddr_storage sa;
  480.     socklen_t salen = sizeof(sa);
  481.     getsockname(socket, (struct sockaddr *)&sa, &salen);
  482.    
  483.     // Get numeric host and port from socket address:
  484.     char host[NI_MAXHOST];
  485.     char service[NI_MAXSERV];
  486.     getnameinfo((struct sockaddr *)&sa, salen, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST|NI_NUMERICSERV);
  487.    
  488.     serverAddress = std::string(host);
  489.     serverPort = (u_int16_t)atoi(service);
  490.    
  491.     NSLog(@"Local address: %s, local port: %d", serverAddress.c_str(), serverPort);
  492. }
  493.  
  494. void CNSsocket::CloseConnection()
  495. {
  496.     [m_pNSsocket CloseConnection];
  497. }
  498.  
  499. int CNSsocket::Send(const char* dataToSend, int sizeOfData)
  500. {
  501.     return [m_pNSsocket Send:std::string(dataToSend, sizeOfData)];
  502. }
  503.  
  504. int CNSsocket::Recv(char dataReceived[], int bufferSize)
  505. {
  506.     return [m_pNSsocket Recv:dataReceived withBufferSize:bufferSize];
  507. }
  508.  
  509.  
  510. // [TODO] We should use callback instead of select() to reduce processing cost.
  511. // This needs to be called after invoking CreateAndConnect to get connection status.
  512.  
  513. int CNSsocket::Select(u_int64_t timeOutValue)
  514. {
  515.     return [m_pNSsocket Select:timeOutValue];
  516. }
  517.  
  518. int CNSsocket::WaitForConnect(u_int64_t timeOutValue)
  519. {
  520.     u_int64_t slept = 0;
  521.     const u_int64_t duration = 50;
  522.     while(slept < timeOutValue){
  523.         if([m_pNSsocket IsConnected])
  524.             return 1;
  525.         usleep(duration * 1000);
  526.         slept += duration;
  527.     }
  528.     return [m_pNSsocket IsConnected] ? 1 : -1;
  529. }
  530.  
  531. void CNSsocket::Signal()
  532. {
  533.     [m_pNSsocket Signal];
  534. }
Advertisement
Add Comment
Please, Sign In to add comment