Skip to content

Commit 60fd6e6

Browse files
[[ SocketLocalPort ]] Added the ability to specify the local host and port when
opening a new socket. Updated the parsing of open socket so that it now accepts the following form: open socket [from [<local host>][:<local port>]] to <host>[:<port>] Reworked the name to sockaddr parsing into: - name to host and port - host and port to sockaddr Name to sockaddr now calls name to host and port and then host and port to sockaddr. The reworked name to sockaddr parsing is used to parse any local from details in MCS_connect_socket: It checks to see if any local host or port has been passed. If no local host has been passed, then we use, if set, the networkinterface property. It then binds the socket to any found local host and port.
1 parent 7d11a79 commit 60fd6e6

10 files changed

Lines changed: 231 additions & 110 deletions

File tree

engine/src/cmds.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,6 +1530,7 @@ class MCOpen : public MCStatement
15301530

15311531
// MM-2014-06-13: [[ Bug 12567 ]] Added new "open socket <socket> with verification for <host>" variant.
15321532
MCExpression *verifyhostname;
1533+
MCExpression *fromaddress;
15331534
public:
15341535
MCOpen()
15351536
{
@@ -1545,6 +1546,7 @@ class MCOpen : public MCStatement
15451546
elevated = False;
15461547
textmode = True;
15471548
verifyhostname = NULL;
1549+
fromaddress = NULL;
15481550
}
15491551
virtual ~MCOpen();
15501552
virtual Parse_stat parse(MCScriptPoint &);

engine/src/cmdsf.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,6 +1816,7 @@ MCOpen::~MCOpen()
18161816
MCValueRelease(destination);
18171817
delete certificate;
18181818
delete verifyhostname;
1819+
delete fromaddress;
18191820
}
18201821

18211822
Parse_stat MCOpen::parse(MCScriptPoint &sp)
@@ -1894,6 +1895,14 @@ Parse_stat MCOpen::parse(MCScriptPoint &sp)
18941895
}
18951896
return PS_NORMAL;
18961897
}
1898+
if (arg == OA_SOCKET && sp.skip_token(SP_FACTOR, TT_FROM, PT_FROM) == PS_NORMAL)
1899+
{
1900+
if (sp.parseexp(False, True, &fromaddress) != PS_NORMAL)
1901+
{
1902+
MCperror->add(PE_OPEN_NOFROM, sp);
1903+
return PS_ERROR;
1904+
}
1905+
}
18971906
sp.skip_token(SP_FACTOR, TT_TO, PT_TO);
18981907
if (sp.parseexp(False, True, &fname) != PS_NORMAL)
18991908
{
@@ -2131,17 +2140,21 @@ void MCOpen::exec_ctxt(MCExecContext &ctxt)
21312140
if (!ctxt . EvalOptionalExprAsNullableNameRef(message, EE_OPEN_BADMESSAGE, &t_message_name))
21322141
return;
21332142

2143+
MCNewAutoNameRef t_from_address;
2144+
if (!ctxt . EvalOptionalExprAsNameRef(fromaddress, kMCEmptyName, EE_OPEN_BADFROMADDRESS, &t_from_address))
2145+
return;
2146+
21342147
// MM-2014-06-13: [[ Bug 12567 ]] Added support for specifying an end host name to verify against.
21352148
MCNewAutoNameRef t_end_hostname;
21362149
if (!ctxt . EvalOptionalExprAsNameRef(verifyhostname, kMCEmptyName, EE_OPEN_BADHOST, &t_end_hostname))
21372150
return;
21382151

21392152
if (datagram)
2140-
MCNetworkExecOpenDatagramSocket(ctxt, *t_name, *t_message_name, *t_end_hostname);
2153+
MCNetworkExecOpenDatagramSocket(ctxt, *t_name, *t_from_address, *t_message_name, *t_end_hostname);
21412154
else if (secure)
2142-
MCNetworkExecOpenSecureSocket(ctxt, *t_name, *t_message_name, *t_end_hostname, secureverify);
2155+
MCNetworkExecOpenSecureSocket(ctxt, *t_name, *t_from_address, *t_message_name, *t_end_hostname, secureverify);
21432156
else
2144-
MCNetworkExecOpenSocket(ctxt, *t_name, *t_message_name, *t_end_hostname);
2157+
MCNetworkExecOpenSocket(ctxt, *t_name, *t_from_address, *t_message_name, *t_end_hostname);
21452158
break;
21462159
}
21472160
default:

