1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 
20 #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
21   import Darwin
22 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
23   import Glibc
24   import Dispatch
25 #endif
26 
27 import Foundation
28 import CoreFoundation
29 
30 public let TSocketServerClientConnectionFinished = "TSocketServerClientConnectionFinished"
31 public let TSocketServerProcessorKey = "TSocketServerProcessor"
32 public let TSocketServerTransportKey = "TSocketServerTransport"
33 
34 class TSocketServer<InProtocol: TProtocol, OutProtocol: TProtocol, Processor: TProcessor, Service> where Processor.Service == Service {
35   var socketFileHandle: FileHandle
36   var processingQueue =  DispatchQueue(label: "TSocketServer.processing",
37                                        qos: .background,
38                                        attributes: .concurrent)
39   var serviceHandler: Service
40 
41   public init(port: Int,
42               service: Service,
43               inProtocol: InProtocol.Type,
44               outProtocol: OutProtocol.Type,
45               processor: Processor.Type) throws {
46     // set service handler
47     self.serviceHandler = service
48 
49     // create a socket
50     var fd: Int32 = -1
51     #if os(Linux)
52       let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, Int32(SOCK_STREAM.rawValue), Int32(IPPROTO_TCP), 0, nil, nil)
53     #else
54       let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, nil, nil)
55     #endif
56     if sock != nil {
57       CFSocketSetSocketFlags(sock, CFSocketGetSocketFlags(sock) & ~kCFSocketCloseOnInvalidate)
58 
59       fd = CFSocketGetNative(sock)
60       var yes = 1
61       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, UInt32(MemoryLayout<Int>.size))
62 
63       #if os(Linux)
64         var addr = sockaddr_in(sin_family: sa_family_t(AF_INET),
65                                sin_port: in_port_t(port.bigEndian),
66                                sin_addr: in_addr(s_addr: in_addr_t(0)),
67                                sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
68       #else
69         var addr = sockaddr_in(sin_len: UInt8(MemoryLayout<sockaddr_in>.size),
70                                sin_family: sa_family_t(AF_INET),
71                                sin_port: in_port_t(port.bigEndian),
72                                sin_addr: in_addr(s_addr: in_addr_t(0)),
73                                sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
74       #endif
75 
76       let ptr = withUnsafePointer(to: &addr) {
77         return UnsafePointer<UInt8>(OpaquePointer($0))
78       }
79 
80       let address = Data(bytes: ptr, count: MemoryLayout<sockaddr_in>.size)
81 
82       let cfaddr = address.withUnsafeBytes {
83         CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, $0, address.count, nil)
84       }
85       if CFSocketSetAddress(sock, cfaddr) != CFSocketError.success { //kCFSocketSuccess {
86         CFSocketInvalidate(sock)
87         print("TSocketServer: Could not bind to address")
88         throw TTransportError(error: .notOpen, message: "Could not bind to address")
89       }
90 
91     } else {
92       print("TSocketServer: No server socket")
93       throw TTransportError(error: .notOpen, message: "Could not create socket")
94     }
95 
96     // wrap it in a file handle so we can get messages from it
97     socketFileHandle = FileHandle(fileDescriptor: fd, closeOnDealloc: true)
98 
99     // throw away our socket
100     CFSocketInvalidate(sock)
101 
102     // register for notifications of accepted incoming connections
103     _ = NotificationCenter.default.addObserver(forName: .NSFileHandleConnectionAccepted,
104                                                object: nil, queue: nil) {
105                                                 [weak self] notification in
106                                                 guard let strongSelf = self else { return }
107                                                 strongSelf.connectionAccepted(strongSelf.socketFileHandle)
108 
109     }
110 
111     // tell socket to listen
112     socketFileHandle.acceptConnectionInBackgroundAndNotify()
113 
114     print("TSocketServer: Listening on TCP port \(port)")
115   }
116 
117   deinit {
118     NotificationCenter.default.removeObserver(self)
119   }
120 
connectionAcceptednull121   func connectionAccepted(_ socket: FileHandle) {
122     // Now that we have a client connected, handle the request on queue
123     processingQueue.async {
124       self.handleClientConnection(socket)
125     }
126   }
127 
handleClientConnectionnull128   func handleClientConnection(_ clientSocket: FileHandle) {
129 
130     let transport = TFileHandleTransport(fileHandle: clientSocket)
131     let processor = Processor(service: serviceHandler)
132 
133     let inProtocol = InProtocol(on: transport)
134     let outProtocol = OutProtocol(on: transport)
135 
136     do {
137       try processor.process(on: inProtocol, outProtocol: outProtocol)
138     } catch let error {
139       print("Error processign request: \(error)")
140     }
141     DispatchQueue.main.async {
142       NotificationCenter.default
143         .post(name: Notification.Name(rawValue: TSocketServerClientConnectionFinished),
144               object: self,
145               userInfo: [TSocketServerProcessorKey: processor,
146                          TSocketServerTransportKey: transport])
147     }
148   }
149 }
150