Return to Smalltalk Networking
Return to P1 Systems Homepage
Sockets/V provides a high-level interface to the industry-standard Windows Sockets interface, allowing TCP/IP communications to take place between cooperating Visual Smalltalk applications or between a Visual Smalltalk application and another TCP/IP-speaking application. Sockets/V provides the recommended asynchronous interface to the TCP/IP stack, allowing other activities to take place both within the Visual Smalltalk application and within Windows while your program is waiting for response from the network.
Datagram- and Stream-type sockets are provided, corresponding to the standard TCP and UDP protocols, as well as a MessageSocket class which provides datagram service over a stream connection and an ObjectSocket class which allows passing objects over a stream connection.
Access to name services is provided using the standard Windows Sockets asynchronous interface.
All defined error codes together with English descriptions are provided in the WinSockErrorMessages dictionary, allowing applications to provide meaningful error messages with minimal effort.
The following classes are provided in Sockets/V: Socket, DatagramSocket, StreamSocket, LineAtATimeSocket, MessageSocket, StringSocket, ObjectSocket, and NetworkMessage.
Introduction to Sockets Communication
Sample Programs
Socket
DatagramSocket
StreamSocket
LineAtATimeSocket
MessageSocket
ObjectSocket
StringSocket
NetworkMessage
ErrorCodes
Development & Runtime Files
Ordering Information
License Agreement
Sockets/V
Version 1.1
Copyright (c) 1995,1998 P1 Systems Incorporated.
All Rights Reserved.
The sample programs MsgSocketTestApp, DgramSocketTestApp, and ObjSocketTestApp are included in your Sockets/V distribution. The applications can play the role of client or server, or both. MsgSocketTestApp uses MessageSocket connections to pass messages, while DgramSocketTestApp uses DatagramSockets, and ObjSocketTestApp uses ObjectSockets
Operation of the test programs is straightforward. The Startup button is pressed, followed by the Server button if the instance of the program is to be a server, otherwise the Client button is pressed. The Server should be initialized before the client. The Test button of the client causes the client to send the string 'Testing 1, 2, 3...' to the server. The server, upon receiving the string, echoes it back to the client. The Cleanup button should be pressed before terminating the applications. Network activity is displayed in the list box contained in the applications' windows.
Note that MsgSocketTestApp cannot communicate with DgramSocketTestApp or ObjSocketTestApp. The test applications can only communicate with other instances of themselves. Note also that a single instance of the application can act as both client and server simultaneously, sending messages to and receiving messages from itself.
The source code to the MsgSocketTestApp is presented below. (The methods have been re-ordered so that they are presented roughly in the order in which they would be executed.) MsgSocketTestApp is invoked with MsgSocketTestApp new open.
ViewManager subclass: #MsgSocketTestApp
instanceVariableNames:' serverAddr skt0 skt1 serverHostName localHostName serverPort serviceName
listBox' classVariableNames: ''
poolDictionaries: ' ColorConstants WinConstants WinSockConstants'
The open method starts the application. It assigns the host and service names (actually the address and
number, respectively, in this case) and goes through the process of setting up the application window. 
open
"Answer self. Create the app views."
| btnStartup btnTest btnCleanup topPane |
self addView: ((topPane := TopPane new)
framingBlock: [ :box | 20 @ 20 corner: 500 @ 300
]; owner: self;
labelWithoutPrefix: 'Stream Sockets Test';
backColor: ClrLightgray;
when: #close perform: #close:).
topPane addSubpane: ((listBox := LoggingPane new)
framingBlock: [ :box |
box leftTop + ( 12 @ 12) corner: box rightBottom - (98 @ 12)
]; owner: self).
topPane addSubpane: ((btnTest := Button new)
contents: 'Startup';
font: SysFont;
framingBlock: [ :box |
box rightTop - ( 92 @ (-12) ) corner:
box rightTop - ( 12 @ (-40) )];
owner: self;
when: #clicked perform: #startup:).
topPane addSubpane: ((btnTest := Button new)
contents: 'Server';
font: SysFont;
framingBlock: [ :box |
box rightTop - ( 92 @ (-46) ) corner:
box rightTop - ( 12 @ (-74) )];
owner: self;
when: #clicked perform: #server:).
topPane addSubpane: ((btnTest := Button new)
contents: 'Client';
font: SysFont;
framingBlock: [ :box |
box rightTop - ( 92 @ (-80) ) corner:
box rightTop - ( 12 @ (-108) )];
owner: self;
when: #clicked perform: #client:).
topPane addSubpane: ((btnCleanup := Button new)
contents: 'Canleup';
font: SysFont;
framingBlock: [ :box |
box rightTop - ( 92 @ (-114) ) corner:
box rightTop - ( 12 @ (-142) )];
owner: self;
when: #clicked perform: #cleanup:).
topPane addSubpane: ((btnCleanup := Button new)
contents: 'Test';
font: SysFont;
framingBlock: [ :box |
box rightTop - ( 92 @ (-148) ) corner:
box rightTop - ( 12 @ (-176) )];
owner: self;
when: #clicked perform: #test:).
self when: #close perform: #close:.
self openWindow.
^self
The startup method is invoked by the Startup button. It displays the Windows Sockets vendor-supplied
information string in a message box like the one shown here (via startupShowInfo) and translates the local host
name to an address string. 
startup: ignored
Socket startupShowInfo.
localHostName := Socket hostName.
Socket
onHostAddrFor: localHostName
evaluate:
[ :name :addr |
listBox insertItem: 'Local host: ', localHostName, '(', addr,
')' ]
error:
[ :err |
Socket
errorBox: 'Error obtaining host address for ',localHostName,':
' socket: err
].
^self
The server method is invoked by the Server button. It solicits a port number to listen on from the user, creates a new MessageSocket and listens for connections, and for each connection it accepts, establishes a block for received messages which simply echoes the message back to the sender.
server: ignored
"Answer self. Set up echo server."
serverPort := Prompter
prompt: 'Service port number to listen on'
default: '6001'.
serverPort = nil
ifTrue: [ ^nil ].
skt0 := MessageSocket new.
skt0
listenOn: serverPort
onAcceptEvaluate:
[ :skt |
skt onNameEvaluate:
[ :name |
listBox insertItem: 'Server: connected to
',name,'.'. skt
onReadEvaluate:
[ :netMsg :skt |
listBox insertItem: 'Server: ',(netMsg at: 1). skt write: netMsg
]
error: nil.
]
]
error: nil.
^self
The client method is invoked when the Client button is pressed. A series of nested blocks performs the following steps after obtaining the host name (or address) and the service name (or port number) from the user: the host address is obtained., a MessageSocket is created and bound, the server port number is obtained, a connection is attempted with the server, and the clientRead:skt: message is established as the message to be sent upon receipt of a message. Error checking is performed for each step by the error: blocks.
client: ignored
"Answer self. Set up client."
serverHostName := Prompter
prompt: 'Server Host Name (or address) to connect
to' default: localHostName.
serverHostName = nil
ifTrue: [ ^nil ].
serviceName := Prompter
prompt: 'Service Name (or port number) to connect to'
default: '6001'.
serviceName = nil ifTrue: [ ^nil].
serverAddr := nil.
Socket
onHostAddrFor: serverHostName
evaluate:
[:name :addr |
serverAddr := addr.
skt1 := MessageSocket new.
Socket
onServicePortFor: serviceName
evaluate:
[ :name :port |
serverPort := port.
skt1
connect: serverAddr
port: serverPort
evaluate:
[ :skt |
skt
onNameEvaluate:
[ :name |
listBox insertItem: 'Client: connected to ', name,'.'
].
skt1
onReadSend: #clientRead:skt:
to: self
error: nil.
]
error: nil
]
error: nil
]
error: nil.
^self
The clientRead:skt: method handles incoming messages. They are displayed in the listbox.
clientRead: netMsg skt: skt
"Answer nil. Handle incoming reads."
listBox insertItem: 'Client: ',(netMsg at: 1).
^nil
The test method, only functional for properly initialized clients, simply sends a test message on the connected socket.
test: aPane
"The test event has been signaled."
skt1
write: (NetworkMessage with:
(Prompter prompt: 'Text to send' default: 'Testing 1, 2, 3...')). ^nil
The cleanup method clears the listbox, closes all the sockets, and sends Socket>>cleanup.
cleanup: ignored
"Cleanup the Windows Sockets session."
| resultCode count |
listBox deleteAll.
Socket socketList do: [ :each |
each close ].
Socket cleanup.
^self
The close method simply invokes cleanup in case it hasn't been done yet.
close: ignored
"Close down the
application." | answer |
Smalltalk isRunTime
ifTrue:
[
(MessageBox confirm: 'Are you sure you want to exit?')
ifTrue:
[
self cleanup: nil.
self close.
^Smalltalk exit
]
ifFalse:
[
^self
]
].
^super close
The basic building block for communication is the socket. A socket is an endpoint of communication to which a name may be bound. Each socket in use has a type and an associated process or program. Sockets exist within communication domains. A communication domain is an abstraction introduced to bundle common properties of threads communicating through sockets. Sockets normally exchange data only with sockets in the same domain (it may be possible to cross domain boundaries, but only if some translation process is performed). The Windows Sockets facilities support a single communication domain: the Internet domain, which is used by processes which communicate using the Internet Protocol Suite.
Two basic types of sockets are available to a user. A stream socket provides for the bi-directional, reliable, sequenced, and unduplicated flow of data without record boundaries. A datagram socket supports bi-directional flow of data which is not promised to be sequenced, reliable, or unduplicated. That is, a process receiving messages on a datagram socket may find messages duplicated, and possibly, in an order different from the order in which it was sent. An important characteristic of a datagram socket is that record boundaries in data are preserved. Datagram sockets closely model the facilities found in many contemporary packet switched networks such as Ethernet.
Instances of the MessageSocket class provided by Sockets/V support record-oriented communication over a stream connection, thus providing bi- directional, reliable, sequenced, and unduplicated data flow while preserving record boundaries. Message sockets also allow dispatching of received messages based on the contents of a particular element of the message.
The LineAtATimeSocket class provided by Sockets/V is specially designed to simplify processing of Internet protocols such as FTP (File Transfer Protocol), SMTP (Simple Mail Transfer Protocol), and POP3 (Post Office Protocol version 3). LineAtATimeSockets deliver records from a TCP Stream connection delimited by carriage returns or carriage return-line feed pairs.
The StringSocket class provided by Sockets/V is a specialization of MessageSocket which allows sending strings between Sockets/V applications.
The Objectsocket class provided by Sockets/V is a specialization of MessageSocket which allows sending Visual Smalltalk objects between Sockets/V applications.
The most commonly used paradigm in constructing distributed applications today is the client/server model. In this scheme client applications request services from a server application. This implies an asymmetry in establishing communication between the client and the server. The client and the server require a well-known set of conventions before service may be rendered (and accepted). This set of conventions compromises a protocol which must be implemented at both ends of a connection. Depending on the situation, the protocol may be symmetric or asymmetric. In a symmetric protocol, either side may play the master or slave roles. In an asymmetric protocol, one side is immutably recognized as the master, with the other as the slave. An example of a symmetric protocol is the TELNET protocol used in the Internet for remote terminal emulation. An example of an asymmetric protocol is the Internet file transfer protocol, FTP. Regardless of whether the specific protocol used in obtaining a service is symmetric or asymmetric, when accessing a service there is a "client process" and a "server process".
A server application normally listens at a well-known address for service requests. that is, the server process remains dormant until a connection is requested by a client's connection to the server's address. At such a time the server process "wakes up" ands services the client, performing whatever appropriate actions the client requests of it. While connection-based services are the norm, some services are based on the use of datagram sockets.
The Windows Sockets specification defines a network programming interface for Microsoft Windows which is based on the "socket" paradigm popularized in the Berkeley Software Distribution (BSD) from the University of California at Berkeley. It encompasses both familiar Berkeley socket style routines and a set of Windows- specific extensions designed to allow the programmer to take advantage of the message-driven nature of Windows.
Windows Sockets operates asynchronously. Sockets/V classes' behavior reflects this aspect of the Windows Sockets interface protocols. Typically, messages sent to a Socket object do not return a useful result immediately. Instead, they send a request to Windows Sockets and evaluate a block or send a message to an object when Windows Sockets has responded. This allows your application (and Windows) to perform other work while your request is being processed (perhaps elsewhere in the network).
In order to communicate with another application via TCP/IP, both parties must have an Internet address. Internet addresses are usually represented as four decimal numbers separated with periods, for example: 124.3.12.2. Internet addresses usually have a hostname associated with them which is easier to remember than the four numbers. Internet addresses and hostnames are usually assigned by a central authority in an organization to prevent conflicts.
A TCP/IP-speaking system is allowed to maintain communications with multiple remote systems at once. In order to do this without getting confused, communications is said to be performed between ports on the communicating systems. Ports are designated by decimal numbers. Like hostnames for Internet addresses, ports can be assigned service names. Here is how Sockets/V objects would depict the service personnelDb on the host named hoochie.p2.com: hoochie.p2.com:personnelDb. Alternatively, the address or port number can be substituted for the names, perhaps resulting in a designation like: 124.3.12.2:6001. A TCP/IP connection is defined at either end by the local host:service pair (which is associated with a remote host:service pair).
Hostnames and service names are often maintained in files called hosts and services, respectively. For two applications to establish communications, one application must attempt to connect to the other by specifying a port (or service) on which the other is listening. If it cannot be determined which application might attempt to connect first, then both applications may listen on a port known to the other. It is up to you to decide what port (and associated service name) you will use for your communications.
Sockets/V provides a high-level interface to Windows Sockets, hiding much of the complexity involved with handling asynchronous notification in Visual Smalltalk. Generally, applications do not need to subclass the Sockets/V classes, but simply create instances of them with which to communicate. The following sections describe setting up server and client applications using Sockets/V.
A Sockets/V server application is normally supplied with a service port name upon which to listen. Here are the steps a server application would normally perform:
An alternative to using the nested evaluation of blocks as in the above is to use the send:to: form of the MessageSocket methods to invoke other application methods.
A Sockets/V client-side application normally performs the following steps after being supplied with the server hostname and service name:
An alternative to using the nested evaluation of blocks as in the above is to use the send:to: form of the MessageSocket methods to invoke other application methods. Note also that the MessageSocket>>onMessageElement:evaluate:method can be used to dispatch based on the contents of specific fields in received messages. Note that in the application startup method (usually NotificationManager>>startUpApplication), you should send the initialize message to the global object Network to perform one-time initialization of Sockets/V internal elements.
Socket is the base class for DatagramSocket, StreamSocket, and MessageSocket. Instance methods common to the three types of sockets are provided. Class methods are provided to perform network database operations for translating host names and addresses, translating service names and ports, obtaining the local host name and address, and obtaining information about the local host Windows Sockets implementation.
Object
(none)
Pool Dictionaries:
Instances of DatagramSocket provide datagram-type communication. Datagram communication does not require that a connection be established before communication can begin as does stream-type communication. Typically, one party to the communication (the server) binds its socket to a port number known to the other parties. The other parties do not explicitly bind to a port number, but simply accept the port assigned to them by the Windows Sockets software. When the server receives data, it can obtain the address and port number of the sender to send a reply.
Datagrams are limited in size by the particular TCP/IP implementation and messages cannot be automatically divided across multiple datagrams. Datagrams are always delivered as a unit and are never combined or fragmented when delivered as stream-type messages can be. Datagrams are not guaranteed to be delivered as are stream-type communications, but this is rarely a problem in a LAN environment. Also, there is no notification provided when the partner in a datagram communications session terminates or closes its socket.
Note that arbitrary byte sequences may be sent and received using ByteArray objects instead of String objects.
Object
(none)
(none)
(none)
Stream sockets provide guaranteed sequential delivery of byte streams between communicating partners. Before stream communication can begin, one party (the server) must listen on a port known to the other party, and the other party must connect to that port. The listening party must then accept the connection. A new socket is created for the accepted connection so that the listening socket remains available to accept additional connections. Communications can then proceed between the server and client using the new server socket and the original client socket.
Termination of stream communications occurs when either party closes their socket. The other party is notified of the closing.
Note that unlike datagram-type communications, stream connections use up a socket on the listening end for each connection. TCP/IP implementations typically place a limit on the number of sockets which may be created and this limits the number of simultaneous stream connections possible.
Stream socket implementations are allowed to deliver received data in pieces different than those in which it was sent, although the bytes are required to be in the same order. Stream socket implementations may coalesce or fragment the data at will. Thus, data may not always be received in the same chunks in which it was sent as is the case with datagram-type communications. Note that the MessageSocket class provides datagram-type messages over a stream- type connection, providing the benefits of both types of socket communication.
Note that arbitrary byte sequences may be sent and received using ByteArray objects instead of String objects.
Object
(none)
(none)
LineAtATimeSocket objects provide a line-at-a-time text record service appropriate for use with Internet protocols such as FTP, SMTP, and POP3. These protocols expect messages to be delimited with carriage returns or carriage return-line feed pairs. The LineAtATimeSocket onReadEvaluate:error: method (inherited from StreamSocket) passes only complete lines to the twoArgumentBlock rather than fragments as might occur with StreamSocket. (LineAtATimeSocket also strips the lines of the delimiting CR or CR-LF characters.) This allows the application to focus on the protocol in use rather than the buffering of data until a complete record is obtained.
The write: method suffixes its argument with the result of evaluating Stream>>crString before sending it to the remote partner.
Object
(none)
(none)
(none)
(none)
(none)
MessageSocket objects provide sequenced and reliable datagram-style communications over stream-type connections. MessageSocket objects pass structured messages using NetworkMessage objects. The NetworkMessage objects are always delivered as a unit. This allows message-based communications to proceed without requiring the application developer to deal with datagram size limitations, unguaranteed delivery, and the lack of close notification as would be the case if datagram sockets were used. NetworkMessage objects allow automatic dispatching of the received message based on the content of the message. See the description of NetworkMessage for more information.
Note that MessageSockets can only be used with another application supporting MessageSockets and NetworkMessages.
Object
(none)
(none)
(none)
StringSocket objects provide a simplified MessageSocket service. StringSockets allow single strings or ByteArrays to be sent and received using a MessageSocket service without the necessity of dealing with NetworkMessages.
The StreamSocket onRead methods are used to read incoming strings.
Object
(none)
(none)
(none)
(none)
(none)
ObjectSocket objects provide a MessageSocket specialized to send and receive objects. Classes of objects to be sent must be defined in the receiving Visual Smalltalk image and must support the storeString method.
The StreamSocket onRead methods are used to read incoming objects.
Object
(none)
(none)
(none)
(none)
(none)
NetworkMessage objects provide a means of sending and receiving record- oriented structures between cooperating Sockets/V applications. NetworkMessage objects are similar to OrderedCollection objects in that they contain numbered elements. NetworkMessage objects automatically expand to accommodate the highest numbered element added. Upon receipt, the MessageSocket onMessageElement methods may be used to dispatch the received message based on the contents of any element.
NetworkMessage objects, combined with MessageSockets, provide the easiest method of transferring complex data between cooperating Sockets/V programs.
WinSockBuffer
ExternalBuffer
Object
(none)
(none)
(none)
The following error codes are contained in WinSockConstants dictionary. The text descriptions are contained in the WinSockErrorDescriptions dictionary. The WinSockErrorCodes dictionary translates the numeric codes returned by Windows Sockets to the error text shown in the first column below.
| Error Code | Description |
| WsaeAcces | The requested address is a broadcast address, but the appropriate flag was not set. |
| WsaeAddrInUse | An attempt has been made to listen on an address in use. |
| WsaeAddrNotAvail | The specified address is not available from the local machine. |
| WsaeAFNoSupport | Addresses in the specified family cannot be used with this socket. |
| WsaeAlready | The asynchronous routine being canceled has already completed. |
| WsaeConnAborted | The connection was aborted due to timeout or other failure. |
| WsaeConnRefused | The attempt to connect was forcefully rejected. |
| WsaeConnReset | The connection was reset by the remote side. |
| WsaeDestAddrReq | A destination address is required. |
| WsaeFault | The optlen argument was invalid. |
| WsaeInProgress | A blocking Windows Sockets call is in progress. |
| WsaeIntr | The call was canceled. |
| WsaeInval | The socket is already bound to an address. |
| WsaeIsConn | The socket is already connected. |
| WsaeMFile | No more file descriptors are available. |
| WsaeMsgSize | The datagram was too large to fit into the specified buffer and was truncated. |
| WsaeNetDown | The Windows Sockets implementation as detected that the network subsystem has failed. |
| WsaeNetReset | The connection must be reset because the Windows Sockets implementation dropped it. |
| WsaeNetUnreach | The network can't be reached from this host at this time. |
| WsaeNoBufs | No/insufficient buffer space is available |
| WsaeNoProtoOpt | The option is unknown or unsupported. In particular, SO_BROADCAST is not supported on sockets of type SOCK_STREAM, while SO_ACCEPTCONN, SO_DONTLINGER, SO_KEEPALIVE, SO_LINGER and SO_OOBINLINE are not supported on sockets of type SOCK_DGRAM. |
| WsaeNotConn | The socket is not connected. |
| WsaeNotSock | The descriptor is not a socket. |
| WsaeOpNotSupp | The specified operatin is not supported by the socket. |
| WsaeOpNotSupp | The referenced socket is not a type that supports connection-oriented service. |
| WsaeProtoType | The specified protocol is the wrong type for this socket. |
| WsaeShutdown | The socket has been shutdown. |
| WsaeSocktNoSupport | The specified socket type is not supported in this address family. |
| WsaeTimedOut | Attempt to connect timed out without establishing a connection |
| WsaeWouldBlock | The asynchronous operation cannot be scheduled at this time due to resource or other constraints. |
| WsaHostNotFound | Authoritative Answer Host not found. |
| WsaNoData | Valid name, no data record of requested type. |
| WsaNoRecovery | Non recoverable errors, FORMERR, REFUSED, NOTIMP. |
| WsaNotInitialised | A successful Socket startup or Socket startupShowInfo must occur before using this API. |
| WsaSysNotReady | Indicates that the underlying network subsystem is not ready for network communication. |
| WsaTryAgain | Non-Authoritative Host not found, or SERVERFAIL. |
| WsaVerNotSupported | The version of Windows Sockets API support requested is not provided by this particular Windows Sockets implementation. |
The following files may be used to develop programs using Sockets/V, but must not, under the terms of your license, be distributed with programs you develop with Sockets/V.
The following files are included with Sockets/V to aid you in developing your programs. You may incorporate portions of these sample programs in your programs, but you may not distribute the sample programs themselves.
The following files are required to both develop and execute programs developed with Sockets/V. These files may be distributed with programs you develop with Sockets/V.
SOCKETSV.SLL
Sockets/V includes all source code. See the text file ORDER.FRM for ordering details.
There are no run-time fees for applications developed with Sockets/V. The run-time SLL's may be distributed freely with your applications.
P1 Systems Incorporated provides 90 days of free technical support via voicemail, FAX, BBS, Internet mail and CompuServe mail. Guarantee: Sockets/V may be returned for a full refund for any reason within 90 days if you are not fully satisfied. VISA, MasterCard, and corporate purchase orders accepted.
Sockets/V for Visual Smalltalk 3.0 Win32
Sockets/V for Smalltalk/V 2.0 Win32
Sockets/V for Smalltalk/V for Windows
PARTSNet for PARTS Win32
PARTSNet for Visual Smalltalk Win32
Network parts including NetInfo, NetIF, and NetEvent. Allows network programming without coding! NetInfo part for general network information, NetIF part for sending/receiving messages, NetEvent part for triggering events in remote applications (allows emulating a remote part's interface). Network parts allow passing objects such as sets, dictionaries, etc. between applications in addition to Strings and ByteArrays.
Sockets/V is available from
P1 Systems Incorporated PMB 320, 1315 Madison Street, Seattle, WA 98104-3512 VoiceMail: +1 206 374-2475 FAX: +1 206 374-2475 Internet: info@p1.com
This is a legal agreement between you, the end user, and P1 Systems Incorporated (P1). Having installed the software on your computer, you have agreed to be bound by the terms of this Agreement. If you do not agree to the terms of this Agreement, do not install the software and promptly return the software and the accompanying items (including written materials and other containers) to the place you obtained them for a full refund.
Grant of License. P1 grants you (i) a non-exclusive, nontransferrable license to use one copy of the enclosed P1 software program (the "Software") on a single computer for your personal use on the understanding that a single person uses each copy, and (ii) a non-exclusive, nontransferable license to use one copy of the related written materials enclosed ("Documentation"). Purchasers of the Software are therefore licensed to use it themselves on one computer at a time, and to make a single backup copy for their own use. No other license is given. In particular, the Software may not be installed on a computer network for use by more than one person. The Software may not be rented or leased to others, and the conditions of this sale apply to the purchaser in any resale.
Limited Warranty. P1 Systems Incorporated (P1) warrants the enclosed diskettes and documentation to be free of defects in materials and workmanship for 90 days from the date of purchase. Defective products returned to P1 during this period will be replaced without charge and are subject to the original warranty. Furnishing such replacements is P1's only obligation under the terms of this sale.
Although P1 has made all efforts to ensure that the Software performs as stated in the Documentation, no representation is made and no guarantee is given regarding the Software's merchantability, performance, or its fitness for any purpose. It is sold as-is and purchasers assume all risks regarding its suitability for their purposes.
P1 is not liable for any loss of profit or other commercial damages, including but not limited to, special, incidental, consequential or other damages, including loss of data, resulting from the use of the Software.
This is the sole and exclusive statement of P1's warranty, and no one is authorized to alter it in any way either orally or in writing.
Copyright. The Software and Documentation are owned by P1 and are protected by US and International copyright laws. You may not copy the Software or Documentation, except that you may make one copy of the Software solely for backup or archival purposes. No part of the Documentation may be reproduced or transmitted in any form or by any means, electronic or mechanical, including but not limited to photocopying, without prior written permission from P1. Copying or duplicating the Documentation or any part thereof is a violation of the law.
Runtime Rights and Limitations. You have a royalty-free right to reproduce and distribute executable files created by using the Software that include the runtime environment portions of the Software (the "Runtime Files") which are identified in the Documentation as being required to execute programs. The executable you distribute must not contain any part of the development environment portions of the Software (the "Development Files") which are identified in the Documentation as being required to develop programs using the Software. You may not distribute any portion of the source code of the Software. You may not distribute executable files whose functionality is similar to that of the Software.
Governing Law. This Agreement shall be governed and construed under the laws of the State of California and subject to the exclusive jurisdiction of the courts therein.
Entire Agreement. You agree that this Agreement expresses the entire understanding between you and P1 and superscedes all other communications, oral or written, relating to the Software.