engine/src/exec-network.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ MC_EXEC_DEFINE_EXEC_METHOD(Network, CloseSocket, 1)
5454
MC_EXEC_DEFINE_EXEC_METHOD(Network, DeleteUrl, 1)
5555
MC_EXEC_DEFINE_EXEC_METHOD(Network, LoadUrl, 2)
5656
MC_EXEC_DEFINE_EXEC_METHOD(Network, UnloadUrl, 1)
57-
MC_EXEC_DEFINE_EXEC_METHOD(Network, OpenSocket, 3)
58-
MC_EXEC_DEFINE_EXEC_METHOD(Network, OpenSecureSocket, 4)
59-
MC_EXEC_DEFINE_EXEC_METHOD(Network, OpenDatagramSocket, 3)
57+
MC_EXEC_DEFINE_EXEC_METHOD(Network, OpenSocket, 4)
58+
MC_EXEC_DEFINE_EXEC_METHOD(Network, OpenSecureSocket, 5)
59+
MC_EXEC_DEFINE_EXEC_METHOD(Network, OpenDatagramSocket, 4)
6060
MC_EXEC_DEFINE_EXEC_METHOD(Network, PostToUrl, 2)
6161
MC_EXEC_DEFINE_EXEC_METHOD(Network, AcceptConnectionsOnPort, 2)
6262
MC_EXEC_DEFINE_EXEC_METHOD(Network, AcceptDatagramConnectionsOnPort, 2)
@@ -547,7 +547,7 @@ void MCNetworkExecDeleteUrl(MCExecContext& ctxt, MCStringRef p_target)
547547

548548
////////////////////////////////////////////////////////////////////////////////
549549

550-
void MCNetworkExecPerformOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, bool p_datagram, bool p_secure, bool p_ssl, MCNameRef p_end_hostname)
550+
void MCNetworkExecPerformOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, bool p_datagram, bool p_secure, bool p_ssl, MCNameRef p_end_hostname)
551551
{
552552
if (!ctxt . EnsureNetworkAccessIsAllowed() && !MCModeCanAccessDomain(MCNameGetString(p_name)))
553553
return;
@@ -563,24 +563,24 @@ void MCNetworkExecPerformOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNam
563563
MCresult -> clear();
564564

565565
// MM-2014-06-13: [[ Bug 12567 ]] Added support for specifying an end host name to verify against.
566-
MCSocket *s = MCS_open_socket(p_name, p_datagram, ctxt . GetObject(), p_message, p_secure, p_ssl, kMCEmptyString, p_end_hostname);
566+
MCSocket *s = MCS_open_socket(p_name, p_from_address, p_datagram, ctxt . GetObject(), p_message, p_secure, p_ssl, kMCEmptyString, p_end_hostname);
567567
if (s != NULL)
568568
MCSocketsAppendToSocketList(s);
569569
}
570570

571-
void MCNetworkExecOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, MCNameRef p_end_hostname)
571+
void MCNetworkExecOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, MCNameRef p_end_hostname)
572572
{
573-
MCNetworkExecPerformOpenSocket(ctxt, p_name, p_message, false, false, false, p_end_hostname);
573+
MCNetworkExecPerformOpenSocket(ctxt, p_name, p_from_address, p_message, false, false, false, p_end_hostname);
574574
}
575575

576-
void MCNetworkExecOpenSecureSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, MCNameRef p_end_hostname, bool p_with_verification)
576+
void MCNetworkExecOpenSecureSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, MCNameRef p_end_hostname, bool p_with_verification)
577577
{
578-
MCNetworkExecPerformOpenSocket(ctxt, p_name, p_message, false, true, p_with_verification, p_end_hostname);
578+
MCNetworkExecPerformOpenSocket(ctxt, p_name, p_from_address, p_message, false, true, p_with_verification, p_end_hostname);
579579
}
580580

581-
void MCNetworkExecOpenDatagramSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, MCNameRef p_end_hostname)
581+
void MCNetworkExecOpenDatagramSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, MCNameRef p_end_hostname)
582582
{
583-
MCNetworkExecPerformOpenSocket(ctxt, p_name, p_message, true, false, false, p_end_hostname);
583+
MCNetworkExecPerformOpenSocket(ctxt, p_name, p_from_address, p_message, true, false, false, p_end_hostname);
584584
}
585585

586586
////////////////////////////////////////////////////////////////////////////////

