Example #1
3
func UnixAudienceListener(sockaddr string) {
	fi, err := os.Stat(sockaddr)
	if err == nil {
		fmode := fi.Mode()
		if fmode&os.ModeType == os.ModeSocket {
			o.Warn("Removing stale socket at %s", sockaddr)
			os.Remove(sockaddr)
		} else {
			o.Fail("%s exists and is not a socket", sockaddr)
		}
	}
	laddr, err := net.ResolveUnixAddr("unix", sockaddr)
	o.MightFail(err, "Couldn't resolve audience socket address")
	l, err := net.ListenUnix("unix", laddr)
	o.MightFail(err, "Couldn't start audience unixsock listener")
	// Fudge the permissions on the unixsock!
	fi, err = os.Stat(sockaddr)
	if err == nil {
		os.Chmod(sockaddr, fi.Mode()|0777)
	} else {
		o.Warn("Couldn't fudge permission on audience socket: %s", err)
	}

	// make sure we clean up the unix socket when we die.
	defer l.Close()
	defer os.Remove(sockaddr)
	AudienceListener(l)
}
Example #2
0
func loadLastId() {
	fh, err := os.Open(checkpointPath())
	if err == nil {
		defer fh.Close()

		// we have a checkpoint file.  blah.
		cbio := bufio.NewReader(fh)
		l, err := cbio.ReadString('\n')
		lastId, err = strconv.ParseUint(strings.TrimSpace(l), 10, 64)
		if err != nil {
			o.Fail("Couldn't read last ID from checkpoint file")
		}
		lastId += IdCheckpointSafetySkip
	} else {
		if !os.IsNotExist(err) {
			o.Fail("Found checkpoint file, but couldn't open it: %s", err)
		}
		fh, err := os.Open(savePath())
		if err != nil {
			if os.IsNotExist(err) {
				lastId = 0
				return
			}
			o.MightFail(err, "Couldn't open last_id file")
		}
		defer fh.Close()
		cbio := bufio.NewReader(fh)
		l, err := cbio.ReadString('\n')
		lastId, err = strconv.ParseUint(strings.TrimSpace(l), 10, 64)
		if err != nil {
			o.Fail("Couldn't read last ID from last_id")
		}
	}
	writeIdCheckpoint()
}
Example #3
0
func UnixAudienceListener(sockaddr string, sockmode os.FileMode, sockuid int, sockgid int) {
	fi, err := os.Stat(sockaddr)
	if err == nil {
		if (fi.Mode() & os.ModeSocket) != 0 {
			os.Remove(sockaddr)
		} else {
			o.Fail("%s exists and is not a socket", sockaddr)
		}
	}
	err = os.MkdirAll(path.Dir(sockaddr), 0755)
	o.MightFail(err, "Couldn't create socket directory")
	laddr, err := net.ResolveUnixAddr("unix", sockaddr)
	o.MightFail(err, "Couldn't resolve audience socket address")
	old_umask := syscall.Umask(0777)
	defer syscall.Umask(old_umask)
	l, err := net.ListenUnix("unix", laddr)
	o.MightFail(err, "Couldn't start audience unixsock listener")
	if sockuid >= 0 || sockgid >= 0 {
		err = os.Chown(sockaddr, sockuid, sockgid)
		o.MightFail(err, "Couldn't chown audience unixsock listener")
	}
	err = os.Chmod(sockaddr, sockmode)
	o.MightFail(err, "Couldn't chmod audience unixsock listener")

	// make sure we clean up the unix socket when we die.
	defer l.Close()
	defer os.Remove(sockaddr)
	AudienceListener(l)
}
Example #4
0
func ConfigLoad() {
	// attempt to open the configuration file.
	fh, err := os.Open(*ConfigFile)
	if nil == err {
		defer fh.Close()
		// reset the config File data, then reload it.
		configFile.Reset()
		ierr := configFile.Read(fh, 1)
		o.MightFail(ierr, "Couldn't parse configuration")
	} else {
		o.Warn("Couldn't open configuration file: %s.  Proceeding anyway.", err)
	}

	playerpath := strings.TrimSpace(GetStringOpt("player file path"))
	pfh, err := os.Open(playerpath)
	o.MightFail(err, "Couldn't open \"%s\"", playerpath)

	pbr := bufio.NewReader(pfh)

	ahmap := make(map[string]bool)
	for err = nil; err == nil; {
		var lb []byte
		var prefix bool

		lb, prefix, err = pbr.ReadLine()

		if nil == lb {
			break
		}
		if prefix {
			o.Fail("ConfigLoad: Short Read (prefix only)!")
		}

		line := strings.TrimSpace(string(lb))
		if line == "" {
			continue
		}
		if line[0] == '#' {
			continue
		}
		ahmap[line] = true
	}
	// convert newAuthorisedHosts to a slice
	authorisedHosts := make([]string, len(ahmap))
	idx := 0
	for k, _ := range ahmap {
		authorisedHosts[idx] = k
		idx++
	}
	ClientUpdateKnown(authorisedHosts)

	// set the spool directory
	SetSpoolDirectory(GetStringOpt("conductor state path"))
}
Example #5
0
func ProcessingLoop() {
	var conn net.Conn = nil
	var nextRetryResp *TaskResponse = nil
	var taskCompletionChan <-chan *TaskResponse = nil
	var connectDelay time.Duration
	var doScoreReload bool = false
	// kick off a new connection attempt.
	go connectMe(connectDelay)

	// and this is where we spin!
	for {
		var retryDelay time.Duration = 0
		var retryChan <-chan time.Time = nil

		if conn != nil {
			for nextRetryResp == nil {
				nextRetryResp = getNextUnacknowledgedResponse()
				if nil == nextRetryResp {
					break
				}
				retryDelay = nextRetryResp.RetryTime.Sub(time.Now())
				if retryDelay < 0 {
					sendResponse(conn, nextRetryResp)
					nextRetryResp = nil
				}
			}
			if nextRetryResp != nil {
				retryChan = time.After(retryDelay)
			}
		}
		if taskCompletionChan == nil {
			nextTask := getNextPendingTask()
			if nextTask != nil {
				taskCompletionChan = ExecuteTask(nextTask)
			} else {
				if conn != nil && !pendingTaskRequest {
					o.Debug("Asking for trouble")
					p := o.MakeReadyForTask()
					p.Send(conn)
					o.Debug("Sent Request for trouble")
					pendingTaskRequest = true
				}
			}
		}
		select {
		// Currently executing job finishes.
		case newresp := <-taskCompletionChan:
			o.Debug("job%d: Completed with State %s\n", newresp.id, newresp.State)
			// preemptively set a retrytime.
			newresp.RetryTime = time.Now()
			// ENOCONN - sub it in as our next retryresponse, and prepend the old one onto the queue.
			if nil == conn {
				if nil != nextRetryResp {
					prequeueResponse(nextRetryResp)
				}
				o.Debug("job%d: Queuing Initial Response", newresp.id)
				nextRetryResp = newresp
			} else {
				o.Debug("job%d: Sending Initial Response", newresp.id)
				sendResponse(conn, newresp)
			}
			if doScoreReload {
				o.Info("Performing Deferred score reload")
				LoadScores()
				doScoreReload = false
			}
			taskCompletionChan = nil
		// If the current unacknowledged response needs a retry, send it.
		case <-retryChan:
			sendResponse(conn, nextRetryResp)
			nextRetryResp = nil
		// New connection.  Set up the receiver thread and Introduce ourselves.
		case nci := <-newConnection:
			if conn != nil {
				conn.Close()
			}
			conn = nci.conn
			connectDelay = nci.timeout
			pendingTaskRequest = false

			// start the reader
			go Reader(conn)

			/* Introduce ourself */
			p := o.MakeIdentifyClient(LocalHostname, PlayerVersion)
			p.Send(conn)
		// Lost connection.  Shut downt he connection.
		case <-lostConnection:
			o.Warn("Lost Connection to Master")
			conn.Close()
			conn = nil
			// restart the connection attempts
			go connectMe(connectDelay)
		// Message received from master.  Decode and action.
		case p := <-receivedMessage:
			// because the message could possibly be an ACK, push the next retry response back into the queue so acknowledge can find it.
			if nil != nextRetryResp {
				prequeueResponse(nextRetryResp)
				nextRetryResp = nil
			}
			var upkt interface{} = nil
			if p.Length > 0 {
				var err error
				upkt, err = p.Decode()
				o.MightFail(err, "Couldn't decode packet from master")
			}
			handler, exists := dispatcher[p.Type]
			if exists {
				connectDelay = 0
				handler(conn, upkt)
			} else {
				o.Fail("Unhandled Pkt Type %d", p.Type)
			}
		// Reload scores
		case <-reloadScores:
			// fortunately this is actually completely safe as
			// long as nobody's currently executing.
			// who'd have thunk it?
			if taskCompletionChan == nil {
				o.Info("Reloading scores")
				LoadScores()
			} else {
				o.Info("Deferring score reload (execution in progress)")
				doScoreReload = true
			}
		// Keepalive delay expired.  Send Nop.
		case <-time.After(KeepaliveDelay):
			if conn == nil {
				break
			}
			o.Debug("Sending NOP")
			p := o.MakeNop()
			p.Send(conn)
		}
	}
}
Example #6
0
func handleIllegal(c net.Conn, message interface{}) {
	o.Fail("Got Illegal Message")
}
Example #7
0
	/* C->P only messages, should never appear on the wire. */
	o.TypeTaskRequest: handleIllegal,
}

