•  Back 
  •  System Services Protocol (SSP) 
  •  Index 
  •  Tree View 
  •  Cross references 
  •  Help page 
  •  Show info about hypertext 
  •  View a new file 
Topic       : TOS - das Betriebssystem
Author      : 
Version     : tos.hyp (5. März 2013)
Subject     : Programmieren/Atari
Nodes       : 3001
Index Size  : 93602
HCP-Version : 5
Compiled on : Atari
@charset    : atarist
@lang       : 
@default    : Titel
@help       : 
@options    : +g -i -s +x +zz -t4
@width      : 70
View Ref-File15.10.10  How to implement an SRA                                  TOS

Here's a step-by-step instruction on how to implement SSP as a Service 
Requesting application. All code provided here is also available as 
sample code in the archive in the file SRAtools.c (SRAtools.gfa for 
GFABasic, SRAtools.s for assembler). Use and modify as necessary :)

The data identification

An important thing is that the SRA does not really request or 
distinguish between specific services. The SRA rather determines a 
dataID depending on the user action, and the type of object the user 
action leading to the use of system services was performed on, and 
sends this dataID to the Server. The Server will then figure out which 
services can be used with the provided data. This makes it possible to 
implement new services into the SSP-Server using the same data-types 
without changing the SRAs.

Communication Session

A second concept that should be understood is the use of sessions. A 
session between an SRA and the Server is started with the SSP_SRASR 
message, and ended when the SRA receives SSP_SSA. The Server can 
handle multiple sessions for one SRA and multiple SRAs at a time (up 
to 32 sessions per SRA at a time, and 32 different SRAs at a time, 
that's 1024 parallel SRA sessions, meaning the use of 1024 service 
requests at a time, max).

Every session is usually bound to a certain shared memory block that 
contains the data necessary for the session. One SRA session always 
refers to one service request. For this, it is necessary also that the 
SRA can distinguish between different sessions. Every session has an 
ID number, which also makes up the last characters of the shared 
memory filename (shmID passed in SSP_SRASR).

Multiple sessions from your application at a time can occur for 
example like this:

   ∙ AtarIRC as SRA of Status Display Service sends SSP_SRASR with 
     dataID SSP_STATUSICON to change the status display, due to 
     starting a dcc download from a user

   ∙ Before the Server acknowledges with SSP_SSA, the user starts a 
     dcc send to another user; a second SSP_SRASR message is sent, 
     opening a second session and hence providing a second shared 
     memory block and the corresponding file in u:/shm/

To implement this, a simple 32-bit bit-vector can be used to determine 
if a session is active or not. Each bit represents a possible session. 
Before starting a session (before sending SSP_SRASR), check the bits 
from 0 to 31. If a bit is not set, another session can be opened. Set 
the bit and use the index of the bit as the session ID (shmID). This 
code uses the global 32-bit integer sessionVector as the indicator for 
active sessions, and returns the next inactive session number, or -1, 
if all possible 32 sessions are active:

long sessionVector;

int determineSessionID(void){

  int idCounter, noMoreSessions=1;

  for(idCounter=0; idCounter
    if( (sessionVector&(1<&ltidCounter)==0 ){

      sessionVector |= (1<<idCounter);
      noMoreSessions = 0;
      break;
    }
  }
  if(noMoreSessions) return(-1);
  else return (idCounter);

}

1. Finding the Server

The SRA has to find the Server's appl_id in order to send messages. Do 
this at program startup and store the application id of the Server for 
later use. This is done basically the same way it is in OLGA:

   ∙ Read environment variable SSP_SERVERNAME to retrieve the Server 
     application name

   ∙ Use appl_find to determine the Server's appl_id

   ∙ If the Server can't be found:

        - Read environment variable SSP_SERVERPATH to retrieve the 
          Server application's path and filename

        - Start Server with shel_write

        - Read environment variable SSP_SERVERNAME to retrieve the 
          Server application name

        - Use appl_find to determine the Server's appl_id

        - If the Server application is not in the specified path or if 
          starting fails:

             * output an understandable error message to the user, 
               possibly referring to a chapter in your application's 
               documentation

             * continue starting your application, not using SSP SSP 
               is an addition to the system, unavailability should not 
               interfer with your application's usual behaviour, 
               except your application explicitly requires SSP to work 
               (complete applications of different kinds that 
               basically consist of an SSP SRA client are possible).

2. Using a service

2.1 Determining the data-type

To use a service, the SSP_SRASR AES message has to be sent to the 
Server. Before sending the message, determine the data-type used. For 
example, if a block has been selected in an editor and the user wants 
to use SSP by right clicking and choosing System Services from the 
context menu, or from the editor's menu bar, the data-type (referred 
to as dataID) is SSP_TEXT. If for example an image file or MP3 is to 
be handled via SSP, the data-type should be SSP_FILENAME.