engine/src/exec.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4440,9 +4440,9 @@ void MCNetworkExecDeleteUrl(MCExecContext& ctxt, MCStringRef p_target);
44404440
void MCNetworkExecLoadUrl(MCExecContext& ctxt, MCStringRef p_url, MCNameRef p_message);
44414441
void MCNetworkExecUnloadUrl(MCExecContext& ctxt, MCStringRef p_url);
44424442

4443-
void MCNetworkExecOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, MCNameRef p_end_hostname);
4444-
void MCNetworkExecOpenSecureSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, MCNameRef p_end_hostname, bool p_with_verification);
4445-
void MCNetworkExecOpenDatagramSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_message, MCNameRef p_end_hostname);
4443+
void MCNetworkExecOpenSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, MCNameRef p_end_hostname);
4444+
void MCNetworkExecOpenSecureSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, MCNameRef p_end_hostname, bool p_with_verification);
4445+
void MCNetworkExecOpenDatagramSocket(MCExecContext& ctxt, MCNameRef p_name, MCNameRef p_from_address, MCNameRef p_message, MCNameRef p_end_hostname);
44464446

44474447
void MCNetworkExecPostToUrl(MCExecContext& ctxt, MCValueRef p_data, MCStringRef p_url);
44484448

engine/src/executionerrors.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,6 +2737,9 @@ enum Exec_errors
27372737

27382738
// {EE-0896} call: type conversion error
27392739
EE_INVOKE_TYPEERROR,
2740+
2741+
// {EE-0897} open: error in from address expression
2742+
EE_OPEN_BADFROMADDRESS,
27402743
};
27412744

27422745
extern const char *MCexecutionerrors;

