/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.cs.princeton.edu/ http://soundlab.cs.princeton.edu/ 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 U.S.A.-----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// name: util_network.c// desc: sockets// // author: Ge Wang (gewang@cs.princeton.edu)// Perry R. Cook (prc@cs.princeton.edu)//// originally randy_socket// author: Peng Bi (pbi@cs.princeton.edu)// Ge Wang (gewang@cs.princeton.edu)// date: Winter 2003//-----------------------------------------------------------------------------#include "util_network.h"#include "chuck_utils.h"#include "chuck_errmsg.h"#include <stdio.h> #if defined(__PLATFORM_WIN32__)// 2022 QTSIN changed from winsock.h to winsock2.h#include <winsock2.h>#else#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <unistd.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <arpa/inet.h>#include <netdb.h>#endif #ifdef __PLATFORM_WIN32__static WSADATA g_wsd;static int g_init = 0;#endif #ifndef socklen_t#define socklen_t unsigned int#endif //-----------------------------------------------------------------------------// name: struct ck_socket_// desc: ...//-----------------------------------------------------------------------------struct ck_socket_{ int sock; int prot; struct sockaddr_in sock_in; socklen_t len;}; //-----------------------------------------------------------------------------// name: ck_udp_create()// desc: create a udp socket//-----------------------------------------------------------------------------ck_socket ck_udp_create( ){ ck_socket sock = NULL; #ifdef __PLATFORM_WIN32__ // winsock init if( g_init == 0 ) if( WSAStartup( MAKEWORD(1,1), &(g_wsd) ) != 0 && WSAStartup( MAKEWORD(1,0), &(g_wsd) ) != 0 ) { fprintf( stderr, "[chuck]: cannot start winsock, networking disabled...\n" ); return NULL; } // count g_init++;#endif sock = (ck_socket)checked_malloc( sizeof( struct ck_socket_ ) ); sock->sock = socket( AF_INET, SOCK_DGRAM, 0 ); sock->prot = SOCK_DGRAM; return sock;} //-----------------------------------------------------------------------------// name: ck_tcp_create()// desc: create a tcp socket//-----------------------------------------------------------------------------ck_socket ck_tcp_create( int flags ){ ck_socket sock = (ck_socket)checked_malloc( sizeof( struct ck_socket_ ) ); int nd = 1; int ru = 1; #ifdef __PLATFORM_WIN32__ // winsock init if( g_init == 0 ) if( WSAStartup( MAKEWORD(1,1), &(g_wsd) ) != 0 && WSAStartup( MAKEWORD(1,0), &(g_wsd) ) != 0 ) { fprintf( stderr, "[chuck]: cannot start winsock, networking disabled...\n" ); return NULL; } // count g_init++;#endif sock->sock = socket( AF_INET, SOCK_STREAM, 0 ); sock->prot = SOCK_STREAM; if( flags ) setsockopt( sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&ru, sizeof(ru) ); // setsockopt( sock->sock, SOL_SOCKET, SO_REUSEPORT, (const char *)&ru, sizeof(ru) ); setsockopt( sock->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&nd, sizeof(nd) ); return sock;} //-----------------------------------------------------------------------------// name: ck_connect2()// desc: connect to a server//-----------------------------------------------------------------------------t_CKBOOL ck_connect2( ck_socket sock, const struct sockaddr * addr, int size ) { int ret = connect( sock->sock, addr, size ); return ( ret >= 0 );} //-----------------------------------------------------------------------------// name: ck_connect()// desc: connect to a server//-----------------------------------------------------------------------------t_CKBOOL ck_connect( ck_socket sock, const char * hostname, int port ){ t_CKINT ret; struct hostent * host; #ifdef __PLATFORM_WIN32__ memset( &sock->sock_in, 0, sizeof(struct sockaddr_in) );#else bzero( &sock->sock_in, sizeof(struct sockaddr_in) );#endif sock->sock_in.sin_family = AF_INET; sock->sock_in.sin_port = htons( (unsigned short)abs(port) ); // lookup name host = gethostbyname( hostname ); if( !host ) { sock->sock_in.sin_addr.s_addr = inet_addr( hostname ); if( sock->sock_in.sin_addr.s_addr == -1 ) return FALSE; } else {#if defined( __PLATFORM_WIN32__ ) || defined( __ANDROID__ ) memcpy( (char *)&sock->sock_in.sin_addr, host->h_addr, host->h_length );#else bcopy( host->h_addr, (char *)&sock->sock_in.sin_addr, host->h_length );#endif } if( port < 0 ) return TRUE; ret = ck_connect2( sock, (struct sockaddr *)&sock->sock_in, sizeof( struct sockaddr_in ) ); return ( ret >= 0 );} //-----------------------------------------------------------------------------// name: ck_bind()// desc: bind to a port//-----------------------------------------------------------------------------t_CKBOOL ck_bind( ck_socket sock, int port ) { int ret; #ifdef __PLATFORM_WIN32__ memset( &sock->sock_in, 0, sizeof(struct sockaddr_in) );#else bzero( &sock->sock_in, sizeof(struct sockaddr_in) );#endif sock->sock_in.sin_family = AF_INET; sock->sock_in.sin_port = htons( (unsigned short)port ); sock->sock_in.sin_addr.s_addr = htonl( INADDR_ANY ); ret = bind( sock->sock, (struct sockaddr *)&sock->sock_in, sizeof(struct sockaddr_in)); // added 1.4.1.0 (PR #157 | @dbadb) // "Support for reporting dynamically assigned otf port." if( port == 0 && ret == 0 ) { struct sockaddr_in sinmsg; unsigned int len = sizeof(sinmsg); memset( &sinmsg, 0, len ); if( getsockname( sock->sock, (struct sockaddr *)&sinmsg, &len ) < 0 ) { CK_FPRINTF_STDERR( "[chuck]: %s\n", "unexpected error in getsockname"); } else { CK_FPRINTF_STDERR( "[chuck]: listening on port %ld\n", ntohs(sinmsg.sin_port)); } } return ( ret >= 0 );} //-----------------------------------------------------------------------------// name: ck_listen()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL ck_listen( ck_socket sock, int backlog ){ int ret; if( sock->prot != SOCK_STREAM ) return FALSE; ret = listen( sock->sock, backlog ); return ( ret >= 0 );} //-----------------------------------------------------------------------------// name: ck_accept()// desc: ...//-----------------------------------------------------------------------------ck_socket ck_accept( ck_socket sock ){ ck_socket client; int nd = 1; if( sock->prot != SOCK_STREAM ) return NULL; client = (ck_socket)checked_malloc( sizeof( struct ck_socket_ ) ); client->len = sizeof( client->sock_in ); client->sock = accept( sock->sock, (struct sockaddr *)&client->sock_in, &client->len ); if( client->sock <= 0 ) goto error; client->prot = SOCK_STREAM; setsockopt( client->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&nd, sizeof(nd) ); #ifdef __PLATFORM_WIN32__ g_init++;#endif return client; error: free( client ); return NULL;} //-----------------------------------------------------------------------------// name: ck_send()// desc: send a datagram//-----------------------------------------------------------------------------int ck_send( ck_socket sock, const char * buffer, int len ) { return send( sock->sock, buffer, len, 0 );} //-----------------------------------------------------------------------------// name: ck_send2()// desc: send a datagram//-----------------------------------------------------------------------------int ck_send2( ck_socket sock, const char * buffer, int len ) { return sendto( sock->sock, buffer, len, 0, (struct sockaddr *)&sock->sock_in, sizeof(struct sockaddr_in) );} //-----------------------------------------------------------------------------// name: ck_sendto()// desc: send a datagram//-----------------------------------------------------------------------------int ck_sendto( ck_socket sock, const char * buffer, int len, const struct sockaddr * to, int tolen ) { if( sock->prot == SOCK_STREAM ) return 0; else return sendto( sock->sock, buffer, len, 0, to, tolen );} //-----------------------------------------------------------------------------// name: ck_recvfrom()// desc: recv a datagram//-----------------------------------------------------------------------------int ck_recvfrom( ck_socket sock, char * buffer, int len, struct sockaddr * from, int * fromlen ) { if( sock->prot == SOCK_STREAM ) { memset( buffer, 0, len ); return 0; } else return recvfrom( sock->sock, buffer, len, 0, from, (unsigned int *)fromlen );} //-----------------------------------------------------------------------------// name: ck_recv()// desc: recv a datagram//-----------------------------------------------------------------------------int ck_recv( ck_socket sock, char * buffer, int len ) { if( sock->prot == SOCK_STREAM ) { int ret; int togo = len; char * p = buffer; while( togo > 0 ) { ret = recv( sock->sock, p, togo, 0 ); if( ret < 0 ) return 0; // negative is an error message if( ret == 0 ) return len - togo; // zero is end-of-transmission togo -= ret; p += ret; } return len; } else return recv( sock->sock, buffer, len, 0 );} //-----------------------------------------------------------------------------// name: ck_recv2()// desc: recv a datagram//-----------------------------------------------------------------------------int ck_recv2( ck_socket sock, char * buffer, int len ) { struct sockaddr_in from; unsigned int flen; memset( &from, 0, sizeof(from) ); flen = sizeof(struct sockaddr_in); return recvfrom( sock->sock, buffer, len, 0, (struct sockaddr *)&from, &flen );} //-----------------------------------------------------------------------------// name: ck_send_timeout()// desc: ...//-----------------------------------------------------------------------------int ck_send_timeout( ck_socket sock, long sec, long usec ){ struct timeval t; t.tv_sec = sec; t.tv_usec = usec; return 0 == setsockopt( sock->sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&t, sizeof(t) );} //-----------------------------------------------------------------------------// name: ck_recv_timeout()// desc: ...//-----------------------------------------------------------------------------int ck_recv_timeout( ck_socket sock, long sec, long usec ){ struct timeval t; t.tv_sec = sec; t.tv_usec = usec; return 0 == setsockopt( sock->sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&t, sizeof(t) );} //-----------------------------------------------------------------------------// name: ck_close()// close the socket//-----------------------------------------------------------------------------void ck_close( ck_socket sock ) { if( !sock ) return; #ifdef __PLATFORM_WIN32__ closesocket( sock->sock );#else close( sock->sock );#endif free( sock ); #ifdef __PLATFORM_WIN32__ // uncount g_init--; // close if( g_init == 0 ) WSACleanup();#endif}
/*----------------------------------------------------------------------------
ChucK Concurrent, On-the-fly Audio Programming Language
Compiler and Virtual Machine
Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
http://chuck.cs.princeton.edu/
http://soundlab.cs.princeton.edu/
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
U.S.A.
-----------------------------------------------------------------------------*/
//-----------------------------------------------------------------------------
// name: util_network.c
// desc: sockets
//
// author: Ge Wang (gewang@cs.princeton.edu)
// Perry R. Cook (prc@cs.princeton.edu)
//
// originally randy_socket
// author: Peng Bi (pbi@cs.princeton.edu)
// Ge Wang (gewang@cs.princeton.edu)
// date: Winter 2003
//-----------------------------------------------------------------------------
#include "util_network.h"
#include "chuck_utils.h"
#include "chuck_errmsg.h"
#include <stdio.h>
#if defined(__PLATFORM_WIN32__)
// 2022 QTSIN changed from winsock.h to winsock2.h
#include <winsock2.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifdef __PLATFORM_WIN32__
static WSADATA g_wsd;
static int g_init = 0;
#endif
#ifndef socklen_t
#define socklen_t unsigned int
#endif
//-----------------------------------------------------------------------------
// name: struct ck_socket_
// desc: ...
//-----------------------------------------------------------------------------
struct ck_socket_
{
int sock;
int prot;
struct sockaddr_in sock_in;
socklen_t len;
};
//-----------------------------------------------------------------------------
// name: ck_udp_create()
// desc: create a udp socket
//-----------------------------------------------------------------------------
ck_socket ck_udp_create( )
{
ck_socket sock = NULL;
#ifdef __PLATFORM_WIN32__
// winsock init
if( g_init == 0 )
if( WSAStartup( MAKEWORD(1,1), &(g_wsd) ) != 0 &&
WSAStartup( MAKEWORD(1,0), &(g_wsd) ) != 0 )
{
fprintf( stderr, "[chuck]: cannot start winsock, networking disabled...\n" );
return NULL;
}
// count
g_init++;
#endif
sock = (ck_socket)checked_malloc( sizeof( struct ck_socket_ ) );
sock->sock = socket( AF_INET, SOCK_DGRAM, 0 );
sock->prot = SOCK_DGRAM;
return sock;
}
//-----------------------------------------------------------------------------
// name: ck_tcp_create()
// desc: create a tcp socket
//-----------------------------------------------------------------------------
ck_socket ck_tcp_create( int flags )
{
ck_socket sock = (ck_socket)checked_malloc( sizeof( struct ck_socket_ ) );
int nd = 1; int ru = 1;
#ifdef __PLATFORM_WIN32__
// winsock init
if( g_init == 0 )
if( WSAStartup( MAKEWORD(1,1), &(g_wsd) ) != 0 &&
WSAStartup( MAKEWORD(1,0), &(g_wsd) ) != 0 )
{
fprintf( stderr, "[chuck]: cannot start winsock, networking disabled...\n" );
return NULL;
}
// count
g_init++;
#endif
sock->sock = socket( AF_INET, SOCK_STREAM, 0 );
sock->prot = SOCK_STREAM;
if( flags )
setsockopt( sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&ru, sizeof(ru) );
// setsockopt( sock->sock, SOL_SOCKET, SO_REUSEPORT, (const char *)&ru, sizeof(ru) );
setsockopt( sock->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&nd, sizeof(nd) );
return sock;
}
//-----------------------------------------------------------------------------
// name: ck_connect2()
// desc: connect to a server
//-----------------------------------------------------------------------------
t_CKBOOL ck_connect2( ck_socket sock, const struct sockaddr * addr, int size )
{
int ret = connect( sock->sock, addr, size );
return ( ret >= 0 );
}
//-----------------------------------------------------------------------------
// name: ck_connect()
// desc: connect to a server
//-----------------------------------------------------------------------------
t_CKBOOL ck_connect( ck_socket sock, const char * hostname, int port )
{
t_CKINT ret;
struct hostent * host;
#ifdef __PLATFORM_WIN32__
memset( &sock->sock_in, 0, sizeof(struct sockaddr_in) );
#else
bzero( &sock->sock_in, sizeof(struct sockaddr_in) );
#endif
sock->sock_in.sin_family = AF_INET;
sock->sock_in.sin_port = htons( (unsigned short)abs(port) );
// lookup name
host = gethostbyname( hostname );
if( !host )
{
sock->sock_in.sin_addr.s_addr = inet_addr( hostname );
if( sock->sock_in.sin_addr.s_addr == -1 )
return FALSE;
}
else
{
#if defined( __PLATFORM_WIN32__ ) || defined( __ANDROID__ )
memcpy( (char *)&sock->sock_in.sin_addr, host->h_addr, host->h_length );
#else
bcopy( host->h_addr, (char *)&sock->sock_in.sin_addr, host->h_length );
#endif
}
if( port < 0 )
return TRUE;
ret = ck_connect2( sock, (struct sockaddr *)&sock->sock_in,
sizeof( struct sockaddr_in ) );
return ( ret >= 0 );
}
//-----------------------------------------------------------------------------
// name: ck_bind()
// desc: bind to a port
//-----------------------------------------------------------------------------
t_CKBOOL ck_bind( ck_socket sock, int port )
{
int ret;
#ifdef __PLATFORM_WIN32__
memset( &sock->sock_in, 0, sizeof(struct sockaddr_in) );
#else
bzero( &sock->sock_in, sizeof(struct sockaddr_in) );
#endif
sock->sock_in.sin_family = AF_INET;
sock->sock_in.sin_port = htons( (unsigned short)port );
sock->sock_in.sin_addr.s_addr = htonl( INADDR_ANY );
ret = bind( sock->sock, (struct sockaddr *)&sock->sock_in,
sizeof(struct sockaddr_in));
// added 1.4.1.0 (PR #157 | @dbadb)
// "Support for reporting dynamically assigned otf port."
if( port == 0 && ret == 0 )
{
struct sockaddr_in sinmsg;
unsigned int len = sizeof(sinmsg);
memset( &sinmsg, 0, len );
if( getsockname( sock->sock, (struct sockaddr *)&sinmsg, &len ) < 0 )
{
CK_FPRINTF_STDERR( "[chuck]: %s\n",
"unexpected error in getsockname");
}
else
{
CK_FPRINTF_STDERR( "[chuck]: listening on port %ld\n",
ntohs(sinmsg.sin_port));
}
}
return ( ret >= 0 );
}
//-----------------------------------------------------------------------------
// name: ck_listen()
// desc: ...
//-----------------------------------------------------------------------------
t_CKBOOL ck_listen( ck_socket sock, int backlog )
{
int ret;
if( sock->prot != SOCK_STREAM ) return FALSE;
ret = listen( sock->sock, backlog );
return ( ret >= 0 );
}
//-----------------------------------------------------------------------------
// name: ck_accept()
// desc: ...
//-----------------------------------------------------------------------------
ck_socket ck_accept( ck_socket sock )
{
ck_socket client;
int nd = 1;
if( sock->prot != SOCK_STREAM ) return NULL;
client = (ck_socket)checked_malloc( sizeof( struct ck_socket_ ) );
client->len = sizeof( client->sock_in );
client->sock = accept( sock->sock, (struct sockaddr *)&client->sock_in,
&client->len );
if( client->sock <= 0 ) goto error;
client->prot = SOCK_STREAM;
setsockopt( client->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&nd, sizeof(nd) );
#ifdef __PLATFORM_WIN32__
g_init++;
#endif
return client;
error:
free( client );
return NULL;
}
//-----------------------------------------------------------------------------
// name: ck_send()
// desc: send a datagram
//-----------------------------------------------------------------------------
int ck_send( ck_socket sock, const char * buffer, int len )
{
return send( sock->sock, buffer, len, 0 );
}
//-----------------------------------------------------------------------------
// name: ck_send2()
// desc: send a datagram
//-----------------------------------------------------------------------------
int ck_send2( ck_socket sock, const char * buffer, int len )
{
return sendto( sock->sock, buffer, len, 0,
(struct sockaddr *)&sock->sock_in, sizeof(struct sockaddr_in) );
}
//-----------------------------------------------------------------------------
// name: ck_sendto()
// desc: send a datagram
//-----------------------------------------------------------------------------
int ck_sendto( ck_socket sock, const char * buffer, int len,
const struct sockaddr * to, int tolen )
{
if( sock->prot == SOCK_STREAM ) return 0;
else return sendto( sock->sock, buffer, len, 0, to, tolen );
}
//-----------------------------------------------------------------------------
// name: ck_recvfrom()
// desc: recv a datagram
//-----------------------------------------------------------------------------
int ck_recvfrom( ck_socket sock, char * buffer, int len,
struct sockaddr * from, int * fromlen )
{
if( sock->prot == SOCK_STREAM )
{
memset( buffer, 0, len );
return 0;
}
else return recvfrom( sock->sock, buffer, len, 0, from, (unsigned int *)fromlen );
}
//-----------------------------------------------------------------------------
// name: ck_recv()
// desc: recv a datagram
//-----------------------------------------------------------------------------
int ck_recv( ck_socket sock, char * buffer, int len )
{
if( sock->prot == SOCK_STREAM )
{
int ret;
int togo = len;
char * p = buffer;
while( togo > 0 )
{
ret = recv( sock->sock, p, togo, 0 );
if( ret < 0 ) return 0; // negative is an error message
if( ret == 0 ) return len - togo; // zero is end-of-transmission
togo -= ret;
p += ret;
}
return len;
}
else return recv( sock->sock, buffer, len, 0 );
}
//-----------------------------------------------------------------------------
// name: ck_recv2()
// desc: recv a datagram
//-----------------------------------------------------------------------------
int ck_recv2( ck_socket sock, char * buffer, int len )
{
struct sockaddr_in from;
unsigned int flen;
memset( &from, 0, sizeof(from) );
flen = sizeof(struct sockaddr_in);
return recvfrom( sock->sock, buffer, len, 0, (struct sockaddr *)&from, &flen );
}
//-----------------------------------------------------------------------------
// name: ck_send_timeout()
// desc: ...
//-----------------------------------------------------------------------------
int ck_send_timeout( ck_socket sock, long sec, long usec )
{
struct timeval t;
t.tv_sec = sec;
t.tv_usec = usec;
return 0 == setsockopt( sock->sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&t, sizeof(t) );
}
//-----------------------------------------------------------------------------
// name: ck_recv_timeout()
// desc: ...
//-----------------------------------------------------------------------------
int ck_recv_timeout( ck_socket sock, long sec, long usec )
{
struct timeval t;
t.tv_sec = sec;
t.tv_usec = usec;
return 0 == setsockopt( sock->sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&t, sizeof(t) );
}
//-----------------------------------------------------------------------------
// name: ck_close()
// close the socket
//-----------------------------------------------------------------------------
void ck_close( ck_socket sock )
{
if( !sock ) return;
#ifdef __PLATFORM_WIN32__
closesocket( sock->sock );
#else
close( sock->sock );
#endif
free( sock );
#ifdef __PLATFORM_WIN32__
// uncount
g_init--;
// close
if( g_init == 0 ) WSACleanup();
#endif
}