diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2005-03-11 00:20:21 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2005-03-11 00:20:21 +0000 |
| commit | e57f9e9964ac16b1fd09028ea533457f3029d296 (patch) | |
| tree | c500d0de9381444ddfc96985b329e7a254cd1a59 | |
| parent | 63e3d7c5b0886a4243dd426b2a9f58d2173b26cf (diff) | |
| download | luasocket-e57f9e9964ac16b1fd09028ea533457f3029d296.tar.gz luasocket-e57f9e9964ac16b1fd09028ea533457f3029d296.tar.bz2 luasocket-e57f9e9964ac16b1fd09028ea533457f3029d296.zip | |
Apparently, non-blocking connect doesn't work on windows if you use 0
timeout in the select call...
| -rw-r--r-- | luasocket.vcproj | 4 | ||||
| -rw-r--r-- | mime.vcproj | 4 | ||||
| -rw-r--r-- | samples/forward.lua | 138 | ||||
| -rw-r--r-- | src/socket.h | 2 | ||||
| -rw-r--r-- | src/tcp.c | 6 | ||||
| -rw-r--r-- | src/usocket.c | 26 | ||||
| -rw-r--r-- | src/wsocket.c | 26 |
7 files changed, 106 insertions, 100 deletions
diff --git a/luasocket.vcproj b/luasocket.vcproj index 14cbebf..71486d6 100644 --- a/luasocket.vcproj +++ b/luasocket.vcproj | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | <Tool | 33 | <Tool |
| 34 | Name="VCLinkerTool" | 34 | Name="VCLinkerTool" |
| 35 | AdditionalDependencies="ws2_32.lib" | 35 | AdditionalDependencies="ws2_32.lib" |
| 36 | OutputFile="$(OutDir)/lsocket.dll" | 36 | OutputFile="$(OutDir)/csocket.dll" |
| 37 | LinkIncremental="2" | 37 | LinkIncremental="2" |
| 38 | GenerateDebugInformation="TRUE" | 38 | GenerateDebugInformation="TRUE" |
| 39 | ProgramDatabaseFile="$(OutDir)/luasocket.pdb" | 39 | ProgramDatabaseFile="$(OutDir)/luasocket.pdb" |
| @@ -81,7 +81,7 @@ | |||
| 81 | <Tool | 81 | <Tool |
| 82 | Name="VCLinkerTool" | 82 | Name="VCLinkerTool" |
| 83 | AdditionalDependencies="ws2_32.lib" | 83 | AdditionalDependencies="ws2_32.lib" |
| 84 | OutputFile="$(OutDir)/lsocket.dll" | 84 | OutputFile="$(OutDir)/csocket.dll" |
| 85 | LinkIncremental="1" | 85 | LinkIncremental="1" |
| 86 | GenerateDebugInformation="TRUE" | 86 | GenerateDebugInformation="TRUE" |
| 87 | SubSystem="2" | 87 | SubSystem="2" |
diff --git a/mime.vcproj b/mime.vcproj index 9e73f7b..43d289a 100644 --- a/mime.vcproj +++ b/mime.vcproj | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | Name="VCCustomBuildTool"/> | 32 | Name="VCCustomBuildTool"/> |
| 33 | <Tool | 33 | <Tool |
| 34 | Name="VCLinkerTool" | 34 | Name="VCLinkerTool" |
| 35 | OutputFile="$(OutDir)/lmime.dll" | 35 | OutputFile="$(OutDir)/cmime.dll" |
| 36 | LinkIncremental="2" | 36 | LinkIncremental="2" |
| 37 | GenerateDebugInformation="TRUE" | 37 | GenerateDebugInformation="TRUE" |
| 38 | ProgramDatabaseFile="$(OutDir)/mime.pdb" | 38 | ProgramDatabaseFile="$(OutDir)/mime.pdb" |
| @@ -79,7 +79,7 @@ | |||
| 79 | Name="VCCustomBuildTool"/> | 79 | Name="VCCustomBuildTool"/> |
| 80 | <Tool | 80 | <Tool |
| 81 | Name="VCLinkerTool" | 81 | Name="VCLinkerTool" |
| 82 | OutputFile="$(OutDir)/lmime.dll" | 82 | OutputFile="$(OutDir)/cmime.dll" |
| 83 | LinkIncremental="1" | 83 | LinkIncremental="1" |
| 84 | GenerateDebugInformation="TRUE" | 84 | GenerateDebugInformation="TRUE" |
| 85 | SubSystem="2" | 85 | SubSystem="2" |
diff --git a/samples/forward.lua b/samples/forward.lua index c3f0605..46f51c8 100644 --- a/samples/forward.lua +++ b/samples/forward.lua | |||
| @@ -35,6 +35,13 @@ local sending = newset() | |||
| 35 | -- context for connections and servers | 35 | -- context for connections and servers |
| 36 | local context = {} | 36 | local context = {} |
| 37 | 37 | ||
| 38 | function wait(who, what) | ||
| 39 | if what == "input" then receiving:insert(who) | ||
| 40 | else sending:insert(who) end | ||
| 41 | context[who].last = socket.gettime() | ||
| 42 | coroutine.yield() | ||
| 43 | end | ||
| 44 | |||
| 38 | -- initializes the forward server | 45 | -- initializes the forward server |
| 39 | function init() | 46 | function init() |
| 40 | if table.getn(arg) < 1 then | 47 | if table.getn(arg) < 1 then |
| @@ -63,145 +70,142 @@ function init() | |||
| 63 | end | 70 | end |
| 64 | 71 | ||
| 65 | -- starts a connection in a non-blocking way | 72 | -- starts a connection in a non-blocking way |
| 66 | function nbkcon(host, port) | 73 | function connect(who, host, port) |
| 67 | local peer, err = socket.tcp() | 74 | who:settimeout(0.1) |
| 68 | if not peer then return nil, err end | 75 | print("trying to connect peer", who, host, port) |
| 69 | peer:settimeout(0) | 76 | local ret, err = who:connect(host, port) |
| 70 | local ret, err = peer:connect(host, port) | 77 | if not ret and err == "timeout" then |
| 71 | if ret then return peer end | 78 | print("got timeout, will wait", who) |
| 72 | if err ~= "timeout" then | 79 | wait(who, "output") |
| 73 | peer:close() | 80 | ret, err = who:connected() |
| 74 | return nil, err | 81 | print("connection results arrived", who, ret, err) |
| 82 | end | ||
| 83 | if not ret then | ||
| 84 | print("connection failed", who) | ||
| 85 | kick(who) | ||
| 86 | kick(context[who].peer) | ||
| 87 | else | ||
| 88 | return forward(who) | ||
| 75 | end | 89 | end |
| 76 | return peer | ||
| 77 | end | 90 | end |
| 78 | 91 | ||
| 79 | -- gets rid of a client | 92 | -- gets rid of a client and its peer |
| 80 | function kick(who) | 93 | function kick(who) |
| 81 | if context[who] then | 94 | if who and context[who] then |
| 82 | sending:remove(who) | 95 | sending:remove(who) |
| 83 | receiving:remove(who) | 96 | receiving:remove(who) |
| 97 | local peer = context[who].peer | ||
| 84 | context[who] = nil | 98 | context[who] = nil |
| 85 | who:close() | 99 | who:close() |
| 86 | end | 100 | end |
| 87 | end | 101 | end |
| 88 | 102 | ||
| 89 | -- decides what to do with a thread based on coroutine return | ||
| 90 | function route(who, status, what) | ||
| 91 | if status and what then | ||
| 92 | if what == "receiving" then receiving:insert(who) end | ||
| 93 | if what == "sending" then sending:insert(who) end | ||
| 94 | else kick(who) end | ||
| 95 | end | ||
| 96 | |||
| 97 | -- loops accepting connections and creating new threads to deal with them | 103 | -- loops accepting connections and creating new threads to deal with them |
| 98 | function accept(server) | 104 | function accept(server) |
| 99 | while true do | 105 | while true do |
| 100 | -- accept a new connection and start a new coroutine to deal with it | 106 | -- accept a new connection and start a new coroutine to deal with it |
| 101 | local client = server:accept() | 107 | local client = server:accept() |
| 108 | print("accepted ", client) | ||
| 102 | if client then | 109 | if client then |
| 103 | -- start a new connection, non-blockingly, to the forwarding address | 110 | -- create contexts for client and peer. |
| 104 | local ohost = context[server].ohost | 111 | local peer, err = socket.tcp() |
| 105 | local oport = context[server].oport | ||
| 106 | local peer = nbkcon(ohost, oport) | ||
| 107 | if peer then | 112 | if peer then |
| 108 | context[client] = { | 113 | context[client] = { |
| 109 | last = socket.gettime(), | 114 | last = socket.gettime(), |
| 115 | -- client goes straight to forwarding loop | ||
| 110 | thread = coroutine.create(forward), | 116 | thread = coroutine.create(forward), |
| 111 | peer = peer, | 117 | peer = peer, |
| 112 | } | 118 | } |
| 113 | -- make sure peer will be tested for writing in the next select | ||
| 114 | -- round, which means the connection attempt has finished | ||
| 115 | sending:insert(peer) | ||
| 116 | context[peer] = { | 119 | context[peer] = { |
| 120 | last = socket.gettime(), | ||
| 117 | peer = client, | 121 | peer = client, |
| 118 | thread = coroutine.create(chkcon), | 122 | -- peer first tries to connect to forwarding address |
| 123 | thread = coroutine.create(connect), | ||
| 119 | last = socket.gettime() | 124 | last = socket.gettime() |
| 120 | } | 125 | } |
| 121 | -- put both in non-blocking mode | 126 | -- resume peer and client so they can do their thing |
| 122 | client:settimeout(0) | 127 | local ohost = context[server].ohost |
| 123 | peer:settimeout(0) | 128 | local oport = context[server].oport |
| 129 | coroutine.resume(context[peer].thread, peer, ohost, oport) | ||
| 130 | coroutine.resume(context[client].thread, client) | ||
| 124 | else | 131 | else |
| 125 | -- otherwise just dump the client | 132 | print(err) |
| 126 | client:close() | 133 | client:close() |
| 127 | end | 134 | end |
| 128 | end | 135 | end |
| 129 | -- tell scheduler we are done for now | 136 | -- tell scheduler we are done for now |
| 130 | coroutine.yield("receiving") | 137 | wait(server, "input") |
| 131 | end | 138 | end |
| 132 | end | 139 | end |
| 133 | 140 | ||
| 134 | -- forwards all data arriving to the appropriate peer | 141 | -- forwards all data arriving to the appropriate peer |
| 135 | function forward(who) | 142 | function forward(who) |
| 143 | print("starting to foward", who) | ||
| 144 | who:settimeout(0) | ||
| 136 | while true do | 145 | while true do |
| 146 | -- wait until we have something to read | ||
| 147 | wait(who, "input") | ||
| 137 | -- try to read as much as possible | 148 | -- try to read as much as possible |
| 138 | local data, rec_err, partial = who:receive("*a") | 149 | local data, rec_err, partial = who:receive("*a") |
| 139 | -- if we had an error other than timeout, abort | 150 | -- if we had an error other than timeout, abort |
| 140 | if rec_err and rec_err ~= "timeout" then return error(rec_err) end | 151 | if rec_err and rec_err ~= "timeout" then return kick(who) end |
| 141 | -- if we got a timeout, we probably have partial results to send | 152 | -- if we got a timeout, we probably have partial results to send |
| 142 | data = data or partial | 153 | data = data or partial |
| 143 | -- renew our timestamp so scheduler sees we are active | ||
| 144 | context[who].last = socket.gettime() | ||
| 145 | -- forward what we got right away | 154 | -- forward what we got right away |
| 146 | local peer = context[who].peer | 155 | local peer = context[who].peer |
| 147 | while true do | 156 | while true do |
| 148 | -- tell scheduler we need to wait until we can send something | 157 | -- tell scheduler we need to wait until we can send something |
| 149 | coroutine.yield("sending") | 158 | wait(who, "output") |
| 150 | local ret, snd_err | 159 | local ret, snd_err |
| 151 | local start = 0 | 160 | local start = 0 |
| 152 | ret, snd_err, start = peer:send(data, start+1) | 161 | ret, snd_err, start = peer:send(data, start+1) |
| 153 | if ret then break | 162 | if ret then break |
| 154 | elseif snd_err ~= "timeout" then return error(snd_err) end | 163 | elseif snd_err ~= "timeout" then return kick(who) end |
| 155 | -- renew our timestamp so scheduler sees we are active | ||
| 156 | context[who].last = socket.gettime() | ||
| 157 | end | 164 | end |
| 158 | -- if we are done receiving, we are done with this side of the | 165 | -- if we are done receiving, we are done |
| 159 | -- connection | 166 | if not rec_err then return kick(who) end |
| 160 | if not rec_err then return nil end | ||
| 161 | -- otherwise tell schedule we have to wait for more data to arrive | ||
| 162 | coroutine.yield("receiving") | ||
| 163 | end | 167 | end |
| 164 | end | 168 | end |
| 165 | 169 | ||
| 166 | -- checks if a connection completed successfully and if it did, starts | ||
| 167 | -- forwarding all data | ||
| 168 | function chkcon(who) | ||
| 169 | local ret, err = who:connected() | ||
| 170 | if ret then | ||
| 171 | receiving:insert(context[who].peer) | ||
| 172 | context[who].last = socket.gettime() | ||
| 173 | coroutine.yield("receiving") | ||
| 174 | return forward(who) | ||
| 175 | else return error(err) end | ||
| 176 | end | ||
| 177 | |||
| 178 | -- loop waiting until something happens, restarting the thread to deal with | 170 | -- loop waiting until something happens, restarting the thread to deal with |
| 179 | -- what happened, and routing it to wait until something else happens | 171 | -- what happened, and routing it to wait until something else happens |
| 180 | function go() | 172 | function go() |
| 181 | while true do | 173 | while true do |
| 174 | print("will select for reading") | ||
| 175 | for i,v in ipairs(receiving) do | ||
| 176 | print(i, v) | ||
| 177 | end | ||
| 178 | print("will select for sending") | ||
| 179 | for i,v in ipairs(sending) do | ||
| 180 | print(i, v) | ||
| 181 | end | ||
| 182 | -- check which sockets are interesting and act on them | 182 | -- check which sockets are interesting and act on them |
| 183 | readable, writable = socket.select(receiving, sending, 3) | 183 | readable, writable = socket.select(receiving, sending, 3) |
| 184 | -- for all readable connections, resume its thread and route it | 184 | print("was readable") |
| 185 | for i,v in ipairs(readable) do | ||
| 186 | print(i, v) | ||
| 187 | end | ||
| 188 | print("was writable") | ||
| 189 | for i,v in ipairs(writable) do | ||
| 190 | print(i, v) | ||
| 191 | end | ||
| 192 | -- for all readable connections, resume its thread | ||
| 185 | for _, who in ipairs(readable) do | 193 | for _, who in ipairs(readable) do |
| 186 | receiving:remove(who) | 194 | receiving:remove(who) |
| 187 | if context[who] then | 195 | coroutine.resume(context[who].thread, who) |
| 188 | route(who, coroutine.resume(context[who].thread, who)) | ||
| 189 | end | ||
| 190 | end | 196 | end |
| 191 | -- for all writable connections, do the same | 197 | -- for all writable connections, do the same |
| 192 | for _, who in ipairs(writable) do | 198 | for _, who in ipairs(writable) do |
| 193 | sending:remove(who) | 199 | sending:remove(who) |
| 194 | if context[who] then | 200 | coroutine.resume(context[who].thread, who) |
| 195 | route(who, coroutine.resume(context[who].thread, who)) | ||
| 196 | end | ||
| 197 | end | 201 | end |
| 198 | -- put all inactive threads in death row | 202 | -- put all inactive threads in death row |
| 199 | local now = socket.gettime() | 203 | local now = socket.gettime() |
| 200 | local deathrow | 204 | local deathrow |
| 201 | for who, data in pairs(context) do | 205 | for who, data in pairs(context) do |
| 202 | if data.last then | 206 | if data.peer then |
| 203 | if now - data.last > TIMEOUT then | 207 | if now - data.last > TIMEOUT then |
| 204 | -- only create table if someone is doomed | 208 | -- only create table if at least one is doomed |
| 205 | deathrow = deathrow or {} | 209 | deathrow = deathrow or {} |
| 206 | deathrow[who] = true | 210 | deathrow[who] = true |
| 207 | end | 211 | end |
diff --git a/src/socket.h b/src/socket.h index 639229d..4443bcc 100644 --- a/src/socket.h +++ b/src/socket.h | |||
| @@ -49,7 +49,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, | |||
| 49 | void sock_setnonblocking(p_sock ps); | 49 | void sock_setnonblocking(p_sock ps); |
| 50 | void sock_setblocking(p_sock ps); | 50 | void sock_setblocking(p_sock ps); |
| 51 | 51 | ||
| 52 | int sock_waitfd(int fd, int sw, p_tm tm); | 52 | int sock_waitfd(p_sock ps, int sw, p_tm tm); |
| 53 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm); | 53 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm); |
| 54 | 54 | ||
| 55 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); | 55 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); |
| @@ -228,8 +228,10 @@ static int meth_connect(lua_State *L) | |||
| 228 | 228 | ||
| 229 | static int meth_connected(lua_State *L) | 229 | static int meth_connected(lua_State *L) |
| 230 | { | 230 | { |
| 231 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | 231 | p_tcp tcp; |
| 232 | int err = sock_connected(&tcp->sock, &tcp->tm); | 232 | int err; |
| 233 | tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | ||
| 234 | err = sock_connected(&tcp->sock, &tcp->tm); | ||
| 233 | if (err != IO_DONE) { | 235 | if (err != IO_DONE) { |
| 234 | lua_pushnil(L); | 236 | lua_pushnil(L); |
| 235 | lua_pushstring(L, sock_strerror(err)); | 237 | lua_pushstring(L, sock_strerror(err)); |
diff --git a/src/usocket.c b/src/usocket.c index 3428a0c..3e151bf 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
| @@ -22,10 +22,10 @@ | |||
| 22 | #define WAITFD_R POLLIN | 22 | #define WAITFD_R POLLIN |
| 23 | #define WAITFD_W POLLOUT | 23 | #define WAITFD_W POLLOUT |
| 24 | #define WAITFD_C (POLLIN|POLLOUT) | 24 | #define WAITFD_C (POLLIN|POLLOUT) |
| 25 | int sock_waitfd(int fd, int sw, p_tm tm) { | 25 | int sock_waitfd(p_sock ps, int sw, p_tm tm) { |
| 26 | int ret; | 26 | int ret; |
| 27 | struct pollfd pfd; | 27 | struct pollfd pfd; |
| 28 | pfd.fd = fd; | 28 | pfd.fd = *ps; |
| 29 | pfd.events = sw; | 29 | pfd.events = sw; |
| 30 | pfd.revents = 0; | 30 | pfd.revents = 0; |
| 31 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | 31 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ |
| @@ -44,7 +44,7 @@ int sock_waitfd(int fd, int sw, p_tm tm) { | |||
| 44 | #define WAITFD_W 2 | 44 | #define WAITFD_W 2 |
| 45 | #define WAITFD_C (WAITFD_R|WAITFD_W) | 45 | #define WAITFD_C (WAITFD_R|WAITFD_W) |
| 46 | 46 | ||
| 47 | int sock_waitfd(int fd, int sw, p_tm tm) { | 47 | int sock_waitfd(p_sock ps, int sw, p_tm tm) { |
| 48 | int ret; | 48 | int ret; |
| 49 | fd_set rfds, wfds, *rp, *wp; | 49 | fd_set rfds, wfds, *rp, *wp; |
| 50 | struct timeval tv, *tp; | 50 | struct timeval tv, *tp; |
| @@ -53,8 +53,8 @@ int sock_waitfd(int fd, int sw, p_tm tm) { | |||
| 53 | do { | 53 | do { |
| 54 | /* must set bits within loop, because select may have modifed them */ | 54 | /* must set bits within loop, because select may have modifed them */ |
| 55 | rp = wp = NULL; | 55 | rp = wp = NULL; |
| 56 | if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rp = &rfds; } | 56 | if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; } |
| 57 | if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(fd, &wfds); wp = &wfds; } | 57 | if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } |
| 58 | t = tm_getretry(tm); | 58 | t = tm_getretry(tm); |
| 59 | tp = NULL; | 59 | tp = NULL; |
| 60 | if (t >= 0.0) { | 60 | if (t >= 0.0) { |
| @@ -62,11 +62,11 @@ int sock_waitfd(int fd, int sw, p_tm tm) { | |||
| 62 | tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); | 62 | tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); |
| 63 | tp = &tv; | 63 | tp = &tv; |
| 64 | } | 64 | } |
| 65 | ret = select(fd+1, rp, wp, NULL, tp); | 65 | ret = select(*ps+1, rp, wp, NULL, tp); |
| 66 | } while (ret == -1 && errno == EINTR); | 66 | } while (ret == -1 && errno == EINTR); |
| 67 | if (ret == -1) return errno; | 67 | if (ret == -1) return errno; |
| 68 | if (ret == 0) return IO_TIMEOUT; | 68 | if (ret == 0) return IO_TIMEOUT; |
| 69 | if (sw == WAITFD_C && FD_ISSET(fd, &rfds)) return IO_CLOSED; | 69 | if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED; |
| 70 | return IO_DONE; | 70 | return IO_DONE; |
| 71 | } | 71 | } |
| 72 | #endif | 72 | #endif |
| @@ -177,7 +177,7 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { | |||
| 177 | \*-------------------------------------------------------------------------*/ | 177 | \*-------------------------------------------------------------------------*/ |
| 178 | int sock_connected(p_sock ps, p_tm tm) { | 178 | int sock_connected(p_sock ps, p_tm tm) { |
| 179 | int err; | 179 | int err; |
| 180 | if ((err = sock_waitfd(*ps, WAITFD_C, tm) == IO_CLOSED)) { | 180 | if ((err = sock_waitfd(ps, WAITFD_C, tm) == IO_CLOSED)) { |
| 181 | if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; | 181 | if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; |
| 182 | else return errno; | 182 | else return errno; |
| 183 | } else return err; | 183 | } else return err; |
| @@ -198,7 +198,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) { | |||
| 198 | err = errno; | 198 | err = errno; |
| 199 | if (err == EINTR) continue; | 199 | if (err == EINTR) continue; |
| 200 | if (err != EAGAIN && err != ECONNABORTED) return err; | 200 | if (err != EAGAIN && err != ECONNABORTED) return err; |
| 201 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; | 201 | if ((err = sock_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 202 | } | 202 | } |
| 203 | /* can't reach here */ | 203 | /* can't reach here */ |
| 204 | return IO_UNKNOWN; | 204 | return IO_UNKNOWN; |
| @@ -230,7 +230,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) | |||
| 230 | /* if failed fatal reason, report error */ | 230 | /* if failed fatal reason, report error */ |
| 231 | if (err != EAGAIN) return err; | 231 | if (err != EAGAIN) return err; |
| 232 | /* wait until we can send something or we timeout */ | 232 | /* wait until we can send something or we timeout */ |
| 233 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; | 233 | if ((err = sock_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; |
| 234 | } | 234 | } |
| 235 | /* can't reach here */ | 235 | /* can't reach here */ |
| 236 | return IO_UNKNOWN; | 236 | return IO_UNKNOWN; |
| @@ -255,7 +255,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 255 | if (put == 0 || err == EPIPE) return IO_CLOSED; | 255 | if (put == 0 || err == EPIPE) return IO_CLOSED; |
| 256 | if (err == EINTR) continue; | 256 | if (err == EINTR) continue; |
| 257 | if (err != EAGAIN) return err; | 257 | if (err != EAGAIN) return err; |
| 258 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; | 258 | if ((err = sock_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; |
| 259 | } | 259 | } |
| 260 | return IO_UNKNOWN; | 260 | return IO_UNKNOWN; |
| 261 | } | 261 | } |
| @@ -277,7 +277,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { | |||
| 277 | if (taken == 0) return IO_CLOSED; | 277 | if (taken == 0) return IO_CLOSED; |
| 278 | if (err == EINTR) continue; | 278 | if (err == EINTR) continue; |
| 279 | if (err != EAGAIN) return err; | 279 | if (err != EAGAIN) return err; |
| 280 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; | 280 | if ((err = sock_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 281 | } | 281 | } |
| 282 | return IO_UNKNOWN; | 282 | return IO_UNKNOWN; |
| 283 | } | 283 | } |
| @@ -300,7 +300,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
| 300 | if (taken == 0) return IO_CLOSED; | 300 | if (taken == 0) return IO_CLOSED; |
| 301 | if (err == EINTR) continue; | 301 | if (err == EINTR) continue; |
| 302 | if (err != EAGAIN) return err; | 302 | if (err != EAGAIN) return err; |
| 303 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; | 303 | if ((err = sock_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 304 | } | 304 | } |
| 305 | return IO_UNKNOWN; | 305 | return IO_UNKNOWN; |
| 306 | } | 306 | } |
diff --git a/src/wsocket.c b/src/wsocket.c index c0686cd..8b00fa5 100644 --- a/src/wsocket.c +++ b/src/wsocket.c | |||
| @@ -45,15 +45,15 @@ int sock_close(void) { | |||
| 45 | #define WAITFD_E 4 | 45 | #define WAITFD_E 4 |
| 46 | #define WAITFD_C (WAITFD_E|WAITFD_W) | 46 | #define WAITFD_C (WAITFD_E|WAITFD_W) |
| 47 | 47 | ||
| 48 | int sock_waitfd(t_sock fd, int sw, p_tm tm) { | 48 | int sock_waitfd(p_sock ps, int sw, p_tm tm) { |
| 49 | int ret; | 49 | int ret; |
| 50 | fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; | 50 | fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; |
| 51 | struct timeval tv, *tp = NULL; | 51 | struct timeval tv, *tp = NULL; |
| 52 | double t; | 52 | double t; |
| 53 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ | 53 | if (tm_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ |
| 54 | if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rp = &rfds; } | 54 | if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; } |
| 55 | if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(fd, &wfds); wp = &wfds; } | 55 | if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } |
| 56 | if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(fd, &efds); ep = &efds; } | 56 | if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; } |
| 57 | if ((t = tm_get(tm)) >= 0.0) { | 57 | if ((t = tm_get(tm)) >= 0.0) { |
| 58 | tv.tv_sec = (int) t; | 58 | tv.tv_sec = (int) t; |
| 59 | tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); | 59 | tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); |
| @@ -62,7 +62,7 @@ int sock_waitfd(t_sock fd, int sw, p_tm tm) { | |||
| 62 | ret = select(0, rp, wp, ep, tp); | 62 | ret = select(0, rp, wp, ep, tp); |
| 63 | if (ret == -1) return WSAGetLastError(); | 63 | if (ret == -1) return WSAGetLastError(); |
| 64 | if (ret == 0) return IO_TIMEOUT; | 64 | if (ret == 0) return IO_TIMEOUT; |
| 65 | if (sw == WAITFD_C && FD_ISSET(fd, &efds)) return IO_CLOSED; | 65 | if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; |
| 66 | return IO_DONE; | 66 | return IO_DONE; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| @@ -127,15 +127,15 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { | |||
| 127 | /*-------------------------------------------------------------------------*\ | 127 | /*-------------------------------------------------------------------------*\ |
| 128 | * Check if socket is connected | 128 | * Check if socket is connected |
| 129 | \*-------------------------------------------------------------------------*/ | 129 | \*-------------------------------------------------------------------------*/ |
| 130 | int sock_connected(p_sock ps) { | 130 | int sock_connected(p_sock ps, p_tm tm) { |
| 131 | int err; | 131 | int err; |
| 132 | if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) { | 132 | if ((err = sock_waitfd(ps, WAITFD_C, tm)) == IO_CLOSED) { |
| 133 | int len = sizeof(err); | 133 | int len = sizeof(err); |
| 134 | /* give windows time to set the error (yes, disgusting) */ | 134 | /* give windows time to set the error (yes, disgusting) */ |
| 135 | Sleep(0); | 135 | Sleep(0); |
| 136 | /* find out why we failed */ | 136 | /* find out why we failed */ |
| 137 | getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); | 137 | getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); |
| 138 | /* we KNOW there was an error. if why is 0, we will return | 138 | /* we KNOW there was an error. if 'why' is 0, we will return |
| 139 | * "unknown error", but it's not really our fault */ | 139 | * "unknown error", but it's not really our fault */ |
| 140 | return err > 0? err: IO_UNKNOWN; | 140 | return err > 0? err: IO_UNKNOWN; |
| 141 | } else return err; | 141 | } else return err; |
| @@ -181,7 +181,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *len, p_tm tm) { | |||
| 181 | /* if we failed because there was no connectoin, keep trying */ | 181 | /* if we failed because there was no connectoin, keep trying */ |
| 182 | if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; | 182 | if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; |
| 183 | /* call select to avoid busy wait */ | 183 | /* call select to avoid busy wait */ |
| 184 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; | 184 | if ((err = sock_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 185 | } | 185 | } |
| 186 | /* can't reach here */ | 186 | /* can't reach here */ |
| 187 | return IO_UNKNOWN; | 187 | return IO_UNKNOWN; |
| @@ -213,7 +213,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm) | |||
| 213 | /* we can only proceed if there was no serious error */ | 213 | /* we can only proceed if there was no serious error */ |
| 214 | if (err != WSAEWOULDBLOCK) return err; | 214 | if (err != WSAEWOULDBLOCK) return err; |
| 215 | /* avoid busy wait */ | 215 | /* avoid busy wait */ |
| 216 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; | 216 | if ((err = sock_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; |
| 217 | } | 217 | } |
| 218 | /* can't reach here */ | 218 | /* can't reach here */ |
| 219 | return IO_UNKNOWN; | 219 | return IO_UNKNOWN; |
| @@ -236,7 +236,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 236 | } | 236 | } |
| 237 | err = WSAGetLastError(); | 237 | err = WSAGetLastError(); |
| 238 | if (err != WSAEWOULDBLOCK) return err; | 238 | if (err != WSAEWOULDBLOCK) return err; |
| 239 | if ((err = sock_waitfd(*ps, WAITFD_W, tm)) != IO_DONE) return err; | 239 | if ((err = sock_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; |
| 240 | } | 240 | } |
| 241 | return IO_UNKNOWN; | 241 | return IO_UNKNOWN; |
| 242 | } | 242 | } |
| @@ -257,7 +257,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) { | |||
| 257 | if (taken == 0) return IO_CLOSED; | 257 | if (taken == 0) return IO_CLOSED; |
| 258 | err = WSAGetLastError(); | 258 | err = WSAGetLastError(); |
| 259 | if (err != WSAEWOULDBLOCK) return err; | 259 | if (err != WSAEWOULDBLOCK) return err; |
| 260 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; | 260 | if ((err = sock_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 261 | } | 261 | } |
| 262 | return IO_UNKNOWN; | 262 | return IO_UNKNOWN; |
| 263 | } | 263 | } |
| @@ -279,7 +279,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
| 279 | if (taken == 0) return IO_CLOSED; | 279 | if (taken == 0) return IO_CLOSED; |
| 280 | err = WSAGetLastError(); | 280 | err = WSAGetLastError(); |
| 281 | if (err != WSAEWOULDBLOCK) return err; | 281 | if (err != WSAEWOULDBLOCK) return err; |
| 282 | if ((err = sock_waitfd(*ps, WAITFD_R, tm)) != IO_DONE) return err; | 282 | if ((err = sock_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 283 | } | 283 | } |
| 284 | return IO_UNKNOWN; | 284 | return IO_UNKNOWN; |
| 285 | } | 285 | } |
