[527b508] | 1 | /* |
---|
| 2 | * sock.c -- Posix Socket upper layer support module for general posix use |
---|
| 3 | * |
---|
| 4 | * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. |
---|
[ee3afa2] | 5 | * |
---|
| 6 | * $Id$ |
---|
[527b508] | 7 | */ |
---|
| 8 | |
---|
| 9 | /******************************** Description *********************************/ |
---|
| 10 | |
---|
| 11 | /* |
---|
| 12 | * Posix Socket Module. This supports blocking and non-blocking buffered |
---|
| 13 | * socket I/O. |
---|
| 14 | */ |
---|
| 15 | |
---|
| 16 | /********************************** Includes **********************************/ |
---|
| 17 | |
---|
| 18 | #include <string.h> |
---|
| 19 | #include <stdlib.h> |
---|
| 20 | |
---|
[ee3afa2] | 21 | #ifdef UEMF |
---|
[527b508] | 22 | #include "uemf.h" |
---|
| 23 | #else |
---|
| 24 | #include <socket.h> |
---|
| 25 | #include <types.h> |
---|
| 26 | #include <unistd.h> |
---|
| 27 | #include "emfInternal.h" |
---|
| 28 | #endif |
---|
| 29 | |
---|
| 30 | /************************************ Locals **********************************/ |
---|
| 31 | |
---|
| 32 | socket_t **socketList; /* List of open sockets */ |
---|
| 33 | int socketMax; /* Maximum size of socket */ |
---|
| 34 | int socketHighestFd = -1; /* Highest socket fd opened */ |
---|
| 35 | |
---|
| 36 | /***************************** Forward Declarations ***************************/ |
---|
| 37 | |
---|
| 38 | static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode); |
---|
| 39 | static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i, |
---|
| 40 | struct sockaddr *server); |
---|
| 41 | |
---|
| 42 | /*********************************** Code *************************************/ |
---|
| 43 | /* |
---|
| 44 | * Write to a socket. Absorb as much data as the socket can buffer. Block if |
---|
| 45 | * the socket is in blocking mode. Returns -1 on error, otherwise the number |
---|
| 46 | * of bytes written. |
---|
| 47 | */ |
---|
| 48 | |
---|
| 49 | int socketWrite(int sid, char *buf, int bufsize) |
---|
| 50 | { |
---|
| 51 | socket_t *sp; |
---|
| 52 | ringq_t *rq; |
---|
| 53 | int len, bytesWritten, room; |
---|
| 54 | |
---|
| 55 | a_assert(buf); |
---|
| 56 | a_assert(bufsize >= 0); |
---|
| 57 | |
---|
| 58 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 59 | return -1; |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | /* |
---|
| 63 | * Loop adding as much data to the output ringq as we can absorb. Initiate a |
---|
| 64 | * flush when the ringq is too full and continue. Block in socketFlush if the |
---|
| 65 | * socket is in blocking mode. |
---|
| 66 | */ |
---|
| 67 | rq = &sp->outBuf; |
---|
| 68 | for (bytesWritten = 0; bufsize > 0; ) { |
---|
| 69 | if ((room = ringqPutBlkMax(rq)) == 0) { |
---|
| 70 | if (socketFlush(sid) < 0) { |
---|
| 71 | return -1; |
---|
| 72 | } |
---|
| 73 | if ((room = ringqPutBlkMax(rq)) == 0) { |
---|
| 74 | if (sp->flags & SOCKET_BLOCK) { |
---|
[ee3afa2] | 75 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 76 | int errCode; |
---|
| 77 | if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE, |
---|
| 78 | &errCode)) { |
---|
| 79 | return -1; |
---|
| 80 | } |
---|
| 81 | #endif |
---|
| 82 | continue; |
---|
| 83 | } |
---|
| 84 | break; |
---|
| 85 | } |
---|
| 86 | continue; |
---|
| 87 | } |
---|
| 88 | len = min(room, bufsize); |
---|
| 89 | ringqPutBlk(rq, (unsigned char *) buf, len); |
---|
| 90 | bytesWritten += len; |
---|
| 91 | bufsize -= len; |
---|
| 92 | buf += len; |
---|
| 93 | } |
---|
| 94 | return bytesWritten; |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | /******************************************************************************/ |
---|
| 98 | /* |
---|
| 99 | * Write a string to a socket |
---|
| 100 | */ |
---|
| 101 | |
---|
| 102 | int socketWriteString(int sid, char_t *buf) |
---|
| 103 | { |
---|
[ee3afa2] | 104 | #ifdef UNICODE |
---|
[527b508] | 105 | char *byteBuf; |
---|
| 106 | int r, len; |
---|
| 107 | |
---|
| 108 | len = gstrlen(buf); |
---|
| 109 | byteBuf = ballocUniToAsc(buf, len); |
---|
| 110 | r = socketWrite(sid, byteBuf, len); |
---|
| 111 | bfreeSafe(B_L, byteBuf); |
---|
| 112 | return r; |
---|
| 113 | #else |
---|
| 114 | return socketWrite(sid, buf, strlen(buf)); |
---|
| 115 | #endif /* UNICODE */ |
---|
| 116 | } |
---|
| 117 | |
---|
| 118 | /******************************************************************************/ |
---|
| 119 | /* |
---|
| 120 | * Read from a socket. Return the number of bytes read if successful. This |
---|
| 121 | * may be less than the requested "bufsize" and may be zero. Return -1 for |
---|
| 122 | * errors. Return 0 for EOF. Otherwise return the number of bytes read. |
---|
| 123 | * If this routine returns zero it indicates an EOF condition. |
---|
| 124 | * which can be verified with socketEof() |
---|
| 125 | |
---|
| 126 | * Note: this ignores the line buffer, so a previous socketGets |
---|
| 127 | * which read a partial line may cause a subsequent socketRead to miss some |
---|
| 128 | * data. This routine may block if the socket is in blocking mode. |
---|
| 129 | * |
---|
| 130 | */ |
---|
| 131 | |
---|
| 132 | int socketRead(int sid, char *buf, int bufsize) |
---|
| 133 | { |
---|
| 134 | socket_t *sp; |
---|
| 135 | ringq_t *rq; |
---|
| 136 | int len, room, errCode, bytesRead; |
---|
| 137 | |
---|
| 138 | a_assert(buf); |
---|
| 139 | a_assert(bufsize > 0); |
---|
| 140 | |
---|
| 141 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 142 | return -1; |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | if (sp->flags & SOCKET_EOF) { |
---|
| 146 | return 0; |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | rq = &sp->inBuf; |
---|
| 150 | for (bytesRead = 0; bufsize > 0; ) { |
---|
| 151 | len = min(ringqLen(rq), bufsize); |
---|
| 152 | if (len <= 0) { |
---|
| 153 | /* |
---|
| 154 | * if blocking mode and already have data, exit now or it may block |
---|
| 155 | * forever. |
---|
| 156 | */ |
---|
| 157 | if ((sp->flags & SOCKET_BLOCK) && |
---|
| 158 | (bytesRead > 0)) { |
---|
| 159 | break; |
---|
| 160 | } |
---|
| 161 | /* |
---|
| 162 | * This flush is critical for readers of datagram packets. If the |
---|
| 163 | * buffer is not big enough to read the whole datagram in one hit, |
---|
| 164 | * the recvfrom call will fail. |
---|
| 165 | */ |
---|
| 166 | ringqFlush(rq); |
---|
| 167 | room = ringqPutBlkMax(rq); |
---|
| 168 | len = socketGetInput(sid, (char *) rq->endp, room, &errCode); |
---|
| 169 | if (len < 0) { |
---|
| 170 | if (errCode == EWOULDBLOCK) { |
---|
| 171 | if ((sp->flags & SOCKET_BLOCK) && |
---|
| 172 | (bytesRead == 0)) { |
---|
| 173 | continue; |
---|
| 174 | } |
---|
| 175 | if (bytesRead >= 0) { |
---|
| 176 | return bytesRead; |
---|
| 177 | } |
---|
| 178 | } |
---|
| 179 | return -1; |
---|
| 180 | |
---|
| 181 | } else if (len == 0) { |
---|
| 182 | /* |
---|
| 183 | * If bytesRead is 0, this is EOF since socketRead should never |
---|
| 184 | * be called unless there is data yet to be read. Set the flag. |
---|
| 185 | * Then pass back the number of bytes read. |
---|
| 186 | */ |
---|
| 187 | if (bytesRead == 0) { |
---|
| 188 | sp->flags |= SOCKET_EOF; |
---|
| 189 | } |
---|
| 190 | return bytesRead; |
---|
| 191 | } |
---|
| 192 | ringqPutBlkAdj(rq, len); |
---|
| 193 | len = min(len, bufsize); |
---|
| 194 | } |
---|
| 195 | memcpy(&buf[bytesRead], rq->servp, len); |
---|
| 196 | ringqGetBlkAdj(rq, len); |
---|
| 197 | bufsize -= len; |
---|
| 198 | bytesRead += len; |
---|
| 199 | } |
---|
| 200 | return bytesRead; |
---|
| 201 | } |
---|
| 202 | |
---|
| 203 | /******************************************************************************/ |
---|
| 204 | /* |
---|
| 205 | * Get a string from a socket. This returns data in *buf in a malloced string |
---|
| 206 | * after trimming the '\n'. If there is zero bytes returned, *buf will be set |
---|
| 207 | * to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when |
---|
| 208 | * no complete line yet read. If doing blocking I/O, it will block until an |
---|
| 209 | * entire line is read. If a partial line is read socketInputBuffered or |
---|
| 210 | * socketEof can be used to distinguish between EOF and partial line still |
---|
| 211 | * buffered. This routine eats and ignores carriage returns. |
---|
| 212 | */ |
---|
| 213 | |
---|
| 214 | int socketGets(int sid, char_t **buf) |
---|
| 215 | { |
---|
| 216 | socket_t *sp; |
---|
| 217 | ringq_t *lq; |
---|
| 218 | char c; |
---|
| 219 | int rc, len; |
---|
| 220 | |
---|
| 221 | a_assert(buf); |
---|
| 222 | *buf = NULL; |
---|
| 223 | |
---|
| 224 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 225 | return -1; |
---|
| 226 | } |
---|
| 227 | lq = &sp->lineBuf; |
---|
| 228 | |
---|
| 229 | while (1) { |
---|
| 230 | |
---|
| 231 | if ((rc = socketRead(sid, &c, 1)) < 0) { |
---|
| 232 | return rc; |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | if (rc == 0) { |
---|
| 236 | /* |
---|
| 237 | * If there is a partial line and we are at EOF, pretend we saw a '\n' |
---|
| 238 | */ |
---|
| 239 | if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) { |
---|
| 240 | c = '\n'; |
---|
| 241 | } else { |
---|
| 242 | return -1; |
---|
| 243 | } |
---|
| 244 | } |
---|
| 245 | /* |
---|
| 246 | * If a newline is seen, return the data excluding the new line to the |
---|
| 247 | * caller. If carriage return is seen, just eat it. |
---|
| 248 | */ |
---|
| 249 | if (c == '\n') { |
---|
| 250 | len = ringqLen(lq); |
---|
| 251 | if (len > 0) { |
---|
[ee3afa2] | 252 | *buf = ballocAscToUni((char *)lq->servp, len); |
---|
[527b508] | 253 | } else { |
---|
| 254 | *buf = NULL; |
---|
| 255 | } |
---|
| 256 | ringqFlush(lq); |
---|
| 257 | return len; |
---|
| 258 | |
---|
| 259 | } else if (c == '\r') { |
---|
| 260 | continue; |
---|
| 261 | } |
---|
| 262 | ringqPutcA(lq, c); |
---|
| 263 | } |
---|
| 264 | return 0; |
---|
| 265 | } |
---|
| 266 | |
---|
| 267 | /******************************************************************************/ |
---|
| 268 | /* |
---|
| 269 | * Flush the socket. Block if the socket is in blocking mode. |
---|
| 270 | * This will return -1 on errors and 0 if successful. |
---|
| 271 | */ |
---|
| 272 | |
---|
| 273 | int socketFlush(int sid) |
---|
| 274 | { |
---|
| 275 | socket_t *sp; |
---|
| 276 | ringq_t *rq; |
---|
| 277 | int len, bytesWritten, errCode; |
---|
| 278 | |
---|
| 279 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 280 | return -1; |
---|
| 281 | } |
---|
| 282 | rq = &sp->outBuf; |
---|
| 283 | |
---|
| 284 | /* |
---|
| 285 | * Set the background flushing flag which socketEventProc will check to |
---|
| 286 | * continue the flush. |
---|
| 287 | */ |
---|
| 288 | if (! (sp->flags & SOCKET_BLOCK)) { |
---|
| 289 | sp->flags |= SOCKET_FLUSHING; |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | /* |
---|
| 293 | * Break from loop if not blocking after initiating output. If we are blocking |
---|
| 294 | * we wait for a write event. |
---|
| 295 | */ |
---|
| 296 | while (ringqLen(rq) > 0) { |
---|
| 297 | len = ringqGetBlkMax(&sp->outBuf); |
---|
| 298 | bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode); |
---|
| 299 | if (bytesWritten < 0) { |
---|
| 300 | if (errCode == EINTR) { |
---|
| 301 | continue; |
---|
| 302 | } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) { |
---|
[ee3afa2] | 303 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 304 | if (sp->flags & SOCKET_BLOCK) { |
---|
| 305 | int errCode; |
---|
| 306 | if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE, |
---|
| 307 | &errCode)) { |
---|
| 308 | return -1; |
---|
| 309 | } |
---|
| 310 | continue; |
---|
| 311 | } |
---|
| 312 | #endif |
---|
| 313 | /* |
---|
| 314 | * Ensure we get a FD_WRITE message when the socket can absorb |
---|
| 315 | * more data (non-blocking only.) Store the user's mask if we |
---|
| 316 | * haven't done it already. |
---|
| 317 | */ |
---|
| 318 | if (sp->saveMask < 0 ) { |
---|
| 319 | sp->saveMask = sp->handlerMask; |
---|
| 320 | socketRegisterInterest(sp, |
---|
| 321 | sp->handlerMask | SOCKET_WRITABLE); |
---|
| 322 | } |
---|
| 323 | return 0; |
---|
| 324 | } |
---|
| 325 | return -1; |
---|
| 326 | } |
---|
| 327 | ringqGetBlkAdj(rq, bytesWritten); |
---|
| 328 | } |
---|
| 329 | /* |
---|
| 330 | * If the buffer is empty, reset the ringq pointers to point to the start |
---|
| 331 | * of the buffer. This is essential to ensure that datagrams get written |
---|
| 332 | * in one single I/O operation. |
---|
| 333 | */ |
---|
| 334 | if (ringqLen(rq) == 0) { |
---|
| 335 | ringqFlush(rq); |
---|
| 336 | } |
---|
| 337 | /* |
---|
| 338 | * Restore the users mask if it was saved by the non-blocking code above. |
---|
| 339 | * Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask |
---|
| 340 | */ |
---|
| 341 | if (sp->saveMask >= 0) { |
---|
| 342 | socketRegisterInterest(sp, sp->saveMask); |
---|
| 343 | sp->saveMask = -1; |
---|
| 344 | } |
---|
| 345 | sp->flags &= ~SOCKET_FLUSHING; |
---|
| 346 | return 0; |
---|
| 347 | } |
---|
| 348 | |
---|
| 349 | /******************************************************************************/ |
---|
| 350 | /* |
---|
| 351 | * Return the count of input characters buffered. We look at both the line |
---|
| 352 | * buffer and the input (raw) buffer. Return -1 on error or EOF. |
---|
| 353 | */ |
---|
| 354 | |
---|
| 355 | int socketInputBuffered(int sid) |
---|
| 356 | { |
---|
| 357 | socket_t *sp; |
---|
| 358 | |
---|
| 359 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 360 | return -1; |
---|
| 361 | } |
---|
| 362 | if (socketEof(sid)) { |
---|
| 363 | return -1; |
---|
| 364 | } |
---|
| 365 | return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf); |
---|
| 366 | } |
---|
| 367 | |
---|
| 368 | /******************************************************************************/ |
---|
| 369 | /* |
---|
| 370 | * Return true if EOF |
---|
| 371 | */ |
---|
| 372 | |
---|
| 373 | int socketEof(int sid) |
---|
| 374 | { |
---|
| 375 | socket_t *sp; |
---|
| 376 | |
---|
| 377 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 378 | return -1; |
---|
| 379 | } |
---|
| 380 | return sp->flags & SOCKET_EOF; |
---|
| 381 | } |
---|
| 382 | |
---|
| 383 | /******************************************************************************/ |
---|
| 384 | /* |
---|
| 385 | * Return the number of bytes the socket can absorb without blocking |
---|
| 386 | */ |
---|
| 387 | |
---|
| 388 | int socketCanWrite(int sid) |
---|
| 389 | { |
---|
| 390 | socket_t *sp; |
---|
| 391 | |
---|
| 392 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 393 | return -1; |
---|
| 394 | } |
---|
| 395 | return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1; |
---|
| 396 | } |
---|
| 397 | |
---|
| 398 | /******************************************************************************/ |
---|
| 399 | /* |
---|
| 400 | * Add one to allow the user to write exactly SOCKET_BUFSIZ |
---|
| 401 | */ |
---|
| 402 | |
---|
| 403 | void socketSetBufferSize(int sid, int in, int line, int out) |
---|
| 404 | { |
---|
| 405 | socket_t *sp; |
---|
| 406 | |
---|
| 407 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 408 | return; |
---|
| 409 | } |
---|
| 410 | |
---|
| 411 | if (in >= 0) { |
---|
| 412 | ringqClose(&sp->inBuf); |
---|
| 413 | in++; |
---|
| 414 | ringqOpen(&sp->inBuf, in, in); |
---|
| 415 | } |
---|
| 416 | |
---|
| 417 | if (line >= 0) { |
---|
| 418 | ringqClose(&sp->lineBuf); |
---|
| 419 | line++; |
---|
| 420 | ringqOpen(&sp->lineBuf, line, line); |
---|
| 421 | } |
---|
| 422 | |
---|
| 423 | if (out >= 0) { |
---|
| 424 | ringqClose(&sp->outBuf); |
---|
| 425 | out++; |
---|
| 426 | ringqOpen(&sp->outBuf, out, out); |
---|
| 427 | } |
---|
| 428 | } |
---|
| 429 | |
---|
| 430 | /******************************************************************************/ |
---|
| 431 | /* |
---|
| 432 | * Create a user handler for this socket. The handler called whenever there |
---|
| 433 | * is an event of interest as defined by handlerMask (SOCKET_READABLE, ...) |
---|
| 434 | */ |
---|
| 435 | |
---|
| 436 | void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler, |
---|
| 437 | int data) |
---|
| 438 | { |
---|
| 439 | socket_t *sp; |
---|
| 440 | |
---|
| 441 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 442 | return; |
---|
| 443 | } |
---|
| 444 | sp->handler = handler; |
---|
| 445 | sp->handler_data = data; |
---|
| 446 | socketRegisterInterest(sp, handlerMask); |
---|
| 447 | } |
---|
| 448 | |
---|
| 449 | /******************************************************************************/ |
---|
| 450 | /* |
---|
| 451 | * Delete a handler |
---|
| 452 | */ |
---|
| 453 | |
---|
| 454 | void socketDeleteHandler(int sid) |
---|
| 455 | { |
---|
| 456 | socket_t *sp; |
---|
| 457 | |
---|
| 458 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 459 | return; |
---|
| 460 | } |
---|
| 461 | sp->handler = NULL; |
---|
| 462 | socketRegisterInterest(sp, 0); |
---|
| 463 | } |
---|
| 464 | |
---|
| 465 | /******************************************************************************/ |
---|
| 466 | /* |
---|
| 467 | * Socket output procedure. Return -1 on errors otherwise return the number |
---|
| 468 | * of bytes written. |
---|
| 469 | */ |
---|
| 470 | |
---|
| 471 | static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode) |
---|
| 472 | { |
---|
| 473 | struct sockaddr_in server; |
---|
| 474 | int bytes; |
---|
| 475 | |
---|
| 476 | a_assert(sp); |
---|
| 477 | a_assert(buf); |
---|
| 478 | a_assert(toWrite > 0); |
---|
| 479 | a_assert(errCode); |
---|
| 480 | |
---|
| 481 | *errCode = 0; |
---|
| 482 | |
---|
[ee3afa2] | 483 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 484 | if ((sp->flags & SOCKET_ASYNC) |
---|
| 485 | && ! socketWaitForEvent(sp, FD_CONNECT, errCode)) { |
---|
| 486 | return -1; |
---|
| 487 | } |
---|
| 488 | #endif |
---|
| 489 | |
---|
| 490 | /* |
---|
| 491 | * Write the data |
---|
| 492 | */ |
---|
| 493 | if (sp->flags & SOCKET_BROADCAST) { |
---|
| 494 | server.sin_family = AF_INET; |
---|
[ee3afa2] | 495 | #if (defined (UEMF) || defined (LITTLEFOOT)) |
---|
[527b508] | 496 | server.sin_addr.s_addr = INADDR_BROADCAST; |
---|
| 497 | #else |
---|
| 498 | server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress()); |
---|
| 499 | #endif |
---|
| 500 | server.sin_port = htons((short)(sp->port & 0xFFFF)); |
---|
| 501 | if ((bytes = sendto(sp->sock, buf, toWrite, 0, |
---|
| 502 | (struct sockaddr *) &server, sizeof(server))) < 0) { |
---|
| 503 | bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0, |
---|
| 504 | (struct sockaddr *) &server); |
---|
| 505 | } |
---|
| 506 | } else if (sp->flags & SOCKET_DATAGRAM) { |
---|
| 507 | server.sin_family = AF_INET; |
---|
| 508 | server.sin_addr.s_addr = inet_addr(sp->host); |
---|
| 509 | server.sin_port = htons((short)(sp->port & 0xFFFF)); |
---|
| 510 | bytes = sendto(sp->sock, buf, toWrite, 0, |
---|
| 511 | (struct sockaddr *) &server, sizeof(server)); |
---|
| 512 | |
---|
| 513 | } else { |
---|
| 514 | bytes = send(sp->sock, buf, toWrite, 0); |
---|
| 515 | } |
---|
| 516 | |
---|
| 517 | if (bytes < 0) { |
---|
| 518 | *errCode = socketGetError(); |
---|
[ee3afa2] | 519 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 520 | sp->currentEvents &= ~FD_WRITE; |
---|
| 521 | #endif |
---|
| 522 | |
---|
| 523 | return -1; |
---|
| 524 | |
---|
| 525 | } else if (bytes == 0 && bytes != toWrite) { |
---|
| 526 | *errCode = EWOULDBLOCK; |
---|
[ee3afa2] | 527 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 528 | sp->currentEvents &= ~FD_WRITE; |
---|
| 529 | #endif |
---|
| 530 | return -1; |
---|
| 531 | } |
---|
| 532 | |
---|
| 533 | /* |
---|
| 534 | * Ensure we get to write some more data real soon if the socket can absorb |
---|
| 535 | * more data |
---|
| 536 | */ |
---|
[ee3afa2] | 537 | #ifndef UEMF |
---|
| 538 | #ifdef WIN |
---|
[527b508] | 539 | if (sp->interestEvents & FD_WRITE) { |
---|
| 540 | emfTime_t blockTime = { 0, 0 }; |
---|
| 541 | emfSetMaxBlockTime(&blockTime); |
---|
| 542 | } |
---|
| 543 | #endif /* WIN */ |
---|
| 544 | #endif |
---|
| 545 | return bytes; |
---|
| 546 | } |
---|
| 547 | |
---|
| 548 | /******************************************************************************/ |
---|
| 549 | /* |
---|
| 550 | * If the sendto failed, swap the first two bytes in the |
---|
| 551 | * sockaddr structure. This is a kludge due to a change in |
---|
| 552 | * VxWorks between versions 5.3 and 5.4, but we want the |
---|
| 553 | * product to run on either. |
---|
| 554 | */ |
---|
| 555 | static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i, |
---|
| 556 | struct sockaddr *server) |
---|
| 557 | { |
---|
[ee3afa2] | 558 | #ifdef VXWORKS |
---|
[527b508] | 559 | char *ptr; |
---|
| 560 | |
---|
| 561 | ptr = (char *)server; |
---|
| 562 | *ptr = *(ptr+1); |
---|
| 563 | *(ptr+1) = 0; |
---|
| 564 | return sendto(sock, buf, toWrite, i, server, sizeof(struct sockaddr)); |
---|
| 565 | #else |
---|
| 566 | return -1; |
---|
| 567 | #endif /* VXWORKS */ |
---|
| 568 | } |
---|
| 569 | |
---|
| 570 | /******************************************************************************/ |
---|
| 571 | /* |
---|
| 572 | * Allocate a new socket structure |
---|
| 573 | */ |
---|
| 574 | |
---|
| 575 | int socketAlloc(char *host, int port, socketAccept_t accept, int flags) |
---|
| 576 | { |
---|
| 577 | socket_t *sp; |
---|
| 578 | int sid; |
---|
| 579 | |
---|
[bfb4c547] | 580 | if ((sid = hAllocEntry((void*) &socketList, &socketMax, |
---|
[527b508] | 581 | sizeof(socket_t))) < 0) { |
---|
| 582 | return -1; |
---|
| 583 | } |
---|
| 584 | sp = socketList[sid]; |
---|
| 585 | |
---|
| 586 | sp->sid = sid; |
---|
| 587 | sp->accept = accept; |
---|
| 588 | sp->port = port; |
---|
| 589 | sp->fileHandle = -1; |
---|
| 590 | sp->saveMask = -1; |
---|
| 591 | |
---|
| 592 | if (host) { |
---|
| 593 | strncpy(sp->host, host, sizeof(sp->host)); |
---|
| 594 | } |
---|
| 595 | |
---|
| 596 | /* |
---|
| 597 | * Preserve only specified flags from the callers open |
---|
| 598 | */ |
---|
| 599 | a_assert((flags & ~(SOCKET_BROADCAST|SOCKET_DATAGRAM|SOCKET_BLOCK| |
---|
| 600 | SOCKET_LISTENING)) == 0); |
---|
| 601 | sp->flags = flags & (SOCKET_BROADCAST | SOCKET_DATAGRAM | SOCKET_BLOCK| |
---|
| 602 | SOCKET_LISTENING); |
---|
| 603 | |
---|
| 604 | /* |
---|
| 605 | * Add one to allow the user to write exactly SOCKET_BUFSIZ |
---|
| 606 | */ |
---|
| 607 | ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ); |
---|
| 608 | ringqOpen(&sp->outBuf, SOCKET_BUFSIZ + 1, SOCKET_BUFSIZ + 1); |
---|
| 609 | ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1); |
---|
| 610 | |
---|
| 611 | return sid; |
---|
| 612 | } |
---|
| 613 | |
---|
| 614 | /******************************************************************************/ |
---|
| 615 | /* |
---|
| 616 | * Free a socket structure |
---|
| 617 | */ |
---|
| 618 | |
---|
| 619 | void socketFree(int sid) |
---|
| 620 | { |
---|
| 621 | socket_t *sp; |
---|
| 622 | char_t buf[256]; |
---|
| 623 | int i; |
---|
| 624 | |
---|
| 625 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 626 | return; |
---|
| 627 | } |
---|
| 628 | |
---|
| 629 | /* |
---|
| 630 | * To close a socket, remove any registered interests, set it to |
---|
| 631 | * non-blocking so that the recv which follows won't block, do a |
---|
| 632 | * shutdown on it so peers on the other end will receive a FIN, |
---|
| 633 | * then read any data not yet retrieved from the receive buffer, |
---|
| 634 | * and finally close it. If these steps are not all performed |
---|
| 635 | * RESETs may be sent to the other end causing problems. |
---|
| 636 | */ |
---|
| 637 | socketRegisterInterest(sp, 0); |
---|
| 638 | if (sp->sock >= 0) { |
---|
| 639 | socketSetBlock(sid, 0); |
---|
| 640 | if (shutdown(sp->sock, 1) >= 0) { |
---|
| 641 | recv(sp->sock, buf, sizeof(buf), 0); |
---|
| 642 | } |
---|
[ee3afa2] | 643 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 644 | closesocket(sp->sock); |
---|
| 645 | #else |
---|
| 646 | close(sp->sock); |
---|
| 647 | #endif |
---|
| 648 | } |
---|
| 649 | |
---|
| 650 | ringqClose(&sp->inBuf); |
---|
| 651 | ringqClose(&sp->outBuf); |
---|
| 652 | ringqClose(&sp->lineBuf); |
---|
| 653 | |
---|
| 654 | bfree(B_L, sp); |
---|
[bfb4c547] | 655 | socketMax = hFree((void*) &socketList, sid); |
---|
[527b508] | 656 | |
---|
| 657 | /* |
---|
| 658 | * Calculate the new highest socket number |
---|
| 659 | */ |
---|
| 660 | socketHighestFd = -1; |
---|
| 661 | for (i = 0; i < socketMax; i++) { |
---|
| 662 | if ((sp = socketList[i]) == NULL) { |
---|
| 663 | continue; |
---|
| 664 | } |
---|
| 665 | socketHighestFd = max(socketHighestFd, sp->sock); |
---|
| 666 | } |
---|
| 667 | } |
---|
| 668 | |
---|
| 669 | /******************************************************************************/ |
---|
| 670 | /* |
---|
| 671 | * Validate a socket handle |
---|
| 672 | */ |
---|
| 673 | |
---|
| 674 | socket_t *socketPtr(int sid) |
---|
| 675 | { |
---|
| 676 | if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) { |
---|
| 677 | a_assert(NULL); |
---|
| 678 | errno = EBADF; |
---|
| 679 | return NULL; |
---|
| 680 | } |
---|
| 681 | |
---|
| 682 | a_assert(socketList[sid]); |
---|
| 683 | return socketList[sid]; |
---|
| 684 | } |
---|
| 685 | |
---|
| 686 | /******************************************************************************/ |
---|
| 687 | /* |
---|
| 688 | * Get the operating system error code |
---|
| 689 | */ |
---|
| 690 | |
---|
| 691 | int socketGetError() |
---|
| 692 | { |
---|
[ee3afa2] | 693 | #if (defined (WIN) || defined (CE)) |
---|
[527b508] | 694 | switch (WSAGetLastError()) { |
---|
| 695 | case WSAEWOULDBLOCK: |
---|
| 696 | return EWOULDBLOCK; |
---|
| 697 | case WSAECONNRESET: |
---|
| 698 | return ECONNRESET; |
---|
| 699 | case WSAENETDOWN: |
---|
| 700 | return ENETDOWN; |
---|
| 701 | case WSAEPROCLIM: |
---|
| 702 | return EAGAIN; |
---|
| 703 | case WSAEINTR: |
---|
| 704 | return EINTR; |
---|
| 705 | default: |
---|
| 706 | return EINVAL; |
---|
| 707 | } |
---|
| 708 | #else |
---|
| 709 | return errno; |
---|
| 710 | #endif |
---|
| 711 | } |
---|
| 712 | |
---|
| 713 | /******************************************************************************/ |
---|
| 714 | /* |
---|
| 715 | * Return the underlying socket handle |
---|
| 716 | */ |
---|
| 717 | |
---|
| 718 | int socketGetHandle(int sid) |
---|
| 719 | { |
---|
| 720 | socket_t *sp; |
---|
| 721 | |
---|
| 722 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 723 | return -1; |
---|
| 724 | } |
---|
| 725 | return sp->sock; |
---|
| 726 | } |
---|
| 727 | |
---|
| 728 | /******************************************************************************/ |
---|
| 729 | /* |
---|
| 730 | * Get blocking mode |
---|
| 731 | */ |
---|
| 732 | |
---|
| 733 | int socketGetBlock(int sid) |
---|
| 734 | { |
---|
| 735 | socket_t *sp; |
---|
| 736 | |
---|
| 737 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 738 | a_assert(0); |
---|
| 739 | return 0; |
---|
| 740 | } |
---|
| 741 | return (sp->flags & SOCKET_BLOCK); |
---|
| 742 | } |
---|
| 743 | |
---|
| 744 | /******************************************************************************/ |
---|
| 745 | /* |
---|
| 746 | * Get mode |
---|
| 747 | */ |
---|
| 748 | |
---|
| 749 | int socketGetMode(int sid) |
---|
| 750 | { |
---|
| 751 | socket_t *sp; |
---|
| 752 | |
---|
| 753 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 754 | a_assert(0); |
---|
| 755 | return 0; |
---|
| 756 | } |
---|
| 757 | return sp->flags; |
---|
| 758 | } |
---|
| 759 | |
---|
| 760 | /******************************************************************************/ |
---|
| 761 | /* |
---|
| 762 | * Set mode |
---|
| 763 | */ |
---|
| 764 | |
---|
| 765 | void socketSetMode(int sid, int mode) |
---|
| 766 | { |
---|
| 767 | socket_t *sp; |
---|
| 768 | |
---|
| 769 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 770 | a_assert(0); |
---|
| 771 | return; |
---|
| 772 | } |
---|
| 773 | sp->flags = mode; |
---|
| 774 | } |
---|
| 775 | |
---|
| 776 | /******************************************************************************/ |
---|
| 777 | /* |
---|
| 778 | * Get port. |
---|
| 779 | */ |
---|
| 780 | |
---|
| 781 | int socketGetPort(int sid) |
---|
| 782 | { |
---|
| 783 | socket_t *sp; |
---|
| 784 | |
---|
| 785 | if ((sp = socketPtr(sid)) == NULL) { |
---|
| 786 | return -1; |
---|
| 787 | } |
---|
| 788 | return sp->port; |
---|
| 789 | } |
---|
| 790 | |
---|
| 791 | /******************************************************************************/ |
---|