For the Status Display Service, the data-type has to be 
SSP_STATUSICON. This service should be initialized automatically, 
without user interaction, after the Server has been started, at 
program startup. See also 'Data identification' for SSP_SRASR for 
short explanations of the data-types and the corresponding data in the 
shared memory block.

2.2 Requesting a service

2.2.1 Creating shared memory file

Data is sent in a shared memory file. Whether one has to be created or 
not depends on the dataID (thus on the service type). There is a 
unique ID for every shm-file used for each service request, and the 
name of the file is built by the following conventions: 
u:/shm/[appl_id]_data[shmID].ssp For example if Smurf with appl_id 25 
is sending a file and chose ID 0: u:/shm/25_data0.ssp

The shared memory ID is vital to the Server, because it is used to 
distinguish between different service requests and SRA communication 
sessions that are 'alive' at the same time. A session is 'alive' 
between the sending of SSP_SRASR and receiving SSP_SSA. For example, 
the user could make your application request Send File Service, while 
you haven't gotten the SSP_SSA response for the SSP_STATUSICON 
request. This would make you open a second session, and a second 
shared memory file, while the session for the status display is still 
alive.

There are two different ways to handle this: 1. Wait until the SSP_SSA 
response for one request has come in before sending the second request

2. Keep track of sent requests and received responses. Make an array, 
the index being the number of the request sent (which can be the shmID 
as well), and set the array value to 1 if a request has been sent. If 
SSP_SSA comes in, set the referring array value to 0. Use only indices 
(shmIDs) if the array value is 0.

The second way is recommended.

After you have built the name for the shared memory file, use Fcreate 
to create the file. Read/Write access rights have to be set correctly, 
depending on the request type!

Then, bind the memory block that contains the data (text, filename, 
icon data, etc., depending on dataID) to the file using Fcntl. Close 
the file with Fclose. The following code calls the above routine 
detemineSessionID, uses the returned ID to build the filename and 
creates the file. The function openSession takes two parameters: 
access describes the access rights to the memory block, and *memPtr is 
a pointer to the memory block to share. buildFilename takes a 
determined session ID as parameter, builds a filename from it and 
returns a pointer to the static string containing the filename. 
buildFileName assumes appl_id being the SRA's (your) application ID 
available as a global variable!

int openSession(int access, void *memPtr)
{
  int fHandle;
  int sessionID = determineSessionID();
  char *filename = buildFileName(sessionID);

  fHandle = Fcreate(filename, access);
  Fcntl(fHandle, memPtr, SHMSETBLK);

  return(sessionID);
}

char *buildFilename(int sessionID)
{
  static char filename[256] = "u:/shm/";
  char tmpstring[4];

  strcat(&filename, itoa(appl_id, tmpstring, 10));
  strcat(&filename, "_data");
  strcat(&filename, itoa(sessionID, tmpstring, 10));
  strcat(&filename, ".ssp");

  return(&filename);
}

The return value of openSession is the new sessionID which can be used 
to pass to the Server in the service request. The filename could also 
be stored, but that's not really necessary because the Server passes 
the shmID that it received from the SRA back to it, in the SSP_SSA 
acknowledge message, so the filename can be built again to delete the 
file.

