00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024
00025 #include <unistd.h>
00026 #include <fcntl.h>
00027 #include <sys/errno.h>
00028 #include <sys/socket.h>
00029 #include <sys/time.h>
00030 #include <sys/types.h>
00031 #include <netdb.h>
00032 #include <sys/uio.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 #include <sys/un.h>
00036
00037 #include <pthread.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <ctype.h>
00041
00042 #include <httpstream.h>
00043
00044 #define SOCKET_ERROR (-1)
00045 #define INVALID_SOCKET (-1)
00046
00047
00048 static int
00049 rread( int fd, void *buf, int len )
00050 {
00051 int ret;
00052
00053 do {
00054 ret = read(fd, buf, len);
00055 } while (ret==-1 && errno==EINTR);
00056 return ret;
00057 }
00058
00059
00060 static int
00061 rwrite( int fd, const void *buf, int len )
00062 {
00063 int ret;
00064
00065 do {
00066 ret = write(fd, buf, len);
00067 } while (ret==-1 && errno==EINTR);
00068 return ret;
00069 }
00070
00071
00072 static int
00073 rsend( int sock, const char *buf, int len, int flags )
00074 {
00075 int ret;
00076
00077 do {
00078 ret = send(sock, buf, len, flags);
00079 } while (ret==-1 && errno==EINTR);
00080 return ret;
00081 }
00082
00083
00084 static int
00085 rrecv( int sock, char *buf, int len, int flags )
00086 {
00087 int ret;
00088
00089 do {
00090 ret = recv(sock, buf, len, flags);
00091 } while (ret==-1 && errno==EINTR);
00092 return ret;
00093 }
00094
00095
00096
00097 static bool
00098 socket_nonblock( int sock )
00099 {
00100 int file_flags;
00101 int old_errno = errno;
00102
00103
00104 if ( (file_flags = fcntl(sock, F_GETFL, 0)) == -1 ) {
00105 return false;
00106 }
00107 if ( fcntl(sock, F_SETFL, (file_flags | O_NONBLOCK)) ) {
00108 return false;
00109 }
00110
00111 errno = old_errno;
00112 return true;
00113 }
00114
00115
00116 static bool
00117 socket_block( int sock )
00118 {
00119 int file_flags;
00120
00121 if ( (file_flags = fcntl(sock, F_GETFL, 0)) == -1 ) {
00122 return false;
00123 }
00124 if ( fcntl(sock, F_SETFL, (file_flags & ~O_NONBLOCK)) ) {
00125 return false;
00126 }
00127
00128 return true;
00129 }
00130
00131
00132 static int
00133 raccept( int s, struct sockaddr *addr, socklen_t *addrlen )
00134 {
00135 int rc;
00136
00137 do {
00138 rc = accept( s, addr, addrlen );
00139 } while ( rc == -1 && errno == EINTR );
00140
00141 return rc;
00142 }
00143
00144
00145 static int
00146 rconnect( int sock, const struct sockaddr *saddr, socklen_t slen )
00147 {
00148 int rc;
00149
00150 do {
00151 rc = connect( sock, saddr, slen );
00152 } while ( rc == -1 && errno == EINTR );
00153
00154 return rc;
00155 }
00156
00157
00158 in_addr_t
00159 host_to_ip( const char* name )
00160 {
00161 struct hostent* hostStruct = NULL;
00162 struct in_addr* hostNode = NULL;
00163 in_addr_t ret = (in_addr_t)0;
00164
00165
00166 ret = inet_addr( name );
00167 if ( ret != (in_addr_t)-1 )
00168 return ret;
00169
00170 hostStruct = gethostbyname( name );
00171 if ( NULL == hostStruct )
00172 return( (in_addr_t)0 );
00173
00174
00175 hostNode = (struct in_addr*) hostStruct->h_addr;
00176 return( hostNode->s_addr );
00177 }
00178
00179
00180 int
00181 fullsend( int sock, const char *buf, int buflen, int flags )
00182 {
00183 int sent = 0, lastsend = 0;
00184
00185 while (sent < buflen) {
00186 errno = 0;
00187 lastsend = rsend(sock, buf+sent*sizeof(char), buflen-sent, flags);
00188 if (lastsend < 0) {
00189
00190
00191 if (errno==EAGAIN || errno==EINTR) {
00192 continue;
00193 } else {
00194 return sent;
00195 }
00196 } else if (lastsend == 0) {
00197 return sent;
00198 } else {
00199 sent += lastsend;
00200 }
00201 }
00202
00203 return sent;
00204 }
00205
00206
00207 int
00208 fullrecv( int sock, char *buf, int buflen, int flags )
00209 {
00210 int recvsofar = 0, lastrecv = 0;
00211
00212 while (recvsofar < buflen) {
00213 errno = 0;
00214 lastrecv = rrecv(sock, buf+recvsofar*sizeof(char), buflen-recvsofar, flags);
00215
00216
00217 if ( lastrecv == 0 ) {
00218 return recvsofar;
00219 } else if (lastrecv < 0) {
00220 return lastrecv;
00221 } else {
00222 recvsofar += lastrecv;
00223 }
00224 }
00225
00226 return recvsofar;
00227 }
00228
00229
00230
00231
00232
00233 static int
00234 rselect( int n, fd_set *rds, fd_set *wds, fd_set *eds, struct timeval *tout )
00235 {
00236 int rc;
00237
00238 do {
00239 rc = select( n, rds, wds, eds, tout );
00240 } while ( rc == -1 && errno == EINTR );
00241
00242 return rc;
00243 }
00244
00245
00246
00247 static bool
00248 check_ip_options( int sock )
00249 {
00250 int ipproto;
00251 struct protoent *ip;
00252 unsigned char optbuf[BUFSIZ/3];
00253 int optsz = sizeof(optbuf);
00254
00255 if ( (ip=getprotobyname("ip")) != NULL )
00256 ipproto = ip->p_proto;
00257 else
00258 ipproto = IPPROTO_IP;
00259
00260 if ( getsockopt(sock, ipproto, IP_OPTIONS, (char*)optbuf, (socklen_t*)&optsz) == 0
00261 && optsz != 0 ) {
00262
00263 if ( setsockopt(sock, ipproto, IP_OPTIONS, NULL, optsz ) != 0 )
00264 return false;
00265 }
00266
00267 return true;
00268 }
00269
00270
00271 static int
00272 muse_connect( const char* host, int port )
00273 {
00274 int rsrv = INVALID_SOCKET;
00275 struct sockaddr_in rsrvINETAddress;
00276 struct sockaddr *rsrvSockAddrPtr = NULL;
00277 int selret, conret;
00278 struct timeval tval = {5, 0};
00279 fd_set rset, wset;
00280
00281 rsrvSockAddrPtr = (struct sockaddr*)&rsrvINETAddress;
00282 memset( (char*)&rsrvINETAddress, 0, sizeof(rsrvINETAddress) );
00283 rsrvINETAddress.sin_family = AF_INET;
00284 rsrvINETAddress.sin_addr.s_addr = host_to_ip( host );
00285 rsrvINETAddress.sin_port = htons( port );
00286
00287 rsrv = socket( AF_INET, SOCK_STREAM, 0 );
00288 if ( !socket_nonblock(rsrv) ) {
00289 close( rsrv );
00290 return INVALID_SOCKET;
00291 }
00292
00293 conret = rconnect( rsrv, (struct sockaddr*)rsrvSockAddrPtr, sizeof(rsrvINETAddress) );
00294 if ( conret == 0 )
00295 goto ok;
00296
00297 if ( conret < 0 && errno != EINPROGRESS ) {
00298 close( rsrv );
00299 return INVALID_SOCKET;
00300 }
00301 errno = 0;
00302
00303
00304
00305
00306
00307 FD_ZERO( &rset );
00308 FD_SET( rsrv, &rset );
00309 wset = rset;
00310 selret = rselect( rsrv+1, &rset, &wset, NULL, &tval );
00311 if ( selret == 0 ) {
00312 close( rsrv );
00313 errno = ETIMEDOUT;
00314 return INVALID_SOCKET;
00315 }
00316
00317 if ( FD_ISSET(rsrv, &rset) || FD_ISSET(rsrv, &wset) ) {
00318 int error=0, optret, len=sizeof(error);
00319 optret = getsockopt( rsrv, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len );
00320 if ( optret < 0 || error != 0 ) {
00321
00322 errno = error;
00323 warning(" SOL_SOCKET SO_ERROR=%d", error);
00324
00325 close( rsrv );
00326 return INVALID_SOCKET;
00327 }
00328 } else {
00329 warning(" select error: sockfd not set");
00330 close( rsrv );
00331 return INVALID_SOCKET;
00332 }
00333
00334 if ( !socket_block(rsrv) ) {
00335 close( rsrv );
00336 return INVALID_SOCKET;
00337 }
00338 ok:
00339 notice("Connected to %s:%d", host, port);
00340 return rsrv;
00341 }
00342
00343
00344 static int
00345 disconnect( int sock )
00346 {
00347
00348 return shutdown(sock, 2);
00349 }
00350
00351
00352 #define HTTP_PREFIX "http://"
00353 FILE *
00354 http_open( const char *url )
00355 {
00356 int sock = INVALID_SOCKET;
00357 FILE *fd = NULL;
00358 char *host=NULL, *file=NULL, *p;
00359 int port = 0;
00360
00361 host = (char*)calloc( 1, strlen(url)+1 );
00362 file = (char*)calloc( 1, strlen(url)+1 );
00363 if (!host || !file) goto out;
00364
00365 p = strstr(url, HTTP_PREFIX); if (!p) goto out;
00366 p += 7;
00367 strcpy(host, p);
00368
00369 p = strchr(host, '/');
00370 if (p) {
00371 strcpy(file, p);
00372 *p = '\0';
00373 } else {
00374 *file = '/';
00375 }
00376
00377 p = strchr(host, ':');
00378 if (p) {
00379 *p++ = '\0';
00380 port = atoi(p);
00381 } else {
00382 port = 80;
00383 }
00384
00385 notice("http_open host='%s', port=%d, file='%s'", host, port, file);
00386 sock = muse_connect(host, port);
00387 if (sock > 0 ) {
00388 fd = fdopen(sock, "rb");
00389 fullsend(sock, "GET ", 4, 0);
00390 fullsend(sock, file, strlen(file), 0);
00391 fullsend(sock, " HTTP/1.0\r\n\r\n", 13, 0);
00392 }
00393
00394 out:
00395 if (host) free(host);
00396 if (file) free(file);
00397 return fd;
00398 }
00399
00400
00401 static void
00402 strip_header( FILE *fd )
00403 {
00404 int crlf=0;
00405 while (crlf<2 && !feof(fd)) {
00406 int ch = fgetc(fd);
00407 if (ch == '\n') crlf++;
00408 else if (ch == '\r') ;
00409 else crlf = 0;
00410 }
00411 }
00412
00413
00414 FILE *
00415 hopen( const char *url, const char *mode )
00416 {
00417 FILE *fd = NULL;
00418 if (!url) return NULL;
00419 notice("hopen: '%s'", url);
00420 if (strstr(url, HTTP_PREFIX)) {
00421 fd = http_open(url);
00422 if (fd) {
00423 strip_header(fd);
00424
00425 if (feof(fd)) {fclose(fd); fd=NULL;}
00426 }
00427 return fd;
00428 } else {
00429 return fopen(url, mode);
00430 }
00431 }
00432
00433
00434
00435 static char *
00436 read_header( FILE *fd )
00437 {
00438 int crlf=0;
00439 int len=128, used=0;
00440 char *header = (char*)calloc(1, 128);
00441
00442 if (!header) return NULL;
00443
00444 while (crlf<2 && !feof(fd)) {
00445 int ch = fgetc(fd);
00446
00447 if (ch == '\n') crlf++;
00448 else if (ch == '\r') ;
00449 else crlf = 0;
00450
00451
00452 header[used++] = ch;
00453
00454 if (used == len) {
00455 len *= 2;
00456 header = (char*)realloc(header, len);
00457 if (!header) return NULL;
00458 }
00459 }
00460
00461 header[used] = '\0';
00462 return header;
00463 }
00464
00465
00466 hstream
00467 stream_detect( const char *url )
00468 {
00469 FILE *fd;
00470 char *hdr = NULL;
00471 hstream ret = HS_NONE;
00472
00473 notice("stream_detect: '%d'", ret);
00474 if (!url) return HS_NONE;
00475 if (!strstr(url, HTTP_PREFIX)) return HS_NONE;
00476 if ((fd=http_open(url)) == NULL) return HS_NONE;
00477
00478 hdr = read_header(fd);
00479 fclose(fd);
00480 if (!hdr) return HS_NONE;
00481
00482
00483 if (strstr(hdr,"application/ogg"))
00484 ret = HS_OGG;
00485 else if (strstr(hdr,"SHOUTcast") || strstr(hdr,"ICY 200"))
00486 ret = HS_MP3;
00487 notice("stream_detect: '%d'", ret);
00488
00489 free(hdr);
00490 return ret;
00491 }
00492