SKoT McDonald
2004-Aug-06 14:57 UTC
[icecast-dev] Submission: Patch to libshout/sock.c for MacOSX
Hi, re libshout: MacOSX doesn't have poll(), which prevents sock.c from compiling. I've patched sock.c to use select(), which is supported on MacOSX, and should be elsewhere too. I've marked my changes with "SKoT" comments in the file below. Main changes are in sock_write_bytes(). - SKoT ------8<----- /* sock.c * - General Socket Functions * * Copyright (c) 1999 Jack Moffitt, Barath Raghavan, and Alexander Haväng * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifdef HAVE_CONFIG_H #ifdef _WIN32 #include <win32config.h> #else #include <config.h> #endif #endif #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <sys/time.h> // - SKoT #include <sys/types.h> // #include <sys/poll.h> // - SKoT #include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <string.h> #include <errno.h> #include <fcntl.h> #ifndef _WIN32 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/time.h> #include <netdb.h> #else #include <winsock.h> #endif #ifndef HAVE_SOCKLEN_T #define socklen_t int #endif #ifndef _WIN32 extern int h_errno, errno; #endif #include "sock.h" int sock_recoverable(int error) { if (error == EAGAIN || error == EINTR || error == EINPROGRESS || error =EWOULDBLOCK) { return 1; } return 0; } int sock_valid_socket(SOCKET sockfd) { return (sockfd >= 0); } #ifdef _WIN32 int inet_aton(const char *s, struct in_addr *a) { int lsb, b2, b3, msb; if (sscanf(s, "%d.%d.%d.%d", &lsb, &b2, &b3, &msb) < 4) { return 0; } #ifdef HAVE_INET_ADDR a->s_addr = inet_addr(s); if(a->s_addr == -1) return 0; #else a->s_addr = lsb + (b2 << 8) + (b3 << 16) + (msb << 24); #endif return 1; } #endif /* _WIN32 */ int sock_set_blocking(SOCKET sockfd, const int block) { #ifdef _WIN32 int varblock = block; #endif if ((!sock_valid_socket(sockfd)) || (block < 0) || (block > 1)) return SOCKET_ERROR; #ifdef _WIN32 return ioctlsocket(sockfd, FIONBIO, &varblock); #else return fcntl(sockfd, F_SETFL, (block == SOCK_BLOCK) ? 0 : O_NONBLOCK); #endif } int sock_close(SOCKET sockfd) { #ifdef _WIN32 return closesocket(sockfd); #else return close(sockfd); #endif } /* * Write len bytes from buf to the socket. */ int sock_write_bytes(SOCKET sockfd, const char *buff, const int len) { int wrote, res, polled; // struct pollfd socks; // <SKoT> fd_set writefds; // struct timeval timeout; // </SKoT> /* sanity check */ if (!buff) { return SOCKET_ERROR; } else if (len <= 0) { return SOCKET_ERROR; } else if (!sock_valid_socket(sockfd)) { return SOCKET_ERROR; } FD_ZERO(&writefds); // <SKoT> FD_SET(sockfd, &writefds); // // socks.fd = sockfd; // // socks.events = POLLOUT; // timeout.tv_sec = 0; // timeout.tv_usec = 1000; // </SKoT> wrote = 0; while (wrote < len) { // SKoT: replaced poll with select polled = select(sockfd+1, 0, &writefds, 0, &timeout); // polled = poll(socks, 1, 30000); if ((polled == -1) && sock_recoverable(errno)) continue; if (polled != 1) return SOCKET_ERROR; res = send(sockfd, &buff[wrote], len - wrote, 0); if ((res < 0) && (!sock_recoverable(errno))) return SOCKET_ERROR; if (res > 0) wrote += res; } return wrote; } /* * Write a string to a socket. */ int sock_write_string(SOCKET sockfd, const char *buff) { return (sock_write_bytes(sockfd, buff, strlen(buff)) > 0); } /* * Write a printf() style formatted message to the socket * Return 1 if all bytes where successfully written, and 0 if not. * Potential problems: Will truncate the string if longer than 1024 bytes. * Might fuck everything up if no vsnprintf is available */ int sock_write(SOCKET sockfd, const char *fmt, ...) { char buff[1024]; va_list ap; va_start(ap, fmt); #ifdef HAVE_VSNPRINTF vsnprintf(buff, 1024, fmt, ap); #else vsprintf(buff, fmt, ap); #endif va_end(ap); return (sock_write_bytes(sockfd, buff, strlen(buff)) > 0); } /* * Read one line of at max len bytes from sockfd into buff. * If ok, return 1 and nullterminate buff. Otherwize return 0. * Terminating \n is not put into the buffer. * Assert Class: 2 */ int sock_read_line(SOCKET sockfd, char *buff, const int len) { char c = '\0'; int read_bytes, pos; if (!sock_valid_socket(sockfd)) { return 0; } else if (!buff) { return 0; } else if (len <= 0) { return 0; } pos = 0; read_bytes = recv(sockfd, &c, 1, 0); if (read_bytes < 0) { return 0; } while ((c != '\n') && (pos < len) && (read_bytes == 1)) { if (c != '\r') buff[pos++] = c; read_bytes = recv(sockfd, &c, 1, 0); } if (read_bytes == 1) { buff[pos] = '\0'; return 1; } else { return 0; } } /* * Connect to hostname on specified port and return the created socket. */ SOCKET sock_connect_wto(const char *hostname, const int port, const int timeout) { SOCKET sockfd; struct sockaddr_in sin, server; if (!hostname || !hostname[0]) { return INVALID_SOCKET; } else if (port <= 0) { return INVALID_SOCKET; } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == INVALID_SOCKET) { sock_close(sockfd); return INVALID_SOCKET; } memset(&sin, 0, sizeof(sin)); memset(&server, 0, sizeof(struct sockaddr_in)); if (inet_aton(hostname, (struct in_addr *)&sin.sin_addr) == 0) { sock_close(sockfd); return INVALID_SOCKET; } memcpy(&server.sin_addr, &sin.sin_addr, sizeof(sin)); server.sin_family = AF_INET; server.sin_port = htons(port); /* if we have a timeout, use select, if not, use connect straight. */ /* dunno if this is portable, and it sure is complicated for such a simple thing to want to do. damn BSD sockets! */ if (timeout > 0) { fd_set wfds; struct timeval tv; int retval; int val; socklen_t valsize = sizeof(int); FD_ZERO(&wfds); FD_SET(sockfd, &wfds); tv.tv_sec = timeout; tv.tv_usec = 0; sock_set_blocking(sockfd, SOCK_NONBLOCK); retval = connect(sockfd, (struct sockaddr *)&server, sizeof(server)); if (retval == 0) { sock_set_blocking(sockfd, SOCK_BLOCK); return sockfd; } else { #ifdef _WIN32 if (WSAGetLastError() == WSAEINPROGRESS) { #else if (!sock_recoverable(errno)) { #endif sock_close(sockfd); return SOCKET_ERROR; } } if (select(sockfd + 1, NULL, &wfds, NULL, &tv)) { retval = getsockopt (sockfd, SOL_SOCKET, SO_ERROR, (void *)&val, (socklen_t *)&valsize); if ((retval == 0) && (val == 0)) { sock_set_blocking(sockfd, SOCK_BLOCK); return sockfd; } else { sock_close(sockfd); return SOCKET_ERROR; } } else { sock_close(sockfd); return SOCKET_ERROR; } } else { if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == 0) { return sockfd; } else { sock_close(sockfd); return SOCKET_ERROR; } } } --- >8 ---- List archives: http://www.xiph.org/archives/ icecast project homepage: http://www.icecast.org/ To unsubscribe from this list, send a message to 'icecast-dev-request@xiph.org' containing only the word 'unsubscribe' in the body. No subject is needed. Unsubscribe messages sent to the list will be ignored/filtered.