2.2.2 Sending a Service Request

Send an SSP_SRASR message to the Server, filling the AES message- 
buffer with the following values:

    [0] = SSP_SRASR
    [1] = appl_id
    [2][3] = (long)dataLen
    [4] = dataID
    [5] = shmID

appl_id (messagebuf[1])
This is your appl_id. Make sure to fill this correctly, because the 
Server will distinguish different SRA-communication sessions by the 
application IDs of the SRAs.

dataLen (messagebuf[2]/[3])
The length of the data to transfer (32 bit!). For example the length 
of the string to send if dataID is SSP_TEXT or SSP_FILENAME, or the 
length of the icon data in the SSP_STATUSICON case.
messagebuf[2] holds the upper 16 bits, [3] the lower 16 bits:
messagebuf[2] = (int)(dataLen>>16);
messagebuf[3] = (int)(dataLen&0xFFFF);

dataID (messagebuf[3])
The identification value of the data you determined, for the Server to 
find out which services can be possibly used.

shmID (messagebuf[4])
The identification number for the shared memory block (your session 
ID). This is absolutely necessary for the Server to distinguish 
different sessions with one SRA.

If the Server is in debug mode (environment variable SSP_SERVERDEBUG 
is defined), it will print out all information received from the SRA 
in an understandable form into a window, and write it to a logfile 
sspdebug.log in the same directory the Server application is in. It 
will post error-messages and possible suggestions on how to fix the 
error in both the window and the log file.

3. Closing a session on SSP_SSA

When your application receives SSP_SSA, this means that a service has 
been performed (DRS), or has been started to be performed (IRS).

messagebuf[1] will contain the shmID you passed to the Server in 
SSP_SRASR. This makes it possible for you to find out which session 
the response is for. Build a filename like in 2.2.1 (or store the 
filename when sending SSP_SRASR) and delete the shared memory file, 
free all temporary memory you have possibly allocated for the service 
request, and you're done. The following code uses the above function 
buildFilename and the sessionID from messagebuf[1] as a parameter to 
build a filename, delete the shm-file, and clear the bit of the 
session in the global sessionVector variable:

int closeSession(int sessionID){

  char *fileName = buildFilename(sessionID);
  return Fdelete(fileName);
  sessionVector &= ~(1-sessionID);

}

Don't forget to free temporary memory that you might have allocated to 
compose the data. You could also store the memory pointer for each 
session in an array of pointers and implement the Mfree/free into the 
closeSession function. NULL pointers in the array could indicate that 
no temporary buffer was allocated (e.g. when you share your internal 
buffers for filenames, text or other data, directly). This could be 
done by adding a parameter tmpFlag to the openSession function that 
indicates if memPtr is a temporary buffer. openSession could then 
automatically insert memPtr or NULL at the appropriate position in a 
global array, one entry for every session, with sessionID as the 
index. closeSession could then get the pointer from the array at the 
index of its parameter sessionID and perform @{"Mfree" ignore} on the 
pointer, if it's not NULL. This would automate and connect the 
processes of opening and closing sessions internally, creating and 
deleting shared memory files, and freeing possible temporary buffers.

4. The different dataIDs and their impact on sessions

4.1 SSP_STATUSICON request and the Status Display Service

The dataIDs have an influence on how a session and service is handled 
internally. For SSP_TEXT and SSP_FILENAME, you don't have to worry 
about it, just go by the above scheme. For SSP_STATUSICON however, 
there is a twist. The status icon will be displayed by all 
applications that are switched on for Status Display Service. The 
service is invisible, meaning it won't be triggered by a user action 
rather than automatically, on program startup and anytime the status 
of your program changes. When that happens, and you want to display a 
different status icon, you have to send another request with 
SSP_STATUSICON as dataID. All 'on' applications for Status Display 
Service will then update the icon they display for your application's 
status.

When you exit your application and have sent a service request with 
SSP_STATUSICON, you have to inform the Server that your status icon is 
to be removed from all displaying applications! Implement a service 
request with the dataID SSP_ENDSDS into the exit code of your 
application. The Server will then inform all applications that display 
your status icon that the icon has to be removed.

