浏览代码

Refactored error handling by introducing Errno class.

Damian Kołakowski 10 年之前
父节点
当前提交
2140324b44
共有 5 个文件被更改,包括 121 次插入80 次删除
  1. 16 0
      Sources/Errno.swift
  2. 1 67
      Sources/HttpServerIO.swift
  3. 83 0
      Sources/Socket+File.swift
  4. 9 13
      Sources/Socket.swift
  5. 12 0
      XCode/Swifter.xcodeproj/project.pbxproj

+ 16 - 0
Sources/Errno.swift

@@ -0,0 +1,16 @@
+//
+//  Errno.swift
+//  Swifter
+//
+//  Created by Damian Kolakowski on 13/07/16.
+//  Copyright © 2016 Damian Kołakowski. All rights reserved.
+//
+
+import Foundation
+
+public class Errno {
+    
+    public class func description() -> String {
+        return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
+    }
+}

+ 1 - 67
Sources/HttpServerIO.swift

@@ -85,11 +85,7 @@ public class HttpServerIO {
         let socket: Socket
 
         func write(file: File) throws {
-            var offset: off_t = 0
-            let result = sendfile(fileno(file.pointer), socket.socketFileDescriptor, 0, &offset, nil, 0)
-            if result == -1 {
-              throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
-            }
+            try socket.writeFile(file)
         }
 
         func write(data: [UInt8]) throws {
@@ -129,65 +125,3 @@ public class HttpServerIO {
     }
 }
 
-#if os(Linux)
-    
-    import Glibc
-    
-    struct sf_hdtr { }
-    
-    func sendfile(source: Int32, _ target: Int32, _: off_t, _: UnsafeMutablePointer<off_t>, _: UnsafeMutablePointer<sf_hdtr>, _: Int32) -> Int32 {
-        var buffer = [UInt8](count: 1024, repeatedValue: 0)
-        while true {
-            let readResult = read(source, &buffer, buffer.count)
-            guard readResult > 0 else {
-                return Int32(readResult)
-            }
-            var writeCounter = 0
-            while writeCounter < readResult {
-                let writeResult = write(target, &buffer + writeCounter, readResult - writeCounter)
-                guard writeResult > 0 else {
-                    return Int32(writeResult)
-                }
-                writeCounter = writeCounter + writeResult
-            }
-        }
-    }
-
-    public class NSLock {
-    
-        private var mutex = pthread_mutex_t()
-	    
-        init() { pthread_mutex_init(&mutex, nil) }
-	    
-        public func lock() { pthread_mutex_lock(&mutex) }
-	    
-        public func unlock() { pthread_mutex_unlock(&mutex) }
-	    
-        deinit { pthread_mutex_destroy(&mutex) }
-    }
-
-    
-    let DISPATCH_QUEUE_PRIORITY_BACKGROUND = 0
-    
-    private class dispatch_context {
-        let block: ((Void) -> Void)
-        init(_ block: ((Void) -> Void)) {
-            self.block = block
-        }
-    }
-    
-    func dispatch_get_global_queue(queueId: Int, _ arg: Int) -> Int { return 0 }
-    
-    func dispatch_async(queueId: Int, _ block: ((Void) -> Void)) {
-        let unmanagedDispatchContext = Unmanaged.passRetained(dispatch_context(block))
-        let context = UnsafeMutablePointer<Void>(unmanagedDispatchContext.toOpaque())
-        var pthread: pthread_t = 0
-        pthread_create(&pthread, nil, { (context: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> in
-            let unmanaged = Unmanaged<dispatch_context>.fromOpaque(COpaquePointer(context))
-            unmanaged.takeUnretainedValue().block()
-            unmanaged.release()
-            return context
-        }, context)
-    }
-    
-#endif

+ 83 - 0
Sources/Socket+File.swift

@@ -0,0 +1,83 @@
+//
+//  Socket+File.swift
+//  Swifter
+//
+//  Created by Damian Kolakowski on 13/07/16.
+//
+
+import Foundation
+
+extension Socket {
+    
+    public func writeFile(file: File) throws -> Void {
+        var offset: off_t = 0
+        let result = sendfile(fileno(file.pointer), self.socketFileDescriptor, 0, &offset, nil, 0)
+        if result == -1 {
+            throw SocketError.WriteFailed("sendfile: " + Errno.description())
+        }
+    }
+    
+}
+
+#if os(Linux)
+    
+import Glibc
+
+struct sf_hdtr { }
+
+func sendfile(source: Int32, _ target: Int32, _: off_t, _: UnsafeMutablePointer<off_t>, _: UnsafeMutablePointer<sf_hdtr>, _: Int32) -> Int32 {
+    var buffer = [UInt8](count: 1024, repeatedValue: 0)
+    while true {
+        let readResult = read(source, &buffer, buffer.count)
+        guard readResult > 0 else {
+            return Int32(readResult)
+        }
+        var writeCounter = 0
+        while writeCounter < readResult {
+            let writeResult = write(target, &buffer + writeCounter, readResult - writeCounter)
+            guard writeResult > 0 else {
+                return Int32(writeResult)
+            }
+            writeCounter = writeCounter + writeResult
+        }
+    }
+}
+
+public class NSLock {
+    
+    private var mutex = pthread_mutex_t()
+    
+    init() { pthread_mutex_init(&mutex, nil) }
+    
+    public func lock() { pthread_mutex_lock(&mutex) }
+    
+    public func unlock() { pthread_mutex_unlock(&mutex) }
+    
+    deinit { pthread_mutex_destroy(&mutex) }
+}
+
+
+let DISPATCH_QUEUE_PRIORITY_BACKGROUND = 0
+
+private class dispatch_context {
+    let block: ((Void) -> Void)
+    init(_ block: ((Void) -> Void)) {
+        self.block = block
+    }
+}
+
+func dispatch_get_global_queue(queueId: Int, _ arg: Int) -> Int { return 0 }
+
+func dispatch_async(queueId: Int, _ block: ((Void) -> Void)) {
+    let unmanagedDispatchContext = Unmanaged.passRetained(dispatch_context(block))
+    let context = UnsafeMutablePointer<Void>(unmanagedDispatchContext.toOpaque())
+    var pthread: pthread_t = 0
+    pthread_create(&pthread, nil, { (context: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> in
+        let unmanaged = Unmanaged<dispatch_context>.fromOpaque(COpaquePointer(context))
+        unmanaged.takeUnretainedValue().block()
+        unmanaged.release()
+        return context
+        }, context)
+}
+    
+#endif

+ 9 - 13
Sources/Socket.swift

@@ -37,12 +37,12 @@ public class Socket: Hashable, Equatable {
         #endif
         
         if socketFileDescriptor == -1 {
-            throw SocketError.SocketCreationFailed(Socket.descriptionOfLastError())
+            throw SocketError.SocketCreationFailed(Errno.description())
         }
         
         var value: Int32 = 1
         if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) == -1 {
-            let details = Socket.descriptionOfLastError()
+            let details = Errno.description()
             Socket.release(socketFileDescriptor)
             throw SocketError.SocketSettingReUseAddrFailed(details)
         }
@@ -89,13 +89,13 @@ public class Socket: Hashable, Equatable {
         #endif
 
         if bindResult == -1 {
-            let details = Socket.descriptionOfLastError()
+            let details = Errno.description()
             Socket.release(socketFileDescriptor)
             throw SocketError.BindFailed(details)
         }
         
         if listen(socketFileDescriptor, maxPendingConnection ) == -1 {
-            let details = Socket.descriptionOfLastError()
+            let details = Errno.description()
             Socket.release(socketFileDescriptor)
             throw SocketError.ListenFailed(details)
         }
@@ -123,7 +123,7 @@ public class Socket: Hashable, Equatable {
         var len: socklen_t = 0
         let clientSocket = accept(self.socketFileDescriptor, &addr, &len)
         if clientSocket == -1 {
-            throw SocketError.AcceptFailed(Socket.descriptionOfLastError())
+            throw SocketError.AcceptFailed(Errno.description())
         }
         Socket.setNoSigPipe(clientSocket)
         return Socket(socketFileDescriptor: clientSocket)
@@ -147,7 +147,7 @@ public class Socket: Hashable, Equatable {
                     let s = write(self.socketFileDescriptor, $0.baseAddress + sent, Int(data.count - sent))
                 #endif
                 if s <= 0 {
-                    throw SocketError.WriteFailed(Socket.descriptionOfLastError())
+                    throw SocketError.WriteFailed(Errno.description())
                 }
                 sent += s
             }
@@ -158,7 +158,7 @@ public class Socket: Hashable, Equatable {
         var buffer = [UInt8](count: 1, repeatedValue: 0)
         let next = recv(self.socketFileDescriptor as Int32, &buffer, Int(buffer.count), 0)
         if next <= 0 {
-            throw SocketError.RecvFailed(Socket.descriptionOfLastError())
+            throw SocketError.RecvFailed(Errno.description())
         }
         return buffer[0]
     }
@@ -179,11 +179,11 @@ public class Socket: Hashable, Equatable {
     public func peername() throws -> String {
         var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr))
         if getpeername(self.socketFileDescriptor, &addr, &len) != 0 {
-            throw SocketError.GetPeerNameFailed(Socket.descriptionOfLastError())
+            throw SocketError.GetPeerNameFailed(Errno.description())
         }
         var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
         if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
-            throw SocketError.GetNameInfoFailed(Socket.descriptionOfLastError())
+            throw SocketError.GetNameInfoFailed(Errno.description())
         }
         guard let name = String.fromCString(hostBuffer) else {
             throw SocketError.ConvertingPeerNameFailed
@@ -191,10 +191,6 @@ public class Socket: Hashable, Equatable {
         return name
     }
     
-    private class func descriptionOfLastError() -> String {
-        return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
-    }
-    
     private class func setNoSigPipe(socket: Int32) {
         #if os(Linux)
             // There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),

+ 12 - 0
XCode/Swifter.xcodeproj/project.pbxproj

@@ -14,6 +14,10 @@
 		7C4785EA1C71D15600A9FE73 /* SwifterTestsWebSocketSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4785E81C71D15600A9FE73 /* SwifterTestsWebSocketSession.swift */; };
 		7C71C5B11A1EC49B00682BF0 /* logo.png in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7CB102DF1A17381D00CBA3B4 /* logo.png */; };
 		7C73C6921C26179C00AEF6CA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CDAB80C1BE2A1D400C8A977 /* AppDelegate.swift */; };
+		7C76B29F1D369BEC00D35BFB /* Socket+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B29E1D369BEC00D35BFB /* Socket+File.swift */; };
+		7C76B2A01D369BEC00D35BFB /* Socket+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B29E1D369BEC00D35BFB /* Socket+File.swift */; };
+		7C76B2A21D369C9D00D35BFB /* Errno.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B2A11D369C9D00D35BFB /* Errno.swift */; };
+		7C76B2A31D369C9D00D35BFB /* Errno.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B2A11D369C9D00D35BFB /* Errno.swift */; };
 		7C76B70D1D2C456A0030FC98 /* DemoServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B6EA1D2C44F30030FC98 /* DemoServer.swift */; };
 		7C76B70E1D2C456B0030FC98 /* DemoServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B6EA1D2C44F30030FC98 /* DemoServer.swift */; };
 		7C76B70F1D2C456D0030FC98 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C76B6EB1D2C44F30030FC98 /* File.swift */; };