var loopFudge time.Duration = 10 * time.Millisecond /* 10 ms should be enough fudgefactor */
func clientLogic(client *ClientInfo) {
	loop := true
	for loop {
		var retryWait <-chan time.Time
		var retryTask *TaskRequest
		if client.Player != "" {
			var waitTime, now time.Time
			cleanPass := false
			attempts := 0
			for !cleanPass && attempts < 10 {
				/* reset our state for the pass */
				waitTime = time.Time{}
				retryTask = nil
				attempts++
				cleanPass = true
				now = time.Now().Add(loopFudge)
				// if the client is correctly associated,
				// evaluate all jobs for outstanding retries,
				// and work out when our next retry is due.
				for _, v := range client.pendingTasks {
					if v.RetryTime.Before(now) {
						client.SendTask(v)
						cleanPass = false
					} else {
						if waitTime == (time.Time{}) || v.RetryTime.Before(waitTime) {
							retryTask = v
							waitTime = v.RetryTime
						}
					}
				}
			}
			if attempts > 10 {
				o.Fail("Couldn't find next timeout without restarting excessively")
			}
			if retryTask != nil {
				retryWait = time.After(waitTime.Sub(time.Now()))
			}
		}
		select {
		case <-retryWait:
			client.SendTask(retryTask)
		case p := <-client.PktInQ:
			/* we've received a packet.  do something with it. */
			if client.Player == "" && p.Type != o.TypeIdentifyClient {
				o.Warn("Client %s: didn't identify self,- got type %d instead", client.Name(), p.Type)
				client.Abort()
				break
			}
			var upkt interface{}
			if p.Length > 0 {
				var err error

				upkt, err = p.Decode()
				if err != nil {
					o.Warn("Client %s: error unmarshalling message: %s", client.Name(), err)
					client.Abort()
					break
				}
			}
			handler, exists := dispatcher[p.Type]
			if exists {
				handler(client, upkt)
			} else {
				o.Warn("Client %s: Unhandled packet type: %d", client.Name(), p.Type)
			}
		case p := <-client.PktOutQ:
			if p != nil {
				client.sendNow(p)
			}
		case t := <-client.TaskQ:
			client.GotTask(t)
		case <-client.abortQ:
			loop = false
		case <-time.After(KeepaliveDelay):
			p := o.MakeNop()
			_, err := p.Send(client.connection)
			if err != nil {
				o.Warn("Client %s: error sending packet: %s", client.Name(), err)
				client.Abort()
			}
		}
	}
	client.connection.Close()
}
Example #8
0
func handleIllegal(c net.Conn, message interface{}) {
	o.Fail("Received illegal message")
}
Example #9
0
func handleAudienceRequest(c net.Conn) {
	defer c.Close()

	c.SetTimeout(0)
	r, _ := c.(io.Reader)
	w, _ := c.(io.Writer)
	dec := json.NewDecoder(r)
	enc := json.NewEncoder(w)

	outobj := new(GenericJsonRequest)
	err := dec.Decode(outobj)
	if err != nil {
		o.Warn("Error decoding JSON talking to audience: %s", err)
		return
	}

	if nil == outobj.Op {
		o.Warn("Malformed JSON message talking to audience.  Missing Op")
		return
	}
	switch *(outobj.Op) {
	case "status":
		if nil == outobj.Id {
			o.Warn("Malformed Status message talking to audience. Missing Job ID")
			return
		}
		job := o.JobGet(*outobj.Id)
		jresp := new([2]interface{})
		if nil != job {
			jresp[0] = "OK"
			iresp := NewJsonStatusResponse()
			switch job.State {
			case o.JOB_PENDING:
				iresp.Status = "PENDING"
			case o.JOB_SUCCESSFUL:
				iresp.Status = "OK"
			case o.JOB_FAILED_PARTIAL:
				iresp.Status = "PARTIAL_FAIL"
			case o.JOB_FAILED:
				iresp.Status = "FAIL"
			default:
				o.Fail("Blargh.  %d is an unknown job state!", job.State)
			}
			resnames := o.JobGetResultNames(*outobj.Id)
			for i := range resnames {
				tr := o.JobGetResult(*outobj.Id, resnames[i])
				if nil != tr {
					presp := NewJsonPlayerStatus()
					switch tr.State {
					case o.RESP_RUNNING:
						presp.Status = "PENDING"
					case o.RESP_FINISHED:
						presp.Status = "OK"
					case o.RESP_FAILED:
						presp.Status = "FAIL"
					case o.RESP_FAILED_UNKNOWN_SCORE:
						presp.Status = "UNK_SCORE"
					case o.RESP_FAILED_HOST_ERROR:
						presp.Status = "HOST_ERROR"
					case o.RESP_FAILED_UNKNOWN:
						presp.Status = "UNKNOWN_FAILURE"
					}
					for k, v := range tr.Response {
						presp.Response[k] = v
					}
					iresp.Players[resnames[i]] = presp
				}

			}
			jresp[1] = iresp
		} else {
			jresp[0] = "Error"
			jresp[1] = nil
		}
		enc.Encode(jresp)
		o.Debug("Status...")
	case "queue":
		if nil == outobj.Score {
			o.Warn("Malformed Queue message talking to audience. Missing Score")
			sendQueueFailureResponse("Missing Score", enc)
			return
		}
		if nil == outobj.Scope {
			o.Warn("Malformed Queue message talking to audience. Missing Scope")
			sendQueueFailureResponse("Missing Scope", enc)
			return
		}
		if nil == outobj.Players || len(outobj.Players) < 1 {
			o.Warn("Malformed Queue message talking to audience. Missing Players")
			sendQueueFailureResponse("Missing Players", enc)
			return
		}
		for _, player := range outobj.Players {
			if !HostAuthorised(player) {
				o.Warn("Malformed Queue message - unknown player %s specified.", player)
				sendQueueFailureResponse("Invalid Player", enc)
				return
			}
		}
		job := NewRequest()
		job.Score = *outobj.Score
		switch *outobj.Scope {
		case "one":
			job.Scope = o.SCOPE_ONEOF
		case "all":
			job.Scope = o.SCOPE_ALLOF
		default:
			sendQueueFailureResponse("Invalid Scope", enc)
			return
		}
		job.Players = outobj.Players
		job.Params = outobj.Params

		QueueJob(job)
		sendQueueSuccessResponse(job, enc)
	default:
		o.Warn("Unknown operation talking to audience: \"%s\"", *(outobj.Op))
		return
	}

	_ = enc
}