A nice idea would be to display the download status of internet 
applications in the status icon, by making the icon a 16 pixel high or 
wide progress bar. Update the status icon every time enough data has 
been downloaded to fill another pixel line of the progress bar, and 
there you go. Memory could be saved, if necessary, by updating the 
icon data dynamically instead of including a separate icon for every 
progress bar phase.

4.2 Requesting SSP_STATUSICON will make your SRA an SPA

Applications that provide Status Display Service will usually be able 
to request the SSP_DISPLAYINFO and SSP_CONTEXTPOPUP services. This 
means that if you request service with SSP_STATUSICON as dataID, you 
will probably receive a request for SSP_DISPLAYINFO or 
SSP_CONTEXTPOPUP at some point! Look at How to implement an SPA on how 
to provide the Display Information and Context Popup services.

4.3 The icon data

The icon data has to be put into the shm-block as follows:

  mono_icon1 monomask1
  [16col_icon1 16colmask1]
  [256col_icon1 256colmask1]
  [CRLF]
  [mono_icon2 monomask2]
  [16col_icon2 16colmask2]
  [256col_icon2 256colmask2]
  NULL

Entries in [] are optional. That means the SRA has to send at least 
one monochrome status icon and its mask. The application providing the 
status display will pick the icon best for the current screen colour 
depth. The mask data directly follows the icon data without any 
separation! The spaces above are just for readability. All mask data 
is 1 bit, as provided by the GEM ICNBLK and CICNBLK structures. The 
xx_icon2 data blocks are optional second icons for animation. The SPA 
will read, if provided, both icon data blocks for the current screen 
mode and switch in 1 second intervals between the 2 icon blocks. This 
is useful to make status changes noticeable. To make the 'blinking' 
animation stop, send another service request with SSP_STATUSICON and 
only the xx_icon1 icon data. Blinking should be done for no longer 
than 8 seconds, after that the second status display request should be 
performed by your application to switch to a static icon. The data 
should be in the regular screen format, meaning you should incorporate 
possible status icons in your application's resource file, and copy 
the raw graphics data from the icon objects into the memory block that 
will be shared, one after another, and terminate with a NULL byte. The 
icons must have 16x16 pixel dimensions. A good approach would be to 
have the status icons in every available colour depth in the above 
format ready in each a memory block, to be able to request the service 
without having to copy around icon data. That makes the interactions 
between SRA and SPA quicker and saves the hassle of building memory 
blocks before every request. Memory saving is not really an issue 
here, as one icon in all 3 colour depths uses just 512 bytes, so even 
keeping 20 different icons in all 3 colour depths, and their 2-phase 
animated pendants, in memory, would only cost 30 kBytes. This can be 
reduced to 20 kBytes by just keeping the 2-phase versions in memory 
and inserting NULL or CRLF at the middle position to switch between 
animated and static versions. Usually it will be less, because 256- 
colour icons will rarely be needed at 16x16 pixels size. And, which 
application really has 20 different statii?

5. Guidelines for implementing SPAs

   ∙ Make your icons for the Status Display Service distinguishable 
     (so people can see it is this specific application's status icon) 
     and recognizeable (so the user doesn't have to wonder 'what the 
     heck is that supposed to be?').

   ∙ Use status icons intelligent and carefully. There is no point in 
     displaying a different status for an operation that only takes 
     1/10 second.

   ∙ The SSP protocol is rather easy to implement on SRA side. Try to 
     make the implementation as transparent to the user as possible, 
     without the user noticing much of the different applications and 
     processes involved.

   ∙ Request invisible services like Status Display really invisible, 
     without any direct output to or input from the user.

   ∙ After implementing SSP, switch the server into debug mode and try 
     requesting different services with different data types. If 
     everything works and the server outputs no error or warning 
     messages, your implementation is OK.

   ∙ Remember, the user doesn't care much about how it works, only 
     that it works.