@@ -112,6 +116,8 @@
 		7AE893FF1C0512C400A29F63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		7AE8940C1C05151100A29F63 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
 		7C4785E81C71D15600A9FE73 /* SwifterTestsWebSocketSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwifterTestsWebSocketSession.swift; sourceTree = "<group>"; };
+		7C76B29E1D369BEC00D35BFB /* Socket+File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Socket+File.swift"; sourceTree = "<group>"; };
+		7C76B2A11D369C9D00D35BFB /* Errno.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errno.swift; sourceTree = "<group>"; };
 		7C76B6EA1D2C44F30030FC98 /* DemoServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoServer.swift; sourceTree = "<group>"; };
 		7C76B6EB1D2C44F30030FC98 /* File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
 		7C76B6EC1D2C44F30030FC98 /* Files.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Files.swift; sourceTree = "<group>"; };
@@ -226,10 +232,12 @@
 				7C76B6F31D2C44F30030FC98 /* Process.swift */,
 				7C76B6F41D2C44F30030FC98 /* Scopes.swift */,
 				7C76B6F51D2C44F30030FC98 /* Socket.swift */,
+				7C76B29E1D369BEC00D35BFB /* Socket+File.swift */,
 				7C76B6F61D2C44F30030FC98 /* String+BASE64.swift */,
 				7C76B6F71D2C44F30030FC98 /* String+Misc.swift */,
 				7C76B6F81D2C44F30030FC98 /* String+SHA1.swift */,
 				7C76B6F91D2C44F30030FC98 /* WebSockets.swift */,