engine/src/opensslsocket.cpp

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -655,29 +655,76 @@ bool MCS_connect_socket(MCSocket *p_socket, struct sockaddr_in *p_addr)
655655
if (p_socket != NULL && p_socket->fd != 0)
656656
{
657657

658-
// MM-2011-07-07: Added support for binding sockets to a network interface.
659-
if (MCdefaultnetworkinterface != NULL)
660-
{
661-
struct sockaddr_in t_bind_addr;
662-
MCAutoStringRef MCdefaultnetworkinterface_string;
663-
/* UNCHECKED */ MCStringCreateWithCString(MCdefaultnetworkinterface, &MCdefaultnetworkinterface_string);
664-
if (!MCS_name_to_sockaddr(*MCdefaultnetworkinterface_string, t_bind_addr))
665-
{
666-
p_socket->error = strclone("can't resolve network interface");
667-
p_socket->doclose();
668-
return false;
669-
}
670-
671-
t_bind_addr.sin_port = 0;
672-
673-
if (0 != bind(p_socket->fd, (struct sockaddr *)&t_bind_addr, sizeof(struct sockaddr_in)))
674-
{
675-
p_socket->error = strclone("can't bind to network interface address");
676-
p_socket->doclose();
677-
return false;
678-
}
679-
}
680-
658+
// check to see if a local host or port has been passed and if so, attempt to bind
659+
// if no local host has been passed then, if set, use the network interface
660+
MCAutoStringRef t_from_host;
661+
MCAutoNumberRef t_from_port;
662+
if (!MCValueIsEmpty(p_socket->from))
663+
{
664+
if (!MCS_name_to_host_and_port(MCNameGetString(p_socket->from), &t_from_host, &t_from_port))
665+
{
666+
p_socket->error = strclone("error parsing the local host and port");
667+
p_socket->doclose();
668+
return false;
669+
}
670+
}
671+
if (!t_from_host.IsSet() && MCdefaultnetworkinterface != NULL)
672+
{
673+
if (!MCStringCreateWithCString(MCdefaultnetworkinterface, &t_from_host))
674+
{
675+
p_socket->error = strclone("error parsing the network interface address");
676+
p_socket->doclose();
677+
return false;
678+
}
679+
}
680+
681+
if (t_from_host.IsSet() || t_from_port.IsSet())
682+
{
683+
// the 0 defaults tell the OS to choose any avaliable host or port
684+
if (!t_from_host.IsSet())
685+
{
686+
if (!MCStringCreateWithCString("0.0.0.0", &t_from_host))
687+
{
688+
p_socket->error = strclone("error setting the default local host");
689+
p_socket->doclose();
690+
return false;
691+
}
692+
}
693+
else if (!t_from_port.IsSet())
694+
{
695+
if (!MCNumberCreateWithUnsignedInteger(0, &t_from_port))
696+
{
697+
p_socket->error = strclone("error setting the default local port");
698+
p_socket->doclose();
699+
return false;
700+
}
701+
}
702+
703+
struct sockaddr_in t_bind_addr;
704+
if (!MCS_host_and_port_to_sockaddr(*t_from_host, *t_from_port, t_bind_addr))
705+
{
706+
p_socket->error = strclone("can't resolve local host and port");
707+
p_socket->doclose();
708+
return false;
709+
}
710+
711+
// setting the SO_REUSEPORT option allows the same local port to be used to connect to multiple hosts
712+
int t_port_reuse = 1;
713+
if (setsockopt(p_socket->fd, SOL_SOCKET, SO_REUSEPORT, (const char *)&t_port_reuse, sizeof(t_port_reuse)) != 0)
714+
{
715+
p_socket->error = strclone("can't use the local port");
716+
p_socket->doclose();
717+
return false;
718+
}
719+
720+
if (bind(p_socket->fd, (struct sockaddr *)&t_bind_addr, sizeof(struct sockaddr_in)) != 0)
721+
{
722+
p_socket->error = strclone("can't bind to local host and port");
723+
p_socket->doclose();
724+
return false;
725+
}
726+
}
727+
681728
p_socket->setselect();
682729

683730
#if defined(_WINDOWS_DESKTOP) || defined(_WINDOWS_SERVER)
@@ -738,7 +785,7 @@ bool open_socket_resolve_callback(void *p_context, bool p_resolved, bool p_final
738785
}
739786

740787
// MM-2014-06-13: [[ Bug 12567 ]] Added support for specifying an end host name to verify against.
741-
MCSocket *MCS_open_socket(MCNameRef name, Boolean datagram, MCObject *o, MCNameRef mess, Boolean secure, Boolean sslverify, MCStringRef sslcertfile, MCNameRef hostname)
788+
MCSocket *MCS_open_socket(MCNameRef name, MCNameRef from, Boolean datagram, MCObject *o, MCNameRef mess, Boolean secure, Boolean sslverify, MCStringRef sslcertfile, MCNameRef hostname)
742789
{
743790
if (!MCS_init_sockets())
744791
return NULL;
@@ -775,7 +822,7 @@ MCSocket *MCS_open_socket(MCNameRef name, Boolean datagram, MCObject *o, MCNameR
775822
MCS_socket_ioctl(sock, FIONBIO, on);
776823

777824
MCSocket *s = NULL;
778-
s = (MCSocket *)new MCSocket(name, o, mess, datagram, sock, False, False,secure);
825+
s = (MCSocket *)new MCSocket(name, from, o, mess, datagram, sock, False, False,secure);
779826

780827
if (s != NULL)
781828
{
@@ -1137,7 +1184,7 @@ MCSocket *MCS_accept(uint2 port, MCObject *object, MCNameRef message, Boolean da
11371184
if (!MCNameCreateWithNativeChars(*t_port_chars, t_length, &t_portname))
11381185
return nil;
11391186

1140-
return new MCSocket(*t_portname, object, message, datagram, sock, True, False, secure);
1187+
return new MCSocket(*t_portname, NULL, object, message, datagram, sock, True, False, secure);
11411188
}
11421189

11431190
// MM-2014-02-12: [[ SecureSocket ]] New secure socket command. If socket is not already secure, flag as secure to ensure future communications are encrypted.
@@ -1337,7 +1384,7 @@ MCSocketwrite::~MCSocketwrite()
13371384

13381385
////////////////////////////////////////////////////////////////////////////////
13391386

1340-
MCSocket::MCSocket(MCNameRef n, MCObject *o, MCNameRef m, Boolean d, MCSocketHandle sock, Boolean a, Boolean s, Boolean issecure)
1387+
MCSocket::MCSocket(MCNameRef n, MCNameRef f, MCObject *o, MCNameRef m, Boolean d, MCSocketHandle sock, Boolean a, Boolean s, Boolean issecure)
13411388
{
13421389
name = MCValueRetain(n);
13431390
object = o;
@@ -1366,6 +1413,7 @@ MCSocket::MCSocket(MCNameRef n, MCObject *o, MCNameRef m, Boolean d, MCSocketHan
13661413

13671414
// MM-2014-06-13: [[ Bug 12567 ]] Added support for specifying an end host name to verify against.
13681415
endhostname = MCValueRetain(kMCEmptyName);
1416+
from = MCValueRetain(f);
13691417
}
13701418

13711419
MCSocket::~MCSocket()
@@ -1379,6 +1427,7 @@ MCSocket::~MCSocket()
13791427

13801428
// MM-2014-06-13: [[ Bug 12567 ]] Added support for specifying an end host name to verify against.
13811429
MCValueRelease(endhostname);
1430+
MCValueRelease(from);
13821431
}
13831432

13841433
void MCSocket::deletereads()
@@ -1546,7 +1595,7 @@ void MCSocket::readsome()
15461595
if (accepting && !IO_findsocket(*t_name, index))
15471596
{
15481597
MCSocket *t_socket;
1549-
t_socket = new (nothrow) MCSocket(*t_name, object, NULL, True, fd, False, True,False);
1598+
t_socket = new (nothrow) MCSocket(*t_name, NULL, object, NULL, True, fd, False, True,False);
15501599
if (t_socket != NULL)
15511600
MCSocketsAppendToSocketList(t_socket);
15521601
}
@@ -1590,7 +1639,7 @@ void MCSocket::readsome()
15901639
/* UNCHECKED */ MCStringFormat(&n, "%s:%d", t, MCSwapInt16NetworkToHost(addr.sin_port));
15911640
/* UNCHECKED */ MCNameCreate(*n, &t_name);
15921641
MCSocket *t_socket;
1593-
t_socket = new (nothrow) MCSocket(*t_name, object, NULL, False, newfd, False, False,secure);
1642+
t_socket = new (nothrow) MCSocket(*t_name, NULL, object, NULL, False, newfd, False, False,secure);
15941643
if (t_socket != NULL)
15951644
{
15961645
MCSocketsAppendToSocketList(t_socket);

engine/src/osspec.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ extern void MCS_setplayloudness(uint2 p_loudness);
187187

188188
extern bool MCS_init_sockets();
189189
extern bool MCS_compare_host_domain(MCStringRef p_host_a, MCStringRef p_host_b);
190-
extern MCSocket *MCS_open_socket(MCNameRef name, Boolean datagram, MCObject *o, MCNameRef m, Boolean secure, Boolean sslverify, MCStringRef sslcertfile, MCNameRef p_end_hostname);
190+
extern MCSocket *MCS_open_socket(MCNameRef name, MCNameRef from, Boolean datagram, MCObject *o, MCNameRef m, Boolean secure, Boolean sslverify, MCStringRef sslcertfile, MCNameRef p_end_hostname);
191191
extern void MCS_close_socket(MCSocket *s);
192192
extern MCDataRef MCS_read_socket(MCSocket *s, MCExecContext &ctxt, uint4 length, const char *until, MCNameRef m);
193193
extern void MCS_write_socket(const MCStringRef d, MCSocket *s, MCObject *optr, MCNameRef m);

engine/src/parseerrors.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,9 @@ enum Parse_errors
17741774

17751775
// {PE-0574} folders: bad folder expression
17761776
PE_FOLDERS_BADPARAM,
1777+
1778+
// {PE-0575} open: expected 'from' address
1779+
PE_OPEN_NOFROM,
17771780
};
17781781

17791782
extern const char *MCparsingerrors;

engine/src/socket.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ class MCSocket
142142
MCSocketHandle fd;
143143
// MM-2014-06-13: [[ Bug 12567 ]] Added support for specifying an end host name to verify against.
144144
MCNameRef endhostname;
145+
MCNameRef from;
145146

146-
MCSocket(MCNameRef n, MCObject *o, MCNameRef m, Boolean d, MCSocketHandle sock, Boolean a, Boolean s, Boolean issecure);
147+
MCSocket(MCNameRef n, MCNameRef f, MCObject *o, MCNameRef m, Boolean d, MCSocketHandle sock, Boolean a, Boolean s, Boolean issecure);
147148

148149
void setselect();
149150
void setselect(uint2 sflags);
@@ -209,6 +210,9 @@ bool MCS_name_to_sockaddr(MCStringRef p_name_in, struct sockaddr_in *r_addr,
209210

210211
bool MCS_name_to_sockaddr(MCStringRef p_name, struct sockaddr_in &r_addr);
211212

213+
bool MCS_name_to_host_and_port(MCStringRef p_name, MCStringRef &r_host, MCNumberRef &r_port);
214+
bool MCS_host_and_port_to_sockaddr(MCStringRef p_host, MCNumberRef p_port, struct sockaddr_in *r_addr, MCHostNameResolveCallback p_callback, void *p_context);
215+
bool MCS_host_and_port_to_sockaddr(MCStringRef p_host, MCNumberRef p_port, struct sockaddr_in &r_addr);
212216

213217

214218
bool addrinfo_lookup(const char *p_name, const char *p_port, int p_socktype, struct addrinfo *&r_addrinfo);

0 commit comments

Comments
 (0)