+				7C76B2A11D369C9D00D35BFB /* Errno.swift */,
 			);
 			name = Sources;
 			path = ../Sources;
@@ -559,11 +567,13 @@
 				7C76B7151D2C45760030FC98 /* HttpRequest.swift in Sources */,
 				7C76B70D1D2C456A0030FC98 /* DemoServer.swift in Sources */,
 				7C76B70F1D2C456D0030FC98 /* File.swift in Sources */,
+				7C76B29F1D369BEC00D35BFB /* Socket+File.swift in Sources */,
 				7C76B7231D2C45890030FC98 /* Socket.swift in Sources */,
 				7C76B71D1D2C45820030FC98 /* HttpServerIO.swift in Sources */,
 				7C76B7111D2C45710030FC98 /* Files.swift in Sources */,
 				7C76B7191D2C457C0030FC98 /* HttpRouter.swift in Sources */,
 				7C76B7291D2C45920030FC98 /* String+SHA1.swift in Sources */,
+				7C76B2A21D369C9D00D35BFB /* Errno.swift in Sources */,
 				7C76B7251D2C458C0030FC98 /* String+BASE64.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -582,11 +592,13 @@
 				7C76B7161D2C45760030FC98 /* HttpRequest.swift in Sources */,
 				7C76B70E1D2C456B0030FC98 /* DemoServer.swift in Sources */,
 				7C76B7101D2C456D0030FC98 /* File.swift in Sources */,
+				7C76B2A01D369BEC00D35BFB /* Socket+File.swift in Sources */,
 				7C76B7241D2C458A0030FC98 /* Socket.swift in Sources */,
 				7C76B71E1D2C45820030FC98 /* HttpServerIO.swift in Sources */,
 				7C76B7121D2C45710030FC98 /* Files.swift in Sources */,
 				7C76B71A1D2C457C0030FC98 /* HttpRouter.swift in Sources */,
 				7C76B72A1D2C45920030FC98 /* String+SHA1.swift in Sources */,
+				7C76B2A31D369C9D00D35BFB /* Errno.swift in Sources */,
 				7C76B7261D2C458D0030FC98 /* String+BASE64.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;